aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngenic <ftp.ingenic.cn/3sw/01linux/02kernel/linux-2.6.31>2020-10-30 01:27:32 +0100
committerLubomir Rintel <lkundrak@v3.sk>2020-10-30 01:46:12 +0100
commit18dcc300098ed8517d46b3e4b01f79d5b1bb2acc (patch)
treeb613d856a50f3dc27fa1163470c79572e2eb2e01
parent8adec3b28d288381d5e001dbb49b908c132b2909 (diff)
downloadlinux-jz47xx-18dcc300098ed8517d46b3e4b01f79d5b1bb2acc.tar.gz
linux-2.6.31.3-20100304.patch.bz2
* Init version, ported drviers and platform supports from linux-2.6.24.3-jz to linux-2.6.31.3. * Fixed start/stop UHC routines on JZ4740. * Added gadget controller number for JZ4750D. * Remarked old power leagcy API. * Added support of i2c bus driver for jz4750/jz4750d. * Removed pcm_natvie.c. * Fixed a bug when a block cache is allocated for every partition which works over mtdblock-jz, and disable nand suspend/resume. * Fixed an IO coherent bug in __do_fault path. * Shutdown the board by poweroff command and remove poweroff interface in sysfs. * Enable JZ47XX RTC driver and modified for Mplayer running on JZSOC. * Correct GPIO_USB_DETE -> GPIOC15 in apus. * New simple I2C driver & Userspace driver & examples for JZ4750. * Corrected 2 bugs when 512-byte pagesize nand using yaffs1. * Fixed NAND LB Cache enable/flush/control bugs. * Fixed wake up problems in userspace sleep()/nanosleep(). * Added MEMPAGEWRITE ioctl to support nandwrite_mlc utils. * Fixed kernel bug. Do not call tty_flip_buffer_push() in tasklet context, We use workqueue instead. * Fixed MTD partition size calculation error. * Added IPU MM support option. * Defaut input_touchscreen is y, deleted JZ_TPANEL under char/jzchar. * Fixed missing spin_unlock_irq when rtc is busy. * Added the Ingenic NFTL source code.
-rw-r--r--Changelog426
-rw-r--r--Makefile4
-rw-r--r--README-JZ1181
-rw-r--r--arch/mips/Kconfig144
-rw-r--r--arch/mips/Makefile52
-rw-r--r--arch/mips/boot/Makefile23
-rw-r--r--arch/mips/boot/compressed/Makefile42
-rw-r--r--arch/mips/boot/compressed/dummy.c4
-rw-r--r--arch/mips/boot/compressed/head.S85
-rw-r--r--arch/mips/boot/compressed/ld.script151
-rw-r--r--arch/mips/boot/compressed/misc.c203
-rw-r--r--arch/mips/boot/tools/entry12
-rw-r--r--arch/mips/boot/tools/filesize7
-rw-r--r--arch/mips/configs/apus_defconfig1392
-rw-r--r--arch/mips/configs/cetus_defconfig1206
-rw-r--r--arch/mips/configs/dipper_defconfig1281
-rw-r--r--arch/mips/configs/f4750l_defconfig981
-rw-r--r--arch/mips/configs/fuwa1_defconfig1029
-rw-r--r--arch/mips/configs/fuwa_defconfig928
-rw-r--r--arch/mips/configs/leo_defconfig1256
-rw-r--r--arch/mips/configs/lyra_defconfig981
-rw-r--r--arch/mips/configs/pavo_defconfig1406
-rw-r--r--arch/mips/configs/pmp_defconfig1212
-rw-r--r--arch/mips/configs/slt50_defconfig1036
-rw-r--r--arch/mips/configs/virgo_defconfig1281
-rw-r--r--arch/mips/include/asm/asm-offsets.h212
-rw-r--r--arch/mips/include/asm/bootinfo.h157
-rw-r--r--arch/mips/include/asm/cpu.h13
-rw-r--r--arch/mips/include/asm/jzsoc.h53
-rw-r--r--arch/mips/include/asm/mach-generic/irq.h2
-rw-r--r--arch/mips/include/asm/mach-jz4730/board-pmp.h83
-rw-r--r--arch/mips/include/asm/mach-jz4730/clock.h184
-rw-r--r--arch/mips/include/asm/mach-jz4730/dma.h272
-rw-r--r--arch/mips/include/asm/mach-jz4730/jz4730.h42
-rw-r--r--arch/mips/include/asm/mach-jz4730/misc.h28
-rw-r--r--arch/mips/include/asm/mach-jz4730/ops.h2541
-rw-r--r--arch/mips/include/asm/mach-jz4730/regs.h2550
-rw-r--r--arch/mips/include/asm/mach-jz4730/serial.h33
-rw-r--r--arch/mips/include/asm/mach-jz4730/war.h25
-rw-r--r--arch/mips/include/asm/mach-jz4740/board-dipper.h69
-rw-r--r--arch/mips/include/asm/mach-jz4740/board-leo.h56
-rw-r--r--arch/mips/include/asm/mach-jz4740/board-lyra.h70
-rw-r--r--arch/mips/include/asm/mach-jz4740/board-pavo.h70
-rw-r--r--arch/mips/include/asm/mach-jz4740/board-virgo.h67
-rw-r--r--arch/mips/include/asm/mach-jz4740/clock.h173
-rw-r--r--arch/mips/include/asm/mach-jz4740/dma.h265
-rw-r--r--arch/mips/include/asm/mach-jz4740/jz4740.h58
-rw-r--r--arch/mips/include/asm/mach-jz4740/misc.h43
-rw-r--r--arch/mips/include/asm/mach-jz4740/ops.h2224
-rw-r--r--arch/mips/include/asm/mach-jz4740/regs.h2396
-rw-r--r--arch/mips/include/asm/mach-jz4740/serial.h30
-rw-r--r--arch/mips/include/asm/mach-jz4740/war.h25
-rw-r--r--arch/mips/include/asm/mach-jz4750/board-apus.h209
-rw-r--r--arch/mips/include/asm/mach-jz4750/board-fuwa.h93
-rw-r--r--arch/mips/include/asm/mach-jz4750/clock.h204
-rw-r--r--arch/mips/include/asm/mach-jz4750/dma.h307
-rw-r--r--arch/mips/include/asm/mach-jz4750/i2c.h70
-rw-r--r--arch/mips/include/asm/mach-jz4750/jz4750.h47
-rw-r--r--arch/mips/include/asm/mach-jz4750/misc.h44
-rw-r--r--arch/mips/include/asm/mach-jz4750/ops.h3570
-rw-r--r--arch/mips/include/asm/mach-jz4750/regs.h3415
-rw-r--r--arch/mips/include/asm/mach-jz4750/serial.h30
-rw-r--r--arch/mips/include/asm/mach-jz4750/war.h25
-rw-r--r--arch/mips/include/asm/mach-jz4750d/board-cetus.h263
-rw-r--r--arch/mips/include/asm/mach-jz4750d/board-draco.h126
-rw-r--r--arch/mips/include/asm/mach-jz4750d/board-fuwa1.h126
-rw-r--r--arch/mips/include/asm/mach-jz4750d/clock.h230
-rw-r--r--arch/mips/include/asm/mach-jz4750d/dma.h307
-rw-r--r--arch/mips/include/asm/mach-jz4750d/jz4750d.h45
-rw-r--r--arch/mips/include/asm/mach-jz4750d/misc.h44
-rw-r--r--arch/mips/include/asm/mach-jz4750d/ops.h3433
-rw-r--r--arch/mips/include/asm/mach-jz4750d/regs.h3400
-rw-r--r--arch/mips/include/asm/mach-jz4750d/serial.h30
-rw-r--r--arch/mips/include/asm/mach-jz4750d/war.h25
-rw-r--r--arch/mips/include/asm/mach-jz4750l/board-f4750l.h127
-rw-r--r--arch/mips/include/asm/mach-jz4750l/clock.h231
-rw-r--r--arch/mips/include/asm/mach-jz4750l/dma.h307
-rw-r--r--arch/mips/include/asm/mach-jz4750l/jz4750l.h42
-rw-r--r--arch/mips/include/asm/mach-jz4750l/misc.h44
-rw-r--r--arch/mips/include/asm/mach-jz4750l/ops.h3400
-rw-r--r--arch/mips/include/asm/mach-jz4750l/regs.h3390
-rw-r--r--arch/mips/include/asm/mach-jz4750l/serial.h30
-rw-r--r--arch/mips/include/asm/mach-jz4750l/war.h25
-rw-r--r--arch/mips/include/asm/ptrace.h4
-rw-r--r--arch/mips/include/asm/r4kcache.h239
-rw-r--r--arch/mips/include/asm/stackframe.h25
-rw-r--r--arch/mips/jz4730/Makefile22
-rw-r--r--arch/mips/jz4730/board-pmp.c109
-rw-r--r--arch/mips/jz4730/cpufreq.c596
-rw-r--r--arch/mips/jz4730/dma.c509
-rw-r--r--arch/mips/jz4730/i2c.c214
-rw-r--r--arch/mips/jz4730/irq.c267
-rw-r--r--arch/mips/jz4730/platform.c140
-rw-r--r--arch/mips/jz4730/pm.c1098
-rw-r--r--arch/mips/jz4730/proc.c292
-rw-r--r--arch/mips/jz4730/prom.c198
-rw-r--r--arch/mips/jz4730/reset.c40
-rw-r--r--arch/mips/jz4730/setup.c182
-rw-r--r--arch/mips/jz4730/sleep.S307
-rw-r--r--arch/mips/jz4730/time.c129
-rw-r--r--arch/mips/jz4740/Makefile26
-rw-r--r--arch/mips/jz4740/board-dipper.c117
-rw-r--r--arch/mips/jz4740/board-leo.c67
-rw-r--r--arch/mips/jz4740/board-lyra.c114
-rw-r--r--arch/mips/jz4740/board-pavo.c114
-rw-r--r--arch/mips/jz4740/board-virgo.c114
-rw-r--r--arch/mips/jz4740/cpufreq.c602
-rw-r--r--arch/mips/jz4740/dma.c768
-rw-r--r--arch/mips/jz4740/i2c.c273
-rw-r--r--arch/mips/jz4740/irq.c266
-rw-r--r--arch/mips/jz4740/platform.c169
-rw-r--r--arch/mips/jz4740/pm.c400
-rw-r--r--arch/mips/jz4740/proc.c834
-rw-r--r--arch/mips/jz4740/prom.c198
-rw-r--r--arch/mips/jz4740/reset.c42
-rw-r--r--arch/mips/jz4740/setup.c182
-rw-r--r--arch/mips/jz4740/time.c158
-rw-r--r--arch/mips/jz4750/Makefile23
-rw-r--r--arch/mips/jz4750/board-apus.c64
-rw-r--r--arch/mips/jz4750/board-fuwa.c105
-rw-r--r--arch/mips/jz4750/board-slt50.c64
-rw-r--r--arch/mips/jz4750/cpufreq.c601
-rw-r--r--arch/mips/jz4750/dma.c836
-rw-r--r--arch/mips/jz4750/i2c.c388
-rw-r--r--arch/mips/jz4750/irq.c299
-rw-r--r--arch/mips/jz4750/platform.c173
-rw-r--r--arch/mips/jz4750/pm.c401
-rw-r--r--arch/mips/jz4750/proc.c857
-rw-r--r--arch/mips/jz4750/prom.c198
-rw-r--r--arch/mips/jz4750/reset.c42
-rw-r--r--arch/mips/jz4750/setup.c197
-rw-r--r--arch/mips/jz4750/time.c214
-rw-r--r--arch/mips/jz4750d/Makefile23
-rw-r--r--arch/mips/jz4750d/board-cetus.c72
-rw-r--r--arch/mips/jz4750d/board-fuwa1.c72
-rw-r--r--arch/mips/jz4750d/cpufreq.c598
-rw-r--r--arch/mips/jz4750d/dma.c822
-rw-r--r--arch/mips/jz4750d/i2c.c273
-rw-r--r--arch/mips/jz4750d/irq.c299
-rw-r--r--arch/mips/jz4750d/platform.c172
-rw-r--r--arch/mips/jz4750d/pm.c400
-rw-r--r--arch/mips/jz4750d/proc.c1112
-rw-r--r--arch/mips/jz4750d/prom.c198
-rw-r--r--arch/mips/jz4750d/reset.c42
-rw-r--r--arch/mips/jz4750d/setup.c199
-rw-r--r--arch/mips/jz4750d/time.c156
-rw-r--r--arch/mips/jz4750l/Makefile22
-rw-r--r--arch/mips/jz4750l/board-f4750l.c72
-rw-r--r--arch/mips/jz4750l/cpufreq.c598
-rw-r--r--arch/mips/jz4750l/dma.c822
-rw-r--r--arch/mips/jz4750l/i2c.c273
-rw-r--r--arch/mips/jz4750l/irq.c299
-rw-r--r--arch/mips/jz4750l/platform.c141
-rw-r--r--arch/mips/jz4750l/pm.c461
-rw-r--r--arch/mips/jz4750l/proc.c885
-rw-r--r--arch/mips/jz4750l/prom.c198
-rw-r--r--arch/mips/jz4750l/reset.c46
-rw-r--r--arch/mips/jz4750l/setup.c199
-rw-r--r--arch/mips/jz4750l/time.c156
-rw-r--r--arch/mips/kernel/cpu-probe.c24
-rw-r--r--arch/mips/kernel/entry.S15
-rw-r--r--arch/mips/mm/c-r4k.c29
-rw-r--r--arch/mips/mm/cache.c2
-rw-r--r--arch/mips/mm/tlbex.c5
-rw-r--r--drivers/char/Kconfig11
-rw-r--r--drivers/char/Makefile4
-rw-r--r--drivers/char/jzchar/Kconfig74
-rw-r--r--drivers/char/jzchar/Makefile25
-rw-r--r--drivers/char/jzchar/ak4182.c657
-rw-r--r--drivers/char/jzchar/ak4182.h16
-rw-r--r--drivers/char/jzchar/ata2508.c227
-rw-r--r--drivers/char/jzchar/cim.c366
-rw-r--r--drivers/char/jzchar/cim.h36
-rw-r--r--drivers/char/jzchar/example/i_i2c_tool.c81
-rw-r--r--drivers/char/jzchar/i_i2c.c190
-rw-r--r--drivers/char/jzchar/i_i2c_abi.h33
-rw-r--r--drivers/char/jzchar/jz_ow.c497
-rw-r--r--drivers/char/jzchar/jz_ts.c443
-rw-r--r--drivers/char/jzchar/jz_ts.h54
-rw-r--r--drivers/char/jzchar/jz_tssi.c457
-rw-r--r--drivers/char/jzchar/jz_tssi.h76
-rw-r--r--drivers/char/jzchar/jzchars.c159
-rw-r--r--drivers/char/jzchar/jzchars.h47
-rw-r--r--drivers/char/jzchar/poweroff.c410
-rw-r--r--drivers/char/jzchar/sadc.c580
-rw-r--r--drivers/char/jzchar/sensor.c182
-rw-r--r--drivers/char/jzchar/tcsm.c123
-rw-r--r--drivers/char/jzchar/ucb1400.c585
-rw-r--r--drivers/char/jzchar/ucb1400.h113
-rw-r--r--drivers/char/jzchar/udc_hotplug.c451
-rw-r--r--drivers/char/jzchar/wm9712.c334
-rw-r--r--drivers/char/jzchar/wm9712.h58
-rw-r--r--drivers/char/rtc_jz.c504
-rw-r--r--drivers/char/rtc_jz.h74
-rw-r--r--drivers/char/rtc_pcf8563.c448
-rw-r--r--drivers/i2c/busses/Kconfig9
-rw-r--r--drivers/i2c/busses/Makefile2
-rw-r--r--drivers/i2c/busses/i2c-jz47xx.c357
-rw-r--r--drivers/i2c/busses/i2c-jz47xx.h20
-rw-r--r--drivers/i2c/i2c-dev.c21
-rw-r--r--drivers/input/keyboard/Kconfig48
-rw-r--r--drivers/input/keyboard/Makefile2
-rw-r--r--drivers/input/keyboard/gpio_keys.c253
-rw-r--r--drivers/input/keyboard/jz_keypad.c362
-rw-r--r--drivers/input/keyboard/jz_keypad_5x5.c334
-rw-r--r--drivers/input/touchscreen/Kconfig24
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/jz_ts.c892
-rw-r--r--drivers/media/video/Kconfig18
-rw-r--r--drivers/media/video/Makefile5
-rw-r--r--drivers/media/video/jz4730_cim.c622
-rw-r--r--drivers/media/video/jz4740_cim.c622
-rw-r--r--drivers/media/video/jz4750_cim.c734
-rw-r--r--drivers/media/video/jz4750_cim.h49
-rw-r--r--drivers/media/video/jz_cim.h36
-rw-r--r--drivers/media/video/jz_sensor.c202
-rw-r--r--drivers/mmc/card/block.c4
-rw-r--r--drivers/mmc/core/mmc.c6
-rw-r--r--drivers/mmc/core/sd.c14
-rw-r--r--drivers/mmc/host/Kconfig98
-rw-r--r--drivers/mmc/host/Makefile4
-rw-r--r--drivers/mmc/host/jz4750_mmc.c1037
-rw-r--r--drivers/mmc/host/jz4750_mmc.h88
-rw-r--r--drivers/mmc/host/jz_mmc.c998
-rw-r--r--drivers/mmc/host/jz_mmc.h65
-rw-r--r--drivers/mtd/Makefile8
-rw-r--r--drivers/mtd/mtd-utils/COPYING340
-rw-r--r--drivers/mtd/mtd-utils/MAKEDEV42
-rw-r--r--drivers/mtd/mtd-utils/Makefile105
-rw-r--r--drivers/mtd/mtd-utils/compr.c538
-rw-r--r--drivers/mtd/mtd-utils/compr.h119
-rw-r--r--drivers/mtd/mtd-utils/compr_lzo.c120
-rw-r--r--drivers/mtd/mtd-utils/compr_rtime.c119
-rw-r--r--drivers/mtd/mtd-utils/compr_zlib.c145
-rw-r--r--drivers/mtd/mtd-utils/crc32.c95
-rw-r--r--drivers/mtd/mtd-utils/crc32.h19
-rw-r--r--drivers/mtd/mtd-utils/device_table.txt129
-rw-r--r--drivers/mtd/mtd-utils/doc_loadbios.c148
-rw-r--r--drivers/mtd/mtd-utils/docfdisk.c317
-rw-r--r--drivers/mtd/mtd-utils/feature-removal-schedule.txt9
-rw-r--r--drivers/mtd/mtd-utils/fec.c917
-rw-r--r--drivers/mtd/mtd-utils/fectest.c92
-rw-r--r--drivers/mtd/mtd-utils/flash_erase.c189
-rw-r--r--drivers/mtd/mtd-utils/flash_eraseall.c286
-rw-r--r--drivers/mtd/mtd-utils/flash_info.c55
-rw-r--r--drivers/mtd/mtd-utils/flash_lock.c84
-rw-r--r--drivers/mtd/mtd-utils/flash_otp_dump.c54
-rw-r--r--drivers/mtd/mtd-utils/flash_otp_info.c63
-rw-r--r--drivers/mtd/mtd-utils/flash_otp_lock.c70
-rw-r--r--drivers/mtd/mtd-utils/flash_otp_write.c96
-rw-r--r--drivers/mtd/mtd-utils/flash_unlock.c64
-rw-r--r--drivers/mtd/mtd-utils/flashcp.c389
-rw-r--r--drivers/mtd/mtd-utils/ftl_check.c232
-rw-r--r--drivers/mtd/mtd-utils/ftl_format.c342
-rw-r--r--drivers/mtd/mtd-utils/include/linux/jffs2.h218
-rw-r--r--drivers/mtd/mtd-utils/include/mtd/ftl-user.h76
-rw-r--r--drivers/mtd/mtd-utils/include/mtd/inftl-user.h91
-rw-r--r--drivers/mtd/mtd-utils/include/mtd/jffs2-user.h82
-rw-r--r--drivers/mtd/mtd-utils/include/mtd/mtd-abi.h186
-rw-r--r--drivers/mtd/mtd-utils/include/mtd/mtd-user.h19
-rw-r--r--drivers/mtd/mtd-utils/include/mtd/nftl-user.h76
-rw-r--r--drivers/mtd/mtd-utils/include/mtd/ubi-header.h372
-rw-r--r--drivers/mtd/mtd-utils/include/mtd/ubi-user.h284
-rw-r--r--drivers/mtd/mtd-utils/include/mtd_swab.h51
-rw-r--r--drivers/mtd/mtd-utils/jffs-dump.c359
-rw-r--r--drivers/mtd/mtd-utils/jffs2dump.c690
-rw-r--r--drivers/mtd/mtd-utils/jffs2reader.c939
-rw-r--r--drivers/mtd/mtd-utils/load_nandsim.sh123
-rw-r--r--drivers/mtd/mtd-utils/mcast_image.h54
-rw-r--r--drivers/mtd/mtd-utils/mkfs.jffs2.1259
-rw-r--r--drivers/mtd/mtd-utils/mkfs.jffs2.c1902
-rw-r--r--drivers/mtd/mtd-utils/mtd-utils.spec40
-rw-r--r--drivers/mtd/mtd-utils/mtd_debug.c418
-rw-r--r--drivers/mtd/mtd-utils/nanddump.c403
-rw-r--r--drivers/mtd/mtd-utils/nanddump_vfat.c365
-rw-r--r--drivers/mtd/mtd-utils/nandtest.c284
-rw-r--r--drivers/mtd/mtd-utils/nandwrite.c525
-rw-r--r--drivers/mtd/mtd-utils/nandwrite_mlc.c446
-rw-r--r--drivers/mtd/mtd-utils/nftl_format.c419
-rw-r--r--drivers/mtd/mtd-utils/nftldump.c281
-rw-r--r--drivers/mtd/mtd-utils/rbtree.c390
-rw-r--r--drivers/mtd/mtd-utils/rbtree.h168
-rw-r--r--drivers/mtd/mtd-utils/recv_image.c484
-rw-r--r--drivers/mtd/mtd-utils/rfddump.c336
-rw-r--r--drivers/mtd/mtd-utils/rfdformat.c158
-rw-r--r--drivers/mtd/mtd-utils/serve_image.c299
-rw-r--r--drivers/mtd/mtd-utils/summary.h178
-rw-r--r--drivers/mtd/mtd-utils/sumtool.c951
-rw-r--r--drivers/mtd/mtd-utils/tests/checkfs/Makefile14
-rw-r--r--drivers/mtd/mtd-utils/tests/checkfs/README173
-rw-r--r--drivers/mtd/mtd-utils/tests/checkfs/checkfs.c695
-rw-r--r--drivers/mtd/mtd-utils/tests/checkfs/comm.c67
-rw-r--r--drivers/mtd/mtd-utils/tests/checkfs/common.h7
-rw-r--r--drivers/mtd/mtd-utils/tests/checkfs/makefiles.c264
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/Makefile8
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/help_all.sh27
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/integrity/Makefile22
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/integrity/integck.c1422
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile18
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c1091
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h199
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh49
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile28
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c111
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c184
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c150
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c201
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile11
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile40
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c209
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c259
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c143
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c133
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c157
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c431
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c201
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c109
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c120
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c122
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh52
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh40
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile19
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c56
-rw-r--r--drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c281
-rw-r--r--drivers/mtd/mtd-utils/tests/jittertest/COPYING340
-rw-r--r--drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c1044
-rw-r--r--drivers/mtd/mtd-utils/tests/jittertest/Makefile46
-rw-r--r--drivers/mtd/mtd-utils/tests/jittertest/README197
-rw-r--r--drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh16
-rw-r--r--drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c312
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/Makefile48
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/README.udev25
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/common.c336
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/common.h103
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/integ.c783
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c179
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c249
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c388
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c298
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c301
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c250
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c110
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c305
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh39
-rw-r--r--drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c122
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/Makefile88
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/README236
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/UBI.TXT108
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff123
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h268
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am58
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser21
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile84
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/README55
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h280
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h73
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h112
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h382
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h110
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c194
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h84
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c95
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h19
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c405
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h174
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c646
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c314
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c225
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c1154
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h133
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c335
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c205
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c124
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c94
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c221
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c181
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c264
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c712
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c310
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c409
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c582
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c99
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirmvol.c195
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c335
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg38
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg39
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi723
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl74
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile75
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/README11
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/TODO5
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh184
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl94
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh91
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl32
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt16
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh101
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg23
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh411
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh328
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh252
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh105
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c344
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c1032
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h434
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/config.h28
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/crc32.c83
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/crc32.h36
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c281
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/error.c240
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/error.h84
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h28
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c412
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h49
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c1325
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/libubi.c915
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h129
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c487
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c237
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/list.c149
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/list.h56
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c168
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c493
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c95
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c159
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h29
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c516
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/peb.c116
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/peb.h41
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/pfi.c458
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/pfi.h244
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c682
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c264
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h76
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h75
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/reader.c482
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/reader.h87
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c359
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h149
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c213
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h66
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/unubi.c1024
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c463
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h87
-rw-r--r--drivers/mtd/mtd-utils/ubi-utils/testcases.txt9
-rw-r--r--drivers/mtd/mtdblock-jz.c1320
-rw-r--r--drivers/mtd/mtdblock.c52
-rw-r--r--drivers/mtd/mtdchar.c78
-rw-r--r--drivers/mtd/mtdcore.c4
-rw-r--r--drivers/mtd/mtdpart.c68
-rw-r--r--drivers/mtd/nand/Kconfig130
-rw-r--r--drivers/mtd/nand/Makefile3
-rw-r--r--drivers/mtd/nand/jz4730_nand.c367
-rw-r--r--drivers/mtd/nand/jz4740_nand.c1076
-rw-r--r--drivers/mtd/nand/jz4750_nand.c1900
-rw-r--r--drivers/mtd/nand/nand_base.c460
-rw-r--r--drivers/mtd/nand/nand_bbt.c56
-rw-r--r--drivers/mtd/nand/nand_ids.c4
-rw-r--r--drivers/mtd/ubi/bdev.c432
-rw-r--r--drivers/mtd/ubi/ubiblk.c359
-rw-r--r--drivers/mtd/ubi/ubiblk.h85
-rw-r--r--drivers/mtd/udc_cache.c531
-rw-r--r--drivers/net/Kconfig18
-rw-r--r--drivers/net/Makefile3
-rw-r--r--drivers/net/jz_eth.c1299
-rw-r--r--drivers/net/jz_eth.h403
-rw-r--r--drivers/net/jzcs8900a.c646
-rw-r--r--drivers/net/jzcs8900a.h235
-rw-r--r--drivers/serial/8250.c105
-rw-r--r--drivers/usb/Kconfig1
-rw-r--r--drivers/usb/core/hub.c47
-rw-r--r--drivers/usb/gadget/Kconfig80
-rw-r--r--drivers/usb/gadget/Makefile5
-rw-r--r--drivers/usb/gadget/file_storage.c97
-rw-r--r--drivers/usb/gadget/gadget_chips.h33
-rw-r--r--drivers/usb/gadget/jz4730_udc.c1403
-rw-r--r--drivers/usb/gadget/jz4730_udc.h107
-rw-r--r--drivers/usb/gadget/jz4740_udc.c2326
-rw-r--r--drivers/usb/gadget/jz4740_udc.h105
-rw-r--r--drivers/usb/gadget/u_serial.c16
-rw-r--r--drivers/usb/gadget/u_serial.h67
-rw-r--r--drivers/usb/gadget/udc_hotplug.c766
-rw-r--r--drivers/usb/host/ohci-hcd.c5
-rw-r--r--drivers/usb/host/ohci-jz.c258
-rw-r--r--drivers/video/Kconfig221
-rw-r--r--drivers/video/Makefile4
-rw-r--r--drivers/video/console/Kconfig8
-rw-r--r--drivers/video/console/fbcon.c2
-rw-r--r--drivers/video/jz4740_slcd.c1334
-rw-r--r--drivers/video/jz4740_slcd.h376
-rw-r--r--drivers/video/jz4750_lcd.c2385
-rw-r--r--drivers/video/jz4750_lcd.h789
-rw-r--r--drivers/video/jz4750_tve.c104
-rw-r--r--drivers/video/jz4750_tve.h45
-rw-r--r--drivers/video/jz_kgm_spfd5420a.h385
-rw-r--r--drivers/video/jz_toppoly_td043mgeb1.h264
-rw-r--r--drivers/video/jzlcd.c1571
-rw-r--r--drivers/video/jzlcd.h791
-rw-r--r--drivers/watchdog/Kconfig9
-rw-r--r--drivers/watchdog/jz_wdt.c203
-rw-r--r--fs/Kconfig5
-rw-r--r--fs/Makefile4
-rw-r--r--fs/mpage.c11
-rw-r--r--fs/yaffs2/Kconfig167
-rw-r--r--fs/yaffs2/Makefile10
-rw-r--r--fs/yaffs2/devextras.h264
-rw-r--r--fs/yaffs2/moduleconfig.h51
-rw-r--r--fs/yaffs2/utils/Makefile73
-rw-r--r--fs/yaffs2/utils/README11
-rw-r--r--fs/yaffs2/utils/mkyaffs2image.c794
-rw-r--r--fs/yaffs2/utils/mkyaffsimage.c593
-rw-r--r--fs/yaffs2/utils/ssfdc_rs_ecc.c180
-rw-r--r--fs/yaffs2/utils/ssfdc_rs_ecc.h29
-rw-r--r--fs/yaffs2/yaffs_checkptrw.c384
-rw-r--r--fs/yaffs2/yaffs_checkptrw.h33
-rw-r--r--fs/yaffs2/yaffs_ecc.c446
-rw-r--r--fs/yaffs2/yaffs_ecc.h48
-rw-r--r--fs/yaffs2/yaffs_fs.c2508
-rw-r--r--fs/yaffs2/yaffs_guts.c6676
-rw-r--r--fs/yaffs2/yaffs_guts.h889
-rw-r--r--fs/yaffs2/yaffs_mtdif.c248
-rw-r--r--fs/yaffs2/yaffs_mtdif.h27
-rw-r--r--fs/yaffs2/yaffs_mtdif2.c369
-rw-r--r--fs/yaffs2/yaffs_mtdif2.h29
-rw-r--r--fs/yaffs2/yaffs_nand.c134
-rw-r--r--fs/yaffs2/yaffs_nand.h44
-rw-r--r--fs/yaffs2/yaffs_nandemul2k.h39
-rw-r--r--fs/yaffs2/yaffs_packedtags1.c52
-rw-r--r--fs/yaffs2/yaffs_packedtags1.h37
-rw-r--r--fs/yaffs2/yaffs_packedtags2.c184
-rw-r--r--fs/yaffs2/yaffs_packedtags2.h38
-rw-r--r--fs/yaffs2/yaffs_qsort.c155
-rw-r--r--fs/yaffs2/yaffs_qsort.h23
-rw-r--r--fs/yaffs2/yaffs_tagscompat.c530
-rw-r--r--fs/yaffs2/yaffs_tagscompat.h36
-rw-r--r--fs/yaffs2/yaffs_tagsvalidity.c28
-rw-r--r--fs/yaffs2/yaffs_tagsvalidity.h24
-rw-r--r--fs/yaffs2/yaffsinterface.h21
-rw-r--r--fs/yaffs2/yportenv.h163
-rw-r--r--include/linux/i2c-dev.h3
-rw-r--r--include/linux/i2c.h2
-rw-r--r--include/linux/mtd/mtd.h50
-rw-r--r--include/linux/mtd/nand.h26
-rw-r--r--include/linux/mtd/partitions.h4
-rw-r--r--include/linux/vt.h14
-rw-r--r--include/mtd/mtd-abi.h35
-rw-r--r--include/sound/pcm.h22
-rw-r--r--init/do_mounts.c3
-rw-r--r--sound/core/pcm_lib.c103
-rw-r--r--sound/core/pcm_native.c15
-rw-r--r--sound/oss/Kconfig56
-rw-r--r--sound/oss/Makefile6
-rw-r--r--sound/oss/ak4642en.c711
-rw-r--r--sound/oss/jz_ac97.c2252
-rw-r--r--sound/oss/jz_i2s.c2895
-rw-r--r--sound/oss/jz_i2s_4750.c3010
-rw-r--r--sound/oss/jz_i2s_dlv_dma_test.c2808
-rw-r--r--sound/oss/jz_i2s_for_4750.c2981
-rw-r--r--sound/oss/jz_pcm_tlv320aic1106_dma.c1837
-rw-r--r--sound/oss/jzcodec.c442
-rw-r--r--sound/oss/jzdlv.c644
-rw-r--r--sound/oss/jzdlv.h21
-rw-r--r--sound/oss/os.h1
-rw-r--r--sound/soc/Kconfig2
-rw-r--r--sound/soc/Makefile3
-rw-r--r--sound/soc/codecs/Kconfig182
-rw-r--r--sound/soc/codecs/Makefile68
-rw-r--r--sound/soc/codecs/jzcodec.c745
-rw-r--r--sound/soc/codecs/jzcodec.h22
-rw-r--r--sound/soc/codecs/jzdlv.c969
-rw-r--r--sound/soc/codecs/jzdlv.h51
-rw-r--r--sound/soc/jz4740/Kconfig34
-rw-r--r--sound/soc/jz4740/Makefile15
-rw-r--r--sound/soc/jz4740/jz4740-ac97.c261
-rw-r--r--sound/soc/jz4740/jz4740-ac97.h21
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c309
-rw-r--r--sound/soc/jz4740/jz4740-i2s.h18
-rw-r--r--sound/soc/jz4740/jz4740-pcm.c687
-rw-r--r--sound/soc/jz4740/jz4740-pcm.h33
-rw-r--r--sound/soc/jz4740/pavo.c374
-rw-r--r--sound/soc/jz4750/Kconfig34
-rw-r--r--sound/soc/jz4750/Makefile15
-rw-r--r--sound/soc/jz4750/apus.c365
-rw-r--r--sound/soc/jz4750/jz4750-ac97.c258
-rw-r--r--sound/soc/jz4750/jz4750-ac97.h21
-rw-r--r--sound/soc/jz4750/jz4750-i2s.c320
-rw-r--r--sound/soc/jz4750/jz4750-i2s.h18
-rw-r--r--sound/soc/jz4750/jz4750-pcm.c700
-rw-r--r--sound/soc/jz4750/jz4750-pcm.h33
589 files changed, 204098 insertions, 635 deletions
diff --git a/Changelog b/Changelog
new file mode 100644
index 00000000000..8eb423da02c
--- /dev/null
+++ b/Changelog
@@ -0,0 +1,426 @@
+2009.04.22
+* Which mode a partition works with, cpu mode or dma mode, could be determined by the
+ value of cpu_mode in partition_info[] in drivers/mtd/nand/jz47xx_nand.c
+ Update Files:
+ include/linux/mtd/partitions.h
+ include/mtd/mtd-abi.h
+ include/asm-mips/mach-jz4750/ops.h
+ drivers/mtd/nand/jz4750_nand.c
+ drivers/mtd/nand/nand_base.c
+ drivers/mtd/mtdpart.c
+ drivers/mtd/mtdcore.c
+
+* Vmalloc instead of kmalloc a block cache for mtdblock-jz when the partition works
+ in cpu mode.
+ Update Files:
+ drivers/mtd/mtdblock-jz.c
+ <lhhuang@ingenic.cn>
+
+2009.04.17
+* Allocate a block cache for every partitions which works over mtdblock-jz early
+ in nand_base.c if CONFIG_ALLOCATE_MTDBLOCK_JZ_ERALY defined.
+ Update Files:
+ drivers/mtd/nand/nand_base.c
+ drivers/mtd/mtdblock-jz.c
+ drivers/mtd/nand/jz4740_nand.c
+ drivers/mtd/nand/jz4750_nand.c
+
+* The eccpos in nand_oob_64 was changed to 24 when using 4-bit BCH to conform with
+ the eccpos of nand_oob_128 when using 8-bit BCH.
+ Update Files:
+ drivers/mtd/nand/nand_base.c
+
+* set CONFIG_PREEMPT_NONE=y to make the speed of UDC using NAND highly. And set
+ CONFIG_MTD_HW_BCH_8BIT=y for 4KB pagesize NAND.
+ Update Files:
+ arch/mips/configs/apus_defconfig
+ <lhhuang@ingenic.cn>
+
+
+2009.04.11
+* Whether a partition works over mtdblock-jz or not could be determined by the
+ value of mtdblock_jz_invalid in partition_info[] in drivers/mtd/nand/jz47xx_nand.c
+
+ Update Files:
+ drivers/mtd/nand/jz4740_nand.c
+ drivers/mtd/nand/jz4750_nand.c
+ include/linux/mtd/partitions.h
+ include/mtd/mtd-abi.h
+ drivers/mtd/mtdpart.c
+ drivers/mtd/mtdblock-jz.c
+ <lhhuang@ingenic.cn>
+
+2009.03.30
+* Set ECCPOS of 4K page nand to 28. (For 4750, only set 4bit BCH ECCPOS to 28)
+ Modify nand partitions of PAVO & APUS.
+
+ Update Files:
+ drivers/mtd/nand/nand_base.c
+ drivers/mtd/nand/jz4740_nand.c
+ drivers/mtd/nand/jz4750_nand.c
+ <zyliu@ingenic.cn>
+
+2009.02.17
+* Modify oss driver to support jz4750 i2s codec.
+ Update Files:
+ sound/oss/Kconfig
+ sound/oss/Makefile
+ sound/oss/jz_i2s.c
+ Add Files:
+ sound/oss/jzdlv.h
+ sound/oss/jzdlv.c
+ <cjfeng@ingenic.cn>
+2008.12.08
+* Power management is supported for jz4750.
+ Update Files:
+ arch/mips/jz4750/pm.c
+ drivers/char/jzchar/poweroff.c
+
+2008.12.04
+* Whether NAND multiple planes operation for one partition is used or not could be
+ determined by the value of use_planes in partition_info[] in drivers/mtd/nand/jz47xx_nand.c
+ Updated files:
+ include/linux/mtd/partitions.h
+ drivers/mtd/nand/nand_base.c
+ drivers/mtd/nand/jz4740_nand.c
+ drivers/mtd/mtdpart.c
+* Supported 4KB page size nand with 2 planes
+ Update Files:
+ include/linux/mtd/nand.h
+ drivers/mtd/nand/nand_base.c
+ fs/yaffs2/utils/mkyaffs2image.c
+ drivers/mtd/mtd-utils/nandwrite_mlc.c
+ <lhhuang@ingenic.cn>
+
+2008.11.07
+* The ubi was modified to support MTD of 64bit.
+ Updated file:
+ drivers/mtd/ubi/io.c
+* The ubi and ubifs were modified by changing vmalloc and vfree to kmalloc and kfree
+ to provide DMA buffer for NAND driver. But the NAND driver will use DMA buffer in
+ itself instead of in ubi and ubifs when CONFIG_MTD_NAND_DMABUF is defined.
+ Updated files:
+ drivers/mtd/ubi/build.c
+ drivers/mtd/ubi/cdev.c
+ drivers/mtd/ubi/gluebi.c
+ drivers/mtd/ubi/misc.c
+ drivers/mtd/ubi/scan.c
+ drivers/mtd/ubi/ubiblk.c
+ drivers/mtd/ubi/upd.c
+ drivers/mtd/ubi/vtbl.c
+ fs/ubifs/build.c
+ fs/ubifs/log.c
+ fs/ubifs/lpt.c
+ fs/ubifs/lpt_commit.c
+ fs/ubifs/orphan.c
+ fs/ubifs/recovery.c
+ fs/ubifs/replay.c
+ fs/ubifs/super.c
+ <lhhuang@ingenic.cn>
+
+2008.10.31
+* Converted MTD from 32bit to 64bit to support the NAND larger than 4GB, and yaffs2 was
+ modified accordingly. <lhhuang@ingenic.cn>
+ Updated file:
+ include/mtd/mtd-abi.h
+ include/linux/mtd/mtd.h
+ include/linux/mtd/partitions.h
+ include/linux/mtd/nand.h
+ drivers/mtd/mtdcore.c
+ drivers/mtd/mtdchar.c
+ drivers/mtd/mtdpart.c
+ drivers/mtd/mtdblock-jz.c
+ drivers/mtd/nand/nand_base.c
+ drivers/mtd/nand/nand_bbt.c
+ drivers/mtd/mtd-utils/include/mtd/mtd-abi.h
+ drivers/mtd/mtd-utils/flash_eraseall.c
+ drivers/mtd/mtd-utils/nandwrite_mlc.c
+ drivers/mtd/mtd-utils/nandwrite.c
+ fs/yaffs2/yaffs_fs.c
+ fs/yaffs2/yaffs_mtdif.c
+ fs/yaffs2/yaffs_mtdif2.c
+
+2008.10.29
+* Modified yaffs2 utils mkyaffs2image to support writting 4KB pagesize NAND. NAND layout
+ is (0 - raw(512B pagesize), 1 - nand_oob_64(2KB pagesize), 2 - nand_oob_128(4KB pagesize)).
+ <lhhuang@ingenic.cn>
+ Updated file:
+ fs/yaffs2/utils/mkyaffs2image.c
+
+2008.10.27
+* Supported multiply chip selecting for NAND flash. <lhhuang@ingenic.cn>
+ Updated files:
+ include/linux/mtd/nand.h
+ drivers/mtd/nand/nand_base.c
+ drivers/mtd/nand/jz4750_nand.c
+ drivers/mtd/nand/jz4740_nand.c
+
+2008.10.23
+* Modified yaffs2 utils mkyaffs2image to enable writing soft reed-solomn ECC for
+ yaffs2 file system information in oob area of MLC nand, getting CONFIG_YAFFS_ECC_RS
+ from .config, so when CONFIG_YAFFS_ECC_RS is changed, mkyaffs2image should be built
+ again. <lhhuang@ingenic.cn>
+ Updated files:
+ fs/yaffs2/yaffs_ecc.c
+ fs/yaffs2/utils/Makefile
+ Added files:
+ fs/yaffs2/utils/ssfdc_rs_ecc.c
+ fs/yaffs2/utils/ssfdc_rs_ecc.h
+
+2008.09.26
+
+* Fixed a fatal bug for mplayer, which may cause some files cannot be played and
+ the system is crashed. <jlwei@ingenic.cn>
+ Updated file: arch/mips/jz4740/proc.c
+
+2008.08.30
+* For jz4750, DMA clock for each channel should be enabled before using the channel.
+ So REG_DMAC_DMACKE and __dmac_channel_enable_clk(n) were added.
+ Updated files:
+ include/asm-mips/mach-jz4750/regs.h
+ include/asm-mips/mach-jz4750/ops.h
+ Regen, <lhhuang@ingenic.cn>
+
+2008.08.19
+* Modify jzfb_mmap() for cacheable framebuffer access. <jlwei@ingenic.cn>
+ Updated files:
+ drivers/video/jzlcd.c
+ drivers/video/jz4740_slcd.c
+ drivers/video/jz4750_lcd.c
+
+2008.08.15
+* Modify ipu interface to toggle PID of MPlayer in TLB.
+* Modify OSS ioctl function to play movie with mono channel better.
+ Update Files:
+ arch/mips/jz4740/proc.c
+ sound/oss/jz_i2s.c
+ Richard Feng, <cjfeng@ingenic.cn>
+
+2008.08.04
+* Check whether the free block is erased before erasing it, 'unsigned int' instead of
+ 'unsigned short' was used to store block number, and heap sort for lifetime after
+ erasing a block was replaced by another faster method.
+ Update File:
+ drivers/mtd/mtdblock-jz.uu
+
+* Cache read was used in nand_read_page_hwecc_rs() for Jz4740.
+ Update File:
+ drivers/mtd/nand/nand_base.c
+
+* Faster timing in REG_EMC_SMCR1 whose value is 0x09221200 was used.
+ Update File:
+ drivers/mtd/nand/jz4740_nand.c
+
+ Regen, <lhhuang@ingenic.cn>
+
+2008.07.21
+* Supported 4KB page size nand
+ Update File:
+ drivers/mtd/nand/nand_base.c
+ include/linux/mtd/nand.h
+ include/mtd/mtd-abi.h
+ drivers/mtd/mtd-utils/include/mtd/mtd-abi.h
+ Regen, <lhhuang@ingenic.cn>
+
+2008.07.18
+* Soft reed solomon ECC was supported for yaffs2 information which is 16 bytes in nand
+ oob, and it should be used for MLC nand.
+ Update File:
+ fs/yaffs2/yaffs_ecc.c
+ fs/yaffs2/yaffs_ecc.h
+ fs/yaffs2/yaffs_fs.c
+ fs/yaffs2/yaffs_packedtags2.c
+ Regen, <lhhuang@ingenic.cn>
+
+2008.07.10
+* Added support to generate any frequency baud rate of uart for both Jz4740 and Jz4750.
+ Update File:
+ drivers/serial/8250.c
+ Regen, <lhhuang@ingenic.cn>
+
+2008.07.03
+* Modified Jz4750's INTC, CIM, TSSI, macros.
+ Update Files:
+ include/asm-mips/mach-jz4750/regs.h
+ include/asm-mips/mach-jz4750/ops.h
+
+2008.06.24
+* Combined Jz4750 SLCD Controller support into drivers/video/jz4750_lcd.c.
+* drivers/video/jz4750_lcd.c, now support: LCD Controller, Slcd Controller, TVE.
+* And add smart lcd panel TRULY_TFT_GG1P0319LTSW_W support.
+ Update Files:
+ drivers/video/Kconfig
+ drivers/video/jz4750_lcd.h
+ drivers/video/jz4750_lcd.c
+ Wolfgang Wang, <lgwang@ingenic.cn>
+
+2008.06.20
+* Add Jz4750 LCDC and TVE driver. <lgwang@ingenic.cn>
+ Update Files:
+ arch/asm-mips/mach-jz4750/regs.h
+ arch/asm-mips/mach-jz4750/ops.h
+ drivers/video/Kconfig
+ drivers/video/Makefile
+ Add Files:
+ drivers/video/jz4750_lcd.h
+ drivers/video/jz4750_lcd.c
+ drivers/video/jz4750_tve.h
+ drivers/video/jz4750_tve.c
+
+2008.06.12
+* Modified CONFIG_FB_JZXXX macros, rename drivers/video/jzslcd.x to drivers/video/jz4740_slcd.x
+ Update Files:
+ drivers/video/Kconfig
+ drivers/video/Makefile
+ arch/mips/configs/dipper_defconfig
+ arch/mips/configs/leo_defconfig
+ arch/mips/configs/lyra_defconfig
+ arch/mips/configs/pavo_defconfig
+ arch/mips/configs/virgo_defconfig
+ <lgwang@ingenic.cn>
+
+2008.06.10
+* Add jz_clocksource, upgrade the system time's accuracy from 10ms to about 1(or 2) us.
+ but the system timer remained 10ms.
+ Files modified:
+ arch/mips/jz4730/time.c
+ arch/mips/jz4740/time.c
+ arch/mips/jz4750/time.c
+ <lgwang@ingenic.cn>
+
+2008.05.31
+
+* Updated UBIFS. <yrtan@ingenic.cn>
+
+2008.05.30
+
+* Added JZ4720 virgo board support. <zyliu@ingenic.cn>
+
+2008.05.29
+
+* Added definition of CONFIG_SOC_JZ4725 and CONFIG_SOC_JZ4720. <zyliu@ingenic.cn>
+* Added selection of 4-bit/1-bit data bus for MMC/SD card driver. <zyliu@ingenic.cn>
+* Added dipper_defconfig for JZ4725 DIPPER board. <zyliu@ingenic.cn>
+
+2008.05.29:
+
+* Modified sound/oss/jz_i2s.c to increase the sound buffer.
+* Modified pavo_defconfig to select the oss sound driver by default.
+* Fixed jzlcd.h for jz4730 pmp.
+* Modified jzcs8900a.c to not test the chip ID.
+
+2008.05.22:
+
+* jzcs8900a.c: fixed the bug of "No network devices available". <jlwei@ingenic.cn>
+
+2008.05.13:
+
+* Rewrote all of the UBI and UBIFS codes. <yrtan@ingenic.cn>
+
+2008.05.07:
+* Add GPIO group E group F irq, DMAC1 irq. Add SSI1 macros.
+ <lgwang@ingenic.cn>
+
+2008.05.06:
+
+* Modified MMC/SD driver jz_mmc.c to support PM callback. <cwjia@ingenic.cn>
+
+2008.05.04:
+
+* Fixed a bug of mtdblock-jz.uu of using the badblock_table. <yrtan@ingenic.cn>
+
+2008.04.26:
+
+* Patch jz4740_nand.c to optimize the RS correction algorithm. <zengzhaoxiu>
+
+2008.04.24
+* Jzlcd driver add Framebuffer Rotate support.
+ Update files:
+ drivers/video/Kconfig
+ drivers/video/jzlcd.h
+ drivers/video/jzlcd.c
+ <lgwang@ingenic.cn>
+
+2008.04.21:
+* Modified LCD_CFG_MODE_INTER_CCIR656 define
+ #define LCD_CFG_MODE_INTER_CCIR656 (5 << LCD_CFG_MODE_BIT)
+ should be ==>>
+ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT)
+ Update files:
+ include/asm-mips/mach-jz4730/regs.h
+ include/asm-mips/mach-jz4740/regs.h
+ include/asm-mips/mach-jz4750/regs.h
+
+2008.04.14:
+
+* Modify drivers/video/jzslcd.c to suport Smart LCD switches between
+ always refresh and event-driven refresh . <zyliu@ingenic.cn>
+
+2008.04.01:
+
+* Support multi-framebuffers, update files:
+ drivers/video/Kconfig, add: CONFIG_JZLCD_FRAMEBUFFER_MAX=1
+ drivers/video/jzlcd.h
+ drivers/video/jzlcd.c
+ arch/mips/configs/pavo_defconfig, add: CONFIG_JZLCD_FRAMEBUFFER_MAX=1
+ <lgwang@ingenic.cn>
+
+2008.03.29:
+
+* Modified sound/soc/jz4740/jz4740-i2s.c to support 32KHz PCM sample. <cjfeng@ingenic.cn>
+
+2008.03.28
+
+* Ported new mtd-utils and mkfs.ubifs. <yrtan@ingenic.cn>
+
+2008.03.27
+
+* board_fuwa.h, change GPIO_DISP_OFF_N to GPD25. <lgwang@ingenic.cn>
+* Added lyra_defconfig for JZ4740 LYRA (MP4) board. <zyliu@ingenic.cn>
+
+2008.03.24:
+
+* Added jzslcd.c for Smart LCD framebuffer driver. <zyliu@ingenic.cn>
+* Modified rtc_jz.c to use some functions in rtc library instead of our function.
+ <cjfeng@ingenic.cn>
+* Added jz_keypad.c and gpio_keys.c for scan keypad drivers. <cjfeng@ingenic.cn>
+
+2008.03.19:
+
+* Added block-jz.c to support block device layer on top of ubi.
+ <yrtan@ingenic.cn>
+
+2008.03.17:
+
+* Modified jz4740_udc.c to enable the suspend irq when host unloads us.
+ <jlwei@ingenic.cn>
+* pavo_defconfig: select CONFIG_WIRELESS_EXT, CONFIG_PNP and CONFIG_SERIAL_8250_PNP.
+ <lgwang@ingenic.cn>
+
+2008.03.14:
+
+* Modified jz_ts.c jz_ts.h and sadc.c to release CPU by interrupt mode instead of pio mode.
+ <cjfeng@ingenic.cn>
+
+2008.03.13:
+
+* Fixed a bug in jz4740_udc.c and jz4730_udc.c during rmmod the driver.
+ <cjfeng@ingenic.cn>
+
+2008.03.10:
+
+* Modified jz_i2s.c to fix the jz_audio_release(). <cjfeng@ingenic.cn>
+
+2008.03.08:
+
+* Fixed udc_hotplug.c to avoid the "unexpected IRQ". <jlwei@ingenic.cn>
+* Fixed jz4740/cpufreq.c of calculating the new_mclk. <lhhuang@ingenic.cn>
+
+2008.03.05:
+
+* Modified drivers/video/console/fbcon.c by adding fb_flashcursor selection.
+ <lgwang@ingenic.cn>
+
+2008.03.04:
+
+* Initial release.
diff --git a/Makefile b/Makefile
index 01385571d09..43d750f1699 100644
--- a/Makefile
+++ b/Makefile
@@ -180,8 +180,8 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
# Default value for CROSS_COMPILE is not to prefix executables
# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
export KBUILD_BUILDHOST := $(SUBARCH)
-ARCH ?= $(SUBARCH)
-CROSS_COMPILE ?=
+ARCH ?= mips
+CROSS_COMPILE ?= mipsel-linux-
# Architecture as present in compile.h
UTS_MACHINE := $(ARCH)
diff --git a/README-JZ b/README-JZ
new file mode 100644
index 00000000000..120e6e1311a
--- /dev/null
+++ b/README-JZ
@@ -0,0 +1,1181 @@
+
+ Linux 2.6 Kernel Release for Ingenic
+
+ (Updated: 2008-12-29)
+
+-------------
+** Content **
+-------------
+
+** Quick start **
+** Supported SOC and Platforms **
+** Overview of source tree **
+** NAND Flash Filesystem **
+** UBI, UBIFS and UBI Block Layer **
+** UBI and UBIFS images **
+** YAFFS2 **
+** MTD Block Layer **
+** About Bad Blocks of NAND **
+** SLC and MLC NAND Flash **
+** Initramfs **
+** Audio full duplex mode **
+** Support **
+
+
+-----------------
+** Quick Start **
+-----------------
+
+To build linux 2.6, you needs a mipsel-linux-gcc version 4. Please
+download it from Ingenic website http://www.ingenic.cn.
+
+You should have downloaded the linux-2.6.24.3.tar.bz2 and the latest kernel
+patch. The patch file was named as "linux-2.6.24.3-jz-yyyymmdd.patch.gz".
+
+Follow next steps to install the full kernel source:
+
+ $ tar -xjf linux-2.6.24.3.tar.bz2
+ $ cd linux-2.6.24.3
+ $ gzip -cd ../linux-2.6.24.3-jz-yyyymmdd.patch.gz | patch -p1
+
+Now you can configure and build the kernel.
+
+First, you need to do a 'make board_defconfig' to select a board.
+
+For example:
+
+ - make pavo_defconfig # JZ4740 PAVO board default configuration
+ - make pmp_defconfig # JZ4730 PMP ver 2.x board default configuration
+ - make dipper_defconfig # JZ4725 PMP ver 1.x board default configuration
+
+Then, configure and compile the kernel:
+
+ - make xconfig or make menuconfig, if you want to change the configuration.
+ - make, make uImage, or make zImage, to build the kernel.
+
+The ELF format kernel image is linux-2.6.24.3/vmlinux.
+The U-Boot format kernel image is linux-2.6.24.3/arch/mips/boot/uImage.
+The compressed raw kernel image is linux-2.6.24.3/arch/mips/boot/compressed/zImage.
+
+
+---------------------------------
+** Supported SOC and Platforms **
+---------------------------------
+
+This release supports several platforms based on JZ4730, JZ4740 and JZ4750.
+
+JZ4750 based platforms:
+
+ - apus: JZ4750 development board
+
+JZ4740 based platforms:
+
+ - pavo: JZ4740 reference board
+ - leo: JZ4740 development board
+
+JZ4730 based platforms:
+
+ - pmp: JZ4730 reference board version 2.x
+
+JZ4725 based platforms:
+
+ - dipper: JZ4725 reference board version 1.x
+
+
+-----------------------------
+** Overview of source tree **
+-----------------------------
+
+ - Changelog : Revision history
+ - README-JZ : This file
+ - arch/mips/
+ - kernel/ : MIPS kernel common code
+ - mm/ : MIPS memory common code
+ - jz4730/ : JZ4730 code
+ - jz4740/ : JZ4740 JZ4725 JZ4720 code
+ - jz4750/ : JZ4750 code
+ - configs/
+ - apus_defconfig : jz4750 based apus default configuration
+ - pavo_defconfig : jz4740 based pavo default configuration
+ - pmp_defconfig : jz4730 based pmp default configuration
+ - dipper_defconfig : jz4725 based dipper default configuration
+ - include/asm-mips/ : MIPS asm common include
+ - jzsoc.h : JZ SoC common include
+ - mach-jz4730/ : JZ4730 SoC headers
+ - mach-jz4740/ : JZ4740 JZ4725 JZ4720 SoC headers
+ - mach-jz4750/ : JZ4750 SoC headers
+ - fs/
+ - jffs2/ : JFFS2 file system
+ - yaffs2/ : YAFFS2 file system
+ - utils/ : YAFFS2 utilities, like mkyaffs2image
+ - ubifs/ : ubifs file system
+ - mkfs.ubifs/ : mkfs.ubifs util to create UBIFS
+ - sound/
+ oss/ : OSS audio driver
+ soc/jz4740/ : JZ4740 ALSA audio driver
+ - drivers/
+ - char/
+ - serial.c : serial port driver
+ - rtc_pcf8563.c : PCF8563 RTC driver
+ - rtc_jz.c : JZSOC On-Chip RTC driver
+ - jzchar/ : jzchar devices
+ - jz_ts.c : generic touch screen driver
+ - sadc.c : JZ4740 SADC driver
+ - ak4182.c : AK4182 touch driver
+ - udc_hotplug.c : UDC hotplug management
+ - poweroff.c : suspend/poweroff management
+ - input/keyboard/
+ - jz_keypad.c : scan keypad driver
+ - gpio_keys.c : gpio keypad driver
+ - media/video/
+ - jz_cim.c : generic camera driver
+ - jz_sensor.c : generic sensor driver
+ - mmc/host/
+ - jz_mmc.c : jz mmc/sd card driver
+ - mtd/
+ - mtdblock-jz.c : NAND Flash translation layer driver
+ - nand/
+ - nand_base.c : NAND flash interface to MTD
+ - jz4730_nand.c : NAND flash definition on JZ4730 boards
+ - jz4740_nand.c : NAND flash definition on JZ4740 boards
+ - jz4750_nand.c : NAND flash definition on JZ4750 boards
+ - ubi/ : MTD utilities like flash_eraseall, nandwrite etc.
+ - ubiblk.c : UBI block layer driver on top of UBI
+ - mtd-utils/ : MTD and UBI utilities, like flash_eraseall, nandwrite and ubimkvol etc.
+ - ubi-utils : UBI utils like ubimkvol/ubirmvol/ubinize etc.
+ - net/
+ - jz_eth.c : JZ4730 On-Chip ethernet driver
+ - jzcs8900a.c : cs8900a ethernet driver
+ - serial/
+ - 8250.c : standard 16550A serial driver
+ - usb/ : USB OHCI host driver
+ - usb/host/
+ ohci-jz.c : JZ OHCI driver
+ - usb/gadget/
+ - jz4730_udc.c : JZ4730 UDC low-level driver
+ - jz4740_udc.c : JZ4740 and JZ4750 UDC low-level driver
+ - file_storage.c : USB mass storage class driver
+ - serial.c : USB serial class driver
+ - video/
+ - jzlcd.c : JZ LCD controller framebuffer driver for JZ4730 and JZ4740
+ - jz4740_slcd.c : JZ Smart LCD controller framebuffer driver for JZ4740
+ - jz4750_lcd.c : JZ LCD and Smart LCD controller driver for JZ4750
+ - jz4750_tve.c : JZ TV encoder controller driver for JZ4750
+ - watchdog/
+ - jz_wdt.c : JZ On-Chip watchdog driver
+
+
+---------------------------
+** NAND Flash Filesystem **
+---------------------------
+
+NAND Flash is the main non-volatile storage for most embedded devices.
+So, it's very important to implement a stable and reasonable filesystem on
+NAND flash.
+
+In Linux, the MTD subsystem provides a common interface for operating with
+many flash devices, such as NOR, NAND etc. And the MTD subsystem was modified
+by Ingenic to support the NAND larger than 2GB.
+
+Above MTD layer, we can implement the YAFFS2 filesystem. Or we can implement
+a MTD block device, on top of it we can implement the general filesystem
+such as FAT and EXT2.
+
+The Linux 2.6 kernel also implements the UBI (Unsorted Block Images). UBI
+is a software layer above MTD layer which admits of LVM-like logical volumes
+on top of MTD devices, hides some complexities of flash chips like wear
+and bad blocks and provides some other useful capabilities. Please, consult
+the MTD web site for more details (www.linux-mtd.infradead.org).
+
+On top of UBI, we can implement the UBIFS filesystem. We can also emulate
+block devices above UBI, such that we can use the general filesystem such as
+FAT and EXT2 on it.
+
+The architecture of the NAND flash filesystem is illustrated as below:
+
+
+
+ +-----------+ +-------------+ +-------------+
+ | YAFFS2 | | UBIFS | | FAT or EXT2 | Filesystems
+ +-----------+ +-------------+ +-------------+
+ \ | / \
+ \ | / \
+ \ | / \
+ \ | +-----------------+ +-----------------+
+ \ | | UBI Block Layer | | MTD Block Layer |
+ \ | +-----------------+ +-----------------+
+ \ | / /
+ \ | / /
+ \ +-------------+ /
+ \ | UBI | /
+ \ +-------------+ /
+ \ | /
+ +-------------------------------------------+
+ | MTD |
+ +-------------------------------------------+
+ |
+ +--------------------+
+ | nand_base.c |
+ +--------------------+
+ |
+ +--------------------+
+ | jz4740_nand.c |
+ +--------------------+
+
+
+The related source codes are listed below:
+
+fs/yaffs2: YAFFS2
+fs/ubifs: UBIFS
+fs/fat: FAT
+fs/ext2: EXT2
+drivers/mtd: MTD
+drivers/mtd/ubi: UBI
+drivers/mtd/ubi/ubiblk.c: UBI Block Layer
+drivers/mtd/mtdblock-jz.c: MTD Block Layer
+drivers/mtd/mtd-utils: MTD and UBI utils (flash_eraseall/ubimkvol/ubinfo/ubinize etc.)
+fs/ubifs/mkfs.ubifs: UBIFS util to create ubifs image (mkfs.ubifs)
+fs/yaffs2/util: YAFFS2 util (mkyaffs2image)
+
+To build mtd utils, go to drivers/mtd/mtd-utils, type 'make' and
+'make install DESTDIR=/nfsroot/root26'.
+
+To build yaffs2 util, go to fs/yaffs2/utils and type 'make'.
+
+To build ubifs util, go to fs/ubifs/mkfs.ubifs and type 'make'.
+
+Except 'UBI Block Layer' and 'MTD Block Layer', which are implement by Ingenic
+ourself, the others are general in the linux kernel tree.
+
+User can select any one of these drivers to implement the filesystem. It all
+depends on yourself.
+
+Following sections will describe how to use these drivers in details.
+
+
+------------------------------------
+** UBI, UBIFS and UBI Block Layer **
+------------------------------------
+
+UBIFS is a new flash file system which is designed to work on top of UBI.
+
+Here is a short and unsorted list of some of UBIFS features:
+
+* write-back support - This dramatically improves the throughput of the
+file-system comparing to JFFS2, which is write-through;
+
+* fast mount time
+
+* tolerance to unclean reboots - UBIFS is a journaling file system and it
+tolerates sudden crashes and unclean reboots;
+
+* fast I/O - even with write-back disabled;
+
+* on-the-flight compression - the data is stored in compressed form on
+the flash media, which makes it possible to put considerably more data to
+the flash as if the data would not be compressed;
+
+Please, consult the MTD web site for more details (www.linux-mtd.infradead.org).
+
+The UBI and UBIFS can be compiled as modules or built into the kernel.
+
+To enable UBI, you need to select following configurations:
+
+CONFIG_MTD_UBI: Enable UBI
+CONFIG_MTD_UBI_WL_THRESHOLD: UBI wear-leveling threshold
+CONFIG_MTD_UBI_BEB_RESERVE: Percentage of reserved eraseblocks for bad eraseblocks handling
+
+To enable 'UBI Block Layer', you need to select following configurations:
+
+CONFIG_MTD_UBI_BLKDEVS: Common interface to block layer for UBI
+CONFIG_MTD_UBI_BLOCK: Emulate block devices
+
+To enable UBIFS, you need to select following configurations:
+
+CONFIG_UBIFS_FS: UBIFS file system support
+CONFIG_UBIFS_COMPRESSION_OPTIONS: Advanced compression options for UBIFS
+CONFIG_UBIFS_LZO: UBIFS LZO compression support
+CONFIG_UBIFS_ZLIB: UBIFS ZLIB compression support
+CONFIG_UBIFS_FS_DEBUG: UBIFS debugging
+
+If you want to compile as modules, take next steps:
+
+Type 'make modules' to compile the modules.
+
+Type 'make modules_install INSTALL_MOD_PATH=/nfsroot/root26' to install the
+modules to the target root.
+
+You also need to compile the MTD and UBIFS utilities and install them to the
+target root.
+
+
+Now boot your board and mounted root FS with these modules, and below is a
+simple guide to test and use the UBIFS and 'UBI Block Layer':
+
+Here we will create UBI volumes on mtd5.
+
+First, format mtd5:
+
+# flash_eraseall /dev/mtd5
+Erasing 256 Kibyte @ 1ffc0000 -- 99 % complete.
+
+Install UBI module, attached it to mtd5:
+
+# modprobe ubi mtd=5
+UBI: empty MTD device detected
+UBI: create volume table (copy #1)
+UBI: create volume table (copy #2)
+UBI: attached mtd5 to ubi0
+UBI: MTD device name: "NAND VFAT partition"
+UBI: MTD device size: 512 MiB
+UBI: physical eraseblock size: 262144 bytes (256 KiB)
+UBI: logical eraseblock size: 258048 bytes
+UBI: number of good PEBs: 2048
+UBI: number of bad PEBs: 0
+UBI: smallest flash I/O unit: 2048
+UBI: VID header offset: 2048 (aligned 2048)
+UBI: data offset: 4096
+UBI: max. allowed volumes: 128
+UBI: wear-leveling threshold: 4096
+UBI: number of internal volumes: 1
+UBI: number of user volumes: 0
+UBI: available PEBs: 2024
+UBI: total number of reserved PEBs: 24
+UBI: number of PEBs reserved for bad PEB handling: 20
+UBI: max/mean erase counter: 0/0
+UBI: background thread "ubi_bgt0d" started, PID 241
+
+Now, create two UBI volumes, one is called ubifs and size is 200MB, the
+other is called vfat and size is 298MB.
+
+# ubimkvol /dev/ubi0 -s 200MiB -N ubifs
+Volume ID 0, size 813 LEBs (209793024 bytes, 200.1 MiB), LEB size 258048 bytes (252.0 KiB), dynamic, name "ubifs", alignment 1
+# ubimkvol /dev/ubi0 -s 298MiB -N vfat
+Volume ID 1, size 1211 LEBs (312496128 bytes, 298.0 MiB), LEB size 258048 bytes (252.0 KiB), dynamic, name "vfat", alignment 1
+
+Then you can use 'ubinfo' to query the UBI volume info:
+
+# ubinfo -a
+UBI version: 1
+Count of UBI devices: 1
+UBI control device major/minor: 10:63
+Present UBI devices: ubi0
+
+ubi0:
+Volumes count: 2
+Logical eraseblock size: 258048
+Total amount of logical eraseblocks: 2048 (528482304 bytes, 504.0 MiB)
+Amount of available logical eraseblocks: 0 (0 bytes)
+Maximum count of volumes 128
+Count of bad physical eraseblocks: 0
+Count of reserved physical eraseblocks: 20
+Current maximum erase counter value: 3
+Minimum input/output unit size: 2048 bytes
+Character device major/minor: 252:0
+Present volumes: 0, 1
+
+Volume ID: 0 (on ubi0)
+Type: dynamic
+Alignment: 1
+Size: 813 LEBs (209793024 bytes, 200.1 MiB)
+State: OK
+Name: ubifs
+Character device major/minor: 252:1
+-----------------------------------
+Volume ID: 1 (on ubi0)
+Type: dynamic
+Alignment: 1
+Size: 1211 LEBs (312496128 bytes, 298.0 MiB)
+State: OK
+Name: vfat
+Character device major/minor: 252:2
+
+
+It shows that we have successfully created two UBI volumes (Volume ID 0 and 1)
+on ubi0.
+
+Now you can install the UBIFS and 'UBI Block Layer' modules and create
+UBIFS and FAT on UBI volume 0 and 1 respectively.
+
+# modprobe ubifs
+# modprobe ubiblk
+
+# lsmod
+Module Size Used by Not tainted
+ubiblk 7696 0
+bdev 10016 1 ubiblk
+deflate 4256 1
+zlib_deflate 22256 1 deflate
+zlib_inflate 16992 1 deflate
+lzo 2400 1
+lzo_decompress 2816 1 lzo
+lzo_compress 2848 1 lzo
+ubifs 208560 0
+crc16 2048 1 ubifs
+ubi 103664 4 ubiblk,bdev,ubifs
+
+Mount UBI volume 0 (the name is "ubifs") on ubi0 with type ubifs:
+
+# mount -t ubifs ubi0:ubifs /mnt/ubifs/
+UBIFS: mounted UBI device 0, volume 0
+UBIFS: minimal I/O unit size: 2048 bytes
+UBIFS: logical eraseblock size: 258048 bytes (252 KiB)
+UBIFS: file system size: 207212544 bytes (202356 KiB, 197 MiB, 803 LEBs)
+UBIFS: journal size: 9420800 bytes (9200 KiB, 8 MiB, 37 LEBs)
+UBIFS: data journal heads: 1
+UBIFS: default compressor: LZO
+
+It shows that we have mounted it sucessfully.
+
+Format /dev/ubiblock1 (the block device for UBI volume 1) and mount it with
+type vfat:
+
+# mkfs.vfat /dev/ubiblock1
+# mount -t vfat /dev/ubiblock1 /mnt/ubiblock1
+
+Please refer to the linux26_developer_guide.pdf for more details about
+the UBI and UBIFS.
+
+
+--------------------------
+** UBI and UBIFS images **
+--------------------------
+
+Generally, you want to create UBIFS and VFAT images respectively and combine
+these two images into one single image, and then use the nandwrite command
+to write this image to the MTD partition.
+
+First of all, you need to compile the mkfs.ubifs utility. We use mkfs.ubifs
+to create the UBIFS image, like this:
+
+Note: download the linux-nand-utils.tar.gz package from www.ingenic.cn and
+follows the guide to compile and run the mkfs.ubifs.
+
+On the PC host:
+
+$ mkfs.ubifs -h
+Usage: mkfs.ubifs [OPTIONS]
+Make a UBIFS file system image from an existing directory tree
+
+Options:
+ -r, -d, --root=DIR Build file system from directory DIR
+ -m, --min-io-size=SIZE Minimum I/O size SIZE
+ -e, --leb-size=SIZE Use logical erase block size SIZE
+ -c, --max-leb-cnt=COUNT Use maximum logical erase block count COUNT
+ -o, --output=FILE Output to FILE
+ -j, --jrn-size=SIZE Use journal size SIZE bytes
+ -x, --compr=TYPE Use compression type TYPE (lzo, zlib or none) (default: lzo)
+ -f, --fanout=NUM Use fanout NUM (default: 8)
+ -k, --keyhash=TYPE Use key hash type TYPE (r5 or test) (default: r5)
+ -l, --log-lebs=COUNT Use COUNT erase blocks for the log
+ -p, --orph-lebs=COUNT Use COUNT erase blocks for orphans (default: 1)
+ -v, --verbose Verbose operation
+ -V, --version Display version information
+ -g, --debug=LEVEL Display debug information
+ -h, --help Display this help text
+
+$ mkfs.ubifs -r /nfsroot/root26 -m 2048 -e 258048 -c 813 -o ubifs.img
+
+This will create an UBIFS image called ubifs.img. The argument values
+can be obtained from the 'ubinfo -a' command.
+
+Follow next steps to create a 30MB FAT32 image called vfat.img:
+
+# dd if=/dev/zero of=vfat.img bs=1M count=30
+# losetup /dev/loop0 vfat.img
+# mkfs.vfat /dev/loop0
+# mount -t vfat /dev/loop0 /mnt/vfat
+# cp * /mnt/vfat
+# umount /mnt/vfat
+# losetup -d /dev/loop0
+
+Now the two images ubifs.img and vfat.img are ready, and we want to
+create two UBI volumes and write these two images to the two UBI volumes
+respectively. We can do like this:
+
+First, use 'ubinize' command to combine ubifs.img and vfat.img into one
+UBI image called ubi.img.
+
+Second, use 'nandwrite_mlc_ubi' command to write the ubi.img to the
+MTD partition.
+
+To use 'ubinize' command, you should prepare an INI file for it. The
+content of the INI file are as below:
+
+# cat ubinize.cfg
+[ubifs]
+mode=ubi
+image=ubifs.img
+vol_id=0
+vol_size=200MiB
+vol_type=dynamic
+vol_name=ubifs
+vol_alignment=1
+vol_flag=autoresize
+
+[vfat]
+mode=ubi
+image=vfat.img
+vol_id=1
+vol_size=298MiB
+vol_type=dynamic
+vol_name=vfat
+vol_alignment=1
+vol_flag=autoresize
+
+
+Now you can boot your board and follow next guides to create the UBI
+image and burn the UBI image.
+
+On the target board side:
+
+# ubinize -o ubi.img ubinize.cfg -p 262144 -m 2048
+
+If things go well, you can get the UBI image ubi.img.
+
+Then use 'nandwrite_ubi' command to write it to the MTD partition.
+
+# flash_eraseall /dev/mtd5
+# nandwrite_ubi -a -q -m /dev/mtd5 ubi.img
+
+Now the UBI image has been written to the NAND mtd5 partition.
+
+Use next commands to test it.
+
+# modprobe ubi mtd=5
+
+# ubinfo -a
+UBI version: 1
+Count of UBI devices: 1
+UBI control device major/minor: 10:63
+Present UBI devices: ubi0
+
+ubi0:
+Volumes count: 2
+Logical eraseblock size: 258048
+Total amount of logical eraseblocks: 2048 (528482304 bytes, 504.0 MiB)
+Amount of available logical eraseblocks: 0 (0 bytes)
+Maximum count of volumes 128
+Count of bad physical eraseblocks: 0
+Count of reserved physical eraseblocks: 20
+Current maximum erase counter value: 1
+Minimum input/output unit size: 2048 bytes
+Character device major/minor: 252:0
+Present volumes: 0, 1
+
+Volume ID: 0 (on ubi0)
+Type: dynamic
+Alignment: 1
+Size: 813 LEBs (209793024 bytes, 200.1 MiB)
+State: OK
+Name: ubifs
+Character device major/minor: 252:1
+-----------------------------------
+Volume ID: 1 (on ubi0)
+Type: dynamic
+Alignment: 1
+Size: 1211 LEBs (312496128 bytes, 298.0 MiB)
+State: OK
+Name: vfat
+Character device major/minor: 252:2
+
+
+This shows that two UBI volumes are present on ubi0.
+
+# modprobe ubifs
+# mount -t ubifs ubi0:ubifs /mnt/ubifs/
+UBIFS: mounted UBI device 0, volume 0
+UBIFS: minimal I/O unit size: 2048 bytes
+UBIFS: logical eraseblock size: 258048 bytes (252 KiB)
+UBIFS: file system size: 207212544 bytes (202356 KiB, 197 MiB, 803 LEBs)
+UBIFS: journal size: 9420800 bytes (9200 KiB, 8 MiB, 37 LEBs)
+UBIFS: data journal heads: 1
+UBIFS: default compressor: LZO
+
+# modprobe ubiblk
+# mount -t vfat /dev/ubiblock1 /mnt/ubiblock1
+
+# df
+Filesystem 1k-blocks Used Available Use% Mounted on
+tmpfs 30196 56 30140 0% /dev
+ubi0:ubifs 197536 48228 149308 24% /mnt/ubifs
+/dev/ubiblock1 30642 5762 24880 19% /mnt/ubiblock1
+
+It shows that the UBIFS and VFAT are all mounted successfully.
+
+
+------------
+** YAFFS2 **
+------------
+
+YAFFS (Yet Another Flash File System) was written to satisfy the
+special needs of NAND flash. The second release of YAFFS especially
+points to supporting newer NAND flash chips with 2k page size and
+up to 128MB capacity.
+
+YAFFS2 is supported in this kernel. It's built on top of MTD directly.
+Go to fs/yaffs2 for more details.
+
+To build the utility of YAFFS2, change to directory fs/yaffs2/utils/
+and type 'make'.
+
+To create a YAFFS2 image, mkyaffs2image command is used On PC host:
+
+ usage: mkyaffs2image layout# dir image_file [convert]
+
+ layout# NAND OOB layout:
+ 0 - nand_oob_raw, no used,
+ 1 - nand_oob_64, for 2KB pagesize,
+ 2 - nand_oob_128, for 2KB pagesize using multiple planes or 4KB pagesize,
+ 3 - nand_oob_256, for 4KB pagesize using multiple planes
+ dir the directory tree to be converted
+ image_file the output file to hold the image
+
+ e.g., for 2KB page size NAND not using multi-plane:
+
+ $ mkyaffs2image 1 /nfsroot/root26 root26.yaffs2
+
+To burn the yaffs2 image to the NAND, use next command (On target board):
+
+ # nandwrite -a -o /dev/mtd2 root26.yaffs2
+
+To format and mount YAFFS2 (On target board):
+
+ # flash_eraseall /dev/mtd2
+ # mount -t yaffs2 /dev/mtdblock2 /mnt/mtdblock2
+
+
+---------------------
+** MTD Block Layer **
+---------------------
+
+Ingenic implement the 'MTD Block Layer' by ourself. This gives you a choice
+to implement a general filesystem such as FAT and ext2 on NAND flash.
+
+Which partition used for VFAT should be set in bootargs of u-boot for kernel cmdline,
+so the kernel kowns other partitions aren't base on MTD Block Layer, and their mounting
+speed will be faster. For example, if mtdblock5 is used for VFAT, you can
+
+set bootargs mem=64M console=ttyS1,57600n8 ip=dhcp root=/dev/mtdblock2 rw mtdblk=5
+
+and the mounting speed of mtdblock2 which is not based on MTD Block Layer will be faster.
+
+
+Features of the 'MTD Block Layer' include:
+
+1. Block unit management (address mapping & block cache operations)
+2. Wear-leveling
+3. Bad block management
+4. Write verify enable
+5. mutiple choice of ECC algorithms (hardware Hamming ECC & Reed Solomon ECC,
+software Hamming ECC)
+
+Kernel configurations related to the 'MTD Block Layer':
+
+* CONFIG_MTD_OOB_COPIES: defines how many copies of the critical oob data for
+ each block. Since the page data can be corrected by the ECC algorithm but
+ the oob data can't, we want to ensure the correction of the oob data by this
+ way. The mtdblock-jz translation layer driver uses block mode to manipulate
+ the NAND flash. It makes several copies of the oobinfo data for each block,
+ so that it can get a correct copy even there is an error in one of them.
+
+* CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE: defines this to enable the write
+ verification function, which will read back data to verify during a write
+ operation.
+
+Take following steps to use the 'MTD Block Layer':
+
+ # flash_eraseall /dev/mtd3
+ # mkfs.vfat /dev/mtdblock3
+ # mount -t vfat /dev/mtdblock3 /mnt/vfat
+
+
+NOTICE:
+
+You can define mutiple VFAT partitions, all the VFAT partitions share
+the same above configurations.
+
+Each VFAT partition have its own block cache which resides only in RAM.
+Generally, the block cache flush operation is triggered when the access
+address exceeds block boundary. The last block cache usually will be
+flushed to NAND device when the device is closed (eg: umount /mnt/vfat;
+use system call close(fd)).
+
+Abrupt poweroff without flushing the last block cache will cause the
+VFAT partition to lose the most significant data which records the
+information of the file system management such as FAT table, inodes ...
+
+To avoid this bad thing, you have to flush block cache as soon as possible.
+Please do remember to flush block cache manually when you finish
+a write operation.
+
+The MTD block layer driver supplys an ioctl for triggering flush block cache
+operation. The code attached behind is a reference for you to use.
+
+eg:
+
+ # cp * /mnt/vfat
+ # sync ; this step is necessary to flush the FS cache
+ # flushcache /dev/mtdblock3 ; this step is necessary to flush the NFTL block cache
+
+
+/* flushcache.c */
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+int main(int argc,char **argv)
+{
+ int fd;
+
+ if( argc != 2 ){
+ printf( "Usage:%s device name(full path)\n", argv[0] );
+ return -1;
+ }
+
+ if( (fd = open( argv[1], O_RDONLY ) ) == -1) {
+ printf( "Open %s failed\n", argv[1] );
+ return -1;
+ }
+
+ if( ioctl( fd, BLKFLSBUF) == -1)
+ printf("flush catche failed\n");
+
+ close(fd);
+ return 0;
+}
+
+
+------------------------------
+** About Bad Blocks of NAND **
+------------------------------
+
+NAND is a special flash type which there are new bad blocks generated during
+the whole period of using it. So the NAND driver should know how to detect
+a bad block and how to mark a new block bad.
+
+Some types of NAND flash mark the bad block in the spare area of the first
+page but others in the last page. So we define a kernel configuration called
+CONFIG_MTD_BADBLOCK_FLAG_PAGE and use it to decide the bad block.
+
+CONFIG_MTD_BADBLOCK_FLAG_PAGE: page in a block to store the badblock mark
+
+Following functions should be cared:
+
+nand_base.c:
+
+ - nand_block_bad()
+ - nand_default_block_markbad()
+
+nand_bbt.c:
+
+ - create_bbt()
+
+---------------------------------------
+** Multiple plane operation for NAND **
+---------------------------------------
+
+NAND multiple plane is a feature enabling support of simultaneous write/erase
+operations for NAND devices with multiplane architecture. This feature
+significantly increases write performance. It could give performance benefits
+if NAND device supports ultiple plane architecture only. If NAND device does
+not support multiple plane and CONFIG_MTD_NAND_MULTI_PLANE was set to yes when
+compiling kernel, code will parse device capabilities and NAND device will work
+in single plane mode. For safe, you'd better set CONFIG_MTD_NAND_MULTI_PLANE to
+no if NAND device does not support multiple plane.
+
+If the NAND device support multiple plane, you could determine which partitions
+use multiple plane and which use single plane by setting the value of
+partition_info[] in driver/mtd/nand/jz47xx_nand.c, if the value of use_planes
+for a partition is 0, then the partition uses single plane, or else it uses
+multiple plane. e.g.
+
+static struct mtd_partition partition_info[] = {
+ {name:"NAND BOOT partition",
+ offset:0 * 0x100000,
+ size:4 * 0x100000,
+ use_planes: 0},
+ {name:"NAND KERNEL partition",
+ offset:4 * 0x100000,
+ size:4 * 0x100000,
+ use_planes: 0},
+ {name:"NAND ROOTFS partition",
+ offset:8 * 0x100000,
+ size:120 * 0x100000,
+ use_planes: 1},
+ {name:"NAND DATA1 partition",
+ offset:128 * 0x100000,
+ size:128 * 0x100000,
+ use_planes: 1},
+ {name:"NAND DATA2 partition",
+ offset:256 * 0x100000,
+ size:256 * 0x100000,
+ use_planes: 1},
+ {name:"NAND VFAT partition",
+ offset:512 * 0x100000,
+ size:512 * 0x100000,
+ use_planes: 1},
+};
+
+---------------------------------------
+** Multiple chip selecting for NAND **
+---------------------------------------
+
+CS1_N pin on Jz4740 or Jz4750 will be used for NAND defaultly; besides CS2_N,
+CS3_N, and CS4_N pins could be used for NAND, too. You can configure the kernel
+and select the configuration at:
+
+ [Memory Technology Devices (MTD)] --> [NAND Device Support]
+
+ --> [ECC Type] --> [Use NAND on CS2_N of JZSOC]
+ [Use NAND on CS3_N of JZSOC]
+ [Use NAND on CS4_N of JZSOC]
+
+
+----------------------------
+** SLC and MLC NAND Flash **
+----------------------------
+
+Single-Level Cell (SLC) and Multi-Level Cell (MLC) are both NAND-based
+non-volatile memory technologies. MLC NAND Flash allows each memory cell
+to store two bits of information, compared to the one bit-per-cell SLC
+NAND Flash allows. As a result, 90 nanometer (nm) MLC NAND offers a
+larger capacity (typically twice the density of SLC) and at a cost point
+appropriate for consumer products.
+
+Though SLC NAND offers a lower density, it also provides an enhanced
+level of performance in the form of faster write speeds. Because SLC
+stores only one bit per cell, the likelihood for error is reduced.
+At 90 nanometer process, it is recommended to implement a 1 to 2-bit
+ECC for SLC, whereas 4-bit ECC is recommended on the MLC architecture.
+
+The linux kernel from ingenic provides MLC NAND support through Hardware
+ECC algorithm. Jz4740 supports Reed-Solomon (RS) ECC algorithm, which can
+detect and correct 4-bit errors per 512 bytes at least. Jz4750 supports
+4-bit and 8-bit BCH ECC algorithm, 4-bit BCH ECC can detect and correct
+4 bits for up to 1010 bytes and 8-bit BCH ECC can detect and correct
+8 bits errors for up to 1016 bytes.
+
+To include MLC NAND support, you are required to configure the kernel
+and select the configuration CONFIG_MTD_HW_RS_ECC for Jz4740, and
+CONFIG_MTD_HW_BCH_ECC for Jz4750, which can be found at:
+
+ [Memory Technology Devices (MTD)] --> [NAND Device Support]
+
+ --> [ECC Type] --> [Select hardware RS ECC]
+ [Select hardware BCH ECC]
+
+
+---------------
+** Initramfs **
+---------------
+
+Please read Documentation/filesystems/ramfs-rootfs-initramfs.txt for
+more information about how to use initramfs.
+
+Following are some steps to help you to create root fs by using initramfs:
+
+# cd /rootfs/
+# find . | cpio -c -o | gzip -9 > ../rootfs.cpio.gz
+
+Reconfigure the Linux kernel and select next configurations:
+
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="/rootfs.cpio.gz"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+
+Rebuild the kernel and boot the kernel with next command lines:
+
+"root=/dev/ram0 rw rdinit=/sbin/init"
+
+
+----------------------------
+** Audio full duplex mode **
+----------------------------
+
+OSS audio driver supports full duplex mode, that is to say, you can
+record while replaying.
+
+The user application want to do some jobs to enable the full duplex mode
+of the OSS driver. The following are two examples:
+
+
+One is:
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/soundcard.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#define AUDIO_FILE "/dev/dsp"
+#define FREQS 48000
+#define CHANNELS 2
+#define TEST_TIME 10
+#define SAMPLES 16
+#define BUF_SIZE 8192
+#define MAX_LEN (FREQS * CHANNELS * TEST_TIME * SAMPLES / 8)
+
+int main(int argc, char *argv[])
+{
+ FILE *fp;
+ pid_t pid;
+ int audio_fd, i;
+ char *play_name;
+ char *rec_name;
+
+ int play_count, play_cnt, played;
+ int rec_count, rec_cnt, recorded;
+
+ u_char play_arr[MAX_LEN];
+ u_char rec_arr[MAX_LEN];
+ int err = 0;
+
+ play_name = argv[1];
+ rec_name = argv[2];
+
+ if ((audio_fd = open("/dev/dsp", O_RDWR)) < 0) {
+ printf(" Can't open sound device!\n");
+ exit(-1);
+ }
+
+ i = BUF_SIZE;
+ ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i);
+ ioctl(audio_fd, SNDCTL_DSP_SYNC, NULL);
+
+ i = CHANNELS;
+ ioctl(audio_fd, SNDCTL_DSP_STEREO, (u_char *) &i);
+
+ i = SAMPLES;
+ ioctl(audio_fd, SNDCTL_DSP_SAMPLESIZE, (u_char *) &i);
+
+ i = FREQS;
+ ioctl(audio_fd, SNDCTL_DSP_SPEED, (u_char *) &i);
+
+ fp=fopen(play_name, "r");
+ fread(play_arr, 1, MAX_LEN, fp);
+ fclose(fp);
+
+
+ play_count = MAX_LEN;
+ played = 0;
+
+ rec_count = MAX_LEN;
+ recorded = 0;
+
+ switch(pid = fork()) {
+ case -1:
+ printf("error\n");
+ break;
+ case 0:
+ printf(" playing\n");
+ while (play_count) {
+ play_cnt = play_count;
+ if (play_cnt > BUF_SIZE)
+ play_cnt = BUF_SIZE;
+
+ write (audio_fd, (char *)play_arr+played, play_cnt);
+ played += play_cnt;
+ play_count -= play_cnt;
+ }/* while (count) */
+ exit(0);
+ break;
+ default:
+ printf(" recording\n");
+ while (rec_count) {
+ rec_cnt = rec_count;
+ if (rec_cnt > BUF_SIZE)
+ rec_cnt = BUF_SIZE;
+
+ read (audio_fd, (char *)rec_arr+recorded, rec_cnt);
+ recorded += rec_cnt;
+ rec_count -= rec_cnt;
+ }/* while (count) */
+ break;
+ }
+ close(audio_fd);
+
+ printf("write data to file, waiting for a while\n");
+ fp=fopen(rec_name, "w");
+ fwrite(rec_arr, 1, MAX_LEN, fp);
+ fclose(fp);
+
+ return err;
+}
+
+The other is :
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/soundcard.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#define AUDIO_FILE "/dev/dsp"
+#define FREQS_PLAY 22050
+#define FREQS_REC 8000
+#define FREQS 22050
+#define CHANNELS 1
+#define TEST_TIME 10
+#define SAMPLES 16
+#define BUF_SIZE 8192
+#define MAX_LEN (FREQS * CHANNELS * TEST_TIME * SAMPLES / 8)
+
+int main(int argc, char *argv[])
+{
+ FILE *fp;
+ pid_t pid;
+ int audio_fd, i;
+ char *play_name;
+ char *rec_name1, *rec_name2, *rec_name3;
+ int mixerfd, vol, savevol;
+
+ int count;
+ int play_count, play_cnt, played;
+ int rec_count, rec_cnt, recorded;
+
+ u_char play_arr[MAX_LEN];
+ u_char rec_arr[MAX_LEN];
+ int err = 0;
+
+ play_name = argv[1];
+ rec_name1 = argv[2];
+ rec_name2 = argv[3];
+ rec_name3 = argv[4];
+
+ if ((mixerfd = open("/dev/mixer", O_RDWR)) < 0) {
+ perror("/dev/mixer");
+ exit(1);
+ }
+
+ if ((audio_fd = open("/dev/dsp", O_RDWR)) < 0) {
+ printf(" Can't open sound device!\n");
+ exit(-1);
+ }
+
+ i = BUF_SIZE;
+ ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i);// midify buffer lenth
+ ioctl(audio_fd, SNDCTL_DSP_SYNC, NULL);
+
+ i = CHANNELS;
+ ioctl(audio_fd, SNDCTL_DSP_CHANNELS, (u_char *) &i);
+
+ i = SAMPLES;
+ ioctl(audio_fd, SNDCTL_DSP_SAMPLESIZE, (u_char *) &i);
+
+ fp=fopen(play_name, "r");
+ fread(play_arr, 1, MAX_LEN, fp);
+ fclose(fp);
+
+ if (ioctl(mixerfd, SOUND_MIXER_READ_MIC, &savevol) == -1) {
+ perror("SOUND_MIXER_READ_DEVMASK mic");
+ exit(-1);
+ }
+
+ savevol = savevol & 0xff;
+
+ for (count = 1; count <= 3; count++) {
+
+ play_count = MAX_LEN;
+ played = 0;
+
+ rec_count = MAX_LEN;
+ recorded = 0;
+
+
+ i = FREQS_PLAY;
+ ioctl(audio_fd, SNDCTL_DSP_SPEED, (u_char *) &i);
+
+ printf(" playing %d\n", i);
+ while (play_count) {
+ play_cnt = play_count;
+ if (play_cnt > BUF_SIZE)
+ play_cnt = BUF_SIZE;
+
+ write (audio_fd, (char *)play_arr+played, play_cnt);
+ played += play_cnt;
+ play_count -= play_cnt;
+ }/* while (count) */
+
+ /* wait for sync */
+ ioctl(audio_fd, SNDCTL_DSP_SYNC, NULL);
+
+ /* set mic gain 0 */
+ vol = 0;
+ if (ioctl(mixerfd, SOUND_MIXER_WRITE_MIC, &vol) == -1) {
+ perror("SOUND_MIXER_WRITE_DEVMASK mic");
+ exit(-1);
+ }
+ i = FREQS_REC;
+ ioctl(audio_fd, SNDCTL_DSP_SPEED, (u_char *) &i);
+ /* set mic gain orgin */
+ vol = savevol;
+ if (ioctl(mixerfd, SOUND_MIXER_WRITE_MIC, &vol) == -1) {
+ perror("SOUND_MIXER_READ_DEVMASK mic");
+ exit(-1);
+ }
+
+ printf(" recording %d\n", i);
+ while (rec_count) {
+ rec_cnt = rec_count;
+ if (rec_cnt > BUF_SIZE)
+ rec_cnt = BUF_SIZE;
+
+ read (audio_fd, (char *)rec_arr+recorded, rec_cnt);
+ recorded += rec_cnt;
+ rec_count -= rec_cnt;
+ }/* while (count) */
+
+ switch (count) {
+ case 1:
+ printf(" write to %s\n",rec_name1);
+ fp=fopen(rec_name1, "w");
+ fwrite(rec_arr, 1, MAX_LEN, fp);
+ fclose(fp);
+ break;
+ case 2:
+ printf(" write to %s\n",rec_name2);
+ fp=fopen(rec_name2, "w");
+ fwrite(rec_arr, 1, MAX_LEN, fp);
+ fclose(fp);
+ break;
+ case 3:
+ printf(" write to %s\n",rec_name3);
+ fp=fopen(rec_name3, "w");
+ fwrite(rec_arr, 1, MAX_LEN, fp);
+ fclose(fp);
+ break;
+ }
+ sleep(1);
+ }
+
+ close(audio_fd);
+
+ return err;
+}
+
+-------------
+** Support **
+-------------
+
+Welcome to Ingenic website: <http://www.ingenic.cn>
+
+More details, please refer to linux26_developer_guide.pdf.
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 3ca0fe1a912..645498ecfc6 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -19,6 +19,99 @@ choice
prompt "System type"
default SGI_IP22
+config JZ4730_PMP
+ bool "Ingenic JZ4730 PMP board"
+ select DMA_NONCOHERENT
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SOC_JZ4730
+
+config JZ4740_PAVO
+ bool "Ingenic JZ4740 PAVO board"
+ select DMA_NONCOHERENT
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SOC_JZ4740
+
+config JZ4740_LEO
+ bool "Ingenic JZ4740 LEO board"
+ select DMA_NONCOHERENT
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SOC_JZ4740
+
+config JZ4740_LYRA
+ bool "Ingenic JZ4740 LYRA board"
+ select DMA_NONCOHERENT
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SOC_JZ4740
+
+config JZ4725_DIPPER
+ bool "Ingenic JZ4725 DIPPER board"
+ select DMA_NONCOHERENT
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SOC_JZ4740
+ select SOC_JZ4725
+
+config JZ4720_VIRGO
+ bool "Ingenic JZ4720 VIRGO board"
+ select DMA_NONCOHERENT
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SOC_JZ4740
+ select SOC_JZ4720
+
+config JZ4750_FUWA
+ bool "Ingenic JZ4750 FUWA board"
+ select DMA_NONCOHERENT
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SOC_JZ4750
+ select JZ_FPGA
+
+config JZ4750D_FUWA1
+ bool "Ingenic JZ4750d FUWA1 board"
+ select DMA_NONCOHERENT
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SOC_JZ4750D
+ select JZ_FPGA
+
+config JZ4750_APUS
+ bool "Ingenic JZ4750 APUS board"
+ select DMA_NONCOHERENT
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SOC_JZ4750
+
+config JZ4750D_CETUS
+ bool "Ingenic JZ4750d CETUS board"
+ select DMA_NONCOHERENT
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SOC_JZ4750D
+
+config JZ4750L_F4750L
+ bool "Ingenic JZ4750L FPGA board"
+ select DMA_NONCOHERENT
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SOC_JZ4750L
+ select JZ_FPGA
+
config MACH_ALCHEMY
bool "Alchemy processor based machines"
@@ -671,6 +764,52 @@ source "arch/mips/cavium-octeon/Kconfig"
endmenu
+#####################################################
+# Ingenic SOC series
+#####################################################
+
+config SOC_JZ4730
+ bool
+ select JZSOC
+
+config SOC_JZ4740
+ bool
+ select JZSOC
+
+config SOC_JZ4725
+ bool
+ select JZSOC
+
+config SOC_JZ4720
+ bool
+ select JZSOC
+
+config SOC_JZ4750
+ bool
+ select JZSOC
+
+config SOC_JZ4750D
+ bool
+ select JZSOC
+
+config SOC_JZ4750L
+ bool
+ select JZSOC
+
+config JZ_FPGA
+ bool
+
+config JZSOC
+ bool
+ select JZRISC
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+
+config JZRISC
+ bool
+
+####################################################
+
config RWSEM_GENERIC_SPINLOCK
bool
default y
@@ -2106,6 +2245,11 @@ config I8253
config ZONE_DMA32
bool
+config FORCE_MAX_ZONEORDER
+ int
+ depends on JZSOC
+ default "13"
+
source "drivers/pcmcia/Kconfig"
source "drivers/pci/hotplug/Kconfig"
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 861da514a46..5fdaa4f9289 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -173,6 +173,45 @@ libs-y += arch/mips/fw/lib/
#
#
+# Commond Ingenic JZ4730 series
+#
+core-$(CONFIG_SOC_JZ4730) += arch/mips/jz4730/
+cflags-$(CONFIG_SOC_JZ4730) += -I$(srctree)/arch/mips/include/asm/mach-jz4730
+load-$(CONFIG_SOC_JZ4730) += 0xffffffff80010000
+
+#
+# Commond Ingenic JZ4740 series
+#
+
+core-$(CONFIG_SOC_JZ4740) += arch/mips/jz4740/
+cflags-$(CONFIG_SOC_JZ4740) += -I$(srctree)/arch/mips/include/asm/mach-jz4740
+load-$(CONFIG_SOC_JZ4740) += 0xffffffff80010000
+
+#
+# Commond Ingenic JZ4750 series
+#
+
+core-$(CONFIG_SOC_JZ4750) += arch/mips/jz4750/
+cflags-$(CONFIG_SOC_JZ4750) += -I$(srctree)/arch/mips/include/asm/mach-jz4750
+load-$(CONFIG_SOC_JZ4750) += 0xffffffff80010000
+
+#
+# Commond Ingenic JZ4750d series
+#
+
+core-$(CONFIG_SOC_JZ4750D) += arch/mips/jz4750d/
+cflags-$(CONFIG_SOC_JZ4750D) += -I$(srctree)/arch/mips/include/asm/mach-jz4750d
+load-$(CONFIG_SOC_JZ4750D) += 0xffffffff80010000
+
+#
+# Commond Ingenic JZ4750L series
+#
+
+core-$(CONFIG_SOC_JZ4750L) += arch/mips/jz4750l/
+cflags-$(CONFIG_SOC_JZ4750L) += -I$(srctree)/arch/mips/include/asm/mach-jz4750l
+load-$(CONFIG_SOC_JZ4750L) += 0xffffffff80010000
+
+#
# Texas Instruments AR7
#
core-$(CONFIG_AR7) += arch/mips/ar7/
@@ -310,7 +349,7 @@ load-$(CONFIG_MACH_DECSTATION) += 0xffffffff80040000
# Wind River PPMC Board (4KC + GT64120)
#
core-$(CONFIG_WR_PPMC) += arch/mips/gt64120/wrppmc/
-cflags-$(CONFIG_WR_PPMC) += -I$(srctree)/arch/mips/include/asm/mach-wrppmc
+cflags-$(CONFIG_WR_PPMC) += -I$(srctree)/arch/mips/include/asm/mach-wrppmc
load-$(CONFIG_WR_PPMC) += 0xffffffff80100000
#
@@ -613,6 +652,7 @@ load-$(CONFIG_CPU_CAVIUM_OCTEON) += 0xffffffff81100000
endif
cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic
+
drivers-$(CONFIG_PCI) += arch/mips/pci/
ifdef CONFIG_32BIT
@@ -711,6 +751,12 @@ makeboot =$(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) $(1)
all: $(all-y)
+uImage: $(vmlinux-32)
+ +@$(call makeboot,$@)
+
+zImage: $(vmlinux-32)
+ +@$(call makeboot,$@)
+
vmlinux.bin: $(vmlinux-32)
+@$(call makeboot,$@)
@@ -740,6 +786,7 @@ install:
archclean:
@$(MAKE) $(clean)=arch/mips/boot
+ @$(MAKE) $(clean)=arch/mips/boot/compressed
@$(MAKE) $(clean)=arch/mips/lasat
define archhelp
@@ -747,6 +794,9 @@ define archhelp
echo ' vmlinux.ecoff - ECOFF boot image'
echo ' vmlinux.bin - Raw binary boot image'
echo ' vmlinux.srec - SREC boot image'
+ echo ' uImage - u-boot format image (arch/$(ARCH)/boot/uImage)'
+ echo ' zImage - Compressed binary image (arch/$(ARCH)/boot/compressed/zImage)'
+ echo ' vmlinux.bin - Uncompressed binary image (arch/$(ARCH)/boot/vmlinux.bin)'
echo
echo ' These will be default as apropriate for a configured platform.'
endef
diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
index 2a209d74f0b..1cfce3ef8a3 100644
--- a/arch/mips/boot/Makefile
+++ b/arch/mips/boot/Makefile
@@ -7,6 +7,9 @@
# Copyright (C) 2004 Maciej W. Rozycki
#
+# This one must match the LOADADDR in arch/mips/Makefile!
+LOADADDR=0x80010000
+
#
# Some DECstations need all possible sections of an ECOFF executable
#
@@ -25,7 +28,7 @@ strip-flags = $(addprefix --remove-section=,$(drop-sections))
VMLINUX = vmlinux
-all: vmlinux.ecoff vmlinux.srec addinitrd
+all: vmlinux.ecoff vmlinux.srec addinitrd uImage zImage
vmlinux.ecoff: $(obj)/elf2ecoff $(VMLINUX)
$(obj)/elf2ecoff $(VMLINUX) vmlinux.ecoff $(E2EFLAGS)
@@ -42,8 +45,24 @@ vmlinux.srec: $(VMLINUX)
$(obj)/addinitrd: $(obj)/addinitrd.c
$(HOSTCC) -o $@ $^
+uImage: $(VMLINUX) vmlinux.bin
+ rm -f $(obj)/vmlinux.bin.gz
+ gzip -9 $(obj)/vmlinux.bin
+ mkimage -A mips -O linux -T kernel -C gzip \
+ -a $(LOADADDR) -e $(shell sh ./$(obj)/tools/entry $(NM) $(VMLINUX) ) \
+ -n 'Linux-$(KERNELRELEASE)' \
+ -d $(obj)/vmlinux.bin.gz $(obj)/uImage
+ @echo ' Kernel: arch/mips/boot/$@ is ready'
+
+zImage:
+ $(Q)$(MAKE) $(build)=$(obj)/compressed loadaddr=$(LOADADDR) $@
+ @echo ' Kernel: arch/mips/boot/compressed/$@ is ready'
+
clean-files += addinitrd \
elf2ecoff \
vmlinux.bin \
vmlinux.ecoff \
- vmlinux.srec
+ vmlinux.srec \
+ vmlinux.bin.gz \
+ uImage \
+ zImage
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
new file mode 100644
index 00000000000..3d07486e486
--- /dev/null
+++ b/arch/mips/boot/compressed/Makefile
@@ -0,0 +1,42 @@
+#
+# linux/arch/mips/boot/compressed/Makefile
+#
+# create a compressed zImage from the original vmlinux
+#
+
+targets := zImage vmlinuz vmlinux.bin.gz head.o misc.o piggy.o dummy.o
+
+OBJS := $(obj)/head.o $(obj)/misc.o
+
+LD_ARGS := -T $(obj)/ld.script -Ttext 0x80600000 -Bstatic
+OBJCOPY_ARGS := -O elf32-tradlittlemips
+
+ENTRY := $(obj)/../tools/entry
+FILESIZE := $(obj)/../tools/filesize
+
+drop-sections = .reginfo .mdebug .comment .note .pdr .options .MIPS.options
+strip-flags = $(addprefix --remove-section=,$(drop-sections))
+
+
+$(obj)/vmlinux.bin.gz: vmlinux
+ rm -f $(obj)/vmlinux.bin.gz
+ $(OBJCOPY) -O binary $(strip-flags) vmlinux $(obj)/vmlinux.bin
+ gzip -v9f $(obj)/vmlinux.bin
+
+$(obj)/head.o: $(obj)/head.S $(obj)/vmlinux.bin.gz vmlinux
+ $(CC) $(KBUILD_AFLAGS) $(LINUXINCLUDE) \
+ -DIMAGESIZE=$(shell sh $(FILESIZE) $(obj)/vmlinux.bin.gz) \
+ -DKERNEL_ENTRY=$(shell sh $(ENTRY) $(NM) vmlinux ) \
+ -DLOADADDR=$(loadaddr) \
+ -c -o $(obj)/head.o $<
+
+$(obj)/vmlinuz: $(OBJS) $(obj)/ld.script $(obj)/vmlinux.bin.gz $(obj)/dummy.o
+ $(OBJCOPY) \
+ --add-section=.image=$(obj)/vmlinux.bin.gz \
+ --set-section-flags=.image=contents,alloc,load,readonly,data \
+ $(obj)/dummy.o $(obj)/piggy.o
+ $(LD) $(LD_ARGS) -o $@ $(OBJS) $(obj)/piggy.o
+ $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr -R .initrd -R .sysmap
+
+zImage: $(obj)/vmlinuz
+ $(OBJCOPY) -O binary $(obj)/vmlinuz $(obj)/zImage
diff --git a/arch/mips/boot/compressed/dummy.c b/arch/mips/boot/compressed/dummy.c
new file mode 100644
index 00000000000..31dbf45bf99
--- /dev/null
+++ b/arch/mips/boot/compressed/dummy.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/arch/mips/boot/compressed/head.S b/arch/mips/boot/compressed/head.S
new file mode 100644
index 00000000000..d9700eb5024
--- /dev/null
+++ b/arch/mips/boot/compressed/head.S
@@ -0,0 +1,85 @@
+/*
+ * linux/arch/mips/boot/compressed/head.S
+ *
+ * Copyright (C) 2005-2008 Ingenic Semiconductor Inc.
+ */
+
+#include <asm/asm.h>
+#include <asm/cacheops.h>
+#include <asm/cachectl.h>
+#include <asm/regdef.h>
+
+#define IndexInvalidate_I 0x00
+#define IndexWriteBack_D 0x01
+
+ .set noreorder
+ LEAF(startup)
+startup:
+ move s0, a0 /* Save the boot loader transfered args */
+ move s1, a1
+ move s2, a2
+ move s3, a3
+
+ la a0, _edata
+ la a1, _end
+1: sw zero, 0(a0) /* Clear BSS section */
+ bne a1, a0, 1b
+ addu a0, 4
+
+ la sp, (.stack + 8192)
+
+ la a0, __image_begin
+ la a1, IMAGESIZE
+ la a2, LOADADDR
+ la ra, 1f
+ la k0, decompress_kernel
+ jr k0
+ nop
+1:
+
+ move a0, s0
+ move a1, s1
+ move a2, s2
+ move a3, s3
+ li k0, KERNEL_ENTRY
+ jr k0
+ nop
+2:
+ b 32
+ END(startup)
+
+
+ LEAF(flushcaches)
+ la t0, 1f
+ la t1, 0xa0000000
+ or t0, t0, t1
+ jr t0
+ nop
+1:
+ li k0, 0x80000000 # start address
+ li k1, 0x80004000 # end address (16KB I-Cache)
+ subu k1, 128
+
+2:
+ .set mips3
+ cache IndexWriteBack_D, 0(k0)
+ cache IndexWriteBack_D, 32(k0)
+ cache IndexWriteBack_D, 64(k0)
+ cache IndexWriteBack_D, 96(k0)
+ cache IndexInvalidate_I, 0(k0)
+ cache IndexInvalidate_I, 32(k0)
+ cache IndexInvalidate_I, 64(k0)
+ cache IndexInvalidate_I, 96(k0)
+ .set mips0
+
+ bne k0, k1, 2b
+ addu k0, k0, 128
+ la t0, 3f
+ jr t0
+ nop
+3:
+ jr ra
+ nop
+ END(flushcaches)
+
+ .comm .stack,4096*2,4
diff --git a/arch/mips/boot/compressed/ld.script b/arch/mips/boot/compressed/ld.script
new file mode 100644
index 00000000000..fcf8ba04174
--- /dev/null
+++ b/arch/mips/boot/compressed/ld.script
@@ -0,0 +1,151 @@
+OUTPUT_ARCH(mips)
+ENTRY(startup)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+
+ .init : { *(.init) } =0
+ .text :
+ {
+ _ftext = . ;
+ *(.text)
+ *(.rodata)
+ *(.rodata1)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0
+ .kstrtab : { *(.kstrtab) }
+
+ . = ALIGN(16); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ __start___dbe_table = .; /* Exception table for data bus errors */
+ __dbe_table : { *(__dbe_table) }
+ __stop___dbe_table = .;
+
+ __start___ksymtab = .; /* Kernel symbol table */
+ __ksymtab : { *(__ksymtab) }
+ __stop___ksymtab = .;
+
+ _etext = .;
+
+ . = ALIGN(8192);
+ .data.init_task : { *(.data.init_task) }
+
+ /* Startup code */
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(16);
+ __setup_start = .;
+ .setup.init : { *(.setup.init) }
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : { *(.initcall.init) }
+ __initcall_end = .;
+ . = ALIGN(4096); /* Align double page for init_task_union */
+ __init_end = .;
+
+ . = ALIGN(4096);
+ .data.page_aligned : { *(.data.idt) }
+
+ . = ALIGN(32);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+ .fini : { *(.fini) } =0
+ .reginfo : { *(.reginfo) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. It would
+ be more correct to do this:
+ . = .;
+ The current expression does not correctly handle the case of a
+ text segment ending precisely at the end of a page; it causes the
+ data segment to skip a page. The above expression does not have
+ this problem, but it will currently (2/95) cause BFD to allocate
+ a single segment, combining both text and data, for this case.
+ This will prevent the text segment from being shared among
+ multiple executions of the program; I think that is more
+ important than losing a page of the virtual address space (note
+ that no actual memory is lost; the page which is skipped can not
+ be referenced). */
+ . = .;
+ .data :
+ {
+ _fdata = . ;
+ *(.data)
+
+ /* Put the compressed image here, so bss is on the end. */
+ __image_begin = .;
+ *(.image)
+ __image_end = .;
+ /* Align the initial ramdisk image (INITRD) on page boundaries. */
+ . = ALIGN(4096);
+ __ramdisk_begin = .;
+ *(.initrd)
+ __ramdisk_end = .;
+ . = ALIGN(4096);
+
+ CONSTRUCTORS
+ }
+ .data1 : { *(.data1) }
+ _gp = . + 0x8000;
+ .lit8 : { *(.lit8) }
+ .lit4 : { *(.lit4) }
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ .got : { *(.got.plt) *(.got) }
+ .dynamic : { *(.dynamic) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata : { *(.sdata) }
+ . = ALIGN(4);
+ _edata = .;
+ PROVIDE (edata = .);
+
+ __bss_start = .;
+ _fbss = .;
+ .sbss : { *(.sbss) *(.scommon) }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ . = ALIGN(4);
+ _end = . ;
+ PROVIDE (end = .);
+ }
+
+ /* Sections to be discarded */
+ /DISCARD/ :
+ {
+ *(.text.exit)
+ *(.data.exit)
+ *(.exitcall.exit)
+ }
+
+ /* This is the MIPS specific mdebug section. */
+ .mdebug : { *(.mdebug) }
+ /* These are needed for ELF backends which have not yet been
+ converted to the new style linker. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ /* DWARF debug sections.
+ Symbols in the .debug DWARF section are relative to the beginning of the
+ section so we begin .debug at 0. It's not clear yet what needs to happen
+ for the others. */
+ .debug 0 : { *(.debug) }
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ .line 0 : { *(.line) }
+ /* These must appear regardless of . */
+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+ .comment : { *(.comment) }
+ .note : { *(.note) }
+}
diff --git a/arch/mips/boot/compressed/misc.c b/arch/mips/boot/compressed/misc.c
new file mode 100644
index 00000000000..06643369169
--- /dev/null
+++ b/arch/mips/boot/compressed/misc.c
@@ -0,0 +1,203 @@
+/*
+ * linux/arch/mips/boot/compressed/misc.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ *
+ * Adapted for JZSOC by Peter Wei, 2008
+ *
+ */
+
+#define size_t int
+#define NULL 0
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args) args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n) memset ((s), 0, (n))
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+#define WSIZE 0x8000 /* Window size must be at least 32k, */
+ /* and a power of two */
+
+static uch *inbuf; /* input buffer */
+static uch window[WSIZE]; /* Sliding window buffer */
+
+static unsigned insize = 0; /* valid bytes in inbuf */
+static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
+static unsigned outcnt = 0; /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+static int fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+
+void* memset(void* s, int c, size_t n);
+void* memcpy(void* __dest, __const void* __src, size_t __n);
+
+extern void flushcaches(void); /* defined in head.S */
+
+char *input_data;
+int input_len;
+
+static long bytes_out = 0;
+static uch *output_data;
+static unsigned long output_ptr = 0;
+
+static void error(char *m);
+
+static void puts(const char *str)
+{
+}
+
+extern unsigned char _end[];
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+
+#define HEAP_SIZE 0x10000
+
+#include "../../../../lib/inflate.c"
+
+void* memset(void* s, int c, size_t n)
+{
+ int i;
+ char *ss = (char*)s;
+
+ for (i=0;i<n;i++) ss[i] = c;
+ return s;
+}
+
+void* memcpy(void* __dest, __const void* __src, size_t __n)
+{
+ int i = 0;
+ unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
+
+ for (i = __n >> 3; i > 0; i--) {
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+
+ if (__n & 1 << 2) {
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+
+ if (__n & 1 << 1) {
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+
+ if (__n & 1)
+ *d++ = *s++;
+
+ return __dest;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf(void)
+{
+ if (insize != 0) {
+ error("ran out of input data\n");
+ }
+
+ inbuf = input_data;
+ insize = input_len;
+ inptr = 1;
+ return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+ ulg c = crc; /* temporary variable */
+ unsigned n;
+ uch *in, *out, ch;
+
+ in = window;
+ out = &output_data[output_ptr];
+ for (n = 0; n < outcnt; n++) {
+ ch = *out++ = *in++;
+ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+ }
+ crc = c;
+ bytes_out += (ulg)outcnt;
+ output_ptr += (ulg)outcnt;
+ outcnt = 0;
+}
+
+static void error(char *x)
+{
+ puts("\n\n");
+ puts(x);
+ puts("\n\n -- System halted");
+
+ while(1); /* Halt */
+}
+
+void decompress_kernel(unsigned int imageaddr, unsigned int imagesize, unsigned int loadaddr)
+{
+ input_data = (char *)imageaddr;
+ input_len = imagesize;
+ output_ptr = 0;
+ output_data = (uch *)loadaddr;
+ free_mem_ptr = (unsigned long)_end;
+ free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
+ makecrc();
+ puts("Uncompressing Linux...");
+ gunzip();
+ flushcaches();
+ puts("Ok, booting the kernel.");
+}
diff --git a/arch/mips/boot/tools/entry b/arch/mips/boot/tools/entry
new file mode 100644
index 00000000000..376e822a635
--- /dev/null
+++ b/arch/mips/boot/tools/entry
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# grab the kernel_entry address from the vmlinux elf image
+entry=`$1 $2 | grep kernel_entry`
+
+fs=`echo $entry | grep ffffffff` # check toolchain output
+
+if [ -n "$fs" ]; then
+ echo "0x"`$1 $2 | grep kernel_entry | cut -c9- | awk '{print $1}'`
+else
+ echo "0x"`$1 $2 | grep kernel_entry | cut -c1- | awk '{print $1}'`
+fi
diff --git a/arch/mips/boot/tools/filesize b/arch/mips/boot/tools/filesize
new file mode 100644
index 00000000000..2142ad5af9d
--- /dev/null
+++ b/arch/mips/boot/tools/filesize
@@ -0,0 +1,7 @@
+#!/bin/sh
+HOSTNAME=`uname`
+if [ "$HOSTNAME" = "Linux" ]; then
+echo `ls -l $1 | awk '{print $5}'`
+else
+echo `ls -l $1 | awk '{print $6}'`
+fi
diff --git a/arch/mips/configs/apus_defconfig b/arch/mips/configs/apus_defconfig
new file mode 100644
index 00000000000..4afc450ac0b
--- /dev/null
+++ b/arch/mips/configs/apus_defconfig
@@ -0,0 +1,1392 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.31.3
+# Fri Feb 26 12:16:04 2010
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_JZ4730_PMP is not set
+# CONFIG_JZ4740_PAVO is not set
+# CONFIG_JZ4740_LEO is not set
+# CONFIG_JZ4740_LYRA is not set
+# CONFIG_JZ4725_DIPPER is not set
+# CONFIG_JZ4720_VIRGO is not set
+# CONFIG_JZ4750_FUWA is not set
+# CONFIG_JZ4750D_FUWA1 is not set
+CONFIG_JZ4750_APUS=y
+# CONFIG_JZ4750D_CETUS is not set
+# CONFIG_JZ4750L_F4750L is not set
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_SOC_JZ4750=y
+CONFIG_JZSOC=y
+CONFIG_JZRISC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R5500 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+# CONFIG_CPU_CAVIUM_OCTEON is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_32KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Performance Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_FREEZER=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+CONFIG_FORCE_MAX_ZONEORDER=13
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_HIBERNATION is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_JZ4750=y
+# CONFIG_MTD_NAND_CS2 is not set
+# CONFIG_MTD_NAND_CS3 is not set
+# CONFIG_MTD_NAND_CS4 is not set
+# CONFIG_MTD_NAND_MULTI_PLANE is not set
+# CONFIG_MTD_HW_HM_ECC is not set
+# CONFIG_MTD_SW_HM_ECC is not set
+# CONFIG_MTD_HW_RS_ECC is not set
+CONFIG_MTD_HW_BCH_ECC=y
+# CONFIG_MTD_HW_BCH_4BIT is not set
+CONFIG_MTD_HW_BCH_8BIT=y
+CONFIG_MTD_NAND_DMA=y
+CONFIG_MTD_NAND_DMABUF=y
+CONFIG_ALLOCATE_MTDBLOCK_JZ_EARLY=y
+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
+CONFIG_MTD_OOB_COPIES=3
+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_JZCS8900=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_JZ=y
+# CONFIG_JZ_ADKEY is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=2
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC_PCF8563 is not set
+CONFIG_RTC_JZ=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+
+#
+# JZSOC char device support
+#
+CONFIG_JZCHAR=y
+# CONFIG_JZ_SIMPLE_I2C is not set
+# CONFIG_JZ_CIM is not set
+# CONFIG_JZ_TPANEL_ATA2508 is not set
+# CONFIG_JZ_POWEROFF is not set
+# CONFIG_JZ_OW is not set
+CONFIG_JZ_TCSM=y
+# CONFIG_JZ_TSSI is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_JZ4750_AUO_EPD_EBOOK is not set
+CONFIG_FB_JZSOC=y
+CONFIG_FB_JZ4750_LCD=y
+# CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER is not set
+CONFIG_FB_JZ4750_TVE=y
+CONFIG_JZ4750_IPU_MM=y
+# CONFIG_FB_JZ4750_SLCD is not set
+# CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF01 is not set
+# CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF02 is not set
+CONFIG_JZ4750_LCD_AUO_A043FL01V2=y
+# CONFIG_JZ4750_LCD_FOXCONN_PT035TN01 is not set
+# CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL is not set
+# CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA is not set
+# CONFIG_JZ4750_LCD_TOPPOLY_TD043MGEB1 is not set
+# CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW_18BIT is not set
+# CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W is not set
+# CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A is not set
+# CONFIG_JZ4750D_VGA_DISPLAY is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+# CONFIG_SND is not set
+CONFIG_SOUND_PRIME=y
+# CONFIG_SOUND_JZ_AC97 is not set
+CONFIG_SOUND_JZ_I2S=y
+# CONFIG_SOUND_JZ_PCM is not set
+# CONFIG_I2S_AK4642EN is not set
+# CONFIG_I2S_ICODEC is not set
+CONFIG_I2S_DLV=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_JZ4740 is not set
+CONFIG_USB_GADGET_JZ4750=y
+CONFIG_USB_JZ4750=m
+# CONFIG_USB_GADGET_JZ4750D is not set
+# CONFIG_USB_GADGET_JZ4750L is not set
+# CONFIG_USB_GADGET_JZ4730 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_JZ_UDC_HOTPLUG is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_UDC_USE_LB_CACHE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MSC0_JZ4750=y
+# CONFIG_JZ4750_MSC0_BUS_1 is not set
+CONFIG_JZ4750_MSC0_BUS_4=y
+# CONFIG_JZ4750_MSC0_BUS_8 is not set
+# CONFIG_MSC1_JZ4750 is not set
+# CONFIG_JZ4750_BOOT_FROM_MSC0 is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Yaffs2 Filesystems
+#
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/mips/configs/cetus_defconfig b/arch/mips/configs/cetus_defconfig
new file mode 100644
index 00000000000..fa4d8ee8c5a
--- /dev/null
+++ b/arch/mips/configs/cetus_defconfig
@@ -0,0 +1,1206 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.31.3
+# Fri Feb 26 12:15:30 2010
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_JZ4730_PMP is not set
+# CONFIG_JZ4740_PAVO is not set
+# CONFIG_JZ4740_LEO is not set
+# CONFIG_JZ4740_LYRA is not set
+# CONFIG_JZ4725_DIPPER is not set
+# CONFIG_JZ4720_VIRGO is not set
+# CONFIG_JZ4750_FUWA is not set
+# CONFIG_JZ4750D_FUWA1 is not set
+# CONFIG_JZ4750_APUS is not set
+CONFIG_JZ4750D_CETUS=y
+# CONFIG_JZ4750L_F4750L is not set
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_SOC_JZ4750D=y
+CONFIG_JZSOC=y
+CONFIG_JZRISC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R5500 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+# CONFIG_CPU_CAVIUM_OCTEON is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_32KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Performance Counters
+#
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_FREEZER=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+CONFIG_FORCE_MAX_ZONEORDER=13
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_HIBERNATION is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_JZ4750=y
+# CONFIG_MTD_NAND_CS2 is not set
+# CONFIG_MTD_NAND_CS3 is not set
+# CONFIG_MTD_NAND_CS4 is not set
+CONFIG_MTD_NAND_MULTI_PLANE=y
+# CONFIG_MTD_HW_HM_ECC is not set
+# CONFIG_MTD_SW_HM_ECC is not set
+# CONFIG_MTD_HW_RS_ECC is not set
+CONFIG_MTD_HW_BCH_ECC=y
+# CONFIG_MTD_HW_BCH_4BIT is not set
+CONFIG_MTD_HW_BCH_8BIT=y
+CONFIG_MTD_NAND_DMA=y
+CONFIG_MTD_NAND_DMABUF=y
+CONFIG_ALLOCATE_MTDBLOCK_JZ_EARLY=y
+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
+CONFIG_MTD_OOB_COPIES=3
+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_JZ=y
+# CONFIG_JZ_ADKEY is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=2
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC_PCF8563 is not set
+# CONFIG_RTC_JZ is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+
+#
+# JZSOC char device support
+#
+CONFIG_JZCHAR=y
+# CONFIG_JZ_SIMPLE_I2C is not set
+# CONFIG_JZ_CIM is not set
+# CONFIG_JZ_TPANEL_ATA2508 is not set
+# CONFIG_JZ_POWEROFF is not set
+# CONFIG_JZ_OW is not set
+CONFIG_JZ_TCSM=y
+# CONFIG_JZ_TSSI is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_JZSOC=y
+CONFIG_FB_JZ4750_LCD=y
+# CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER is not set
+CONFIG_FB_JZ4750_TVE=y
+CONFIG_JZ4750_IPU_MM=y
+# CONFIG_FB_JZ4750_SLCD is not set
+# CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF01 is not set
+# CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF02 is not set
+CONFIG_JZ4750_LCD_AUO_A043FL01V2=y
+# CONFIG_JZ4750_LCD_FOXCONN_PT035TN01 is not set
+# CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL is not set
+# CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA is not set
+# CONFIG_JZ4750_LCD_TOPPOLY_TD043MGEB1 is not set
+# CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW_18BIT is not set
+# CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W is not set
+# CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A is not set
+# CONFIG_JZ4750D_VGA_DISPLAY is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+# CONFIG_SND is not set
+CONFIG_SOUND_PRIME=y
+# CONFIG_SOUND_JZ_AC97 is not set
+CONFIG_SOUND_JZ_I2S=y
+# CONFIG_I2S_AK4642EN is not set
+# CONFIG_I2S_ICODEC is not set
+CONFIG_I2S_DLV=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_PID is not set
+
+#
+# Special HID drivers
+#
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_JZ4740 is not set
+# CONFIG_USB_GADGET_JZ4750 is not set
+CONFIG_USB_GADGET_JZ4750D=y
+CONFIG_USB_JZ4750D=m
+# CONFIG_USB_GADGET_JZ4750L is not set
+# CONFIG_USB_GADGET_JZ4730 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_JZ_UDC_HOTPLUG is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_UDC_USE_LB_CACHE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MSC0_JZ4750 is not set
+CONFIG_MSC1_JZ4750=y
+# CONFIG_JZ4750_MSC1_BUS_1 is not set
+CONFIG_JZ4750_MSC1_BUS_4=y
+# CONFIG_JZ4750_BOOT_FROM_MSC0 is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Yaffs2 Filesystems
+#
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/mips/configs/dipper_defconfig b/arch/mips/configs/dipper_defconfig
new file mode 100644
index 00000000000..b046b2ccc94
--- /dev/null
+++ b/arch/mips/configs/dipper_defconfig
@@ -0,0 +1,1281 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24.3
+# Thu Jun 12 13:55:45 2008
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_JZ4730_PMP is not set
+# CONFIG_JZ4740_PAVO is not set
+# CONFIG_JZ4740_LEO is not set
+# CONFIG_JZ4740_LYRA is not set
+CONFIG_JZ4725_DIPPER=y
+# CONFIG_JZ4720_VIRGO is not set
+# CONFIG_JZ4750_FUWA is not set
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_WR_PPMC is not set
+CONFIG_SOC_JZ4740=y
+CONFIG_SOC_JZ4725=y
+CONFIG_JZSOC=y
+CONFIG_JZRISC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ_JZ=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_LEGACY=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+# CONFIG_SUSPEND is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_NAND_JZ4740=y
+# CONFIG_MTD_HW_HM_ECC is not set
+# CONFIG_MTD_SW_HM_ECC is not set
+CONFIG_MTD_HW_RS_ECC=y
+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
+CONFIG_MTD_OOB_COPIES=3
+CONFIG_MTD_BADBLOCK_FLAG_PAGE=0
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=m
+CONFIG_MTD_UBI_WL_THRESHOLD=256
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+CONFIG_MTD_UBI_BLKDEVS=m
+CONFIG_MTD_UBI_BLOCK=m
+# CONFIG_PARPORT is not set
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+
+#
+# Protocols
+#
+# CONFIG_PNPACPI is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_NET_SB1000 is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_JZCS8900=y
+# CONFIG_AX88796 is not set
+# CONFIG_DM9000 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PNP=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=2
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_RTC_PCF8563 is not set
+CONFIG_RTC_JZ=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+
+#
+# JZSOC char device support
+#
+CONFIG_JZCHAR=y
+# CONFIG_JZ_CIM is not set
+# CONFIG_JZ_TPANEL_ATA2508 is not set
+CONFIG_JZ_TPANEL=y
+CONFIG_JZ_SADC=y
+# CONFIG_JZ_TPANEL_AK4182 is not set
+# CONFIG_JZ_TPANEL_UCB1400 is not set
+# CONFIG_JZ_TPANEL_WM9712 is not set
+CONFIG_JZ_UDC_HOTPLUG=y
+CONFIG_JZ_POWEROFF=y
+# CONFIG_JZ_OW is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_JZ_WDT=y
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+CONFIG_VIDEO_JZ_CIM=y
+CONFIG_VIDEO_JZ_SENSOR=y
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_QUICKCAM_MESSENGER is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_ZR364XX is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_USB_DSBR is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_JZSOC=y
+# CONFIG_FB_JZ4740_SLCD is not set
+CONFIG_FB_JZLCD_4730_4740=y
+CONFIG_JZLCD_FRAMEBUFFER_MAX=1
+# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set
+# CONFIG_JZLCD_SHARP_LQ035Q7 is not set
+# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set
+# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set
+# CONFIG_JZLCD_SAMSUNG_LTP400WQF01 is not set
+CONFIG_JZLCD_SAMSUNG_LTP400WQF02=y
+# CONFIG_JZLCD_AUO_A030FL01_V1 is not set
+# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set
+# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set
+# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set
+# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set
+# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set
+# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set
+# CONFIG_JZLCD_HYNIX_HT10X21 is not set
+# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set
+# CONFIG_JZLCD_CSTN_800x600 is not set
+# CONFIG_JZLCD_CSTN_320x240 is not set
+# CONFIG_JZLCD_MSTN_480x320 is not set
+# CONFIG_JZLCD_MSTN_320x240 is not set
+# CONFIG_JZLCD_MSTN_240x128 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+CONFIG_OSS_OBSOLETE=y
+# CONFIG_SOUND_JZ_AC97 is not set
+CONFIG_SOUND_JZ_I2S=y
+# CONFIG_SOUND_JZ_PCM is not set
+# CONFIG_I2S_AK4642EN is not set
+CONFIG_I2S_ICODEC=y
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_JZ4740=y
+CONFIG_USB_JZ4740=m
+# CONFIG_USB_GADGET_JZ4730 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_JZ=y
+# CONFIG_JZ_MMC_BUS_4 is not set
+CONFIG_JZ_MMC_BUS_1=y
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_UBIFS_FS=m
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Yaffs2 Filesystems
+#
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SAMPLES is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_LZO=m
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=m
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/mips/configs/f4750l_defconfig b/arch/mips/configs/f4750l_defconfig
new file mode 100644
index 00000000000..d9264a73e77
--- /dev/null
+++ b/arch/mips/configs/f4750l_defconfig
@@ -0,0 +1,981 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24.3
+# Tue May 26 18:04:53 2009
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_JZ4730_PMP is not set
+# CONFIG_JZ4740_PAVO is not set
+# CONFIG_JZ4740_LEO is not set
+# CONFIG_JZ4740_LYRA is not set
+# CONFIG_JZ4725_DIPPER is not set
+# CONFIG_JZ4720_VIRGO is not set
+# CONFIG_JZ4750_FUWA is not set
+# CONFIG_JZ4750D_FUWA1 is not set
+# CONFIG_JZ4750_APUS is not set
+# CONFIG_JZ4750D_CETUS is not set
+CONFIG_JZ4750L_F4750L=y
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_WR_PPMC is not set
+CONFIG_SOC_JZ4750L=y
+CONFIG_JZ_FPGA=y
+CONFIG_JZSOC=y
+CONFIG_JZRISC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_FORCE_MAX_ZONEORDER=13
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ_JZ is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PNP is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_JZ_ETH=y
+# CONFIG_AX88796 is not set
+# CONFIG_DM9000 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=2
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_RTC_PCF8563 is not set
+# CONFIG_RTC_JZ is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_JZSOC=y
+CONFIG_FB_JZ4750_LCD=y
+# CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER is not set
+# CONFIG_FB_JZ4750_TVE is not set
+# CONFIG_IPU_JZ4750 is not set
+# CONFIG_FB_JZ4750_SLCD is not set
+# CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF01 is not set
+# CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF02 is not set
+CONFIG_JZ4750_LCD_AUO_A043FL01V2=y
+# CONFIG_JZ4750_LCD_FOXCONN_PT035TN01 is not set
+# CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL is not set
+# CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA is not set
+# CONFIG_JZ4750_LCD_TOPPOLY_TD043MGEB1 is not set
+# CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW_18BIT is not set
+# CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W is not set
+# CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A is not set
+# CONFIG_JZ4750D_VGA_DISPLAY is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+CONFIG_OSS_OBSOLETE=y
+# CONFIG_SOUND_JZ_AC97 is not set
+CONFIG_SOUND_JZ_I2S=y
+# CONFIG_I2S_AK4642EN is not set
+# CONFIG_I2S_ICODEC is not set
+# CONFIG_I2S_DLV is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_JZ4740 is not set
+# CONFIG_USB_GADGET_JZ4750 is not set
+# CONFIG_USB_GADGET_JZ4750D is not set
+# CONFIG_USB_GADGET_JZ4730 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+CONFIG_USB_GADGET_M66592=y
+CONFIG_USB_M66592=m
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Yaffs2 Filesystems
+#
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SAMPLES is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/mips/configs/fuwa1_defconfig b/arch/mips/configs/fuwa1_defconfig
new file mode 100644
index 00000000000..ee680814b20
--- /dev/null
+++ b/arch/mips/configs/fuwa1_defconfig
@@ -0,0 +1,1029 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24.3
+# Wed Apr 1 14:00:33 2009
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_JZ4730_PMP is not set
+# CONFIG_JZ4740_PAVO is not set
+# CONFIG_JZ4740_LEO is not set
+# CONFIG_JZ4740_LYRA is not set
+# CONFIG_JZ4725_DIPPER is not set
+# CONFIG_JZ4720_VIRGO is not set
+# CONFIG_JZ4750_FUWA is not set
+CONFIG_JZ4750D_FUWA1=y
+# CONFIG_JZ4750_APUS is not set
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_WR_PPMC is not set
+CONFIG_SOC_JZ4750D=y
+CONFIG_JZ_FPGA=y
+CONFIG_JZSOC=y
+CONFIG_JZRISC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_SYS_HAS_EARLY_PRINTK is not set
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_FORCE_MAX_ZONEORDER=13
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ_JZ is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+CONFIG_MTD_NAND_JZ4750=y
+# CONFIG_MTD_NAND_CS2 is not set
+# CONFIG_MTD_NAND_CS3 is not set
+# CONFIG_MTD_NAND_CS4 is not set
+# CONFIG_MTD_NAND_MULTI_PLANE is not set
+# CONFIG_MTD_HW_HM_ECC is not set
+# CONFIG_MTD_SW_HM_ECC is not set
+# CONFIG_MTD_HW_RS_ECC is not set
+CONFIG_MTD_HW_BCH_ECC=y
+CONFIG_MTD_HW_BCH_4BIT=y
+# CONFIG_MTD_HW_BCH_8BIT is not set
+CONFIG_MTD_NAND_DMA=y
+# CONFIG_MTD_NAND_DMABUF is not set
+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
+CONFIG_MTD_OOB_COPIES=3
+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_MTD_UBI_BLKDEVS is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PNP is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=2
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_RTC_PCF8563 is not set
+# CONFIG_RTC_JZ is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+
+#
+# JZSOC char device support
+#
+CONFIG_JZCHAR=y
+# CONFIG_JZ_CIM is not set
+# CONFIG_JZ_TPANEL_ATA2508 is not set
+# CONFIG_JZ_TPANEL is not set
+# CONFIG_JZ_UDC_HOTPLUG is not set
+# CONFIG_JZ_POWEROFF is not set
+# CONFIG_JZ_OW is not set
+CONFIG_JZ_TCSM=y
+# CONFIG_JZ_TSSI is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_JZSOC=y
+CONFIG_FB_JZ4750_TVE=y
+# CONFIG_IPU_JZ4750 is not set
+CONFIG_FB_JZ4750_LCD=y
+# CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER is not set
+# CONFIG_FB_JZ4750_SLCD is not set
+# CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF01 is not set
+# CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF02 is not set
+CONFIG_JZ4750_LCD_AUO_A043FL01V2=y
+# CONFIG_JZ4750_LCD_FOXCONN_PT035TN01 is not set
+# CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL is not set
+# CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA is not set
+# CONFIG_JZ4750_LCD_TOPPOLY_TD043MGEB1 is not set
+# CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW_18BIT is not set
+# CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W is not set
+# CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+CONFIG_OSS_OBSOLETE=y
+# CONFIG_SOUND_JZ_AC97 is not set
+CONFIG_SOUND_JZ_I2S=y
+# CONFIG_I2S_AK4642EN is not set
+# CONFIG_I2S_ICODEC is not set
+CONFIG_I2S_DLV=y
+# CONFIG_I2S_NULL is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_JZ4740 is not set
+CONFIG_USB_GADGET_JZ4750=y
+CONFIG_USB_JZ4750=m
+# CONFIG_USB_GADGET_JZ4730 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_UDC_USE_LB_CACHE=y
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_MSC0_JZ4750 is not set
+CONFIG_MSC1_JZ4750=y
+# CONFIG_JZ4750_MSC1_BUS_1 is not set
+CONFIG_JZ4750_MSC1_BUS_4=y
+# CONFIG_JZ4750_BOOT_FROM_MSC0 is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Yaffs2 Filesystems
+#
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SAMPLES is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/mips/configs/fuwa_defconfig b/arch/mips/configs/fuwa_defconfig
new file mode 100644
index 00000000000..f0bde8fc38f
--- /dev/null
+++ b/arch/mips/configs/fuwa_defconfig
@@ -0,0 +1,928 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24.3
+# Fri Jul 4 19:20:22 2008
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_JZ4730_PMP is not set
+# CONFIG_JZ4740_PAVO is not set
+# CONFIG_JZ4740_LEO is not set
+# CONFIG_JZ4740_LYRA is not set
+# CONFIG_JZ4725_DIPPER is not set
+# CONFIG_JZ4720_VIRGO is not set
+CONFIG_JZ4750_FUWA=y
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_WR_PPMC is not set
+CONFIG_SOC_JZ4750=y
+CONFIG_JZ_FPGA=y
+CONFIG_JZSOC=y
+CONFIG_JZRISC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ_JZ is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+CONFIG_MTD_NAND_JZ4750=y
+# CONFIG_MTD_HW_HM_ECC is not set
+# CONFIG_MTD_SW_HM_ECC is not set
+# CONFIG_MTD_HW_RS_ECC is not set
+CONFIG_MTD_HW_BCH_ECC=y
+CONFIG_MTD_NAND_DMA=y
+# CONFIG_MTD_NAND_NO_DMA is not set
+CONFIG_MTD_HW_BCH_4BIT=y
+# CONFIG_MTD_HW_BCH_8BIT is not set
+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
+CONFIG_MTD_OOB_COPIES=0
+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_MTD_UBI_BLKDEVS is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PNP is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_JZ_ETH=y
+# CONFIG_AX88796 is not set
+# CONFIG_DM9000 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=2
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_RTC_PCF8563 is not set
+# CONFIG_RTC_JZ is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+
+#
+# JZSOC char device support
+#
+# CONFIG_JZCHAR is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Yaffs2 Filesystems
+#
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SAMPLES is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/mips/configs/leo_defconfig b/arch/mips/configs/leo_defconfig
new file mode 100644
index 00000000000..6d5fbdb9865
--- /dev/null
+++ b/arch/mips/configs/leo_defconfig
@@ -0,0 +1,1256 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24.3
+# Thu Jun 12 13:59:18 2008
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_JZ4730_PMP is not set
+# CONFIG_JZ4740_PAVO is not set
+CONFIG_JZ4740_LEO=y
+# CONFIG_JZ4740_LYRA is not set
+# CONFIG_JZ4725_DIPPER is not set
+# CONFIG_JZ4720_VIRGO is not set
+# CONFIG_JZ4750_FUWA is not set
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_WR_PPMC is not set
+CONFIG_SOC_JZ4740=y
+CONFIG_JZSOC=y
+CONFIG_JZRISC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ_JZ=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_LEGACY=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+# CONFIG_SUSPEND is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLOCK2MTD=y
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_NAND_JZ4740=y
+# CONFIG_MTD_HW_HM_ECC is not set
+CONFIG_MTD_SW_HM_ECC=y
+# CONFIG_MTD_HW_RS_ECC is not set
+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
+CONFIG_MTD_OOB_COPIES=3
+CONFIG_MTD_BADBLOCK_FLAG_PAGE=0
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=m
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+CONFIG_MTD_UBI_BLKDEVS=m
+CONFIG_MTD_UBI_BLOCK=m
+# CONFIG_PARPORT is not set
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+
+#
+# Protocols
+#
+# CONFIG_PNPACPI is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PNP=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=2
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_RTC_PCF8563 is not set
+CONFIG_RTC_JZ=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+
+#
+# JZSOC char device support
+#
+CONFIG_JZCHAR=y
+# CONFIG_JZ_CIM is not set
+# CONFIG_JZ_TPANEL_ATA2508 is not set
+CONFIG_JZ_TPANEL=y
+CONFIG_JZ_SADC=y
+# CONFIG_JZ_TPANEL_AK4182 is not set
+# CONFIG_JZ_TPANEL_UCB1400 is not set
+# CONFIG_JZ_TPANEL_WM9712 is not set
+CONFIG_JZ_UDC_HOTPLUG=y
+CONFIG_JZ_POWEROFF=y
+# CONFIG_JZ_OW is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_JZ_WDT=y
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+CONFIG_VIDEO_JZ_CIM=y
+CONFIG_VIDEO_JZ_SENSOR=y
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_QUICKCAM_MESSENGER is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_ZR364XX is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_USB_DSBR is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_JZSOC=y
+# CONFIG_FB_JZ4740_SLCD is not set
+CONFIG_FB_JZLCD_4730_4740=y
+CONFIG_JZLCD_FRAMEBUFFER_MAX=1
+# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set
+# CONFIG_JZLCD_SHARP_LQ035Q7 is not set
+# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set
+# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set
+# CONFIG_JZLCD_SAMSUNG_LTP400WQF01 is not set
+CONFIG_JZLCD_SAMSUNG_LTP400WQF02=y
+# CONFIG_JZLCD_AUO_A030FL01_V1 is not set
+# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set
+# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set
+# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set
+# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set
+# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set
+# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set
+# CONFIG_JZLCD_HYNIX_HT10X21 is not set
+# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set
+# CONFIG_JZLCD_CSTN_800x600 is not set
+# CONFIG_JZLCD_CSTN_320x240 is not set
+# CONFIG_JZLCD_MSTN_480x320 is not set
+# CONFIG_JZLCD_MSTN_320x240 is not set
+# CONFIG_JZLCD_MSTN_240x128 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA MIPS devices
+#
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# System on Chip audio support
+#
+CONFIG_SND_SOC=y
+
+#
+# SoC Audio support for SuperH
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_JZ4740=y
+CONFIG_USB_JZ4740=m
+# CONFIG_USB_GADGET_JZ4730 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_FILE_STORAGE_TEST=y
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_JZ=y
+CONFIG_JZ_MMC_BUS_4=y
+# CONFIG_JZ_MMC_BUS_1 is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_UBIFS_FS=m
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+CONFIG_UBIFS_FS_DEBUG=y
+CONFIG_UBIFS_FS_DEBUG_MSG_LVL=0
+# CONFIG_UBIFS_FS_DEBUG_CHKS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Yaffs2 Filesystems
+#
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SAMPLES is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_LZO=m
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=m
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/mips/configs/lyra_defconfig b/arch/mips/configs/lyra_defconfig
new file mode 100644
index 00000000000..eeb84d8eadb
--- /dev/null
+++ b/arch/mips/configs/lyra_defconfig
@@ -0,0 +1,981 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24.3
+# Thu Jun 12 13:53:57 2008
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_JZ4730_PMP is not set
+# CONFIG_JZ4740_PAVO is not set
+# CONFIG_JZ4740_LEO is not set
+CONFIG_JZ4740_LYRA=y
+# CONFIG_JZ4725_DIPPER is not set
+# CONFIG_JZ4720_VIRGO is not set
+# CONFIG_JZ4750_FUWA is not set
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_WR_PPMC is not set
+CONFIG_SOC_JZ4740=y
+CONFIG_JZSOC=y
+CONFIG_JZRISC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ_JZ=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_LEGACY=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_UP_POSSIBLE=y
+CONFIG_SUSPEND=y
+
+#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLOCK2MTD=y
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+CONFIG_MTD_NAND_JZ4740=y
+# CONFIG_MTD_HW_HM_ECC is not set
+# CONFIG_MTD_SW_HM_ECC is not set
+CONFIG_MTD_HW_RS_ECC=y
+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
+CONFIG_MTD_OOB_COPIES=3
+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=m
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_GLUEBI=y
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_MTD_UBI_BLKDEVS is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PNP is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_RTC_PCF8563 is not set
+CONFIG_RTC_JZ=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+
+#
+# JZSOC char device support
+#
+CONFIG_JZCHAR=y
+# CONFIG_JZ_CIM is not set
+CONFIG_JZ_TPANEL_ATA2508=y
+# CONFIG_JZ_TPANEL is not set
+CONFIG_JZ_UDC_HOTPLUG=y
+CONFIG_JZ_POWEROFF=y
+# CONFIG_JZ_OW is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_JZ_WDT=y
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_JZSOC=y
+# CONFIG_FB_JZ4740_SLCD is not set
+CONFIG_FB_JZLCD_4730_4740=y
+CONFIG_JZLCD_FRAMEBUFFER_MAX=1
+# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set
+# CONFIG_JZLCD_SHARP_LQ035Q7 is not set
+# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set
+# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set
+# CONFIG_JZLCD_SAMSUNG_LTP400WQF01 is not set
+# CONFIG_JZLCD_SAMSUNG_LTP400WQF02 is not set
+CONFIG_JZLCD_AUO_A030FL01_V1=y
+# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set
+# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set
+# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set
+# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set
+# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set
+# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set
+# CONFIG_JZLCD_HYNIX_HT10X21 is not set
+# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set
+# CONFIG_JZLCD_CSTN_800x600 is not set
+# CONFIG_JZLCD_CSTN_320x240 is not set
+# CONFIG_JZLCD_MSTN_480x320 is not set
+# CONFIG_JZLCD_MSTN_320x240 is not set
+# CONFIG_JZLCD_MSTN_240x128 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+CONFIG_OSS_OBSOLETE=y
+# CONFIG_SOUND_JZ_AC97 is not set
+CONFIG_SOUND_JZ_I2S=y
+# CONFIG_SOUND_JZ_PCM is not set
+# CONFIG_I2S_AK4642EN is not set
+CONFIG_I2S_ICODEC=y
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+CONFIG_USB_GADGET_DEBUG_FILES=y
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_JZ4740=y
+CONFIG_USB_JZ4740=m
+# CONFIG_USB_GADGET_JZ4730 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_MMC_JZ is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_UBIFS_FS=m
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+CONFIG_UBIFS_FS_DEBUG=y
+CONFIG_UBIFS_FS_DEBUG_MSG_LVL=0
+# CONFIG_UBIFS_FS_DEBUG_CHKS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Yaffs2 Filesystems
+#
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SAMPLES is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_LZO=m
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=m
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/mips/configs/pavo_defconfig b/arch/mips/configs/pavo_defconfig
new file mode 100644
index 00000000000..a1b10c6802b
--- /dev/null
+++ b/arch/mips/configs/pavo_defconfig
@@ -0,0 +1,1406 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.31.3
+# Fri Feb 26 12:16:39 2010
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_JZ4730_PMP is not set
+CONFIG_JZ4740_PAVO=y
+# CONFIG_JZ4740_LEO is not set
+# CONFIG_JZ4740_LYRA is not set
+# CONFIG_JZ4725_DIPPER is not set
+# CONFIG_JZ4720_VIRGO is not set
+# CONFIG_JZ4750_FUWA is not set
+# CONFIG_JZ4750D_FUWA1 is not set
+# CONFIG_JZ4750_APUS is not set
+# CONFIG_JZ4750D_CETUS is not set
+# CONFIG_JZ4750L_F4750L is not set
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_SOC_JZ4740=y
+CONFIG_JZSOC=y
+CONFIG_JZRISC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R5500 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+# CONFIG_CPU_CAVIUM_OCTEON is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_32KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Performance Counters
+#
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_FREEZER=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+CONFIG_FORCE_MAX_ZONEORDER=13
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_HIBERNATION is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_JZ4740=y
+# CONFIG_MTD_NAND_CS2 is not set
+# CONFIG_MTD_NAND_CS3 is not set
+# CONFIG_MTD_NAND_CS4 is not set
+CONFIG_MTD_NAND_MULTI_PLANE=y
+# CONFIG_MTD_HW_HM_ECC is not set
+# CONFIG_MTD_SW_HM_ECC is not set
+CONFIG_MTD_HW_RS_ECC=y
+# CONFIG_MTD_HW_BCH_ECC is not set
+CONFIG_MTD_NAND_DMA=y
+CONFIG_ALLOCATE_MTDBLOCK_JZ_EARLY=y
+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
+CONFIG_MTD_OOB_COPIES=3
+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_JZCS8900=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_JZ=y
+# CONFIG_JZ_ADKEY is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=2
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC_PCF8563 is not set
+# CONFIG_RTC_JZ is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+
+#
+# JZSOC char device support
+#
+CONFIG_JZCHAR=y
+# CONFIG_JZ_SIMPLE_I2C is not set
+# CONFIG_JZ_CIM is not set
+# CONFIG_JZ_TPANEL_ATA2508 is not set
+# CONFIG_JZ_POWEROFF is not set
+# CONFIG_JZ_OW is not set
+# CONFIG_JZ_TCSM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_JZ_WDT=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_JZSOC=y
+# CONFIG_FB_JZ4740_SLCD is not set
+CONFIG_FB_JZLCD_4730_4740=y
+CONFIG_JZLCD_FRAMEBUFFER_MAX=1
+# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set
+# CONFIG_JZLCD_SHARP_LQ035Q7 is not set
+# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set
+# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set
+# CONFIG_JZLCD_SAMSUNG_LTP400WQF01 is not set
+CONFIG_JZLCD_SAMSUNG_LTP400WQF02=y
+# CONFIG_JZLCD_AUO_A030FL01_V1 is not set
+# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set
+# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set
+# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set
+# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set
+# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set
+# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set
+# CONFIG_JZLCD_HYNIX_HT10X21 is not set
+# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set
+# CONFIG_JZLCD_CSTN_800x600 is not set
+# CONFIG_JZLCD_CSTN_320x240 is not set
+# CONFIG_JZLCD_MSTN_480x320 is not set
+# CONFIG_JZLCD_MSTN_320x240 is not set
+# CONFIG_JZLCD_MSTN_240x128 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+# CONFIG_SND is not set
+CONFIG_SOUND_PRIME=y
+# CONFIG_SOUND_JZ_AC97 is not set
+CONFIG_SOUND_JZ_I2S=y
+# CONFIG_I2S_AK4642EN is not set
+CONFIG_I2S_ICODEC=y
+# CONFIG_I2S_DLV is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_JZ4740=y
+CONFIG_USB_JZ4740=m
+# CONFIG_USB_GADGET_JZ4750 is not set
+# CONFIG_USB_GADGET_JZ4750D is not set
+# CONFIG_USB_GADGET_JZ4750L is not set
+# CONFIG_USB_GADGET_JZ4730 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_JZ_UDC_HOTPLUG=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_UDC_USE_LB_CACHE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_JZ=y
+# CONFIG_JZ_MMC_BUS_1 is not set
+CONFIG_JZ_MMC_BUS_4=y
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Yaffs2 Filesystems
+#
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_ECC_RS=y
+# CONFIG_YAFFS_ECC_HAMMING is not set
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_REED_SOLOMON=y
+CONFIG_REED_SOLOMON_ENC8=y
+CONFIG_REED_SOLOMON_DEC8=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/mips/configs/pmp_defconfig b/arch/mips/configs/pmp_defconfig
new file mode 100644
index 00000000000..85575b4d33e
--- /dev/null
+++ b/arch/mips/configs/pmp_defconfig
@@ -0,0 +1,1212 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24.3
+# Thu Jun 12 13:37:10 2008
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+CONFIG_JZ4730_PMP=y
+# CONFIG_JZ4740_PAVO is not set
+# CONFIG_JZ4740_LEO is not set
+# CONFIG_JZ4740_LYRA is not set
+# CONFIG_JZ4725_DIPPER is not set
+# CONFIG_JZ4720_VIRGO is not set
+# CONFIG_JZ4750_FUWA is not set
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_WR_PPMC is not set
+CONFIG_SOC_JZ4730=y
+CONFIG_JZSOC=y
+CONFIG_JZRISC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ_JZ=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_LEGACY=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_UP_POSSIBLE=y
+CONFIG_SUSPEND=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_NAND_JZ4730=y
+CONFIG_MTD_HW_HM_ECC=y
+# CONFIG_MTD_SW_HM_ECC is not set
+# CONFIG_MTD_HW_RS_ECC is not set
+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
+CONFIG_MTD_OOB_COPIES=3
+CONFIG_MTD_BADBLOCK_FLAG_PAGE=0
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_MTD_UBI_BLKDEVS is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PNP is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_JZ_ETH=y
+# CONFIG_AX88796 is not set
+# CONFIG_DM9000 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+CONFIG_RTC_PCF8563=y
+# CONFIG_RTC_JZ is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+
+#
+# JZSOC char device support
+#
+CONFIG_JZCHAR=y
+# CONFIG_JZ_CIM is not set
+# CONFIG_JZ_TPANEL_ATA2508 is not set
+CONFIG_JZ_TPANEL=y
+# CONFIG_JZ_SADC is not set
+CONFIG_JZ_TPANEL_AK4182=y
+# CONFIG_JZ_TPANEL_UCB1400 is not set
+# CONFIG_JZ_TPANEL_WM9712 is not set
+# CONFIG_JZ_UDC_HOTPLUG is not set
+CONFIG_JZ_POWEROFF=y
+# CONFIG_JZ_OW is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_JZ_WDT=y
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+# CONFIG_VIDEO_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+
+#
+# Video decoders
+#
+
+#
+# Video and audio decoders
+#
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_VIVI is not set
+CONFIG_VIDEO_JZ_CIM=m
+CONFIG_VIDEO_JZ_SENSOR=m
+# CONFIG_V4L_USB_DRIVERS is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_USB_DSBR is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_JZSOC=y
+CONFIG_FB_JZLCD_4730_4740=y
+CONFIG_JZLCD_FRAMEBUFFER_MAX=1
+# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set
+# CONFIG_JZLCD_SHARP_LQ035Q7 is not set
+# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set
+# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set
+CONFIG_JZLCD_SAMSUNG_LTP400WQF01=y
+# CONFIG_JZLCD_SAMSUNG_LTP400WQF02 is not set
+# CONFIG_JZLCD_AUO_A030FL01_V1 is not set
+# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set
+# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set
+# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set
+# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set
+# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set
+# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set
+# CONFIG_JZLCD_HYNIX_HT10X21 is not set
+# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set
+# CONFIG_JZLCD_CSTN_800x600 is not set
+# CONFIG_JZLCD_CSTN_320x240 is not set
+# CONFIG_JZLCD_MSTN_480x320 is not set
+# CONFIG_JZLCD_MSTN_320x240 is not set
+# CONFIG_JZLCD_MSTN_240x128 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_JZ4740 is not set
+CONFIG_USB_GADGET_JZ4730=y
+CONFIG_USB_JZ4730=m
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_JZ=y
+CONFIG_JZ_MMC_BUS_4=y
+# CONFIG_JZ_MMC_BUS_1 is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Yaffs2 Filesystems
+#
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SAMPLES is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/mips/configs/slt50_defconfig b/arch/mips/configs/slt50_defconfig
new file mode 100644
index 00000000000..53b05215cd0
--- /dev/null
+++ b/arch/mips/configs/slt50_defconfig
@@ -0,0 +1,1036 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24.3
+# Tue Nov 25 09:38:56 2008
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_JZ4730_PMP is not set
+# CONFIG_JZ4740_PAVO is not set
+# CONFIG_JZ4740_LEO is not set
+# CONFIG_JZ4740_LYRA is not set
+# CONFIG_JZ4725_DIPPER is not set
+# CONFIG_JZ4720_VIRGO is not set
+# CONFIG_JZ4750_FUWA is not set
+# CONFIG_JZ4750_APUS is not set
+CONFIG_JZ4750_SLT50=y
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_WR_PPMC is not set
+CONFIG_SOC_JZ4750=y
+CONFIG_JZSOC=y
+CONFIG_JZRISC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ_JZ is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_NAND_JZ4750=y
+# CONFIG_MTD_NAND_CS2 is not set
+# CONFIG_MTD_NAND_CS3 is not set
+# CONFIG_MTD_NAND_CS4 is not set
+# CONFIG_MTD_NAND_MULTI_PLANE is not set
+# CONFIG_MTD_HW_HM_ECC is not set
+# CONFIG_MTD_SW_HM_ECC is not set
+# CONFIG_MTD_HW_RS_ECC is not set
+CONFIG_MTD_HW_BCH_ECC=y
+CONFIG_MTD_HW_BCH_4BIT=y
+# CONFIG_MTD_HW_BCH_8BIT is not set
+CONFIG_MTD_NAND_DMA=y
+# CONFIG_MTD_NAND_DMABUF is not set
+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
+CONFIG_MTD_OOB_COPIES=3
+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_MTD_UBI_BLKDEVS is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PNP is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_NETDEVICES is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_JZ is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=2
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_RTC_PCF8563 is not set
+# CONFIG_RTC_JZ is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+
+#
+# JZSOC char device support
+#
+CONFIG_JZCHAR=y
+# CONFIG_JZ_CIM is not set
+# CONFIG_JZ_TPANEL_ATA2508 is not set
+# CONFIG_JZ_TPANEL is not set
+CONFIG_JZ_UDC_HOTPLUG=y
+# CONFIG_JZ_POWEROFF is not set
+# CONFIG_JZ_OW is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Yaffs2 Filesystems
+#
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+# CONFIG_YAFFS_ECC_BCH is not set
+CONFIG_YAFFS_ECC_RS=y
+# CONFIG_YAFFS_ECC_HAMMING is not set
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SAMPLES is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_REED_SOLOMON=y
+CONFIG_REED_SOLOMON_ENC8=y
+CONFIG_REED_SOLOMON_DEC8=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/mips/configs/virgo_defconfig b/arch/mips/configs/virgo_defconfig
new file mode 100644
index 00000000000..a0e02a02389
--- /dev/null
+++ b/arch/mips/configs/virgo_defconfig
@@ -0,0 +1,1281 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24.3
+# Thu Jun 12 13:52:15 2008
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_JZ4730_PMP is not set
+# CONFIG_JZ4740_PAVO is not set
+# CONFIG_JZ4740_LEO is not set
+# CONFIG_JZ4740_LYRA is not set
+# CONFIG_JZ4725_DIPPER is not set
+CONFIG_JZ4720_VIRGO=y
+# CONFIG_JZ4750_FUWA is not set
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_WR_PPMC is not set
+CONFIG_SOC_JZ4740=y
+CONFIG_SOC_JZ4720=y
+CONFIG_JZSOC=y
+CONFIG_JZRISC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+# CONFIG_KEXEC is not set
+CONFIG_SECCOMP=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ_JZ=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_LEGACY=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+# CONFIG_SUSPEND is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_NAND_JZ4740=y
+# CONFIG_MTD_HW_HM_ECC is not set
+# CONFIG_MTD_SW_HM_ECC is not set
+CONFIG_MTD_HW_RS_ECC=y
+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set
+CONFIG_MTD_OOB_COPIES=3
+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=m
+CONFIG_MTD_UBI_WL_THRESHOLD=256
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+CONFIG_MTD_UBI_BLKDEVS=m
+CONFIG_MTD_UBI_BLOCK=m
+# CONFIG_PARPORT is not set
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+
+#
+# Protocols
+#
+# CONFIG_PNPACPI is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_NET_SB1000 is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_JZCS8900=y
+# CONFIG_AX88796 is not set
+# CONFIG_DM9000 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PNP=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=2
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_RTC_PCF8563 is not set
+CONFIG_RTC_JZ=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+
+#
+# JZSOC char device support
+#
+CONFIG_JZCHAR=y
+# CONFIG_JZ_CIM is not set
+# CONFIG_JZ_TPANEL_ATA2508 is not set
+CONFIG_JZ_TPANEL=y
+CONFIG_JZ_SADC=y
+# CONFIG_JZ_TPANEL_AK4182 is not set
+# CONFIG_JZ_TPANEL_UCB1400 is not set
+# CONFIG_JZ_TPANEL_WM9712 is not set
+CONFIG_JZ_UDC_HOTPLUG=y
+CONFIG_JZ_POWEROFF=y
+# CONFIG_JZ_OW is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_JZ_WDT=y
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+CONFIG_VIDEO_JZ_CIM=y
+CONFIG_VIDEO_JZ_SENSOR=y
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_QUICKCAM_MESSENGER is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_ZR364XX is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_USB_DSBR is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_JZSOC=y
+# CONFIG_FB_JZ4740_SLCD is not set
+CONFIG_FB_JZLCD_4730_4740=y
+CONFIG_JZLCD_FRAMEBUFFER_MAX=1
+# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set
+# CONFIG_JZLCD_SHARP_LQ035Q7 is not set
+# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set
+# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set
+# CONFIG_JZLCD_SAMSUNG_LTP400WQF01 is not set
+CONFIG_JZLCD_SAMSUNG_LTP400WQF02=y
+# CONFIG_JZLCD_AUO_A030FL01_V1 is not set
+# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set
+# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set
+# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set
+# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set
+# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set
+# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set
+# CONFIG_JZLCD_HYNIX_HT10X21 is not set
+# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set
+# CONFIG_JZLCD_CSTN_800x600 is not set
+# CONFIG_JZLCD_CSTN_320x240 is not set
+# CONFIG_JZLCD_MSTN_480x320 is not set
+# CONFIG_JZLCD_MSTN_320x240 is not set
+# CONFIG_JZLCD_MSTN_240x128 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+CONFIG_OSS_OBSOLETE=y
+# CONFIG_SOUND_JZ_AC97 is not set
+CONFIG_SOUND_JZ_I2S=y
+# CONFIG_SOUND_JZ_PCM is not set
+# CONFIG_I2S_AK4642EN is not set
+CONFIG_I2S_ICODEC=y
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_JZ4740=y
+CONFIG_USB_JZ4740=m
+# CONFIG_USB_GADGET_JZ4730 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_JZ=y
+CONFIG_JZ_MMC_BUS_4=y
+# CONFIG_JZ_MMC_BUS_1 is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_UBIFS_FS=m
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Yaffs2 Filesystems
+#
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SAMPLES is not set
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_LZO=m
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=m
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/mips/include/asm/asm-offsets.h b/arch/mips/include/asm/asm-offsets.h
new file mode 100644
index 00000000000..b5c42c430ec
--- /dev/null
+++ b/arch/mips/include/asm/asm-offsets.h
@@ -0,0 +1,212 @@
+#ifndef __ASM_OFFSETS_H__
+#define __ASM_OFFSETS_H__
+/*
+ * DO NOT MODIFY.
+ *
+ * This file was generated by Kbuild
+ *
+ */
+
+/* MIPS pt_regs offsets. */
+#define PT_R0 24 /* offsetof(struct pt_regs, regs[0]) # */
+#define PT_R1 28 /* offsetof(struct pt_regs, regs[1]) # */
+#define PT_R2 32 /* offsetof(struct pt_regs, regs[2]) # */
+#define PT_R3 36 /* offsetof(struct pt_regs, regs[3]) # */
+#define PT_R4 40 /* offsetof(struct pt_regs, regs[4]) # */
+#define PT_R5 44 /* offsetof(struct pt_regs, regs[5]) # */
+#define PT_R6 48 /* offsetof(struct pt_regs, regs[6]) # */
+#define PT_R7 52 /* offsetof(struct pt_regs, regs[7]) # */
+#define PT_R8 56 /* offsetof(struct pt_regs, regs[8]) # */
+#define PT_R9 60 /* offsetof(struct pt_regs, regs[9]) # */
+#define PT_R10 64 /* offsetof(struct pt_regs, regs[10]) # */
+#define PT_R11 68 /* offsetof(struct pt_regs, regs[11]) # */
+#define PT_R12 72 /* offsetof(struct pt_regs, regs[12]) # */
+#define PT_R13 76 /* offsetof(struct pt_regs, regs[13]) # */
+#define PT_R14 80 /* offsetof(struct pt_regs, regs[14]) # */
+#define PT_R15 84 /* offsetof(struct pt_regs, regs[15]) # */
+#define PT_R16 88 /* offsetof(struct pt_regs, regs[16]) # */
+#define PT_R17 92 /* offsetof(struct pt_regs, regs[17]) # */
+#define PT_R18 96 /* offsetof(struct pt_regs, regs[18]) # */
+#define PT_R19 100 /* offsetof(struct pt_regs, regs[19]) # */
+#define PT_R20 104 /* offsetof(struct pt_regs, regs[20]) # */
+#define PT_R21 108 /* offsetof(struct pt_regs, regs[21]) # */
+#define PT_R22 112 /* offsetof(struct pt_regs, regs[22]) # */
+#define PT_R23 116 /* offsetof(struct pt_regs, regs[23]) # */
+#define PT_R24 120 /* offsetof(struct pt_regs, regs[24]) # */
+#define PT_R25 124 /* offsetof(struct pt_regs, regs[25]) # */
+#define PT_R26 128 /* offsetof(struct pt_regs, regs[26]) # */
+#define PT_R27 132 /* offsetof(struct pt_regs, regs[27]) # */
+#define PT_R28 136 /* offsetof(struct pt_regs, regs[28]) # */
+#define PT_R29 140 /* offsetof(struct pt_regs, regs[29]) # */
+#define PT_R30 144 /* offsetof(struct pt_regs, regs[30]) # */
+#define PT_R31 148 /* offsetof(struct pt_regs, regs[31]) # */
+#define PT_LO 160 /* offsetof(struct pt_regs, lo) # */
+#define PT_HI 156 /* offsetof(struct pt_regs, hi) # */
+#define PT_EPC 172 /* offsetof(struct pt_regs, cp0_epc) # */
+#define PT_BVADDR 164 /* offsetof(struct pt_regs, cp0_badvaddr) # */
+#define PT_STATUS 152 /* offsetof(struct pt_regs, cp0_status) # */
+#define PT_CAUSE 168 /* offsetof(struct pt_regs, cp0_cause) # */
+#define PT_SIZE 176 /* sizeof(struct pt_regs) # */
+
+/* MIPS task_struct offsets. */
+#define TASK_STATE 0 /* offsetof(struct task_struct, state) # */
+#define TASK_THREAD_INFO 4 /* offsetof(struct task_struct, stack) # */
+#define TASK_FLAGS 12 /* offsetof(struct task_struct, flags) # */
+#define TASK_MM 216 /* offsetof(struct task_struct, mm) # */
+#define TASK_PID 252 /* offsetof(struct task_struct, pid) # */
+#define TASK_STRUCT_SIZE 1152 /* sizeof(struct task_struct) # */
+
+/* MIPS thread_info offsets. */
+#define TI_TASK 0 /* offsetof(struct thread_info, task) # */
+#define TI_EXEC_DOMAIN 4 /* offsetof(struct thread_info, exec_domain) # */
+#define TI_FLAGS 8 /* offsetof(struct thread_info, flags) # */
+#define TI_TP_VALUE 12 /* offsetof(struct thread_info, tp_value) # */
+#define TI_CPU 16 /* offsetof(struct thread_info, cpu) # */
+#define TI_PRE_COUNT 20 /* offsetof(struct thread_info, preempt_count) # */
+#define TI_ADDR_LIMIT 24 /* offsetof(struct thread_info, addr_limit) # */
+#define TI_RESTART_BLOCK 32 /* offsetof(struct thread_info, restart_block) # */
+#define TI_REGS 72 /* offsetof(struct thread_info, regs) # */
+#define _THREAD_SIZE 8192 /* THREAD_SIZE # */
+#define _THREAD_MASK 8191 /* THREAD_MASK # */
+
+/* MIPS specific thread_struct offsets. */
+#define THREAD_REG16 520 /* offsetof(struct task_struct, thread.reg16) # */
+#define THREAD_REG17 524 /* offsetof(struct task_struct, thread.reg17) # */
+#define THREAD_REG18 528 /* offsetof(struct task_struct, thread.reg18) # */
+#define THREAD_REG19 532 /* offsetof(struct task_struct, thread.reg19) # */
+#define THREAD_REG20 536 /* offsetof(struct task_struct, thread.reg20) # */
+#define THREAD_REG21 540 /* offsetof(struct task_struct, thread.reg21) # */
+#define THREAD_REG22 544 /* offsetof(struct task_struct, thread.reg22) # */
+#define THREAD_REG23 548 /* offsetof(struct task_struct, thread.reg23) # */
+#define THREAD_REG29 552 /* offsetof(struct task_struct, thread.reg29) # */
+#define THREAD_REG30 556 /* offsetof(struct task_struct, thread.reg30) # */
+#define THREAD_REG31 560 /* offsetof(struct task_struct, thread.reg31) # */
+#define THREAD_STATUS 564 /* offsetof(struct task_struct, thread.cp0_status) # */
+#define THREAD_FPU 568 /* offsetof(struct task_struct, thread.fpu) # */
+#define THREAD_BVADDR 884 /* offsetof(struct task_struct, thread.cp0_badvaddr) # */
+#define THREAD_BUADDR 888 /* offsetof(struct task_struct, thread.cp0_baduaddr) # */
+#define THREAD_ECODE 892 /* offsetof(struct task_struct, thread.error_code) # */
+#define THREAD_TRAPNO 896 /* offsetof(struct task_struct, thread.trap_no) # */
+#define THREAD_TRAMP 900 /* offsetof(struct task_struct, thread.irix_trampoline) # */
+#define THREAD_OLDCTX 904 /* offsetof(struct task_struct, thread.irix_oldctx) # */
+
+#define THREAD_FPR0 568 /* offsetof(struct task_struct, thread.fpu.fpr[0]) # */
+#define THREAD_FPR1 576 /* offsetof(struct task_struct, thread.fpu.fpr[1]) # */
+#define THREAD_FPR2 584 /* offsetof(struct task_struct, thread.fpu.fpr[2]) # */
+#define THREAD_FPR3 592 /* offsetof(struct task_struct, thread.fpu.fpr[3]) # */
+#define THREAD_FPR4 600 /* offsetof(struct task_struct, thread.fpu.fpr[4]) # */
+#define THREAD_FPR5 608 /* offsetof(struct task_struct, thread.fpu.fpr[5]) # */
+#define THREAD_FPR6 616 /* offsetof(struct task_struct, thread.fpu.fpr[6]) # */
+#define THREAD_FPR7 624 /* offsetof(struct task_struct, thread.fpu.fpr[7]) # */
+#define THREAD_FPR8 632 /* offsetof(struct task_struct, thread.fpu.fpr[8]) # */
+#define THREAD_FPR9 640 /* offsetof(struct task_struct, thread.fpu.fpr[9]) # */
+#define THREAD_FPR10 648 /* offsetof(struct task_struct, thread.fpu.fpr[10]) # */
+#define THREAD_FPR11 656 /* offsetof(struct task_struct, thread.fpu.fpr[11]) # */
+#define THREAD_FPR12 664 /* offsetof(struct task_struct, thread.fpu.fpr[12]) # */
+#define THREAD_FPR13 672 /* offsetof(struct task_struct, thread.fpu.fpr[13]) # */
+#define THREAD_FPR14 680 /* offsetof(struct task_struct, thread.fpu.fpr[14]) # */
+#define THREAD_FPR15 688 /* offsetof(struct task_struct, thread.fpu.fpr[15]) # */
+#define THREAD_FPR16 696 /* offsetof(struct task_struct, thread.fpu.fpr[16]) # */
+#define THREAD_FPR17 704 /* offsetof(struct task_struct, thread.fpu.fpr[17]) # */
+#define THREAD_FPR18 712 /* offsetof(struct task_struct, thread.fpu.fpr[18]) # */
+#define THREAD_FPR19 720 /* offsetof(struct task_struct, thread.fpu.fpr[19]) # */
+#define THREAD_FPR20 728 /* offsetof(struct task_struct, thread.fpu.fpr[20]) # */
+#define THREAD_FPR21 736 /* offsetof(struct task_struct, thread.fpu.fpr[21]) # */
+#define THREAD_FPR22 744 /* offsetof(struct task_struct, thread.fpu.fpr[22]) # */
+#define THREAD_FPR23 752 /* offsetof(struct task_struct, thread.fpu.fpr[23]) # */
+#define THREAD_FPR24 760 /* offsetof(struct task_struct, thread.fpu.fpr[24]) # */
+#define THREAD_FPR25 768 /* offsetof(struct task_struct, thread.fpu.fpr[25]) # */
+#define THREAD_FPR26 776 /* offsetof(struct task_struct, thread.fpu.fpr[26]) # */
+#define THREAD_FPR27 784 /* offsetof(struct task_struct, thread.fpu.fpr[27]) # */
+#define THREAD_FPR28 792 /* offsetof(struct task_struct, thread.fpu.fpr[28]) # */
+#define THREAD_FPR29 800 /* offsetof(struct task_struct, thread.fpu.fpr[29]) # */
+#define THREAD_FPR30 808 /* offsetof(struct task_struct, thread.fpu.fpr[30]) # */
+#define THREAD_FPR31 816 /* offsetof(struct task_struct, thread.fpu.fpr[31]) # */
+#define THREAD_FCR31 824 /* offsetof(struct task_struct, thread.fpu.fcr31) # */
+
+/* Size of struct page */
+#define STRUCT_PAGE_SIZE 32 /* sizeof(struct page) # */
+
+/* Linux mm_struct offsets. */
+#define MM_USERS 40 /* offsetof(struct mm_struct, mm_users) # */
+#define MM_PGD 36 /* offsetof(struct mm_struct, pgd) # */
+#define MM_CONTEXT 328 /* offsetof(struct mm_struct, context) # */
+
+#define _PAGE_SIZE 4096 /* PAGE_SIZE # */
+#define _PAGE_SHIFT 12 /* PAGE_SHIFT # */
+
+#define _PGD_T_SIZE 4 /* sizeof(pgd_t) # */
+#define _PMD_T_SIZE 4 /* sizeof(pmd_t) # */
+#define _PTE_T_SIZE 4 /* sizeof(pte_t) # */
+
+#define _PGD_T_LOG2 2 /* PGD_T_LOG2 # */
+#define _PMD_T_LOG2 2 /* PMD_T_LOG2 # */
+#define _PTE_T_LOG2 2 /* PTE_T_LOG2 # */
+
+#define _PGD_ORDER 0 /* PGD_ORDER # */
+#define _PMD_ORDER 1 /* PMD_ORDER # */
+#define _PTE_ORDER 0 /* PTE_ORDER # */
+
+#define _PMD_SHIFT 22 /* PMD_SHIFT # */
+#define _PGDIR_SHIFT 22 /* PGDIR_SHIFT # */
+
+#define _PTRS_PER_PGD 1024 /* PTRS_PER_PGD # */
+#define _PTRS_PER_PMD 1 /* PTRS_PER_PMD # */
+#define _PTRS_PER_PTE 1024 /* PTRS_PER_PTE # */
+
+/* Linux sigcontext offsets. */
+#define SC_REGS 16 /* offsetof(struct sigcontext, sc_regs) # */
+#define SC_FPREGS 272 /* offsetof(struct sigcontext, sc_fpregs) # */
+#define SC_ACX 528 /* offsetof(struct sigcontext, sc_acx) # */
+#define SC_MDHI 552 /* offsetof(struct sigcontext, sc_mdhi) # */
+#define SC_MDLO 560 /* offsetof(struct sigcontext, sc_mdlo) # */
+#define SC_PC 8 /* offsetof(struct sigcontext, sc_pc) # */
+#define SC_FPC_CSR 532 /* offsetof(struct sigcontext, sc_fpc_csr) # */
+#define SC_FPC_EIR 536 /* offsetof(struct sigcontext, sc_fpc_eir) # */
+#define SC_HI1 568 /* offsetof(struct sigcontext, sc_hi1) # */
+#define SC_LO1 572 /* offsetof(struct sigcontext, sc_lo1) # */
+#define SC_HI2 576 /* offsetof(struct sigcontext, sc_hi2) # */
+#define SC_LO2 580 /* offsetof(struct sigcontext, sc_lo2) # */
+#define SC_HI3 584 /* offsetof(struct sigcontext, sc_hi3) # */
+#define SC_LO3 588 /* offsetof(struct sigcontext, sc_lo3) # */
+
+/* Linux signal numbers. */
+#define _SIGHUP 1 /* SIGHUP # */
+#define _SIGINT 2 /* SIGINT # */
+#define _SIGQUIT 3 /* SIGQUIT # */
+#define _SIGILL 4 /* SIGILL # */
+#define _SIGTRAP 5 /* SIGTRAP # */
+#define _SIGIOT 6 /* SIGIOT # */
+#define _SIGABRT 6 /* SIGABRT # */
+#define _SIGEMT 7 /* SIGEMT # */
+#define _SIGFPE 8 /* SIGFPE # */
+#define _SIGKILL 9 /* SIGKILL # */
+#define _SIGBUS 10 /* SIGBUS # */
+#define _SIGSEGV 11 /* SIGSEGV # */
+#define _SIGSYS 12 /* SIGSYS # */
+#define _SIGPIPE 13 /* SIGPIPE # */
+#define _SIGALRM 14 /* SIGALRM # */
+#define _SIGTERM 15 /* SIGTERM # */
+#define _SIGUSR1 16 /* SIGUSR1 # */
+#define _SIGUSR2 17 /* SIGUSR2 # */
+#define _SIGCHLD 18 /* SIGCHLD # */
+#define _SIGPWR 19 /* SIGPWR # */
+#define _SIGWINCH 20 /* SIGWINCH # */
+#define _SIGURG 21 /* SIGURG # */
+#define _SIGIO 22 /* SIGIO # */
+#define _SIGSTOP 23 /* SIGSTOP # */
+#define _SIGTSTP 24 /* SIGTSTP # */
+#define _SIGCONT 25 /* SIGCONT # */
+#define _SIGTTIN 26 /* SIGTTIN # */
+#define _SIGTTOU 27 /* SIGTTOU # */
+#define _SIGVTALRM 28 /* SIGVTALRM # */
+#define _SIGPROF 29 /* SIGPROF # */
+#define _SIGXCPU 30 /* SIGXCPU # */
+#define _SIGXFSZ 31 /* SIGXFSZ # */
+
+/* Linux irq_cpustat_t offsets. */
+#define IC_SOFTIRQ_PENDING 0 /* offsetof(irq_cpustat_t, __softirq_pending) # */
+#define IC_IRQ_CPUSTAT_T 32 /* sizeof(irq_cpustat_t) # */
+
+
+#endif
diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h
index 610fe3af7a0..cbd25a2f9b5 100644
--- a/arch/mips/include/asm/bootinfo.h
+++ b/arch/mips/include/asm/bootinfo.h
@@ -26,6 +26,13 @@
#define MACH_UNKNOWN 0 /* whatever... */
/*
+ * Valid machtype values for group JAZZ
+ */
+#define MACH_ACER_PICA_61 0 /* Acer PICA-61 (PICA1) */
+#define MACH_MIPS_MAGNUM_4000 1 /* Mips Magnum 4000 "RC4030" */
+#define MACH_OLIVETTI_M700 2 /* Olivetti M700-10 (-15 ??) */
+
+/*
* Valid machtype for group DEC
*/
#define MACH_DSUNKNOWN 0
@@ -41,6 +48,138 @@
#define MACH_DS5900 10 /* DECsystem 5900 */
/*
+ * Valid machtype for group ARC
+ */
+#define MACH_DESKSTATION_RPC44 0 /* Deskstation rPC44 */
+#define MACH_DESKSTATION_TYNE 1 /* Deskstation Tyne */
+
+/*
+ * Valid machtype for group SNI_RM
+ */
+#define MACH_SNI_RM200_PCI 0 /* RM200/RM300/RM400 PCI series */
+
+/*
+ * Valid machtype for group ACN
+ */
+#define MACH_ACN_MIPS_BOARD 0 /* ACN MIPS single board */
+
+/*
+ * Valid machtype for group SGI
+ */
+#define MACH_SGI_IP22 0 /* Indy, Indigo2, Challenge S */
+#define MACH_SGI_IP27 1 /* Origin 200, Origin 2000, Onyx 2 */
+#define MACH_SGI_IP28 2 /* Indigo2 Impact */
+#define MACH_SGI_IP32 3 /* O2 */
+#define MACH_SGI_IP30 4 /* Octane, Octane2 */
+
+/*
+ * Valid machtype for group COBALT
+ */
+#define MACH_COBALT_27 0 /* Proto "27" hardware */
+
+/*
+ * Valid machtype for group BAGET
+ */
+#define MACH_BAGET201 0 /* BT23-201 */
+#define MACH_BAGET202 1 /* BT23-202 */
+
+/*
+ * Cosine boards.
+ */
+#define MACH_COSINE_ORION 0
+
+/*
+ * Valid machtype for group MOMENCO
+ */
+#define MACH_MOMENCO_OCELOT 0
+#define MACH_MOMENCO_OCELOT_G 1 /* no more supported (may 2007) */
+#define MACH_MOMENCO_OCELOT_C 2 /* no more supported (jun 2007) */
+#define MACH_MOMENCO_JAGUAR_ATX 3 /* no more supported (may 2007) */
+#define MACH_MOMENCO_OCELOT_3 4
+
+/*
+ * Valid machtype for group PHILIPS
+ */
+#define MACH_PHILIPS_NINO 0 /* Nino */
+#define MACH_PHILIPS_VELO 1 /* Velo */
+#define MACH_PHILIPS_JBS 2 /* JBS */
+#define MACH_PHILIPS_STB810 3 /* STB810 */
+
+/*
+ * Valid machtype for group SIBYTE
+ */
+#define MACH_SWARM 0
+
+/*
+ * Valid machtypes for group Toshiba
+ */
+#define MACH_PALLAS 0
+#define MACH_TOPAS 1
+#define MACH_JMR 2
+#define MACH_TOSHIBA_JMR3927 3 /* JMR-TX3927 CPU/IO board */
+#define MACH_TOSHIBA_RBTX4927 4
+#define MACH_TOSHIBA_RBTX4937 5
+#define MACH_TOSHIBA_RBTX4938 6
+
+/*
+ * Valid machtype for group Alchemy
+ */
+#define MACH_PB1000 0 /* Au1000-based eval board */
+#define MACH_PB1100 1 /* Au1100-based eval board */
+#define MACH_PB1500 2 /* Au1500-based eval board */
+#define MACH_DB1000 3 /* Au1000-based eval board */
+#define MACH_DB1100 4 /* Au1100-based eval board */
+#define MACH_DB1500 5 /* Au1500-based eval board */
+#define MACH_XXS1500 6 /* Au1500-based eval board */
+#define MACH_MTX1 7 /* 4G MTX-1 Au1500-based board */
+#define MACH_PB1550 8 /* Au1550-based eval board */
+#define MACH_DB1550 9 /* Au1550-based eval board */
+#define MACH_PB1200 10 /* Au1200-based eval board */
+#define MACH_DB1200 11 /* Au1200-based eval board */
+
+/*
+ * Valid machtype for group NEC_VR41XX
+ *
+ * Various NEC-based devices.
+ *
+ * FIXME: MACH_GROUPs should be by _MANUFACTURER_ of * the device, not by
+ * technical properties, so no new additions to this group.
+ */
+#define MACH_NEC_OSPREY 0 /* Osprey eval board */
+#define MACH_NEC_EAGLE 1 /* NEC Eagle/Hawk board */
+#define MACH_ZAO_CAPCELLA 2 /* ZAO Networks Capcella */
+#define MACH_VICTOR_MPC30X 3 /* Victor MP-C303/304 */
+#define MACH_IBM_WORKPAD 4 /* IBM WorkPad z50 */
+#define MACH_CASIO_E55 5 /* CASIO CASSIOPEIA E-10/15/55/65 */
+#define MACH_TANBAC_TB0226 6 /* TANBAC TB0226 (Mbase) */
+#define MACH_TANBAC_TB0229 7 /* TANBAC TB0229 (VR4131DIMM) */
+#define MACH_NEC_CMBVR4133 8 /* CMB VR4133 Board */
+
+#define MACH_HP_LASERJET 1
+
+/*
+ * Valid machtype for group LASAT
+ */
+#define MACH_LASAT_100 0 /* Masquerade II/SP100/SP50/SP25 */
+#define MACH_LASAT_200 1 /* Masquerade PRO/SP200 */
+
+/*
+ * Valid machtype for group TITAN
+ */
+#define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */
+#define MACH_TITAN_EXCITE 2 /* Basler eXcite */
+
+/*
+ * Valid machtype for group NEC EMMA2RH
+ */
+#define MACH_NEC_MARKEINS 0 /* NEC EMMA2RH Mark-eins */
+
+/*
+ * Valid machtype for group LEMOTE
+ */
+#define MACH_LEMOTE_FULONG 0
+
+/*
* Valid machtype for group PMC-MSP
*/
#define MACH_MSP4200_EVAL 0 /* PMC-Sierra MSP4200 Evaluation */
@@ -51,15 +190,25 @@
#define MACH_MSP7120_FPGA 5 /* PMC-Sierra MSP7120 Emulation */
#define MACH_MSP_OTHER 255 /* PMC-Sierra unknown board type */
+#define MACH_WRPPMC 1
+
+/*
+ * Valid machtype for group Broadcom
+ */
+#define MACH_GROUP_BRCM 23 /* Broadcom */
+#define MACH_BCM47XX 1 /* Broadcom BCM47XX */
+
/*
- * Valid machtype for group Mikrotik
+ * Valid machtype for group INGENIC
*/
-#define MACH_MIKROTIK_RB532 0 /* Mikrotik RouterBoard 532 */
-#define MACH_MIKROTIK_RB532A 1 /* Mikrotik RouterBoard 532A */
+#define MACH_INGENIC_JZ4730 0 /* JZ4730 SOC */
+#define MACH_INGENIC_JZ4740 1 /* JZ4740 SOC */
+#define MACH_INGENIC_JZ4750 2 /* JZ4750 SOC */
+#define MACH_INGENIC_JZ4750D 3 /* JZ4750D SOC */
+#define MACH_INGENIC_JZ4750L 4 /* JZ4750L SOC */
#define CL_SIZE COMMAND_LINE_SIZE
-extern char *system_type;
const char *get_system_type(void);
extern unsigned long mips_machtype;
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index 3bdc0e3d89c..904c574ff7c 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -34,7 +34,7 @@
#define PRID_COMP_LSI 0x080000
#define PRID_COMP_LEXRA 0x0b0000
#define PRID_COMP_CAVIUM 0x0d0000
-
+#define PRID_COMP_INGENIC 0xd00000
/*
* Assigned values for the product ID register. In order to detect a
@@ -127,6 +127,12 @@
#define PRID_IMP_CAVIUM_CN52XX 0x0700
/*
+ * These are the PRID's for when 23:16 == PRID_COMP_INGENIC
+ */
+
+#define PRID_IMP_JZRISC 0x0200
+
+/*
* Definitions for 7:0 on legacy processors
*/
@@ -217,6 +223,11 @@ enum cpu_type_enum {
CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
CPU_CAVIUM_OCTEON,
+ /*
+ * Ingenic class processors
+ */
+ CPU_JZRISC, CPU_XBURST,
+
CPU_LAST
};
diff --git a/arch/mips/include/asm/jzsoc.h b/arch/mips/include/asm/jzsoc.h
new file mode 100644
index 00000000000..0da2887148a
--- /dev/null
+++ b/arch/mips/include/asm/jzsoc.h
@@ -0,0 +1,53 @@
+/*
+ * linux/include/asm-mips/jzsoc.h
+ *
+ * Ingenic's JZXXXX SoC common include.
+ *
+ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZSOC_H__
+#define __ASM_JZSOC_H__
+
+/*
+ * SoC include
+ */
+
+#ifdef CONFIG_SOC_JZ4730
+#include <asm/mach-jz4730/jz4730.h>
+#endif
+
+#ifdef CONFIG_SOC_JZ4740
+#include <asm/mach-jz4740/jz4740.h>
+#endif
+
+#ifdef CONFIG_SOC_JZ4750
+#include <asm/mach-jz4750/jz4750.h>
+#endif
+
+#ifdef CONFIG_SOC_JZ4750D
+#include <asm/mach-jz4750d/jz4750d.h>
+#endif
+
+#ifdef CONFIG_SOC_JZ4750L
+#include <asm/mach-jz4750l/jz4750l.h>
+#endif
+
+/*
+ * Generic I/O routines
+ */
+#define readb(addr) (*(volatile unsigned char *)(addr))
+#define readw(addr) (*(volatile unsigned short *)(addr))
+#define readl(addr) (*(volatile unsigned int *)(addr))
+
+#define writeb(b,addr) ((*(volatile unsigned char *)(addr)) = (b))
+#define writew(b,addr) ((*(volatile unsigned short *)(addr)) = (b))
+#define writel(b,addr) ((*(volatile unsigned int *)(addr)) = (b))
+
+#endif /* __ASM_JZSOC_H__ */
diff --git a/arch/mips/include/asm/mach-generic/irq.h b/arch/mips/include/asm/mach-generic/irq.h
index 70d9a25132c..73b7a83a1db 100644
--- a/arch/mips/include/asm/mach-generic/irq.h
+++ b/arch/mips/include/asm/mach-generic/irq.h
@@ -9,7 +9,7 @@
#define __ASM_MACH_GENERIC_IRQ_H
#ifndef NR_IRQS
-#define NR_IRQS 128
+#define NR_IRQS 256
#endif
#ifdef CONFIG_I8259
diff --git a/arch/mips/include/asm/mach-jz4730/board-pmp.h b/arch/mips/include/asm/mach-jz4730/board-pmp.h
new file mode 100644
index 00000000000..44475d2a8f9
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4730/board-pmp.h
@@ -0,0 +1,83 @@
+/*
+ * linux/include/asm-mips/mach-jz4730/board-pmp.h
+ *
+ * JZ4730-based PMP board ver 2.x definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4730_PMP_H__
+#define __ASM_JZ4730_PMP_H__
+
+/*======================================================================
+ * EXTAL frequency
+ */
+#define JZ_EXTAL 12000000 /* EXTAL: 12 MHz */
+#define JZ_EXTAL2 32768 /* EXTAL2: 32.768 KHz */
+
+
+/*======================================================================
+ * GPIO
+ */
+#define GPIO_PW_I 97
+#define GPIO_PW_O 66
+#define GPIO_LED_EN 92
+#define GPIO_DISP_OFF_N 93
+#define GPIO_PWM0 94
+#define GPIO_RTC_IRQ 96
+#define GPIO_USB_CLK_EN 29
+#define GPIO_CHARG_STAT 125
+#define GPIO_TS_PENIRQ 98
+#define GPIO_UDC_HOTPLUG 86
+
+/*======================================================================
+ * MMC/SD
+ */
+#define MSC_WP_PIN 82
+#define MSC_POWEREN_PIN 91
+#define MSC_HOTPLUG_PIN 90
+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + MSC_HOTPLUG_PIN)
+
+/* enable slot power */
+#define __msc_init_io() \
+do { \
+ __gpio_as_input(MSC_WP_PIN); \
+ __gpio_as_output(MSC_POWEREN_PIN); \
+} while (0)
+
+/* enable slot power */
+#define __msc_enable_power() \
+do { \
+ __gpio_clear_pin(MSC_POWEREN_PIN); \
+} while (0)
+
+/* disable slot power */
+#define __msc_disable_power() \
+do { \
+ __gpio_set_pin(MSC_POWEREN_PIN); \
+} while (0)
+
+/* detect card insertion or not */
+#define __msc_card_detected(slot) \
+({ \
+ int ret; \
+ if (slot == 0) { \
+ __gpio_mask_irq(MSC_HOTPLUG_IRQ); \
+ __gpio_as_input(MSC_HOTPLUG_PIN); \
+ ret = __gpio_get_pin(MSC_HOTPLUG_PIN); \
+ __gpio_unmask_irq(MSC_HOTPLUG_IRQ); \
+ } \
+ else { \
+ ret = 1; \
+ } \
+ ret = !ret; \
+ ret; \
+})
+
+#endif /* __ASM_JZ4730_PMP_H__ */
diff --git a/arch/mips/include/asm/mach-jz4730/clock.h b/arch/mips/include/asm/mach-jz4730/clock.h
new file mode 100644
index 00000000000..16971d0ba73
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4730/clock.h
@@ -0,0 +1,184 @@
+/*
+ * linux/include/asm-mips/mach-jz4730/clock.h
+ *
+ * JZ4730 clocks definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4730_CLOCK_H__
+#define __ASM_JZ4730_CLOCK_H__
+
+#ifndef JZ_EXTAL
+#define JZ_EXTAL 3686400
+#endif
+
+#ifndef JZ_EXTAL2
+#define JZ_EXTAL2 32768
+#endif
+
+/*
+ * JZ4730 clocks structure
+ */
+typedef struct {
+ unsigned int iclk; /* CPU core clock */
+ unsigned int sclk; /* AHB bus clock */
+ unsigned int mclk; /* Memory bus clock */
+ unsigned int pclk; /* APB bus clock */
+ unsigned int devclk; /* Devcie clock to specific modules */
+ unsigned int rtcclk; /* RTC module clock */
+ unsigned int uartclk; /* UART module clock */
+ unsigned int lcdclk; /* LCD module clock */
+ unsigned int pixclk; /* LCD pixel clock */
+ unsigned int usbclk; /* USB module clock */
+ unsigned int i2sclk; /* I2S module clock */
+ unsigned int mscclk; /* MMC/SD module clock */
+} jz_clocks_t;
+
+extern jz_clocks_t jz_clocks;
+
+
+static __inline__ unsigned int __cpm_get_pllout(void)
+{
+ unsigned int nf, nr, no, pllout;
+ unsigned long plcr = REG_CPM_PLCR1;
+ unsigned long od[4] = {1, 2, 2, 4};
+ if (plcr & CPM_PLCR1_PLL1EN) {
+ nf = (plcr & CPM_PLCR1_PLL1FD_MASK) >> CPM_PLCR1_PLL1FD_BIT;
+ nr = (plcr & CPM_PLCR1_PLL1RD_MASK) >> CPM_PLCR1_PLL1RD_BIT;
+ no = od[((plcr & CPM_PLCR1_PLL1OD_MASK) >> CPM_PLCR1_PLL1OD_BIT)];
+ pllout = (JZ_EXTAL) / ((nr+2) * no) * (nf+2);
+ } else
+ pllout = JZ_EXTAL;
+ return pllout;
+}
+
+static __inline__ unsigned int __cpm_get_iclk(void)
+{
+ unsigned int iclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned long cfcr = REG_CPM_CFCR;
+ unsigned long plcr = REG_CPM_PLCR1;
+ if (plcr & CPM_PLCR1_PLL1EN)
+ iclk = __cpm_get_pllout() /
+ div[(cfcr & CPM_CFCR_IFR_MASK) >> CPM_CFCR_IFR_BIT];
+ else
+ iclk = JZ_EXTAL;
+ return iclk;
+}
+
+static __inline__ unsigned int __cpm_get_sclk(void)
+{
+ unsigned int sclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned long cfcr = REG_CPM_CFCR;
+ unsigned long plcr = REG_CPM_PLCR1;
+ if (plcr & CPM_PLCR1_PLL1EN)
+ sclk = __cpm_get_pllout() /
+ div[(cfcr & CPM_CFCR_SFR_MASK) >> CPM_CFCR_SFR_BIT];
+ else
+ sclk = JZ_EXTAL;
+ return sclk;
+}
+
+static __inline__ unsigned int __cpm_get_mclk(void)
+{
+ unsigned int mclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned long cfcr = REG_CPM_CFCR;
+ unsigned long plcr = REG_CPM_PLCR1;
+ if (plcr & CPM_PLCR1_PLL1EN)
+ mclk = __cpm_get_pllout() /
+ div[(cfcr & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT];
+ else
+ mclk = JZ_EXTAL;
+ return mclk;
+}
+
+static __inline__ unsigned int __cpm_get_pclk(void)
+{
+ unsigned int devclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned long cfcr = REG_CPM_CFCR;
+ unsigned long plcr = REG_CPM_PLCR1;
+ if (plcr & CPM_PLCR1_PLL1EN)
+ devclk = __cpm_get_pllout() /
+ div[(cfcr & CPM_CFCR_PFR_MASK) >> CPM_CFCR_PFR_BIT];
+ else
+ devclk = JZ_EXTAL;
+ return devclk;
+}
+
+static __inline__ unsigned int __cpm_get_lcdclk(void)
+{
+ unsigned int lcdclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned long cfcr = REG_CPM_CFCR;
+ unsigned long plcr = REG_CPM_PLCR1;
+ if (plcr & CPM_PLCR1_PLL1EN)
+ lcdclk = __cpm_get_pllout() /
+ div[(cfcr & CPM_CFCR_LFR_MASK) >> CPM_CFCR_LFR_BIT];
+ else
+ lcdclk = JZ_EXTAL;
+ return lcdclk;
+}
+
+static __inline__ unsigned int __cpm_get_pixclk(void)
+{
+ unsigned int pixclk;
+ unsigned long cfcr2 = REG_CPM_CFCR2;
+ pixclk = __cpm_get_pllout() / (cfcr2 + 1);
+ return pixclk;
+}
+
+static __inline__ unsigned int __cpm_get_devclk(void)
+{
+ return JZ_EXTAL;
+}
+
+static __inline__ unsigned int __cpm_get_rtcclk(void)
+{
+ return JZ_EXTAL2;
+}
+
+static __inline__ unsigned int __cpm_get_uartclk(void)
+{
+ return JZ_EXTAL;
+}
+
+static __inline__ unsigned int __cpm_get_usbclk(void)
+{
+ unsigned int usbclk;
+ unsigned long cfcr = REG_CPM_CFCR;
+ if (cfcr & CPM_CFCR_UCS)
+ usbclk = 48000000;
+ else
+ usbclk = __cpm_get_pllout() /
+ (((cfcr &CPM_CFCR_UFR_MASK) >> CPM_CFCR_UFR_BIT) + 1);
+ return usbclk;
+}
+
+static __inline__ unsigned int __cpm_get_i2sclk(void)
+{
+ unsigned int i2sclk;
+ unsigned long cfcr = REG_CPM_CFCR;
+ i2sclk = __cpm_get_pllout() /
+ ((cfcr & CPM_CFCR_I2S) ? 2: 1);
+ return i2sclk;
+}
+
+static __inline__ unsigned int __cpm_get_mscclk(void)
+{
+ if (REG_CPM_CFCR & CPM_CFCR_MSC)
+ return 24000000;
+ else
+ return 16000000;
+}
+
+#endif /* __ASM_JZ4730_CLOCK_H__ */
diff --git a/arch/mips/include/asm/mach-jz4730/dma.h b/arch/mips/include/asm/mach-jz4730/dma.h
new file mode 100644
index 00000000000..511152e39f1
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4730/dma.h
@@ -0,0 +1,272 @@
+/*
+ * linux/include/asm-mips/mach-jz4730/dma.h
+ *
+ * JZ4730 DMA definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4730_DMA_H__
+#define __ASM_JZ4730_DMA_H__
+
+#include <linux/interrupt.h>
+#include <asm/io.h> /* need byte IO */
+#include <linux/spinlock.h> /* And spinlocks */
+#include <linux/delay.h>
+#include <asm/system.h>
+
+#define DMA_UNIT_32 32
+#define DMA_UNIT_16 16
+
+
+/* block-mode EOP: high DREQ: high DACK: low*/
+#define DMA_BLOCK_CONF \
+ DMAC_DCCSR_TM | \
+ DMAC_DCCSR_DS_8b | DMAC_DCCSR_RDIL_IGN | \
+ DMAC_DCCSR_ERDM_HLEVEL | DMAC_DCCSR_EACKS
+
+/* single-mode EOP: high DREQ: high DACK: low */
+#define DMA_SINGLE_CONF \
+ DMAC_DCCSR_DS_8b | DMAC_DCCSR_RDIL_IGN | \
+ DMAC_DCCSR_ERDM_HLEVEL | DMAC_DCCSR_EACKS
+
+#define DMA_8bit_RX_CONF \
+ DMAC_DCCSR_DAM | \
+ DMAC_DCCSR_SWDH_8 | DMAC_DCCSR_DWDH_32 | \
+ DMAC_DCCSR_DS_8b | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_8bit_TX_CONF \
+ DMAC_DCCSR_SAM | \
+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_8 | \
+ DMAC_DCCSR_DS_8b | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_16bit_RX_CONF \
+ DMAC_DCCSR_DAM | \
+ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_32 | \
+ DMAC_DCCSR_DS_16b | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_16bit_TX_CONF \
+ DMAC_DCCSR_SAM | \
+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_16 | \
+ DMAC_DCCSR_DS_16b | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_32bit_RX_CONF \
+ DMAC_DCCSR_DAM | \
+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_32 | \
+ DMAC_DCCSR_DS_32b | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_32bit_TX_CONF \
+ DMAC_DCCSR_SAM | \
+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_32 | \
+ DMAC_DCCSR_DS_32b | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_16BYTE_RX_CONF \
+ DMAC_DCCSR_DAM | \
+ DMAC_DCCSR_SWDH_8 | DMAC_DCCSR_DWDH_32 | \
+ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_16BYTE_TX_CONF \
+ DMAC_DCCSR_SAM | \
+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_8 | \
+ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_AIC_32_16BYTE_TX_CMD \
+ DMAC_DCCSR_SAM | \
+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_32 | \
+ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_AIC_32_16BYTE_RX_CMD \
+ DMAC_DCCSR_DAM | \
+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_32 | \
+ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_AIC_16BIT_TX_CMD \
+ DMAC_DCCSR_SAM | \
+ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_16 | \
+ DMAC_DCCSR_DS_16b | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_AIC_16BIT_RX_CMD \
+ DMAC_DCCSR_DAM | \
+ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_16 | \
+ DMAC_DCCSR_DS_16b | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_AIC_16BYTE_RX_CMD \
+ DMAC_DCCSR_DAM | \
+ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_16 | \
+ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN
+
+#define DMA_AIC_16BYTE_TX_CMD \
+ DMAC_DCCSR_SAM | \
+ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_16 | \
+ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN
+
+/* DMA Device ID's follow */
+enum {
+ DMA_ID_UART0_TX = 0,
+ DMA_ID_UART0_RX,
+ DMA_ID_UART1_TX,
+ DMA_ID_UART1_RX,
+ DMA_ID_UART2_TX,
+ DMA_ID_UART2_RX,
+ DMA_ID_UART3_TX,
+ DMA_ID_UART3_RX,
+ DMA_ID_SSI_TX,
+ DMA_ID_SSI_RX,
+ DMA_ID_MSC_TX,
+ DMA_ID_MSC_RX,
+ DMA_ID_AIC_TX,
+ DMA_ID_AIC_RX,
+ DMA_ID_BLOCK, /* DREQ */
+ DMA_ID_SINGLE, /* DREQ */
+ DMA_ID_PCMCIA0_TX,
+ DMA_ID_PCMCIA0_RX,
+ DMA_ID_PCMCIA1_TX,
+ DMA_ID_PCMCIA2_RX,
+ DMA_ID_AUTO,
+ DMA_ID_RAW_SET,
+ NUM_DMA_DEV
+};
+
+/* dummy DCCSR bit, i386 style DMA macros compitable */
+#define DMA_MODE_READ 0 /* I/O to memory, no autoinit,
+ * increment, single mode */
+#define DMA_MODE_WRITE 1 /* memory to I/O, no autoinit,
+ * increment, single mode */
+#define DMA_MODE_CASCADE 2 /* pass thru DREQ->HRQ,
+ * DACK<-HLDA only */
+#define DMA_AUTOINIT 3
+#define DMA_MODE_MASK 3
+
+struct jz_dma_chan {
+ int dev_id; /* this channel is allocated if >=0,
+ * free otherwise */
+ unsigned int io;
+ const char *dev_str;
+ int irq;
+ void *irq_dev;
+ unsigned int fifo_addr;
+ unsigned int mode;
+ unsigned int source;
+};
+
+extern struct jz_dma_chan jz_dma_table[];
+
+extern int jz_request_dma(int dev_id,
+ const char *dev_str,
+ irqreturn_t (*irqhandler)(int, void *),
+ unsigned long irqflags,
+ void *irq_dev_id);
+extern void jz_free_dma(unsigned int dmanr);
+
+extern int jz_dma_read_proc(char *buf, char **start, off_t fpos,
+ int length, int *eof, void *data);
+extern void dump_jz_dma_channel(unsigned int dmanr);
+
+extern void enable_dma(unsigned int dmanr);
+extern void disable_dma(unsigned int dmanr);
+extern void set_dma_addr(unsigned int dmanr, unsigned int a);
+extern void set_dma_count(unsigned int dmanr, unsigned int count);
+extern void set_dma_mode(unsigned int dmanr, unsigned int mode);
+extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
+extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
+extern int get_dma_residue(unsigned int dmanr);
+
+extern spinlock_t dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dma_spin_lock, flags);
+ return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+ spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ */
+#define clear_dma_ff(channel)
+
+static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr)
+{
+ if (dmanr > NUM_DMA
+ || jz_dma_table[dmanr].dev_id < 0)
+ return NULL;
+ return &jz_dma_table[dmanr];
+}
+
+static __inline__ int dma_halted(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 1;
+ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0;
+}
+
+static __inline__ unsigned int get_dma_mode(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+ return chan->mode;
+}
+
+static __inline__ void clear_dma_done(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR);
+}
+
+static __inline__ void clear_dma_halt(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT);
+ REG_DMAC_DMACR &= ~(DMAC_DMACR_HTR);
+}
+static __inline__ void clear_dma_flag(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR);
+ REG_DMAC_DMACR &= ~(DMAC_DMACR_HTR | DMAC_DMACR_AER);
+}
+
+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
+{
+}
+
+static __inline__ unsigned int get_dma_done_status(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ unsigned long dccsr;
+ if (!chan)
+ return 0;
+
+ dccsr = REG_DMAC_DCCSR(chan->io);
+ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR);
+}
+
+static __inline__ int get_dma_done_irq(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return -1;
+
+ return chan->irq;
+}
+
+#endif /* __ASM_JZ4730_DMA_H__ */
diff --git a/arch/mips/include/asm/mach-jz4730/jz4730.h b/arch/mips/include/asm/mach-jz4730/jz4730.h
new file mode 100644
index 00000000000..d28a107a94e
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4730/jz4730.h
@@ -0,0 +1,42 @@
+/*
+ * linux/include/asm-mips/mach-jz4730/jz4730.h
+ *
+ * JZ4730 common definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4730_H__
+#define __ASM_JZ4730_H__
+
+#include <asm/mach-jz4730/regs.h>
+#include <asm/mach-jz4730/ops.h>
+#include <asm/mach-jz4730/dma.h>
+#include <asm/mach-jz4730/misc.h>
+
+/*------------------------------------------------------------------
+ * Platform definitions
+ */
+#define JZ_SOC_NAME "JZ4730"
+
+#ifdef CONFIG_JZ4730_PMP
+#include <asm/mach-jz4730/board-pmp.h>
+#endif
+
+/* Add other platform definition here ... */
+
+
+/*------------------------------------------------------------------
+ * Follows are related to platform definitions
+ */
+
+#include <asm/mach-jz4730/clock.h>
+#include <asm/mach-jz4730/serial.h>
+
+#endif /* __ASM_JZ4730_H__ */
diff --git a/arch/mips/include/asm/mach-jz4730/misc.h b/arch/mips/include/asm/mach-jz4730/misc.h
new file mode 100644
index 00000000000..ea01474fbd1
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4730/misc.h
@@ -0,0 +1,28 @@
+/*
+ * linux/include/asm-mips/mach-jz4730/misc.h
+ *
+ * JZ4730 miscillaneous definitions.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4730_MISC_H__
+#define __ASM_JZ4730_MISC_H__
+
+/*
+ * I2C routines
+ */
+
+extern void i2c_open(void);
+extern void i2c_close(void);
+extern void i2c_setclk(unsigned int i2cclk);
+extern int i2c_read(unsigned char, unsigned char *, unsigned char, int);
+extern int i2c_write(unsigned char, unsigned char *, unsigned char, int);
+
+#endif /* __ASM_JZ4730_MISC_H__ */
diff --git a/arch/mips/include/asm/mach-jz4730/ops.h b/arch/mips/include/asm/mach-jz4730/ops.h
new file mode 100644
index 00000000000..625419ee313
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4730/ops.h
@@ -0,0 +1,2541 @@
+/*
+ * linux/include/asm-mips/mach-jz4730/ops.h
+ *
+ * JZ4730 module operations definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4730_OPS_H__
+#define __ASM_JZ4730_OPS_H__
+
+/***************************************************************************
+ * MSC
+ ***************************************************************************/
+
+#define __msc_start_op() \
+ ( REG_MSC_STRPCL = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START )
+
+#define __msc_set_resto(to) ( REG_MSC_RESTO = to )
+#define __msc_set_rdto(to) ( REG_MSC_RDTO = to )
+#define __msc_set_cmd(cmd) ( REG_MSC_CMD = cmd )
+#define __msc_set_arg(arg) ( REG_MSC_ARG = arg )
+#define __msc_set_nob(nob) ( REG_MSC_NOB = nob )
+#define __msc_get_nob() ( REG_MSC_NOB )
+#define __msc_set_blklen(len) ( REG_MSC_BLKLEN = len )
+#define __msc_set_cmdat(cmdat) ( REG_MSC_CMDAT = cmdat )
+#define __msc_set_cmdat_ioabort() ( REG_MSC_CMDAT |= MSC_CMDAT_IO_ABORT )
+#define __msc_clear_cmdat_ioabort() ( REG_MSC_CMDAT &= ~MSC_CMDAT_IO_ABORT )
+
+#define __msc_set_cmdat_bus_width1() \
+do { \
+ REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \
+ REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_1BIT; \
+} while(0)
+
+#define __msc_set_cmdat_bus_width4() \
+do { \
+ REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \
+ REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_4BIT; \
+} while(0)
+
+#define __msc_set_cmdat_dma_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DMA_EN )
+#define __msc_set_cmdat_init() ( REG_MSC_CMDAT |= MSC_CMDAT_INIT )
+#define __msc_set_cmdat_busy() ( REG_MSC_CMDAT |= MSC_CMDAT_BUSY )
+#define __msc_set_cmdat_stream() ( REG_MSC_CMDAT |= MSC_CMDAT_STREAM_BLOCK )
+#define __msc_set_cmdat_block() ( REG_MSC_CMDAT &= ~MSC_CMDAT_STREAM_BLOCK )
+#define __msc_set_cmdat_read() ( REG_MSC_CMDAT &= ~MSC_CMDAT_WRITE_READ )
+#define __msc_set_cmdat_write() ( REG_MSC_CMDAT |= MSC_CMDAT_WRITE_READ )
+#define __msc_set_cmdat_data_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DATA_EN )
+
+/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */
+#define __msc_set_cmdat_res_format(r) \
+do { \
+ REG_MSC_CMDAT &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \
+ REG_MSC_CMDAT |= (r); \
+} while(0)
+
+#define __msc_clear_cmdat() \
+ REG_MSC_CMDAT &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \
+ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \
+ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK )
+
+#define __msc_get_imask() ( REG_MSC_IMASK )
+#define __msc_mask_all_intrs() ( REG_MSC_IMASK = 0xff )
+#define __msc_unmask_all_intrs() ( REG_MSC_IMASK = 0x00 )
+#define __msc_mask_rd() ( REG_MSC_IMASK |= MSC_IMASK_RXFIFO_RD_REQ )
+#define __msc_unmask_rd() ( REG_MSC_IMASK &= ~MSC_IMASK_RXFIFO_RD_REQ )
+#define __msc_mask_wr() ( REG_MSC_IMASK |= MSC_IMASK_TXFIFO_WR_REQ )
+#define __msc_unmask_wr() ( REG_MSC_IMASK &= ~MSC_IMASK_TXFIFO_WR_REQ )
+#define __msc_mask_endcmdres() ( REG_MSC_IMASK |= MSC_IMASK_END_CMD_RES )
+#define __msc_unmask_endcmdres() ( REG_MSC_IMASK &= ~MSC_IMASK_END_CMD_RES )
+#define __msc_mask_datatrandone() ( REG_MSC_IMASK |= MSC_IMASK_DATA_TRAN_DONE )
+#define __msc_unmask_datatrandone() ( REG_MSC_IMASK &= ~MSC_IMASK_DATA_TRAN_DONE )
+#define __msc_mask_prgdone() ( REG_MSC_IMASK |= MSC_IMASK_PRG_DONE )
+#define __msc_unmask_prgdone() ( REG_MSC_IMASK &= ~MSC_IMASK_PRG_DONE )
+
+/* n=0,1,2,3,4,5,6,7 */
+#define __msc_set_clkrt(n) \
+do { \
+ REG_MSC_CLKRT = n; \
+} while(0)
+
+#define __msc_get_ireg() ( REG_MSC_IREG )
+#define __msc_ireg_rd() ( REG_MSC_IREG & MSC_IREG_RXFIFO_RD_REQ )
+#define __msc_ireg_wr() ( REG_MSC_IREG & MSC_IREG_TXFIFO_WR_REQ )
+#define __msc_ireg_end_cmd_res() ( REG_MSC_IREG & MSC_IREG_END_CMD_RES )
+#define __msc_ireg_data_tran_done() ( REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE )
+#define __msc_ireg_prg_done() ( REG_MSC_IREG & MSC_IREG_PRG_DONE )
+#define __msc_ireg_clear_end_cmd_res() ( REG_MSC_IREG = MSC_IREG_END_CMD_RES )
+#define __msc_ireg_clear_data_tran_done() ( REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE )
+#define __msc_ireg_clear_prg_done() ( REG_MSC_IREG = MSC_IREG_PRG_DONE )
+
+#define __msc_get_stat() ( REG_MSC_STAT )
+#define __msc_stat_not_end_cmd_res() ( (REG_MSC_STAT & MSC_STAT_END_CMD_RES) == 0)
+#define __msc_stat_crc_err() \
+ ( REG_MSC_STAT & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) )
+#define __msc_stat_res_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_RES_ERR )
+#define __msc_stat_rd_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_READ_ERROR )
+#define __msc_stat_wr_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_WRITE_ERROR_YES )
+#define __msc_stat_resto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_RES )
+#define __msc_stat_rdto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_READ )
+
+#define __msc_rd_resfifo() ( REG_MSC_RES )
+#define __msc_rd_rxfifo() ( REG_MSC_RXFIFO )
+#define __msc_wr_txfifo(v) ( REG_MSC_TXFIFO = v )
+
+#define __msc_reset() \
+do { \
+ REG_MSC_STRPCL = MSC_STRPCL_RESET; \
+ while (REG_MSC_STAT & MSC_STAT_IS_RESETTING); \
+} while (0)
+
+#define __msc_start_clk() \
+do { \
+ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START; \
+} while (0)
+
+#define __msc_stop_clk() \
+do { \
+ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP; \
+} while (0)
+
+#define MMC_CLK 19169200
+#define SD_CLK 24576000
+
+/* msc_clk should little than pclk and little than clk retrieve from card */
+#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \
+do { \
+ unsigned int rate, pclk, i; \
+ pclk = dev_clk; \
+ rate = type?SD_CLK:MMC_CLK; \
+ if (msc_clk && msc_clk < pclk) \
+ pclk = msc_clk; \
+ i = 0; \
+ while (pclk < rate) \
+ { \
+ i ++; \
+ rate >>= 1; \
+ } \
+ lv = i; \
+} while(0)
+
+/* divide rate to little than or equal to 400kHz */
+#define __msc_calc_slow_clk_divisor(type, lv) \
+do { \
+ unsigned int rate, i; \
+ rate = (type?SD_CLK:MMC_CLK)/1000/400; \
+ i = 0; \
+ while (rate > 0) \
+ { \
+ rate >>= 1; \
+ i ++; \
+ } \
+ lv = i; \
+} while(0)
+
+/***************************************************************************
+ * RTC
+ ***************************************************************************/
+
+#define __rtc_start() ( REG_RTC_RCR |= RTC_RCR_START )
+#define __rtc_stop() ( REG_RTC_RCR &= ~RTC_RCR_START )
+
+#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE )
+#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE )
+#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE )
+#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE )
+
+#define __rtc_enable_1hz_irq() ( REG_RTC_RCR |= RTC_RCR_HZIE )
+#define __rtc_disable_1hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_HZIE )
+
+#define __rtc_is_alarm_flag() ( REG_RTC_RCR & RTC_RCR_AF )
+#define __rtc_is_1hz_flag() ( REG_RTC_RCR & RTC_RCR_HZ )
+#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF )
+#define __rtc_clear_1hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_HZ )
+
+#define __rtc_set_second(s) ( REG_RTC_RSR = (s) )
+#define __rtc_get_second() REG_RTC_RSR
+#define __rtc_set_alarm(s) ( REG_RTC_RSAR = (s) )
+#define __rtc_get_alarm() REG_RTC_RSAR
+
+#define __rtc_adjust_1hz(f32k) \
+ ( REG_RTC_RGR = (REG_RTC_RGR & ~(RTC_REG_DIV_MASK | RTC_RGR_ADJ_MASK)) | f32k | 0 )
+#define __rtc_lock_1hz() ( REG_RTC_RGR |= RTC_RGR_LOCK )
+
+
+/***************************************************************************
+ * FIR
+ ***************************************************************************/
+
+/* enable/disable fir unit */
+#define __fir_enable() ( REG_FIR_CR1 |= FIR_CR1_FIRUE )
+#define __fir_disable() ( REG_FIR_CR1 &= ~FIR_CR1_FIRUE )
+
+/* enable/disable address comparison */
+#define __fir_enable_ac() ( REG_FIR_CR1 |= FIR_CR1_ACE )
+#define __fir_disable_ac() ( REG_FIR_CR1 &= ~FIR_CR1_ACE )
+
+/* select frame end mode as underrun or normal */
+#define __fir_set_eous() ( REG_FIR_CR1 |= FIR_CR1_EOUS )
+#define __fir_clear_eous() ( REG_FIR_CR1 &= ~FIR_CR1_EOUS )
+
+/* enable/disable transmitter idle interrupt */
+#define __fir_enable_tii() ( REG_FIR_CR1 |= FIR_CR1_TIIE )
+#define __fir_disable_tii() ( REG_FIR_CR1 &= ~FIR_CR1_TIIE )
+
+/* enable/disable transmit FIFO service request interrupt */
+#define __fir_enable_tfi() ( REG_FIR_CR1 |= FIR_CR1_TFIE )
+#define __fir_disable_tfi() ( REG_FIR_CR1 &= ~FIR_CR1_TFIE )
+
+/* enable/disable receive FIFO service request interrupt */
+#define __fir_enable_rfi() ( REG_FIR_CR1 |= FIR_CR1_RFIE )
+#define __fir_disable_rfi() ( REG_FIR_CR1 &= ~FIR_CR1_RFIE )
+
+/* enable/disable tx function */
+#define __fir_tx_enable() ( REG_FIR_CR1 |= FIR_CR1_TXE )
+#define __fir_tx_disable() ( REG_FIR_CR1 &= ~FIR_CR1_TXE )
+
+/* enable/disable rx function */
+#define __fir_rx_enable() ( REG_FIR_CR1 |= FIR_CR1_RXE )
+#define __fir_rx_disable() ( REG_FIR_CR1 &= ~FIR_CR1_RXE )
+
+
+/* enable/disable serial infrared interaction pulse (SIP) */
+#define __fir_enable_sip() ( REG_FIR_CR2 |= FIR_CR2_SIPE )
+#define __fir_disable_sip() ( REG_FIR_CR2 &= ~FIR_CR2_SIPE )
+
+/* un-inverted CRC value is sent out */
+#define __fir_enable_bcrc() ( REG_FIR_CR2 |= FIR_CR2_BCRC )
+
+/* inverted CRC value is sent out */
+#define __fir_disable_bcrc() ( REG_FIR_CR2 &= ~FIR_CR2_BCRC )
+
+/* enable/disable Transmit Frame Length Register */
+#define __fir_enable_tflr() ( REG_FIR_CR2 |= FIR_CR2_TFLRS )
+#define __fir_disable_tflr() ( REG_FIR_CR2 &= ~FIR_CR2_TFLRS )
+
+/* Preamble is transmitted in idle state */
+#define __fir_set_iss() ( REG_FIR_CR2 |= FIR_CR2_ISS )
+
+/* Abort symbol is transmitted in idle state */
+#define __fir_clear_iss() ( REG_FIR_CR2 &= ~FIR_CR2_ISS )
+
+/* enable/disable loopback mode */
+#define __fir_enable_loopback() ( REG_FIR_CR2 |= FIR_CR2_LMS )
+#define __fir_disable_loopback() ( REG_FIR_CR2 &= ~FIR_CR2_LMS )
+
+/* select transmit pin polarity */
+#define __fir_tpp_negative() ( REG_FIR_CR2 |= FIR_CR2_TPPS )
+#define __fir_tpp_positive() ( REG_FIR_CR2 &= ~FIR_CR2_TPPS )
+
+/* select receive pin polarity */
+#define __fir_rpp_negative() ( REG_FIR_CR2 |= FIR_CR2_RPPS )
+#define __fir_rpp_positive() ( REG_FIR_CR2 &= ~FIR_CR2_RPPS )
+
+/* n=16,32,64,128 */
+#define __fir_set_txfifo_trigger(n) \
+do { \
+ REG_FIR_CR2 &= ~FIR_CR2_TTRG_MASK; \
+ REG_FIR_CR2 |= FIR_CR2_TTRG_##n; \
+} while (0)
+
+/* n=16,32,64,128 */
+#define __fir_set_rxfifo_trigger(n) \
+do { \
+ REG_FIR_CR2 &= ~FIR_CR2_RTRG_MASK; \
+ REG_FIR_CR2 |= FIR_CR2_RTRG_##n; \
+} while (0)
+
+
+/* FIR status checking */
+
+#define __fir_test_rfw() ( REG_FIR_SR & FIR_SR_RFW )
+#define __fir_test_rfa() ( REG_FIR_SR & FIR_SR_RFA )
+#define __fir_test_tfrtl() ( REG_FIR_SR & FIR_SR_TFRTL )
+#define __fir_test_rfrtl() ( REG_FIR_SR & FIR_SR_RFRTL )
+#define __fir_test_urun() ( REG_FIR_SR & FIR_SR_URUN )
+#define __fir_test_rfte() ( REG_FIR_SR & FIR_SR_RFTE )
+#define __fir_test_orun() ( REG_FIR_SR & FIR_SR_ORUN )
+#define __fir_test_crce() ( REG_FIR_SR & FIR_SR_CRCE )
+#define __fir_test_fend() ( REG_FIR_SR & FIR_SR_FEND )
+#define __fir_test_tff() ( REG_FIR_SR & FIR_SR_TFF )
+#define __fir_test_rfe() ( REG_FIR_SR & FIR_SR_RFE )
+#define __fir_test_tidle() ( REG_FIR_SR & FIR_SR_TIDLE )
+#define __fir_test_rb() ( REG_FIR_SR & FIR_SR_RB )
+
+#define __fir_clear_status() \
+do { \
+ REG_FIR_SR |= FIR_SR_RFW | FIR_SR_RFA | FIR_SR_URUN; \
+} while (0)
+
+#define __fir_clear_rfw() ( REG_FIR_SR |= FIR_SR_RFW )
+#define __fir_clear_rfa() ( REG_FIR_SR |= FIR_SR_RFA )
+#define __fir_clear_urun() ( REG_FIR_SR |= FIR_SR_URUN )
+
+#define __fir_set_tflr(len) \
+do { \
+ REG_FIR_TFLR = len; \
+} while (0)
+
+#define __fir_set_addr(a) ( REG_FIR_AR = (a) )
+
+#define __fir_write_data(data) ( REG_FIR_TDR = data )
+#define __fir_read_data(data) ( data = REG_FIR_RDR )
+
+/***************************************************************************
+ * SCC
+ ***************************************************************************/
+
+#define __scc_enable(base) ( REG_SCC_CR(base) |= SCC_CR_SCCE )
+#define __scc_disable(base) ( REG_SCC_CR(base) &= ~SCC_CR_SCCE )
+
+#define __scc_set_tx_mode(base) ( REG_SCC_CR(base) |= SCC_CR_TRS )
+#define __scc_set_rx_mode(base) ( REG_SCC_CR(base) &= ~SCC_CR_TRS )
+
+#define __scc_enable_t2r(base) ( REG_SCC_CR(base) |= SCC_CR_T2R )
+#define __scc_disable_t2r(base) ( REG_SCC_CR(base) &= ~SCC_CR_T2R )
+
+#define __scc_clk_as_devclk(base) \
+do { \
+ REG_SCC_CR(base) &= ~SCC_CR_FDIV_MASK; \
+ REG_SCC_CR(base) |= SCC_CR_FDIV_1; \
+} while (0)
+
+#define __scc_clk_as_half_devclk(base) \
+do { \
+ REG_SCC_CR(base) &= ~SCC_CR_FDIV_MASK; \
+ REG_SCC_CR(base) |= SCC_CR_FDIV_2; \
+} while (0)
+
+/* n=1,4,8,14 */
+#define __scc_set_fifo_trigger(base, n) \
+do { \
+ REG_SCC_CR(base) &= ~SCC_CR_TRIG_MASK; \
+ REG_SCC_CR(base) |= SCC_CR_TRIG_##n; \
+} while (0)
+
+#define __scc_set_protocol(base, p) \
+do { \
+ if (p) \
+ REG_SCC_CR(base) |= SCC_CR_TP; \
+ else \
+ REG_SCC_CR(base) &= ~SCC_CR_TP; \
+} while (0)
+
+#define __scc_flush_fifo(base) ( REG_SCC_CR(base) |= SCC_CR_FLUSH )
+
+#define __scc_set_invert_mode(base) ( REG_SCC_CR(base) |= SCC_CR_CONV )
+#define __scc_set_direct_mode(base) ( REG_SCC_CR(base) &= ~SCC_CR_CONV )
+
+#define SCC_ERR_INTRS \
+ ( SCC_CR_ECIE | SCC_CR_EPIE | SCC_CR_RETIE | SCC_CR_EOIE )
+#define SCC_ALL_INTRS \
+ ( SCC_CR_TXIE | SCC_CR_RXIE | SCC_CR_TENDIE | SCC_CR_RTOIE | \
+ SCC_CR_ECIE | SCC_CR_EPIE | SCC_CR_RETIE | SCC_CR_EOIE )
+
+#define __scc_enable_err_intrs(base) ( REG_SCC_CR(base) |= SCC_ERR_INTRS )
+#define __scc_disable_err_intrs(base) ( REG_SCC_CR(base) &= ~SCC_ERR_INTRS )
+
+#define SCC_ALL_ERRORS \
+ ( SCC_SR_ORER | SCC_SR_RTO | SCC_SR_PER | SCC_SR_RETR_3 | SCC_SR_ECNTO)
+
+#define __scc_clear_errors(base) ( REG_SCC_SR(base) &= ~SCC_ALL_ERRORS )
+
+#define __scc_enable_all_intrs(base) ( REG_SCC_CR(base) |= SCC_ALL_INTRS )
+#define __scc_disable_all_intrs(base) ( REG_SCC_CR(base) &= ~SCC_ALL_INTRS )
+
+#define __scc_enable_tx_intr(base) ( REG_SCC_CR(base) |= SCC_CR_TXIE | SCC_CR_TENDIE )
+#define __scc_disable_tx_intr(base) ( REG_SCC_CR(base) &= ~(SCC_CR_TXIE | SCC_CR_TENDIE) )
+
+#define __scc_enable_rx_intr(base) ( REG_SCC_CR(base) |= SCC_CR_RXIE)
+#define __scc_disable_rx_intr(base) ( REG_SCC_CR(base) &= ~SCC_CR_RXIE)
+
+#define __scc_set_tsend(base) ( REG_SCC_CR(base) |= SCC_CR_TSEND )
+#define __scc_clear_tsend(base) ( REG_SCC_CR(base) &= ~SCC_CR_TSEND )
+
+#define __scc_set_clockstop(base) ( REG_SCC_CR(base) |= SCC_CR_CLKSTP )
+#define __scc_clear_clockstop(base) ( REG_SCC_CR(base) &= ~SCC_CR_CLKSTP )
+
+#define __scc_clockstop_low(base) \
+do { \
+ REG_SCC_CR(base) &= ~SCC_CR_PX_MASK; \
+ REG_SCC_CR(base) |= SCC_CR_PX_STOP_LOW; \
+} while (0)
+
+#define __scc_clockstop_high(base) \
+do { \
+ REG_SCC_CR(base) &= ~SCC_CR_PX_MASK; \
+ REG_SCC_CR(base) |= SCC_CR_PX_STOP_HIGH; \
+} while (0)
+
+
+/* SCC status checking */
+#define __scc_check_transfer_status(base) ( REG_SCC_SR(base) & SCC_SR_TRANS )
+#define __scc_check_rx_overrun_error(base) ( REG_SCC_SR(base) & SCC_SR_ORER )
+#define __scc_check_rx_timeout(base) ( REG_SCC_SR(base) & SCC_SR_RTO )
+#define __scc_check_parity_error(base) ( REG_SCC_SR(base) & SCC_SR_PER )
+#define __scc_check_txfifo_trigger(base) ( REG_SCC_SR(base) & SCC_SR_TFTG )
+#define __scc_check_rxfifo_trigger(base) ( REG_SCC_SR(base) & SCC_SR_RFTG )
+#define __scc_check_tx_end(base) ( REG_SCC_SR(base) & SCC_SR_TEND )
+#define __scc_check_retx_3(base) ( REG_SCC_SR(base) & SCC_SR_RETR_3 )
+#define __scc_check_ecnt_overflow(base) ( REG_SCC_SR(base) & SCC_SR_ECNTO )
+
+
+/***************************************************************************
+ * WDT
+ ***************************************************************************/
+
+#define __wdt_set_count(count) ( REG_WDT_WTCNT = (count) )
+#define __wdt_start() ( REG_WDT_WTCSR |= WDT_WTCSR_START )
+#define __wdt_stop() ( REG_WDT_WTCSR &= ~WDT_WTCSR_START )
+
+
+/***************************************************************************
+ * OST
+ ***************************************************************************/
+
+#define __ost_enable_all() ( REG_OST_TER |= 0x07 )
+#define __ost_disable_all() ( REG_OST_TER &= ~0x07 )
+#define __ost_enable_channel(n) ( REG_OST_TER |= (1 << (n)) )
+#define __ost_disable_channel(n) ( REG_OST_TER &= ~(1 << (n)) )
+#define __ost_set_reload(n, val) ( REG_OST_TRDR(n) = (val) )
+#define __ost_set_count(n, val) ( REG_OST_TCNT(n) = (val) )
+#define __ost_get_count(n) ( REG_OST_TCNT(n) )
+#define __ost_set_clock(n, cs) \
+do { \
+ REG_OST_TCSR(n) &= ~OST_TCSR_CKS_MASK; \
+ REG_OST_TCSR(n) |= cs; \
+} while (0)
+#define __ost_set_mode(n, val) ( REG_OST_TCSR(n) = (val) )
+#define __ost_enable_interrupt(n) ( REG_OST_TCSR(n) |= OST_TCSR_UIE )
+#define __ost_disable_interrupt(n) ( REG_OST_TCSR(n) &= ~OST_TCSR_UIE )
+#define __ost_uf_detected(n) ( REG_OST_TCSR(n) & OST_TCSR_UF )
+#define __ost_clear_uf(n) ( REG_OST_TCSR(n) &= ~OST_TCSR_UF )
+#define __ost_is_busy(n) ( REG_OST_TCSR(n) & OST_TCSR_BUSY )
+#define __ost_clear_busy(n) ( REG_OST_TCSR(n) &= ~OST_TCSR_BUSY )
+
+
+/***************************************************************************
+ * UART
+ ***************************************************************************/
+
+#define __uart_enable(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE )
+#define __uart_disable(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE )
+
+#define __uart_enable_transmit_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE )
+#define __uart_disable_transmit_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE )
+
+#define __uart_enable_receive_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE )
+#define __uart_disable_receive_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) )
+
+#define __uart_enable_loopback(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP )
+#define __uart_disable_loopback(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP )
+
+#define __uart_set_8n1(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 )
+
+#define __uart_set_baud(n, devclk, baud) \
+ do { \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \
+ } while (0)
+
+#define __uart_parity_error(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 )
+
+#define __uart_clear_errors(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) )
+
+#define __uart_transmit_fifo_empty(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 )
+
+#define __uart_transmit_end(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 )
+
+#define __uart_transmit_char(n, ch) \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch)
+
+#define __uart_receive_fifo_full(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 )
+
+#define __uart_receive_ready(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 )
+
+#define __uart_receive_char(n) \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR)
+
+#define __uart_disable_irda() \
+ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) )
+#define __uart_enable_irda() \
+ /* Tx high pulse as 0, Rx low pulse as 0 */ \
+ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS )
+
+
+/***************************************************************************
+ * INTC
+ ***************************************************************************/
+#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) )
+#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) )
+#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) )
+
+/***************************************************************************
+ * CIM
+ ***************************************************************************/
+
+#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA )
+#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA )
+
+#define __cim_input_data_inverse() ( REG_CIM_CFG |= CIM_CFG_INV_DAT )
+#define __cim_input_data_normal() ( REG_CIM_CFG &= ~CIM_CFG_INV_DAT )
+
+#define __cim_vsync_active_low() ( REG_CIM_CFG |= CIM_CFG_VSP )
+#define __cim_vsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_VSP )
+
+#define __cim_hsync_active_low() ( REG_CIM_CFG |= CIM_CFG_HSP )
+#define __cim_hsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_HSP )
+
+#define __cim_sample_data_at_pclk_falling_edge() \
+ ( REG_CIM_CFG |= CIM_CFG_PCP )
+#define __cim_sample_data_at_pclk_rising_edge() \
+ ( REG_CIM_CFG &= ~CIM_CFG_PCP )
+
+#define __cim_enable_dummy_zero() ( REG_CIM_CFG |= CIM_CFG_DUMMY_ZERO )
+#define __cim_disable_dummy_zero() ( REG_CIM_CFG &= ~CIM_CFG_DUMMY_ZERO )
+
+#define __cim_select_external_vsync() ( REG_CIM_CFG |= CIM_CFG_EXT_VSYNC )
+#define __cim_select_internal_vsync() ( REG_CIM_CFG &= ~CIM_CFG_EXT_VSYNC )
+
+/* n=0-7 */
+#define __cim_set_data_packing_mode(n) \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_PACK_MASK; \
+ REG_CIM_CFG |= (CIM_CFG_PACK_##n); \
+} while (0)
+
+#define __cim_enable_ccir656_progressive_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_CPM; \
+} while (0)
+
+#define __cim_enable_ccir656_interlace_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_CIM; \
+} while (0)
+
+#define __cim_enable_gated_clock_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_GCM; \
+} while (0)
+
+#define __cim_enable_nongated_clock_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_NGCM; \
+} while (0)
+
+/* sclk:system bus clock
+ * mclk: CIM master clock
+ */
+#define __cim_set_master_clk(sclk, mclk) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_MCLKDIV_MASK; \
+ REG_CIM_CTRL |= (((sclk)/(mclk) - 1) << CIM_CTRL_MCLKDIV_BIT); \
+} while (0)
+
+#define __cim_enable_sof_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_SOFM )
+#define __cim_disable_sof_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_SOFM )
+
+#define __cim_enable_eof_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_EOFM )
+#define __cim_disable_eof_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EOFM )
+
+#define __cim_enable_stop_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_STOPM )
+#define __cim_disable_stop_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_STOPM )
+
+#define __cim_enable_trig_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_TRIGM )
+#define __cim_disable_trig_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIGM )
+
+#define __cim_enable_rxfifo_overflow_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_OFM )
+#define __cim_disable_rxfifo_overflow_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_OFM )
+
+/* n=1-16 */
+#define __cim_set_frame_rate(n) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_FRC_MASK; \
+ REG_CIM_CTRL |= CIM_CTRL_FRC_##n; \
+} while (0)
+
+#define __cim_enable_dma() ( REG_CIM_CTRL |= CIM_CTRL_DMA_EN )
+#define __cim_disable_dma() ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EN )
+
+#define __cim_reset_rxfifo() ( REG_CIM_CTRL |= CIM_CTRL_RXF_RST )
+#define __cim_unreset_rxfifo() ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_RST )
+
+/* n=4,8,12,16,20,24,28,32 */
+#define __cim_set_rxfifo_trigger(n) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \
+ REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \
+} while (0)
+
+#define __cim_clear_state() ( REG_CIM_STATE = 0 )
+
+#define __cim_disable_done() ( REG_CIM_STATE & CIM_STATE_VDD )
+#define __cim_rxfifo_empty() ( REG_CIM_STATE & CIM_STATE_RXF_EMPTY )
+#define __cim_rxfifo_reach_trigger() ( REG_CIM_STATE & CIM_STATE_RXF_TRIG )
+#define __cim_rxfifo_overflow() ( REG_CIM_STATE & CIM_STATE_RXF_OF )
+#define __cim_clear_rxfifo_overflow() ( REG_CIM_STATE &= ~CIM_STATE_RXF_OF )
+#define __cim_dma_stop() ( REG_CIM_STATE & CIM_STATE_DMA_STOP )
+#define __cim_dma_eof() ( REG_CIM_STATE & CIM_STATE_DMA_EOF )
+#define __cim_dma_sof() ( REG_CIM_STATE & CIM_STATE_DMA_SOF )
+
+#define __cim_get_iid() ( REG_CIM_IID )
+#define __cim_get_image_data() ( REG_CIM_RXFIFO )
+#define __cim_get_dam_cmd() ( REG_CIM_CMD )
+
+#define __cim_set_da(a) ( REG_CIM_DA = (a) )
+
+/***************************************************************************
+ * PWM
+ ***************************************************************************/
+
+/* n is the pwm channel (0,1,..) */
+#define __pwm_enable_module(n) ( REG_PWM_CTR(n) |= PWM_CTR_EN )
+#define __pwm_disable_module(n) ( REG_PWM_CTR(n) &= ~PWM_CTR_EN )
+#define __pwm_graceful_shutdown_mode(n) ( REG_PWM_CTR(n) &= ~PWM_CTR_SD )
+#define __pwm_abrupt_shutdown_mode(n) ( REG_PWM_CTR(n) |= PWM_CTR_SD )
+#define __pwm_set_full_duty(n) ( REG_PWM_DUT(n) |= PWM_DUT_FDUTY )
+
+#define __pwm_set_prescale(n, p) \
+ ( REG_PWM_CTR(n) = ((REG_PWM_CTR(n) & ~PWM_CTR_PRESCALE_MASK) | (p) ) )
+#define __pwm_set_period(n, p) \
+ ( REG_PWM_PER(n) = ( (REG_PWM_PER(n) & ~PWM_PER_PERIOD_MASK) | (p) ) )
+#define __pwm_set_duty(n, d) \
+ ( REG_PWM_DUT(n) = ( (REG_PWM_DUT(n) & ~(PWM_DUT_FDUTY | PWM_DUT_DUTY_MASK)) | (d) ) )
+
+/***************************************************************************
+ * EMC
+ ***************************************************************************/
+
+#define __emc_enable_split() ( REG_EMC_BCR = EMC_BCR_BRE )
+#define __emc_disable_split() ( REG_EMC_BCR = 0 )
+
+#define __emc_smem_bus_width(n) /* 8, 16 or 32*/ \
+ ( REG_EMC_SMCR = (REG_EMC_SMCR & EMC_SMCR_BW_MASK) | \
+ EMC_SMCR_BW_##n##BIT )
+#define __emc_smem_byte_control() \
+ ( REG_EMC_SMCR = (REG_EMC_SMCR | EMC_SMCR_BCM )
+#define __emc_normal_smem() \
+ ( REG_EMC_SMCR = (REG_EMC_SMCR & ~EMC_SMCR_SMT )
+#define __emc_burst_smem() \
+ ( REG_EMC_SMCR = (REG_EMC_SMCR | EMC_SMCR_SMT )
+#define __emc_smem_burstlen(n) /* 4, 8, 16 or 32 */ \
+ ( REG_EMC_SMCR = (REG_EMC_SMCR & EMC_SMCR_BL_MASK) | (EMC_SMCR_BL_##n )
+
+/***************************************************************************
+ * GPIO
+ ***************************************************************************/
+
+/* p is the port number (0,1,2,3)
+ * o is the pin offset (0-31) inside the port
+ * n is the absolute number of a pin (0-124), regardless of the port
+ * m is the interrupt manner (low/high/falling/rising)
+ */
+
+#define __gpio_port_data(p) ( REG_GPIO_GPDR(p) )
+
+#define __gpio_port_as_output(p, o) \
+do { \
+ unsigned int tmp; \
+ REG_GPIO_GPIER(p) &= ~(1 << (o)); \
+ REG_GPIO_GPDIR(p) |= (1 << (o)); \
+ if (o < 16) { \
+ tmp = REG_GPIO_GPALR(p); \
+ tmp &= ~(3 << ((o) << 1)); \
+ REG_GPIO_GPALR(p) = tmp; \
+ } else { \
+ tmp = REG_GPIO_GPAUR(p); \
+ tmp &= ~(3 << (((o) - 16)<< 1)); \
+ REG_GPIO_GPAUR(p) = tmp; \
+ } \
+} while (0)
+
+#define __gpio_port_as_input(p, o) \
+do { \
+ unsigned int tmp; \
+ REG_GPIO_GPIER(p) &= ~(1 << (o)); \
+ REG_GPIO_GPDIR(p) &= ~(1 << (o)); \
+ if (o < 16) { \
+ tmp = REG_GPIO_GPALR(p); \
+ tmp &= ~(3 << ((o) << 1)); \
+ REG_GPIO_GPALR(p) = tmp; \
+ } else { \
+ tmp = REG_GPIO_GPAUR(p); \
+ tmp &= ~(3 << (((o) - 16)<< 1)); \
+ REG_GPIO_GPAUR(p) = tmp; \
+ } \
+} while (0)
+
+#define __gpio_as_output(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_as_output(p, o); \
+} while (0)
+
+#define __gpio_as_input(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_as_input(p, o); \
+} while (0)
+
+#define __gpio_set_pin(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_data(p) |= (1 << o); \
+} while (0)
+
+#define __gpio_clear_pin(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_data(p) &= ~(1 << o); \
+} while (0)
+
+static __inline__ unsigned int __gpio_get_pin(unsigned int n)
+{
+ unsigned int p, o;
+ p = (n) / 32;
+ o = (n) % 32;
+ if (__gpio_port_data(p) & (1 << o))
+ return 1;
+ else
+ return 0;
+}
+
+#define __gpio_set_irq_detect_manner(p, o, m) \
+do { \
+ unsigned int tmp; \
+ if (o < 16) { \
+ tmp = REG_GPIO_GPIDLR(p); \
+ tmp &= ~(3 << ((o) << 1)); \
+ tmp |= ((m) << ((o) << 1)); \
+ REG_GPIO_GPIDLR(p) = tmp; \
+ } else { \
+ tmp = REG_GPIO_GPIDUR(p); \
+ tmp &= ~(3 << (((o)-16) << 1)); \
+ tmp |= ((m) << (((o)-16) << 1)); \
+ REG_GPIO_GPIDUR(p) = tmp; \
+ } \
+} while (0)
+
+#define __gpio_port_as_irq(p, o, m) \
+do { \
+ __gpio_port_as_input(p, o); \
+ __gpio_set_irq_detect_manner(p, o, m); \
+} while (0)
+
+#define __gpio_as_irq(n, m) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_as_irq(p, o, m); \
+} while (0)
+
+
+#define __gpio_as_irq_high_level(n) __gpio_as_irq(n, GPIO_IRQ_HILEVEL)
+#define __gpio_as_irq_low_level(n) __gpio_as_irq(n, GPIO_IRQ_LOLEVEL)
+#define __gpio_as_irq_fall_edge(n) __gpio_as_irq(n, GPIO_IRQ_FALLEDG)
+#define __gpio_as_irq_rise_edge(n) __gpio_as_irq(n, GPIO_IRQ_RAISEDG)
+
+
+#define __gpio_mask_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_GPIER(p) &= ~(1 << o); \
+} while (0)
+
+#define __gpio_unmask_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_GPIER(p) |= (1 << o); \
+} while (0)
+
+#define __gpio_ack_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_GPFR(p) |= (1 << o); \
+} while (0)
+
+
+static __inline__ unsigned int __gpio_get_irq(void)
+{
+ unsigned int tmp, i;
+
+ tmp = REG_GPIO_GPFR(3);
+ for (i=0; i<32; i++)
+ if (tmp & (1 << i))
+ return 0x60 + i;
+ tmp = REG_GPIO_GPFR(2);
+ for (i=0; i<32; i++)
+ if (tmp & (1 << i))
+ return 0x40 + i;
+ tmp = REG_GPIO_GPFR(1);
+ for (i=0; i<32; i++)
+ if (tmp & (1 << i))
+ return 0x20 + i;
+ tmp = REG_GPIO_GPFR(0);
+ for (i=0; i<32; i++)
+ if (tmp & (1 << i))
+ return i;
+ return 0;
+}
+
+#define __gpio_group_irq(n) \
+({ \
+ register int tmp, i; \
+ tmp = REG_GPIO_GPFR((n)); \
+ for (i=31;i>=0;i--) \
+ if (tmp & (1 << i)) \
+ break; \
+ i; \
+})
+
+#define __gpio_enable_pull(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_GPPUR(p) |= (1 << o); \
+} while (0)
+
+#define __gpio_disable_pull(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_GPPUR(p) &= ~(1 << o); \
+} while (0)
+
+
+/* Init the alternate function pins */
+
+
+#define __gpio_as_ssi() \
+do { \
+ REG_GPIO_GPALR(2) &= 0xFC00FFFF; \
+ REG_GPIO_GPALR(2) |= 0x01550000; \
+} while (0)
+
+#define __gpio_as_uart3() \
+do { \
+ REG_GPIO_GPAUR(0) &= 0xFFFF0000; \
+ REG_GPIO_GPAUR(0) |= 0x00005555; \
+} while (0)
+
+#define __gpio_as_uart2() \
+do { \
+ REG_GPIO_GPALR(3) &= 0x3FFFFFFF; \
+ REG_GPIO_GPALR(3) |= 0x40000000; \
+ REG_GPIO_GPAUR(3) &= 0xF3FFFFFF; \
+ REG_GPIO_GPAUR(3) |= 0x04000000; \
+} while (0)
+
+#define __gpio_as_uart1() \
+do { \
+ REG_GPIO_GPAUR(0) &= 0xFFF0FFFF; \
+ REG_GPIO_GPAUR(0) |= 0x00050000; \
+} while (0)
+
+#define __gpio_as_uart0() \
+do { \
+ REG_GPIO_GPAUR(3) &= 0x0FFFFFFF; \
+ REG_GPIO_GPAUR(3) |= 0x50000000; \
+} while (0)
+
+
+#define __gpio_as_scc0() \
+do { \
+ REG_GPIO_GPALR(2) &= 0xFFFFFFCC; \
+ REG_GPIO_GPALR(2) |= 0x00000011; \
+} while (0)
+
+#define __gpio_as_scc1() \
+do { \
+ REG_GPIO_GPALR(2) &= 0xFFFFFF33; \
+ REG_GPIO_GPALR(2) |= 0x00000044; \
+} while (0)
+
+#define __gpio_as_scc() \
+do { \
+ __gpio_as_scc0(); \
+ __gpio_as_scc1(); \
+} while (0)
+
+#define __gpio_as_dma() \
+do { \
+ REG_GPIO_GPALR(0) &= 0x00FFFFFF; \
+ REG_GPIO_GPALR(0) |= 0x55000000; \
+ REG_GPIO_GPAUR(0) &= 0xFF0FFFFF; \
+ REG_GPIO_GPAUR(0) |= 0x00500000; \
+} while (0)
+
+#define __gpio_as_msc() \
+do { \
+ REG_GPIO_GPALR(1) &= 0xFFFF000F; \
+ REG_GPIO_GPALR(1) |= 0x00005550; \
+} while (0)
+
+#define __gpio_as_pcmcia() \
+do { \
+ REG_GPIO_GPAUR(2) &= 0xF000FFFF; \
+ REG_GPIO_GPAUR(2) |= 0x05550000; \
+} while (0)
+
+#define __gpio_as_emc(csmask) \
+do { \
+ REG_GPIO_GPALR(2) &= 0x3FFFFFFF; \
+ REG_GPIO_GPALR(2) |= 0x40000000; \
+ REG_GPIO_GPAUR(2) &= 0xFFFF0000; \
+ REG_GPIO_GPAUR(2) |= 0x00005555; \
+} while (0)
+
+#define __gpio_as_lcd_slave() \
+do { \
+ REG_GPIO_GPALR(1) &= 0x0000FFFF; \
+ REG_GPIO_GPALR(1) |= 0x55550000; \
+ REG_GPIO_GPAUR(1) &= 0x00000000; \
+ REG_GPIO_GPAUR(1) |= 0x55555555; \
+} while (0)
+
+#define __gpio_as_lcd_master() \
+do { \
+ REG_GPIO_GPALR(1) &= 0x0000FFFF; \
+ REG_GPIO_GPALR(1) |= 0x55550000; \
+ REG_GPIO_GPAUR(1) &= 0x00000000; \
+ REG_GPIO_GPAUR(1) |= 0x556A5555; \
+} while (0)
+
+#define __gpio_as_usb() \
+do { \
+ REG_GPIO_GPAUR(0) &= 0x00FFFFFF; \
+ REG_GPIO_GPAUR(0) |= 0x55000000; \
+} while (0)
+
+#define __gpio_as_ac97() \
+do { \
+ REG_GPIO_GPALR(2) &= 0xC3FF03FF; \
+ REG_GPIO_GPALR(2) |= 0x24005400; \
+} while (0)
+
+#define __gpio_as_i2s_slave() \
+do { \
+ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; \
+ REG_GPIO_GPALR(2) |= 0x14005100; \
+} while (0)
+
+#define __gpio_as_i2s_master() \
+do { \
+ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; \
+ REG_GPIO_GPALR(2) |= 0x28005100; \
+} while (0)
+
+#define __gpio_as_eth() \
+do { \
+ REG_GPIO_GPAUR(3) &= 0xFC000000; \
+ REG_GPIO_GPAUR(3) |= 0x01555555; \
+} while (0)
+
+#define __gpio_as_pwm() \
+do { \
+ REG_GPIO_GPAUR(2) &= 0x0FFFFFFF; \
+ REG_GPIO_GPAUR(2) |= 0x50000000; \
+} while (0)
+
+#define __gpio_as_ps2() \
+do { \
+ REG_GPIO_GPALR(1) &= 0xFFFFFFF0; \
+ REG_GPIO_GPALR(1) |= 0x00000005; \
+} while (0)
+
+#define __gpio_as_uprt() \
+do { \
+ REG_GPIO_GPALR(1) &= 0x0000000F; \
+ REG_GPIO_GPALR(1) |= 0x55555550; \
+ REG_GPIO_GPALR(3) &= 0xC0000000; \
+ REG_GPIO_GPALR(3) |= 0x15555555; \
+} while (0)
+
+#define __gpio_as_cim() \
+do { \
+ REG_GPIO_GPALR(0) &= 0xFF000000; \
+ REG_GPIO_GPALR(0) |= 0x00555555; \
+} while (0)
+
+/***************************************************************************
+ * HARB
+ ***************************************************************************/
+
+#define __harb_usb0_udc() \
+do { \
+ REG_HARB_HAPOR &= ~HARB_HAPOR_UCHSEL; \
+} while (0)
+
+#define __harb_usb0_uhc() \
+do { \
+ REG_HARB_HAPOR |= HARB_HAPOR_UCHSEL; \
+} while (0)
+
+#define __harb_set_priority(n) \
+do { \
+ REG_HARB_HAPOR = ((REG_HARB_HAPOR & ~HARB_HAPOR_PRIO_MASK) | n); \
+} while (0)
+
+/***************************************************************************
+ * I2C
+ ***************************************************************************/
+
+#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE )
+#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE )
+
+#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA )
+#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO )
+#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC )
+#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC )
+
+#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF )
+#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF )
+#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF )
+
+#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) )
+#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY )
+#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND )
+
+#define __i2c_set_clk(dev_clk, i2c_clk) \
+ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 )
+
+#define __i2c_read() ( REG_I2C_DR )
+#define __i2c_write(val) ( REG_I2C_DR = (val) )
+
+/***************************************************************************
+ * UDC
+ ***************************************************************************/
+
+#define __udc_set_16bit_phy() ( REG_UDC_DevCFGR |= UDC_DevCFGR_PI )
+#define __udc_set_8bit_phy() ( REG_UDC_DevCFGR &= ~UDC_DevCFGR_PI )
+
+#define __udc_enable_sync_frame() ( REG_UDC_DevCFGR |= UDC_DevCFGR_SS )
+#define __udc_disable_sync_frame() ( REG_UDC_DevCFGR &= ~UDC_DevCFGR_SS )
+
+#define __udc_self_powered() ( REG_UDC_DevCFGR |= UDC_DevCFGR_SP )
+#define __udc_bus_powered() ( REG_UDC_DevCFGR &= ~UDC_DevCFGR_SP )
+
+#define __udc_enable_remote_wakeup() ( REG_UDC_DevCFGR |= UDC_DevCFGR_RW )
+#define __udc_disable_remote_wakeup() ( REG_UDC_DevCFGR &= ~UDC_DevCFGR_RW )
+
+#define __udc_set_speed_high() \
+do { \
+ REG_UDC_DevCFGR &= ~UDC_DevCFGR_SPD_MASK; \
+ REG_UDC_DevCFGR |= UDC_DevCFGR_SPD_HS; \
+} while (0)
+
+#define __udc_set_speed_full() \
+do { \
+ REG_UDC_DevCFGR &= ~UDC_DevCFGR_SPD_MASK; \
+ REG_UDC_DevCFGR |= UDC_DevCFGR_SPD_FS; \
+} while (0)
+
+#define __udc_set_speed_low() \
+do { \
+ REG_UDC_DevCFGR &= ~UDC_DevCFGR_SPD_MASK; \
+ REG_UDC_DevCFGR |= UDC_DevCFGR_SPD_LS; \
+} while (0)
+
+
+#define __udc_set_dma_mode() ( REG_UDC_DevCR |= UDC_DevCR_DM )
+#define __udc_set_slave_mode() ( REG_UDC_DevCR &= ~UDC_DevCR_DM )
+#define __udc_set_big_endian() ( REG_UDC_DevCR |= UDC_DevCR_BE )
+#define __udc_set_little_endian() ( REG_UDC_DevCR &= ~UDC_DevCR_BE )
+#define __udc_generate_resume() ( REG_UDC_DevCR |= UDC_DevCR_RES )
+#define __udc_clear_resume() ( REG_UDC_DevCR &= ~UDC_DevCR_RES )
+
+
+#define __udc_get_enumarated_speed() ( REG_UDC_DevSR & UDC_DevSR_ENUMSPD_MASK )
+#define __udc_suspend_detected() ( REG_UDC_DevSR & UDC_DevSR_SUSP )
+#define __udc_get_alternate_setting() ( (REG_UDC_DevSR & UDC_DevSR_ALT_MASK) >> UDC_DevSR_ALT_BIT )
+#define __udc_get_interface_number() ( (REG_UDC_DevSR & UDC_DevSR_INTF_MASK) >> UDC_DevSR_INTF_BIT )
+#define __udc_get_config_number() ( (REG_UDC_DevSR & UDC_DevSR_CFG_MASK) >> UDC_DevSR_CFG_BIT )
+
+
+#define __udc_sof_detected(r) ( (r) & UDC_DevIntR_SOF )
+#define __udc_usb_suspend_detected(r) ( (r) & UDC_DevIntR_US )
+#define __udc_usb_reset_detected(r) ( (r) & UDC_DevIntR_UR )
+#define __udc_set_interface_detected(r) ( (r) & UDC_DevIntR_SI )
+#define __udc_set_config_detected(r) ( (r) & UDC_DevIntR_SC )
+
+#define __udc_clear_sof() ( REG_UDC_DevIntR |= UDC_DevIntR_SOF )
+#define __udc_clear_usb_suspend() ( REG_UDC_DevIntR |= UDC_DevIntR_US )
+#define __udc_clear_usb_reset() ( REG_UDC_DevIntR |= UDC_DevIntR_UR )
+#define __udc_clear_set_interface() ( REG_UDC_DevIntR |= UDC_DevIntR_SI )
+#define __udc_clear_set_config() ( REG_UDC_DevIntR |= UDC_DevIntR_SC )
+
+#define __udc_mask_sof() ( REG_UDC_DevIntMR |= UDC_DevIntR_SOF )
+#define __udc_mask_usb_suspend() ( REG_UDC_DevIntMR |= UDC_DevIntR_US )
+#define __udc_mask_usb_reset() ( REG_UDC_DevIntMR |= UDC_DevIntR_UR )
+#define __udc_mask_set_interface() ( REG_UDC_DevIntMR |= UDC_DevIntR_SI )
+#define __udc_mask_set_config() ( REG_UDC_DevIntMR |= UDC_DevIntR_SC )
+#define __udc_mask_all_dev_intrs() \
+ ( REG_UDC_DevIntMR = UDC_DevIntR_SOF | UDC_DevIntR_US | \
+ UDC_DevIntR_UR | UDC_DevIntR_SI | UDC_DevIntR_SC )
+
+#define __udc_unmask_sof() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_SOF )
+#define __udc_unmask_usb_suspend() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_US )
+#define __udc_unmask_usb_reset() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_UR )
+#define __udc_unmask_set_interface() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_SI )
+#define __udc_unmask_set_config() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_SC )
+#if 0
+#define __udc_unmask_all_dev_intrs() \
+ ( REG_UDC_DevIntMR = ~(UDC_DevIntR_SOF | UDC_DevIntR_US | \
+ UDC_DevIntR_UR | UDC_DevIntR_SI | UDC_DevIntR_SC) )
+#else
+#define __udc_unmask_all_dev_intrs() \
+ ( REG_UDC_DevIntMR = 0x00000000 )
+#endif
+
+
+#define __udc_ep0out_irq_detected(epintr) \
+ ( (((epintr) & UDC_EPIntR_OUTEP_MASK) >> (UDC_EPIntR_OUTEP_BIT + 0)) & 0x1 )
+#define __udc_ep5out_irq_detected(epintr) \
+ ( (((epintr) & UDC_EPIntR_OUTEP_MASK) >> (UDC_EPIntR_OUTEP_BIT + 5)) & 0x1 )
+#define __udc_ep6out_irq_detected(epintr) \
+ ( (((epintr) & UDC_EPIntR_OUTEP_MASK) >> (UDC_EPIntR_OUTEP_BIT + 6)) & 0x1 )
+#define __udc_ep7out_irq_detected(epintr) \
+ ( (((epintr) & UDC_EPIntR_OUTEP_MASK) >> (UDC_EPIntR_OUTEP_BIT + 7)) & 0x1 )
+
+#define __udc_ep0in_irq_detected(epintr) \
+ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 0)) & 0x1 )
+#define __udc_ep1in_irq_detected(epintr) \
+ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 1)) & 0x1 )
+#define __udc_ep2in_irq_detected(epintr) \
+ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 2)) & 0x1 )
+#define __udc_ep3in_irq_detected(epintr) \
+ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 3)) & 0x1 )
+#define __udc_ep4in_irq_detected(epintr) \
+ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 4)) & 0x1 )
+
+
+#define __udc_mask_ep0out_irq() \
+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_OUTEP_BIT + 0)) )
+#define __udc_mask_ep5out_irq() \
+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_OUTEP_BIT + 5)) )
+#define __udc_mask_ep6out_irq() \
+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_OUTEP_BIT + 6)) )
+#define __udc_mask_ep7out_irq() \
+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_OUTEP_BIT + 7)) )
+
+#define __udc_unmask_ep0out_irq() \
+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_OUTEP_BIT + 0)) )
+#define __udc_unmask_ep5out_irq() \
+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_OUTEP_BIT + 5)) )
+#define __udc_unmask_ep6out_irq() \
+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_OUTEP_BIT + 6)) )
+#define __udc_unmask_ep7out_irq() \
+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_OUTEP_BIT + 7)) )
+
+#define __udc_mask_ep0in_irq() \
+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 0)) )
+#define __udc_mask_ep1in_irq() \
+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 1)) )
+#define __udc_mask_ep2in_irq() \
+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 2)) )
+#define __udc_mask_ep3in_irq() \
+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 3)) )
+#define __udc_mask_ep4in_irq() \
+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 4)) )
+
+#define __udc_unmask_ep0in_irq() \
+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 0)) )
+#define __udc_unmask_ep1in_irq() \
+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 1)) )
+#define __udc_unmask_ep2in_irq() \
+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 2)) )
+#define __udc_unmask_ep3in_irq() \
+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 3)) )
+#define __udc_unmask_ep4in_irq() \
+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 4)) )
+
+#define __udc_mask_all_ep_intrs() \
+ ( REG_UDC_EPIntMR = 0xffffffff )
+#define __udc_unmask_all_ep_intrs() \
+ ( REG_UDC_EPIntMR = 0x00000000 )
+
+
+/* ep0 only CTRL, ep1 only INTR, ep2/3/5/6 only BULK, ep4/7 only ISO */
+#define __udc_config_endpoint_type() \
+do { \
+ REG_UDC_EP0InCR = (REG_UDC_EP0InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_CTRL; \
+ REG_UDC_EP0OutCR = (REG_UDC_EP0OutCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_CTRL; \
+ REG_UDC_EP1InCR = (REG_UDC_EP1InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_INTR; \
+ REG_UDC_EP2InCR = (REG_UDC_EP2InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_BULK; \
+ REG_UDC_EP3InCR = (REG_UDC_EP3InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_BULK; \
+ REG_UDC_EP4InCR = (REG_UDC_EP4InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_ISO; \
+ REG_UDC_EP5OutCR = (REG_UDC_EP5OutCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_BULK; \
+ REG_UDC_EP6OutCR = (REG_UDC_EP6OutCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_BULK; \
+ REG_UDC_EP7OutCR = (REG_UDC_EP7OutCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_ISO; \
+} while (0)
+
+#define __udc_enable_ep0out_snoop_mode() ( REG_UDC_EP0OutCR |= UDC_EPCR_SN )
+#define __udc_enable_ep5out_snoop_mode() ( REG_UDC_EP5OutCR |= UDC_EPCR_SN )
+#define __udc_enable_ep6out_snoop_mode() ( REG_UDC_EP6OutCR |= UDC_EPCR_SN )
+#define __udc_enable_ep7out_snoop_mode() ( REG_UDC_EP7OutCR |= UDC_EPCR_SN )
+
+#define __udc_disable_ep0out_snoop_mode() ( REG_UDC_EP0OutCR &= ~UDC_EPCR_SN )
+#define __udc_disable_ep5out_snoop_mode() ( REG_UDC_EP5OutCR &= ~UDC_EPCR_SN )
+#define __udc_disable_ep6out_snoop_mode() ( REG_UDC_EP6OutCR &= ~UDC_EPCR_SN )
+#define __udc_disable_ep7out_snoop_mode() ( REG_UDC_EP7OutCR &= ~UDC_EPCR_SN )
+
+#define __udc_flush_ep0in_fifo() ( REG_UDC_EP0InCR |= UDC_EPCR_F )
+#define __udc_flush_ep1in_fifo() ( REG_UDC_EP1InCR |= UDC_EPCR_F )
+#define __udc_flush_ep2in_fifo() ( REG_UDC_EP2InCR |= UDC_EPCR_F )
+#define __udc_flush_ep3in_fifo() ( REG_UDC_EP3InCR |= UDC_EPCR_F )
+#define __udc_flush_ep4in_fifo() ( REG_UDC_EP4InCR |= UDC_EPCR_F )
+
+#define __udc_unflush_ep0in_fifo() ( REG_UDC_EP0InCR &= ~UDC_EPCR_F )
+#define __udc_unflush_ep1in_fifo() ( REG_UDC_EP1InCR &= ~UDC_EPCR_F )
+#define __udc_unflush_ep2in_fifo() ( REG_UDC_EP2InCR &= ~UDC_EPCR_F )
+#define __udc_unflush_ep3in_fifo() ( REG_UDC_EP3InCR &= ~UDC_EPCR_F )
+#define __udc_unflush_ep4in_fifo() ( REG_UDC_EP4InCR &= ~UDC_EPCR_F )
+
+#define __udc_enable_ep0in_stall() ( REG_UDC_EP0InCR |= UDC_EPCR_S )
+#define __udc_enable_ep0out_stall() ( REG_UDC_EP0OutCR |= UDC_EPCR_S )
+#define __udc_enable_ep1in_stall() ( REG_UDC_EP1InCR |= UDC_EPCR_S )
+#define __udc_enable_ep2in_stall() ( REG_UDC_EP2InCR |= UDC_EPCR_S )
+#define __udc_enable_ep3in_stall() ( REG_UDC_EP3InCR |= UDC_EPCR_S )
+#define __udc_enable_ep4in_stall() ( REG_UDC_EP4InCR |= UDC_EPCR_S )
+#define __udc_enable_ep5out_stall() ( REG_UDC_EP5OutCR |= UDC_EPCR_S )
+#define __udc_enable_ep6out_stall() ( REG_UDC_EP6OutCR |= UDC_EPCR_S )
+#define __udc_enable_ep7out_stall() ( REG_UDC_EP7OutCR |= UDC_EPCR_S )
+
+#define __udc_disable_ep0in_stall() ( REG_UDC_EP0InCR &= ~UDC_EPCR_S )
+#define __udc_disable_ep0out_stall() ( REG_UDC_EP0OutCR &= ~UDC_EPCR_S )
+#define __udc_disable_ep1in_stall() ( REG_UDC_EP1InCR &= ~UDC_EPCR_S )
+#define __udc_disable_ep2in_stall() ( REG_UDC_EP2InCR &= ~UDC_EPCR_S )
+#define __udc_disable_ep3in_stall() ( REG_UDC_EP3InCR &= ~UDC_EPCR_S )
+#define __udc_disable_ep4in_stall() ( REG_UDC_EP4InCR &= ~UDC_EPCR_S )
+#define __udc_disable_ep5out_stall() ( REG_UDC_EP5OutCR &= ~UDC_EPCR_S )
+#define __udc_disable_ep6out_stall() ( REG_UDC_EP6OutCR &= ~UDC_EPCR_S )
+#define __udc_disable_ep7out_stall() ( REG_UDC_EP7OutCR &= ~UDC_EPCR_S )
+
+
+#define __udc_ep0out_packet_size() \
+ ( (REG_UDC_EP0OutSR & UDC_EPSR_RXPKTSIZE_MASK) >> UDC_EPSR_RXPKTSIZE_BIT )
+#define __udc_ep5out_packet_size() \
+ ( (REG_UDC_EP5OutSR & UDC_EPSR_RXPKTSIZE_MASK) >> UDC_EPSR_RXPKTSIZE_BIT )
+#define __udc_ep6out_packet_size() \
+ ( (REG_UDC_EP6OutSR & UDC_EPSR_RXPKTSIZE_MASK) >> UDC_EPSR_RXPKTSIZE_BIT )
+#define __udc_ep7out_packet_size() \
+ ( (REG_UDC_EP7OutSR & UDC_EPSR_RXPKTSIZE_MASK) >> UDC_EPSR_RXPKTSIZE_BIT )
+
+#define __udc_ep0in_received_intoken() ( (REG_UDC_EP0InSR & UDC_EPSR_IN) )
+#define __udc_ep1in_received_intoken() ( (REG_UDC_EP1InSR & UDC_EPSR_IN) )
+#define __udc_ep2in_received_intoken() ( (REG_UDC_EP2InSR & UDC_EPSR_IN) )
+#define __udc_ep3in_received_intoken() ( (REG_UDC_EP3InSR & UDC_EPSR_IN) )
+#define __udc_ep4in_received_intoken() ( (REG_UDC_EP4InSR & UDC_EPSR_IN) )
+
+#define __udc_ep0out_received_none() \
+ ( (REG_UDC_EP0OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_NONE )
+#define __udc_ep0out_received_data() \
+ ( (REG_UDC_EP0OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVDATA )
+#define __udc_ep0out_received_setup() \
+ ( (REG_UDC_EP0OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVSETUP )
+
+#define __udc_ep5out_received_none() \
+ ( (REG_UDC_EP5OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_NONE )
+#define __udc_ep5out_received_data() \
+ ( (REG_UDC_EP5OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVDATA )
+#define __udc_ep5out_received_setup() \
+ ( (REG_UDC_EP5OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVSETUP )
+
+#define __udc_ep6out_received_none() \
+ ( (REG_UDC_EP6OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_NONE )
+#define __udc_ep6out_received_data() \
+ ( (REG_UDC_EP6OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVDATA )
+#define __udc_ep6out_received_setup() \
+ ( (REG_UDC_EP6OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVSETUP )
+
+#define __udc_ep7out_received_none() \
+ ( (REG_UDC_EP7OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_NONE )
+#define __udc_ep7out_received_data() \
+ ( (REG_UDC_EP7OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVDATA )
+#define __udc_ep7out_received_setup() \
+ ( (REG_UDC_EP7OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVSETUP )
+
+/* ep7out ISO only */
+#define __udc_ep7out_get_pid() \
+ ( (REG_UDC_EP7OutSR & UDC_EPSR_PID_MASK) >> UDC_EPSR_PID_BIT )
+
+
+#define __udc_ep0in_set_buffer_size(n) ( REG_UDC_EP0InBSR = (n) )
+#define __udc_ep1in_set_buffer_size(n) ( REG_UDC_EP1InBSR = (n) )
+#define __udc_ep2in_set_buffer_size(n) ( REG_UDC_EP2InBSR = (n) )
+#define __udc_ep3in_set_buffer_size(n) ( REG_UDC_EP3InBSR = (n) )
+#define __udc_ep4in_set_buffer_size(n) ( REG_UDC_EP4InBSR = (n) )
+
+#define __udc_ep0out_get_frame_number(n) ( UDC_EP0OutPFNR )
+#define __udc_ep5out_get_frame_number(n) ( UDC_EP5OutPFNR )
+#define __udc_ep6out_get_frame_number(n) ( UDC_EP6OutPFNR )
+#define __udc_ep7out_get_frame_number(n) ( UDC_EP7OutPFNR )
+
+
+#define __udc_ep0in_set_max_packet_size(n) ( REG_UDC_EP0InMPSR = (n) )
+#define __udc_ep0out_set_max_packet_size(n) ( REG_UDC_EP0OutMPSR = (n) )
+#define __udc_ep1in_set_max_packet_size(n) ( REG_UDC_EP1InMPSR = (n) )
+#define __udc_ep2in_set_max_packet_size(n) ( REG_UDC_EP2InMPSR = (n) )
+#define __udc_ep3in_set_max_packet_size(n) ( REG_UDC_EP3InMPSR = (n) )
+#define __udc_ep4in_set_max_packet_size(n) ( REG_UDC_EP4InMPSR = (n) )
+#define __udc_ep5out_set_max_packet_size(n) ( REG_UDC_EP5OutMPSR = (n) )
+#define __udc_ep6out_set_max_packet_size(n) ( REG_UDC_EP6OutMPSR = (n) )
+#define __udc_ep7out_set_max_packet_size(n) ( REG_UDC_EP7OutMPSR = (n) )
+
+/* set to 0xFFFF for UDC */
+#define __udc_set_setup_command_address(n) ( REG_UDC_STCMAR = (n) )
+
+/* Init and configure EPxInfR(x=0,1,2,3,4,5,6,7)
+ * c: Configuration number to which this endpoint belongs
+ * i: Interface number to which this endpoint belongs
+ * a: Alternate setting to which this endpoint belongs
+ * p: max Packet size of this endpoint
+ */
+
+#define __udc_ep0info_init(c,i,a,p) \
+do { \
+ REG_UDC_EP0InfR &= ~UDC_EPInfR_MPS_MASK; \
+ REG_UDC_EP0InfR |= ((p) << UDC_EPInfR_MPS_BIT); \
+ REG_UDC_EP0InfR &= ~UDC_EPInfR_ALTS_MASK; \
+ REG_UDC_EP0InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \
+ REG_UDC_EP0InfR &= ~UDC_EPInfR_IFN_MASK; \
+ REG_UDC_EP0InfR |= ((i) << UDC_EPInfR_IFN_BIT); \
+ REG_UDC_EP0InfR &= ~UDC_EPInfR_CGN_MASK; \
+ REG_UDC_EP0InfR |= ((c) << UDC_EPInfR_CGN_BIT); \
+ REG_UDC_EP0InfR &= ~UDC_EPInfR_EPT_MASK; \
+ REG_UDC_EP0InfR |= UDC_EPInfR_EPT_CTRL; \
+ REG_UDC_EP0InfR &= ~UDC_EPInfR_EPD; \
+ REG_UDC_EP0InfR |= UDC_EPInfR_EPD_OUT; \
+ REG_UDC_EP0InfR &= ~UDC_EPInfR_EPN_MASK; \
+ REG_UDC_EP0InfR |= (0 << UDC_EPInfR_EPN_BIT); \
+} while (0)
+
+#define __udc_ep1info_init(c,i,a,p) \
+do { \
+ REG_UDC_EP1InfR &= ~UDC_EPInfR_MPS_MASK; \
+ REG_UDC_EP1InfR |= ((p) << UDC_EPInfR_MPS_BIT); \
+ REG_UDC_EP1InfR &= ~UDC_EPInfR_ALTS_MASK; \
+ REG_UDC_EP1InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \
+ REG_UDC_EP1InfR &= ~UDC_EPInfR_IFN_MASK; \
+ REG_UDC_EP1InfR |= ((i) << UDC_EPInfR_IFN_BIT); \
+ REG_UDC_EP1InfR &= ~UDC_EPInfR_CGN_MASK; \
+ REG_UDC_EP1InfR |= ((c) << UDC_EPInfR_CGN_BIT); \
+ REG_UDC_EP1InfR &= ~UDC_EPInfR_EPT_MASK; \
+ REG_UDC_EP1InfR |= UDC_EPInfR_EPT_INTR; \
+ REG_UDC_EP1InfR &= ~UDC_EPInfR_EPD; \
+ REG_UDC_EP1InfR |= UDC_EPInfR_EPD_IN; \
+ REG_UDC_EP1InfR &= ~UDC_EPInfR_EPN_MASK; \
+ REG_UDC_EP1InfR |= (1 << UDC_EPInfR_EPN_BIT); \
+} while (0)
+
+#define __udc_ep2info_init(c,i,a,p) \
+do { \
+ REG_UDC_EP2InfR &= ~UDC_EPInfR_MPS_MASK; \
+ REG_UDC_EP2InfR |= ((p) << UDC_EPInfR_MPS_BIT); \
+ REG_UDC_EP2InfR &= ~UDC_EPInfR_ALTS_MASK; \
+ REG_UDC_EP2InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \
+ REG_UDC_EP2InfR &= ~UDC_EPInfR_IFN_MASK; \
+ REG_UDC_EP2InfR |= ((i) << UDC_EPInfR_IFN_BIT); \
+ REG_UDC_EP2InfR &= ~UDC_EPInfR_CGN_MASK; \
+ REG_UDC_EP2InfR |= ((c) << UDC_EPInfR_CGN_BIT); \
+ REG_UDC_EP2InfR &= ~UDC_EPInfR_EPT_MASK; \
+ REG_UDC_EP2InfR |= UDC_EPInfR_EPT_BULK; \
+ REG_UDC_EP2InfR &= ~UDC_EPInfR_EPD; \
+ REG_UDC_EP2InfR |= UDC_EPInfR_EPD_IN; \
+ REG_UDC_EP2InfR &= ~UDC_EPInfR_EPN_MASK; \
+ REG_UDC_EP2InfR |= (2 << UDC_EPInfR_EPN_BIT); \
+} while (0)
+
+#define __udc_ep3info_init(c,i,a,p) \
+do { \
+ REG_UDC_EP3InfR &= ~UDC_EPInfR_MPS_MASK; \
+ REG_UDC_EP3InfR |= ((p) << UDC_EPInfR_MPS_BIT); \
+ REG_UDC_EP3InfR &= ~UDC_EPInfR_ALTS_MASK; \
+ REG_UDC_EP3InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \
+ REG_UDC_EP3InfR &= ~UDC_EPInfR_IFN_MASK; \
+ REG_UDC_EP3InfR |= ((i) << UDC_EPInfR_IFN_BIT); \
+ REG_UDC_EP3InfR &= ~UDC_EPInfR_CGN_MASK; \
+ REG_UDC_EP3InfR |= ((c) << UDC_EPInfR_CGN_BIT); \
+ REG_UDC_EP3InfR &= ~UDC_EPInfR_EPT_MASK; \
+ REG_UDC_EP3InfR |= UDC_EPInfR_EPT_BULK; \
+ REG_UDC_EP3InfR &= ~UDC_EPInfR_EPD; \
+ REG_UDC_EP3InfR |= UDC_EPInfR_EPD_IN; \
+ REG_UDC_EP3InfR &= ~UDC_EPInfR_EPN_MASK; \
+ REG_UDC_EP3InfR |= (3 << UDC_EPInfR_EPN_BIT); \
+} while (0)
+
+#define __udc_ep4info_init(c,i,a,p) \
+do { \
+ REG_UDC_EP4InfR &= ~UDC_EPInfR_MPS_MASK; \
+ REG_UDC_EP4InfR |= ((p) << UDC_EPInfR_MPS_BIT); \
+ REG_UDC_EP4InfR &= ~UDC_EPInfR_ALTS_MASK; \
+ REG_UDC_EP4InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \
+ REG_UDC_EP4InfR &= ~UDC_EPInfR_IFN_MASK; \
+ REG_UDC_EP4InfR |= ((i) << UDC_EPInfR_IFN_BIT); \
+ REG_UDC_EP4InfR &= ~UDC_EPInfR_CGN_MASK; \
+ REG_UDC_EP4InfR |= ((c) << UDC_EPInfR_CGN_BIT); \
+ REG_UDC_EP4InfR &= ~UDC_EPInfR_EPT_MASK; \
+ REG_UDC_EP4InfR |= UDC_EPInfR_EPT_ISO; \
+ REG_UDC_EP4InfR &= ~UDC_EPInfR_EPD; \
+ REG_UDC_EP4InfR |= UDC_EPInfR_EPD_IN; \
+ REG_UDC_EP4InfR &= ~UDC_EPInfR_EPN_MASK; \
+ REG_UDC_EP4InfR |= (4 << UDC_EPInfR_EPN_BIT); \
+} while (0)
+
+#define __udc_ep5info_init(c,i,a,p) \
+do { \
+ REG_UDC_EP5InfR &= ~UDC_EPInfR_MPS_MASK; \
+ REG_UDC_EP5InfR |= ((p) << UDC_EPInfR_MPS_BIT); \
+ REG_UDC_EP5InfR &= ~UDC_EPInfR_ALTS_MASK; \
+ REG_UDC_EP5InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \
+ REG_UDC_EP5InfR &= ~UDC_EPInfR_IFN_MASK; \
+ REG_UDC_EP5InfR |= ((i) << UDC_EPInfR_IFN_BIT); \
+ REG_UDC_EP5InfR &= ~UDC_EPInfR_CGN_MASK; \
+ REG_UDC_EP5InfR |= ((c) << UDC_EPInfR_CGN_BIT); \
+ REG_UDC_EP5InfR &= ~UDC_EPInfR_EPT_MASK; \
+ REG_UDC_EP5InfR |= UDC_EPInfR_EPT_BULK; \
+ REG_UDC_EP5InfR &= ~UDC_EPInfR_EPD; \
+ REG_UDC_EP5InfR |= UDC_EPInfR_EPD_OUT; \
+ REG_UDC_EP5InfR &= ~UDC_EPInfR_EPN_MASK; \
+ REG_UDC_EP5InfR |= (5 << UDC_EPInfR_EPN_BIT); \
+} while (0)
+
+#define __udc_ep6info_init(c,i,a,p) \
+do { \
+ REG_UDC_EP6InfR &= ~UDC_EPInfR_MPS_MASK; \
+ REG_UDC_EP6InfR |= ((p) << UDC_EPInfR_MPS_BIT); \
+ REG_UDC_EP6InfR &= ~UDC_EPInfR_ALTS_MASK; \
+ REG_UDC_EP6InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \
+ REG_UDC_EP6InfR &= ~UDC_EPInfR_IFN_MASK; \
+ REG_UDC_EP6InfR |= ((i) << UDC_EPInfR_IFN_BIT); \
+ REG_UDC_EP6InfR &= ~UDC_EPInfR_CGN_MASK; \
+ REG_UDC_EP6InfR |= ((c) << UDC_EPInfR_CGN_BIT); \
+ REG_UDC_EP6InfR &= ~UDC_EPInfR_EPT_MASK; \
+ REG_UDC_EP6InfR |= UDC_EPInfR_EPT_BULK; \
+ REG_UDC_EP6InfR &= ~UDC_EPInfR_EPD; \
+ REG_UDC_EP6InfR |= UDC_EPInfR_EPD_OUT; \
+ REG_UDC_EP6InfR &= ~UDC_EPInfR_EPN_MASK; \
+ REG_UDC_EP6InfR |= (6 << UDC_EPInfR_EPN_BIT); \
+} while (0)
+
+#define __udc_ep7info_init(c,i,a,p) \
+do { \
+ REG_UDC_EP7InfR &= ~UDC_EPInfR_MPS_MASK; \
+ REG_UDC_EP7InfR |= ((p) << UDC_EPInfR_MPS_BIT); \
+ REG_UDC_EP7InfR &= ~UDC_EPInfR_ALTS_MASK; \
+ REG_UDC_EP7InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \
+ REG_UDC_EP7InfR &= ~UDC_EPInfR_IFN_MASK; \
+ REG_UDC_EP7InfR |= ((i) << UDC_EPInfR_IFN_BIT); \
+ REG_UDC_EP7InfR &= ~UDC_EPInfR_CGN_MASK; \
+ REG_UDC_EP7InfR |= ((c) << UDC_EPInfR_CGN_BIT); \
+ REG_UDC_EP7InfR &= ~UDC_EPInfR_EPT_MASK; \
+ REG_UDC_EP7InfR |= UDC_EPInfR_EPT_ISO; \
+ REG_UDC_EP7InfR &= ~UDC_EPInfR_EPD; \
+ REG_UDC_EP7InfR |= UDC_EPInfR_EPD_OUT; \
+ REG_UDC_EP7InfR &= ~UDC_EPInfR_EPN_MASK; \
+ REG_UDC_EP7InfR |= (7 << UDC_EPInfR_EPN_BIT); \
+} while (0)
+
+
+/***************************************************************************
+ * DMAC
+ ***************************************************************************/
+
+/* n is the DMA channel (0 - 7) */
+
+#define __dmac_enable_all_channels() \
+ ( REG_DMAC_DMACR |= DMAC_DMACR_DME | DMAC_DMACR_PR_ROUNDROBIN )
+#define __dmac_disable_all_channels() \
+ ( REG_DMAC_DMACR &= ~DMAC_DMACR_DME )
+
+/* p=0,1,2,3 */
+#define __dmac_set_priority(p) \
+do { \
+ REG_DMAC_DMACR &= ~DMAC_DMACR_PR_MASK; \
+ REG_DMAC_DMACR |= ((p) << DMAC_DMACR_PR_BIT); \
+} while (0)
+
+#define __dmac_test_halt_error() ( REG_DMAC_DMACR & DMAC_DMACR_HTR )
+#define __dmac_test_addr_error() ( REG_DMAC_DMACR & DMAC_DMACR_AER )
+
+#define __dmac_enable_channel(n) \
+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_CHDE )
+#define __dmac_disable_channel(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_CHDE )
+#define __dmac_channel_enabled(n) \
+ ( REG_DMAC_DCCSR(n) & DMAC_DCCSR_CHDE )
+
+#define __dmac_channel_enable_irq(n) \
+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_TCIE )
+#define __dmac_channel_disable_irq(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TCIE )
+
+#define __dmac_channel_transmit_halt_detected(n) \
+ ( REG_DMAC_DCCSR(n) & DMAC_DCCSR_HLT )
+#define __dmac_channel_transmit_end_detected(n) \
+ ( REG_DMAC_DCCSR(n) & DMAC_DCCSR_TC )
+#define __dmac_channel_address_error_detected(n) \
+ ( REG_DMAC_DCCSR(n) & DMAC_DCCSR_AR )
+
+#define __dmac_channel_clear_transmit_halt(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT )
+#define __dmac_channel_clear_transmit_end(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TC )
+#define __dmac_channel_clear_address_error(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR )
+
+#define __dmac_channel_set_single_mode(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TM )
+#define __dmac_channel_set_block_mode(n) \
+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_TM )
+
+#define __dmac_channel_set_transfer_unit_32bit(n) \
+do { \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \
+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_32b; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_16bit(n) \
+do { \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \
+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_16b; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_8bit(n) \
+do { \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \
+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_8b; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_16byte(n) \
+do { \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \
+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_16B; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_32byte(n) \
+do { \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \
+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_32B; \
+} while (0)
+
+/* w=8,16,32 */
+#define __dmac_channel_set_dest_port_width(n,w) \
+do { \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DWDH_MASK; \
+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DWDH_##w; \
+} while (0)
+
+/* w=8,16,32 */
+#define __dmac_channel_set_src_port_width(n,w) \
+do { \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_SWDH_MASK; \
+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_SWDH_##w; \
+} while (0)
+
+/* v=0-15 */
+#define __dmac_channel_set_rdil(n,v) \
+do { \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_RDIL_MASK; \
+ REG_DMAC_DCCSR(n) |= ((v) << DMAC_DCCSR_RDIL_BIT); \
+} while (0)
+
+#define __dmac_channel_dest_addr_fixed(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DAM )
+#define __dmac_channel_dest_addr_increment(n) \
+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DAM )
+
+#define __dmac_channel_src_addr_fixed(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_SAM )
+#define __dmac_channel_src_addr_increment(n) \
+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_SAM )
+
+#define __dmac_channel_set_eop_high(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_EOPM )
+#define __dmac_channel_set_eop_low(n) \
+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_EOPM )
+
+#define __dmac_channel_set_erdm(n,m) \
+do { \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_SWDH_MASK; \
+ REG_DMAC_DCCSR(n) |= ((m) << DMAC_DCCSR_ERDM_BIT); \
+} while (0)
+
+#define __dmac_channel_set_eackm(n) \
+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_EACKM )
+#define __dmac_channel_clear_eackm(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_EACKM )
+
+#define __dmac_channel_set_eacks(n) \
+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_EACKS )
+#define __dmac_channel_clear_eacks(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_EACKS )
+
+
+#define __dmac_channel_irq_detected(n) \
+ ( REG_DMAC_DCCSR(n) & (DMAC_DCCSR_TC | DMAC_DCCSR_AR) )
+
+static __inline__ int __dmac_get_irq(void)
+{
+ int i;
+ for (i=0;i<NUM_DMA;i++)
+ if (__dmac_channel_irq_detected(i))
+ return i;
+ return -1;
+}
+
+/***************************************************************************
+ * AIC (AC'97 & I2S Controller)
+ ***************************************************************************/
+
+#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB )
+#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB )
+#define __aic_reset() ( REG_AIC_FR |= AIC_FR_RST )
+#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL )
+#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL )
+
+#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD )
+#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) )
+
+#define __aic_set_transmit_trigger(n) \
+do { \
+ REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \
+ REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \
+} while(0)
+
+#define __aic_set_receive_trigger(n) \
+do { \
+ REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \
+ REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \
+} while(0)
+
+#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC )
+#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC )
+#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL )
+#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL )
+#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF )
+#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF )
+
+#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH )
+#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH )
+
+#define __aic_enable_transmit_intr() \
+ ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) )
+#define __aic_disable_transmit_intr() \
+ ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) )
+#define __aic_enable_receive_intr() \
+ ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) )
+#define __aic_disable_receive_intr() \
+ ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) )
+
+#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS )
+#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS )
+#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS )
+#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS )
+
+#define __aic_enable_mono2stereo()
+#define __aic_disable_mono2stereo()
+#define __aic_enable_byteswap()
+#define __aic_disable_byteswap()
+#define __aic_enable_unsignadj()
+#define __aic_disable_unsignadj()
+
+#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3
+#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4
+#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6
+#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7
+#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8
+#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9
+
+#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3
+#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4
+#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6
+#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7
+#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8
+#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9
+
+#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK )
+#define __ac97_set_xs_mono() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \
+} while(0)
+#define __ac97_set_xs_stereo() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \
+} while(0)
+
+/* In fact, only stereo is support now. */
+#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK )
+#define __ac97_set_rs_mono() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \
+} while(0)
+#define __ac97_set_rs_stereo() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \
+} while(0)
+
+#define __ac97_warm_reset_codec() \
+ do { \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SA; \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SS; \
+ udelay(1); \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \
+ } while (0)
+
+#define Jz_AC97_RESET_BUG 1
+
+#ifndef Jz_AC97_RESET_BUG
+#define __ac97_cold_reset_codec() \
+ do { \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SA; \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SR; \
+ udelay(1); \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \
+ } while (0)
+#else
+#define __ac97_cold_reset_codec() \
+ do { \
+ __gpio_as_output(70); /* SDATA_OUT */ \
+ __gpio_as_output(71); /* SDATA_IN */ \
+ __gpio_as_output(78); /* SYNC */ \
+ __gpio_as_output(69); /* RESET# */ \
+ __gpio_clear_pin(70); \
+ __gpio_clear_pin(71); \
+ __gpio_clear_pin(78); \
+ __gpio_clear_pin(69); \
+ udelay(10); \
+ __gpio_set_pin(69); \
+ udelay(1); \
+ __gpio_as_ac97(); \
+ } while (0)
+#endif
+
+/* n=8,16,18,20 */
+#define __ac97_set_iass(n) \
+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT )
+#define __ac97_set_oass(n) \
+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT )
+
+#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL )
+#define __i2s_select_left_justified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL )
+
+/* n=8,16,18,20,24 */
+#define __i2s_set_sample_size(n) \
+ ( REG_AIC_I2SCR = (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )
+
+#define __i2s_stop_clock() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK )
+#define __i2s_start_clock() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK )
+
+#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS )
+#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS )
+#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR )
+#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR )
+
+#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) )
+
+#define __aic_get_transmit_resident() \
+ ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT )
+#define __aic_get_receive_count() \
+ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT )
+
+#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT )
+#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR )
+#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO )
+#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM )
+#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY )
+
+#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY )
+
+#define CODEC_READ_CMD (1 << 19)
+#define CODEC_WRITE_CMD (0 << 19)
+#define CODEC_REG_INDEX_BIT 12
+#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */
+#define CODEC_REG_DATA_BIT 4
+#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */
+
+#define __ac97_out_rcmd_addr(reg) \
+do { \
+ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \
+} while (0)
+
+#define __ac97_out_wcmd_addr(reg) \
+do { \
+ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \
+} while (0)
+
+#define __ac97_out_data(value) \
+do { \
+ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \
+} while (0)
+
+#define __ac97_in_data() \
+ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT )
+
+#define __ac97_in_status_addr() \
+ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT )
+
+#define __i2s_set_sample_rate(i2sclk, sync) \
+ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) )
+
+#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) )
+#define __aic_read_rfifo() ( REG_AIC_DR )
+
+//
+// Define next ops for AC97 compatible
+//
+
+#define AC97_ACSR AIC_ACSR
+
+#define __ac97_enable() __aic_enable(); __aic_select_ac97()
+#define __ac97_disable() __aic_disable()
+#define __ac97_reset() __aic_reset()
+
+#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n)
+#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n)
+
+#define __ac97_enable_record() __aic_enable_record()
+#define __ac97_disable_record() __aic_disable_record()
+#define __ac97_enable_replay() __aic_enable_replay()
+#define __ac97_disable_replay() __aic_disable_replay()
+#define __ac97_enable_loopback() __aic_enable_loopback()
+#define __ac97_disable_loopback() __aic_disable_loopback()
+
+#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma()
+#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma()
+#define __ac97_enable_receive_dma() __aic_enable_receive_dma()
+#define __ac97_disable_receive_dma() __aic_disable_receive_dma()
+
+#define __ac97_transmit_request() __aic_transmit_request()
+#define __ac97_receive_request() __aic_receive_request()
+#define __ac97_transmit_underrun() __aic_transmit_underrun()
+#define __ac97_receive_overrun() __aic_receive_overrun()
+
+#define __ac97_clear_errors() __aic_clear_errors()
+
+#define __ac97_get_transmit_resident() __aic_get_transmit_resident()
+#define __ac97_get_receive_count() __aic_get_receive_count()
+
+#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr()
+#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr()
+#define __ac97_enable_receive_intr() __aic_enable_receive_intr()
+#define __ac97_disable_receive_intr() __aic_disable_receive_intr()
+
+#define __ac97_write_tfifo(v) __aic_write_tfifo(v)
+#define __ac97_read_rfifo() __aic_read_rfifo()
+
+//
+// Define next ops for I2S compatible
+//
+
+#define I2S_ACSR AIC_I2SSR
+
+#define __i2s_enable() __aic_enable(); __aic_select_i2s()
+#define __i2s_disable() __aic_disable()
+#define __i2s_reset() __aic_reset()
+
+#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n)
+#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n)
+
+#define __i2s_enable_record() __aic_enable_record()
+#define __i2s_disable_record() __aic_disable_record()
+#define __i2s_enable_replay() __aic_enable_replay()
+#define __i2s_disable_replay() __aic_disable_replay()
+#define __i2s_enable_loopback() __aic_enable_loopback()
+#define __i2s_disable_loopback() __aic_disable_loopback()
+
+#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma()
+#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma()
+#define __i2s_enable_receive_dma() __aic_enable_receive_dma()
+#define __i2s_disable_receive_dma() __aic_disable_receive_dma()
+
+#define __i2s_transmit_request() __aic_transmit_request()
+#define __i2s_receive_request() __aic_receive_request()
+#define __i2s_transmit_underrun() __aic_transmit_underrun()
+#define __i2s_receive_overrun() __aic_receive_overrun()
+
+#define __i2s_clear_errors() __aic_clear_errors()
+
+#define __i2s_get_transmit_resident() __aic_get_transmit_resident()
+#define __i2s_get_receive_count() __aic_get_receive_count()
+
+#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr()
+#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr()
+#define __i2s_enable_receive_intr() __aic_enable_receive_intr()
+#define __i2s_disable_receive_intr() __aic_disable_receive_intr()
+
+#define __i2s_write_tfifo(v) __aic_write_tfifo(v)
+#define __i2s_read_rfifo() __aic_read_rfifo()
+
+#define __i2s_reset_codec() \
+ do { \
+ __gpio_as_output(70); /* SDATA_OUT */ \
+ __gpio_as_input(71); /* SDATA_IN */ \
+ __gpio_as_output(78); /* SYNC */ \
+ __gpio_as_output(69); /* RESET# */ \
+ __gpio_clear_pin(70); \
+ __gpio_clear_pin(71); \
+ __gpio_clear_pin(78); \
+ __gpio_clear_pin(69); \
+ __gpio_as_i2s_master(); \
+ } while (0)
+
+
+/***************************************************************************
+ * LCD
+ ***************************************************************************/
+
+#define __lcd_set_dis() ( REG_LCD_CTRL |= LCD_CTRL_DIS )
+#define __lcd_clr_dis() ( REG_LCD_CTRL &= ~LCD_CTRL_DIS )
+
+#define __lcd_set_ena() ( REG_LCD_CTRL |= LCD_CTRL_ENA )
+#define __lcd_clr_ena() ( REG_LCD_CTRL &= ~LCD_CTRL_ENA )
+
+/* n=1,2,4,8,16 */
+#define __lcd_set_bpp(n) \
+ ( REG_LCD_CTRL = (REG_LCD_CTRL & ~LCD_CTRL_BPP_MASK) | LCD_CTRL_BPP_##n )
+
+/* n=4,8,16 */
+#define __lcd_set_burst_length(n) \
+do { \
+ REG_LCD_CTRL &= ~LCD_CTRL_BST_MASK; \
+ REG_LCD_CTRL |= LCD_CTRL_BST_n##; \
+} while (0)
+
+#define __lcd_select_rgb565() ( REG_LCD_CTRL &= ~LCD_CTRL_RGB555 )
+#define __lcd_select_rgb555() ( REG_LCD_CTRL |= LCD_CTRL_RGB555 )
+
+#define __lcd_set_ofup() ( REG_LCD_CTRL |= LCD_CTRL_OFUP )
+#define __lcd_clr_ofup() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUP )
+
+/* n=2,4,16 */
+#define __lcd_set_stn_frc(n) \
+do { \
+ REG_LCD_CTRL &= ~LCD_CTRL_FRC_MASK; \
+ REG_LCD_CTRL |= LCD_CTRL_FRC_n##; \
+} while (0)
+
+
+#define __lcd_pixel_endian_little() ( REG_LCD_CTRL |= LCD_CTRL_PEDN )
+#define __lcd_pixel_endian_big() ( REG_LCD_CTRL &= ~LCD_CTRL_PEDN )
+
+#define __lcd_reverse_byte_endian() ( REG_LCD_CTRL |= LCD_CTRL_BEDN )
+#define __lcd_normal_byte_endian() ( REG_LCD_CTRL &= ~LCD_CTRL_BEDN )
+
+#define __lcd_enable_eof_intr() ( REG_LCD_CTRL |= LCD_CTRL_EOFM )
+#define __lcd_disable_eof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_EOFM )
+
+#define __lcd_enable_sof_intr() ( REG_LCD_CTRL |= LCD_CTRL_SOFM )
+#define __lcd_disable_sof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_SOFM )
+
+#define __lcd_enable_ofu_intr() ( REG_LCD_CTRL |= LCD_CTRL_OFUM )
+#define __lcd_disable_ofu_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUM )
+
+#define __lcd_enable_ifu0_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM0 )
+#define __lcd_disable_ifu0_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM0 )
+
+#define __lcd_enable_ifu1_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM1 )
+#define __lcd_disable_ifu1_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM1 )
+
+#define __lcd_enable_ldd_intr() ( REG_LCD_CTRL |= LCD_CTRL_LDDM )
+#define __lcd_disable_ldd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_LDDM )
+
+#define __lcd_enable_qd_intr() ( REG_LCD_CTRL |= LCD_CTRL_QDM )
+#define __lcd_disable_qd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_QDM )
+
+
+/* LCD status register indication */
+
+#define __lcd_quick_disable_done() ( REG_LCD_STATE & LCD_STATE_QD )
+#define __lcd_disable_done() ( REG_LCD_STATE & LCD_STATE_LDD )
+#define __lcd_infifo0_underrun() ( REG_LCD_STATE & LCD_STATE_IFU0 )
+#define __lcd_infifo1_underrun() ( REG_LCD_STATE & LCD_STATE_IFU1 )
+#define __lcd_outfifo_underrun() ( REG_LCD_STATE & LCD_STATE_OFU )
+#define __lcd_start_of_frame() ( REG_LCD_STATE & LCD_STATE_SOF )
+#define __lcd_end_of_frame() ( REG_LCD_STATE & LCD_STATE_EOF )
+
+#define __lcd_clr_outfifounderrun() ( REG_LCD_STATE &= ~LCD_STATE_OFU )
+#define __lcd_clr_sof() ( REG_LCD_STATE &= ~LCD_STATE_SOF )
+#define __lcd_clr_eof() ( REG_LCD_STATE &= ~LCD_STATE_EOF )
+
+#define __lcd_panel_white() ( REG_LCD_DEV |= LCD_DEV_WHITE )
+#define __lcd_panel_black() ( REG_LCD_DEV &= ~LCD_DEV_WHITE )
+
+/* n=1,2,4,8 for single mono-STN
+ * n=4,8 for dual mono-STN
+ */
+#define __lcd_set_panel_datawidth(n) \
+do { \
+ REG_LCD_DEV &= ~LCD_DEV_PDW_MASK; \
+ REG_LCD_DEV |= LCD_DEV_PDW_n##; \
+} while (0)
+
+/* m=LCD_DEV_MODE_GENERUIC_TFT_xxx */
+#define __lcd_set_panel_mode(m) \
+do { \
+ REG_LCD_DEV &= ~LCD_DEV_MODE_MASK; \
+ REG_LCD_DEV |= (m); \
+} while(0)
+
+/* n = 0-255 */
+#define __lcd_disable_ac_bias() ( REG_LCD_IO = 0xff )
+#define __lcd_set_ac_bias(n) \
+do { \
+ REG_LCD_IO &= ~LCD_IO_ACB_MASK; \
+ REG_LCD_IO |= ((n) << LCD_IO_ACB_BIT); \
+} while(0)
+
+#define __lcd_io_set_dir() ( REG_LCD_IO |= LCD_IO_DIR )
+#define __lcd_io_clr_dir() ( REG_LCD_IO &= ~LCD_IO_DIR )
+
+#define __lcd_io_set_dep() ( REG_LCD_IO |= LCD_IO_DEP )
+#define __lcd_io_clr_dep() ( REG_LCD_IO &= ~LCD_IO_DEP )
+
+#define __lcd_io_set_vsp() ( REG_LCD_IO |= LCD_IO_VSP )
+#define __lcd_io_clr_vsp() ( REG_LCD_IO &= ~LCD_IO_VSP )
+
+#define __lcd_io_set_hsp() ( REG_LCD_IO |= LCD_IO_HSP )
+#define __lcd_io_clr_hsp() ( REG_LCD_IO &= ~LCD_IO_HSP )
+
+#define __lcd_io_set_pcp() ( REG_LCD_IO |= LCD_IO_PCP )
+#define __lcd_io_clr_pcp() ( REG_LCD_IO &= ~LCD_IO_PCP )
+
+#define __lcd_vsync_get_vps() \
+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPS_MASK) >> LCD_VSYNC_VPS_BIT )
+
+#define __lcd_vsync_get_vpe() \
+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT )
+#define __lcd_vsync_set_vpe(n) \
+do { \
+ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \
+ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \
+} while (0)
+
+#define __lcd_hsync_get_hps() \
+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT )
+#define __lcd_hsync_set_hps(n) \
+do { \
+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \
+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \
+} while (0)
+
+#define __lcd_hsync_get_hpe() \
+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT )
+#define __lcd_hsync_set_hpe(n) \
+do { \
+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \
+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \
+} while (0)
+
+#define __lcd_vat_get_ht() \
+ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT )
+#define __lcd_vat_set_ht(n) \
+do { \
+ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \
+ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \
+} while (0)
+
+#define __lcd_vat_get_vt() \
+ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT )
+#define __lcd_vat_set_vt(n) \
+do { \
+ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \
+ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \
+} while (0)
+
+#define __lcd_dah_get_hds() \
+ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT )
+#define __lcd_dah_set_hds(n) \
+do { \
+ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \
+ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \
+} while (0)
+
+#define __lcd_dah_get_hde() \
+ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT )
+#define __lcd_dah_set_hde(n) \
+do { \
+ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \
+ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \
+} while (0)
+
+#define __lcd_dav_get_vds() \
+ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT )
+#define __lcd_dav_set_vds(n) \
+do { \
+ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \
+ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \
+} while (0)
+
+#define __lcd_dav_get_vde() \
+ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT )
+#define __lcd_dav_set_vde(n) \
+do { \
+ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \
+ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \
+} while (0)
+
+#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT )
+#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT )
+#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT )
+#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT )
+
+#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT )
+#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT )
+#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT )
+#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT )
+
+#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL )
+#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL )
+
+#define __lcd_cmd0_get_len() \
+ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT )
+#define __lcd_cmd1_get_len() \
+ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT )
+
+
+
+/***************************************************************************
+ * DES
+ ***************************************************************************/
+
+
+/***************************************************************************
+ * CPM
+ ***************************************************************************/
+#define __cpm_plcr1_fd() \
+ ((REG_CPM_PLCR1 & CPM_PLCR1_PLL1FD_MASK) >> CPM_PLCR1_PLL1FD_BIT)
+#define __cpm_plcr1_rd() \
+ ((REG_CPM_PLCR1 & CPM_PLCR1_PLL1RD_MASK) >> CPM_PLCR1_PLL1RD_BIT)
+#define __cpm_plcr1_od() \
+ ((REG_CPM_PLCR1 & CPM_PLCR1_PLL1OD_MASK) >> CPM_PLCR1_PLL1OD_BIT)
+#define __cpm_cfcr_mfr() \
+ ((REG_CPM_CFCR & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT)
+#define __cpm_cfcr_pfr() \
+ ((REG_CPM_CFCR & CPM_CFCR_PFR_MASK) >> CPM_CFCR_PFR_BIT)
+#define __cpm_cfcr_sfr() \
+ ((REG_CPM_CFCR & CPM_CFCR_SFR_MASK) >> CPM_CFCR_SFR_BIT)
+#define __cpm_cfcr_ifr() \
+ ((REG_CPM_CFCR & CPM_CFCR_IFR_MASK) >> CPM_CFCR_IFR_BIT)
+
+static __inline__ unsigned int __cpm_divisor_encode(unsigned int n)
+{
+ unsigned int encode[10] = {1,2,3,4,6,8,12,16,24,32};
+ int i;
+ for (i=0;i<10;i++)
+ if (n < encode[i])
+ break;
+ return i;
+}
+
+#define __cpm_set_mclk_div(n) \
+do { \
+ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_MFR_MASK) | \
+ ((n) << (CPM_CFCR_MFR_BIT)); \
+} while (0)
+
+#define __cpm_set_pclk_div(n) \
+do { \
+ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_PFR_MASK) | \
+ ((n) << (CPM_CFCR_PFR_BIT)); \
+} while (0)
+
+#define __cpm_set_sclk_div(n) \
+do { \
+ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_SFR_MASK) | \
+ ((n) << (CPM_CFCR_SFR_BIT)); \
+} while (0)
+
+#define __cpm_set_iclk_div(n) \
+do { \
+ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_IFR_MASK) | \
+ ((n) << (CPM_CFCR_IFR_BIT)); \
+} while (0)
+
+#define __cpm_set_lcdclk_div(n) \
+do { \
+ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_LFR_MASK) | \
+ ((n) << (CPM_CFCR_LFR_BIT)); \
+} while (0)
+
+#define __cpm_enable_cko1() (REG_CPM_CFCR |= CPM_CFCR_CKOEN1)
+#define __cpm_enable_cko2() (REG_CPM_CFCR |= CPM_CFCR_CKOEN2)
+#define __cpm_disable_cko1() (REG_CPM_CFCR &= ~CPM_CFCR_CKOEN1)
+#define __cpm_disable_cko2() (REG_CPM_CFCR &= ~CPM_CFCR_CKOEN2)
+
+#define __cpm_select_msc_clk(type) \
+do { \
+ if (type == 0) \
+ REG_CPM_CFCR &= ~CPM_CFCR_MSC; \
+ else \
+ REG_CPM_CFCR |= CPM_CFCR_MSC; \
+ REG_CPM_CFCR |= CPM_CFCR_UPE; \
+} while(0)
+
+#define __cpm_idle_mode() \
+ (REG_CPM_LPCR = (REG_CPM_LPCR & ~CPM_LPCR_LPM_MASK) | \
+ CPM_LPCR_LPM_IDLE)
+#define __cpm_sleep_mode() \
+ (REG_CPM_LPCR = (REG_CPM_LPCR & ~CPM_LPCR_LPM_MASK) | \
+ CPM_LPCR_LPM_SLEEP)
+#define __cpm_hibernate_mode() \
+ (REG_CPM_LPCR = (REG_CPM_LPCR & ~CPM_LPCR_LPM_MASK) | \
+ CPM_LPCR_LPM_HIBERNATE)
+
+#define __cpm_start_uart0() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UART0))
+#define __cpm_start_uart1() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UART1))
+#define __cpm_start_uart2() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UART2))
+#define __cpm_start_uart3() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UART3))
+#define __cpm_start_ost() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_OST))
+#define __cpm_start_dmac() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_DMAC))
+#define __cpm_start_uhc() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UHC))
+#define __cpm_start_lcd() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_LCD))
+#define __cpm_start_i2c() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_I2C))
+#define __cpm_start_aic_pclk() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_AICPCLK))
+#define __cpm_start_aic_bitclk() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_AICBCLK))
+#define __cpm_start_pwm0() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_PWM0))
+#define __cpm_start_pwm1() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_PWM1))
+#define __cpm_start_ssi() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_SSI))
+#define __cpm_start_msc() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_MSC))
+#define __cpm_start_scc() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_SCC))
+#define __cpm_start_eth() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_ETH))
+#define __cpm_start_kbc() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_KBC))
+#define __cpm_start_cim() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_CIM))
+#define __cpm_start_udc() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UDC))
+#define __cpm_start_uprt() \
+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UPRT))
+#define __cpm_start_all() (REG_CPM_MSCR = 0)
+
+#define __cpm_stop_uart0() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UART0))
+#define __cpm_stop_uart1() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UART1))
+#define __cpm_stop_uart2() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UART2))
+#define __cpm_stop_uart3() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UART3))
+#define __cpm_stop_ost() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_OST))
+#define __cpm_stop_dmac() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_DMAC))
+#define __cpm_stop_uhc() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UHC))
+#define __cpm_stop_lcd() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_LCD))
+#define __cpm_stop_i2c() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_I2C))
+#define __cpm_stop_aic_pclk() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_AICPCLK))
+#define __cpm_stop_aic_bitclk() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_AICBCLK))
+#define __cpm_stop_pwm0() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_PWM0))
+#define __cpm_stop_pwm1() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_PWM1))
+#define __cpm_stop_ssi() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_SSI))
+#define __cpm_stop_msc() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_MSC))
+#define __cpm_stop_scc() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_SCC))
+#define __cpm_stop_eth() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_ETH))
+#define __cpm_stop_kbc() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_KBC))
+#define __cpm_stop_cim() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_CIM))
+#define __cpm_stop_udc() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UDC))
+#define __cpm_stop_uprt() \
+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UPRT))
+#define __cpm_stop_all() (REG_CPM_MSCR = 0xffffffff)
+
+#define __cpm_set_pin(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ if (p == 0) \
+ REG_CPM_GSR0 |= (1 << o); \
+ else if (p == 1) \
+ REG_CPM_GSR1 |= (1 << o); \
+ else if (p == 2) \
+ REG_CPM_GSR2 |= (1 << o); \
+ else if (p == 3) \
+ REG_CPM_GSR3 |= (1 << o); \
+} while (0)
+
+#define __cpm_clear_pin(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ if (p == 0) \
+ REG_CPM_GSR0 &= ~(1 << o); \
+ else if (p == 1) \
+ REG_CPM_GSR1 &= ~(1 << o); \
+ else if (p == 2) \
+ REG_CPM_GSR2 &= ~(1 << o); \
+ else if (p == 3) \
+ REG_CPM_GSR3 &= ~(1 << o); \
+} while (0)
+
+
+/***************************************************************************
+ * SSI
+ ***************************************************************************/
+
+#define __ssi_enable() ( REG_SSI_CR0 |= SSI_CR0_SSIE )
+#define __ssi_disable() ( REG_SSI_CR0 &= ~SSI_CR0_SSIE )
+#define __ssi_select_ce() ( REG_SSI_CR0 &= ~SSI_CR0_FSEL )
+
+#define __ssi_normal_mode() ( REG_SSI_ITR &= ~SSI_ITR_IVLTM_MASK )
+
+#define __ssi_select_ce2() \
+do { \
+ REG_SSI_CR0 |= SSI_CR0_FSEL; \
+ REG_SSI_CR1 &= ~SSI_CR1_MULTS; \
+} while (0)
+
+#define __ssi_select_gpc() \
+do { \
+ REG_SSI_CR0 &= ~SSI_CR0_FSEL; \
+ REG_SSI_CR1 |= SSI_CR1_MULTS; \
+} while (0)
+
+#define __ssi_enable_tx_intr() \
+ ( REG_SSI_CR0 |= SSI_CR0_TIE | SSI_CR0_TEIE )
+
+#define __ssi_disable_tx_intr() \
+ ( REG_SSI_CR0 &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) )
+
+#define __ssi_enable_rx_intr() \
+ ( REG_SSI_CR0 |= SSI_CR0_RIE | SSI_CR0_REIE )
+
+#define __ssi_disable_rx_intr() \
+ ( REG_SSI_CR0 &= ~(SSI_CR0_RIE | SSI_CR0_REIE) )
+
+#define __ssi_enable_loopback() ( REG_SSI_CR0 |= SSI_CR0_LOOP )
+#define __ssi_disable_loopback() ( REG_SSI_CR0 &= ~SSI_CR0_LOOP )
+
+#define __ssi_enable_receive() ( REG_SSI_CR0 &= ~SSI_CR0_DISREV )
+#define __ssi_disable_receive() ( REG_SSI_CR0 |= SSI_CR0_DISREV )
+
+#define __ssi_finish_receive() \
+ ( REG_SSI_CR0 |= (SSI_CR0_RFINE | SSI_CR0_RFINC) )
+
+#define __ssi_disable_recvfinish() \
+ ( REG_SSI_CR0 &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) )
+
+#define __ssi_flush_txfifo() ( REG_SSI_CR0 |= SSI_CR0_TFLUSH )
+#define __ssi_flush_rxfifo() ( REG_SSI_CR0 |= SSI_CR0_RFLUSH )
+
+#define __ssi_flush_fifo() \
+ ( REG_SSI_CR0 |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH )
+
+#define __ssi_finish_transmit() ( REG_SSI_CR1 &= ~SSI_CR1_UNFIN )
+
+#define __ssi_spi_format() \
+do { \
+ REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \
+ REG_SSI_CR1 |= SSI_CR1_FMAT_SPI; \
+ REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\
+ REG_SSI_CR1 |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \
+} while (0)
+
+/* TI's SSP format, must clear SSI_CR1.UNFIN */
+#define __ssi_ssp_format() \
+do { \
+ REG_SSI_CR1 &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \
+ REG_SSI_CR1 |= SSI_CR1_FMAT_SSP; \
+} while (0)
+
+/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */
+#define __ssi_microwire_format() \
+do { \
+ REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \
+ REG_SSI_CR1 |= SSI_CR1_FMAT_MW1; \
+ REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\
+ REG_SSI_CR1 |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \
+ REG_SSI_CR0 &= ~SSI_CR0_RFINE; \
+} while (0)
+
+/* CE# level (FRMHL), CE# in interval time (ITFRM),
+ clock phase and polarity (PHA POL),
+ interval time (SSIITR), interval characters/frame (SSIICR) */
+
+ /* frmhl,endian,mcom,flen,pha,pol MASK */
+#define SSICR1_MISC_MASK \
+ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \
+ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL ) \
+
+#define __ssi_spi_set_misc(frmhl,endian,flen,mcom,pha,pol) \
+do { \
+ REG_SSI_CR1 &= ~SSICR1_MISC_MASK; \
+ REG_SSI_CR1 |= ((frmhl) << 30) | ((endian) << 25) | \
+ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \
+ ((pha) << 1) | (pol); \
+} while(0)
+
+/* Transfer with MSB or LSB first */
+#define __ssi_set_msb() ( REG_SSI_CR1 &= ~SSI_CR1_LFST )
+#define __ssi_set_lsb() ( REG_SSI_CR1 |= SSI_CR1_LFST )
+
+#define __ssi_set_frame_length(n) \
+ REG_SSI_CR1 = (REG_SSI_CR1 & ~SSI_CR1_FLEN_MASK) | (((n) - 2) << 4)
+
+/* n = 1 - 16 */
+#define __ssi_set_microwire_command_length(n) \
+ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##n##BIT) )
+
+/* Set the clock phase for SPI */
+#define __ssi_set_spi_clock_phase(n) \
+ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_PHA) | ((n&0x1) << 1 )))
+
+/* Set the clock polarity for SPI */
+#define __ssi_set_spi_clock_polarity(n) \
+ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_POL) | ((n&0x1) << 0 )))
+
+/* n = 1,4,8,14 */
+#define __ssi_set_tx_trigger(n) \
+do { \
+ REG_SSI_CR1 &= ~SSI_CR1_TTRG_MASK; \
+ REG_SSI_CR1 |= SSI_CR1_TTRG_##n; \
+} while (0)
+
+/* n = 1,4,8,14 */
+#define __ssi_set_rx_trigger(n) \
+do { \
+ REG_SSI_CR1 &= ~SSI_CR1_RTRG_MASK; \
+ REG_SSI_CR1 |= SSI_CR1_RTRG_##n; \
+} while (0)
+
+#define __ssi_get_txfifo_count() \
+ ( (REG_SSI_SR & SSI_SR_TFIFONUM_MASK) >> SSI_SR_TFIFONUM_BIT )
+
+#define __ssi_get_rxfifo_count() \
+ ( (REG_SSI_SR & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT )
+
+#define __ssi_clear_errors() \
+ ( REG_SSI_SR &= ~(SSI_SR_UNDR | SSI_SR_OVER) )
+
+#define __ssi_transfer_end() ( REG_SSI_SR & SSI_SR_END )
+#define __ssi_is_busy() ( REG_SSI_SR & SSI_SR_BUSY )
+
+#define __ssi_txfifo_full() ( REG_SSI_SR & SSI_SR_TFF )
+#define __ssi_rxfifo_empty() ( REG_SSI_SR & SSI_SR_RFE )
+#define __ssi_rxfifo_noempty() ( REG_SSI_SR & SSI_SR_RFHF )
+#define __ssi_rxfifo_half_full() ( REG_SSI_SR & SSI_SR_RFHF )
+#define __ssi_txfifo_half_empty() ( REG_SSI_SR & SSI_SR_TFHE )
+#define __ssi_underrun() ( REG_SSI_SR & SSI_SR_UNDR )
+#define __ssi_overrun() ( REG_SSI_SR & SSI_SR_OVER )
+
+#define __ssi_set_clk(dev_clk, ssi_clk) \
+ ( REG_SSI_GR = (dev_clk) / (2*(ssi_clk)) - 1 )
+
+#define __ssi_receive_data() REG_SSI_DR
+#define __ssi_transmit_data(v) ( REG_SSI_DR = (v) )
+
+#endif /* __ASM_JZ4730_OPS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4730/regs.h b/arch/mips/include/asm/mach-jz4730/regs.h
new file mode 100644
index 00000000000..86bde917888
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4730/regs.h
@@ -0,0 +1,2550 @@
+/*
+ * linux/include/asm-mips/mach-jz4730/regs.h
+ *
+ * JZ4730 registers definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4730_REGS_H__
+#define __ASM_JZ4730_REGS_H__
+
+#if defined(__ASSEMBLY__) || defined(__LANGUAGE_ASSEMBLY)
+#define REG8(addr) (addr)
+#define REG16(addr) (addr)
+#define REG32(addr) (addr)
+#else
+#define REG8(addr) *((volatile unsigned char *)(addr))
+#define REG16(addr) *((volatile unsigned short *)(addr))
+#define REG32(addr) *((volatile unsigned int *)(addr))
+#endif
+
+#define HARB_BASE 0xB3000000
+#define EMC_BASE 0xB3010000
+#define DMAC_BASE 0xB3020000
+#define UHC_BASE 0xB3030000
+#define UDC_BASE 0xB3040000
+#define LCD_BASE 0xB3050000
+#define CIM_BASE 0xB3060000
+#define ETH_BASE 0xB3100000
+#define NBM_BASE 0xB3F00000
+
+#define CPM_BASE 0xB0000000
+#define INTC_BASE 0xB0001000
+#define OST_BASE 0xB0002000
+#define RTC_BASE 0xB0003000
+#define WDT_BASE 0xB0004000
+#define GPIO_BASE 0xB0010000
+#define AIC_BASE 0xB0020000
+#define MSC_BASE 0xB0021000
+#define UART0_BASE 0xB0030000
+#define UART1_BASE 0xB0031000
+#define UART2_BASE 0xB0032000
+#define UART3_BASE 0xB0033000
+#define FIR_BASE 0xB0040000
+#define SCC_BASE 0xB0041000
+#define SCC0_BASE 0xB0041000
+#define I2C_BASE 0xB0042000
+#define SSI_BASE 0xB0043000
+#define SCC1_BASE 0xB0044000
+#define PWM0_BASE 0xB0050000
+#define PWM1_BASE 0xB0051000
+#define DES_BASE 0xB0060000
+#define UPRT_BASE 0xB0061000
+#define KBC_BASE 0xB0062000
+
+
+
+
+/*************************************************************************
+ * MSC
+ *************************************************************************/
+#define MSC_STRPCL (MSC_BASE + 0x000)
+#define MSC_STAT (MSC_BASE + 0x004)
+#define MSC_CLKRT (MSC_BASE + 0x008)
+#define MSC_CMDAT (MSC_BASE + 0x00C)
+#define MSC_RESTO (MSC_BASE + 0x010)
+#define MSC_RDTO (MSC_BASE + 0x014)
+#define MSC_BLKLEN (MSC_BASE + 0x018)
+#define MSC_NOB (MSC_BASE + 0x01C)
+#define MSC_SNOB (MSC_BASE + 0x020)
+#define MSC_IMASK (MSC_BASE + 0x024)
+#define MSC_IREG (MSC_BASE + 0x028)
+#define MSC_CMD (MSC_BASE + 0x02C)
+#define MSC_ARG (MSC_BASE + 0x030)
+#define MSC_RES (MSC_BASE + 0x034)
+#define MSC_RXFIFO (MSC_BASE + 0x038)
+#define MSC_TXFIFO (MSC_BASE + 0x03C)
+
+#define REG_MSC_STRPCL REG16(MSC_STRPCL)
+#define REG_MSC_STAT REG32(MSC_STAT)
+#define REG_MSC_CLKRT REG16(MSC_CLKRT)
+#define REG_MSC_CMDAT REG32(MSC_CMDAT)
+#define REG_MSC_RESTO REG16(MSC_RESTO)
+#define REG_MSC_RDTO REG16(MSC_RDTO)
+#define REG_MSC_BLKLEN REG16(MSC_BLKLEN)
+#define REG_MSC_NOB REG16(MSC_NOB)
+#define REG_MSC_SNOB REG16(MSC_SNOB)
+#define REG_MSC_IMASK REG16(MSC_IMASK)
+#define REG_MSC_IREG REG16(MSC_IREG)
+#define REG_MSC_CMD REG8(MSC_CMD)
+#define REG_MSC_ARG REG32(MSC_ARG)
+#define REG_MSC_RES REG16(MSC_RES)
+#define REG_MSC_RXFIFO REG32(MSC_RXFIFO)
+#define REG_MSC_TXFIFO REG32(MSC_TXFIFO)
+
+/* MSC Clock and Control Register (MSC_STRPCL) */
+
+#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7)
+#define MSC_STRPCL_EXIT_TRANSFER (1 << 6)
+#define MSC_STRPCL_START_READWAIT (1 << 5)
+#define MSC_STRPCL_STOP_READWAIT (1 << 4)
+#define MSC_STRPCL_RESET (1 << 3)
+#define MSC_STRPCL_START_OP (1 << 2)
+#define MSC_STRPCL_CLOCK_CONTROL_BIT 0
+#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT)
+ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */
+ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */
+
+/* MSC Status Register (MSC_STAT) */
+
+#define MSC_STAT_IS_RESETTING (1 << 15)
+#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14)
+#define MSC_STAT_PRG_DONE (1 << 13)
+#define MSC_STAT_DATA_TRAN_DONE (1 << 12)
+#define MSC_STAT_END_CMD_RES (1 << 11)
+#define MSC_STAT_DATA_FIFO_AFULL (1 << 10)
+#define MSC_STAT_IS_READWAIT (1 << 9)
+#define MSC_STAT_CLK_EN (1 << 8)
+#define MSC_STAT_DATA_FIFO_FULL (1 << 7)
+#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6)
+#define MSC_STAT_CRC_RES_ERR (1 << 5)
+#define MSC_STAT_CRC_READ_ERROR (1 << 4)
+#define MSC_STAT_CRC_WRITE_ERROR_BIT 2
+#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT)
+ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */
+ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */
+ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */
+#define MSC_STAT_TIME_OUT_RES (1 << 1)
+#define MSC_STAT_TIME_OUT_READ (1 << 0)
+
+/* MSC Bus Clock Control Register (MSC_CLKRT) */
+
+#define MSC_CLKRT_CLK_RATE_BIT 0
+#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT)
+ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */
+
+/* MSC Command Sequence Control Register (MSC_CMDAT) */
+
+#define MSC_CMDAT_IO_ABORT (1 << 11)
+#define MSC_CMDAT_BUS_WIDTH_BIT 9
+#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT)
+ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */
+ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */
+ #define CMDAT_BUS_WIDTH1 (0x0 << MSC_CMDAT_BUS_WIDTH_BIT)
+ #define CMDAT_BUS_WIDTH4 (0x2 << MSC_CMDAT_BUS_WIDTH_BIT)
+#define MSC_CMDAT_DMA_EN (1 << 8)
+#define MSC_CMDAT_INIT (1 << 7)
+#define MSC_CMDAT_BUSY (1 << 6)
+#define MSC_CMDAT_STREAM_BLOCK (1 << 5)
+#define MSC_CMDAT_WRITE (1 << 4)
+#define MSC_CMDAT_READ (0 << 4)
+#define MSC_CMDAT_DATA_EN (1 << 3)
+#define MSC_CMDAT_RESPONSE_BIT 0
+#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT)
+ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */
+ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */
+ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */
+ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */
+ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */
+ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */
+ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */
+
+#define CMDAT_DMA_EN (1 << 8)
+#define CMDAT_INIT (1 << 7)
+#define CMDAT_BUSY (1 << 6)
+#define CMDAT_STREAM (1 << 5)
+#define CMDAT_WRITE (1 << 4)
+#define CMDAT_DATA_EN (1 << 3)
+
+/* MSC Interrupts Mask Register (MSC_IMASK) */
+
+#define MSC_IMASK_SDIO (1 << 7)
+#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6)
+#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5)
+#define MSC_IMASK_END_CMD_RES (1 << 2)
+#define MSC_IMASK_PRG_DONE (1 << 1)
+#define MSC_IMASK_DATA_TRAN_DONE (1 << 0)
+
+
+/* MSC Interrupts Status Register (MSC_IREG) */
+
+#define MSC_IREG_SDIO (1 << 7)
+#define MSC_IREG_TXFIFO_WR_REQ (1 << 6)
+#define MSC_IREG_RXFIFO_RD_REQ (1 << 5)
+#define MSC_IREG_END_CMD_RES (1 << 2)
+#define MSC_IREG_PRG_DONE (1 << 1)
+#define MSC_IREG_DATA_TRAN_DONE (1 << 0)
+
+
+
+
+/*************************************************************************
+ * RTC
+ *************************************************************************/
+#define RTC_RCR (RTC_BASE + 0x00)
+#define RTC_RSR (RTC_BASE + 0x04)
+#define RTC_RSAR (RTC_BASE + 0x08)
+#define RTC_RGR (RTC_BASE + 0x0c)
+
+#define REG_RTC_RCR REG32(RTC_RCR)
+#define REG_RTC_RSR REG32(RTC_RSR)
+#define REG_RTC_RSAR REG32(RTC_RSAR)
+#define REG_RTC_RGR REG32(RTC_RGR)
+
+#define RTC_RCR_HZ (1 << 6)
+#define RTC_RCR_HZIE (1 << 5)
+#define RTC_RCR_AF (1 << 4)
+#define RTC_RCR_AIE (1 << 3)
+#define RTC_RCR_AE (1 << 2)
+#define RTC_RCR_START (1 << 0)
+
+#define RTC_RGR_LOCK (1 << 31)
+#define RTC_RGR_ADJ_BIT 16
+#define RTC_RGR_ADJ_MASK (0x3ff << RTC_RGR_ADJ_BIT)
+#define RTC_RGR_DIV_BIT 0
+#define RTC_REG_DIV_MASK (0xff << RTC_RGR_DIV_BIT)
+
+
+
+
+/*************************************************************************
+ * FIR
+ *************************************************************************/
+#define FIR_TDR (FIR_BASE + 0x000)
+#define FIR_RDR (FIR_BASE + 0x004)
+#define FIR_TFLR (FIR_BASE + 0x008)
+#define FIR_AR (FIR_BASE + 0x00C)
+#define FIR_CR1 (FIR_BASE + 0x010)
+#define FIR_CR2 (FIR_BASE + 0x014)
+#define FIR_SR (FIR_BASE + 0x018)
+
+#define REG_FIR_TDR REG8(FIR_TDR)
+#define REG_FIR_RDR REG8(FIR_RDR)
+#define REG_FIR_TFLR REG16(FIR_TFLR)
+#define REG_FIR_AR REG8(FIR_AR)
+#define REG_FIR_CR1 REG8(FIR_CR1)
+#define REG_FIR_CR2 REG16(FIR_CR2)
+#define REG_FIR_SR REG16(FIR_SR)
+
+/* FIR Control Register 1 (FIR_CR1) */
+
+#define FIR_CR1_FIRUE (1 << 7)
+#define FIR_CR1_ACE (1 << 6)
+#define FIR_CR1_EOUS (1 << 5)
+#define FIR_CR1_TIIE (1 << 4)
+#define FIR_CR1_TFIE (1 << 3)
+#define FIR_CR1_RFIE (1 << 2)
+#define FIR_CR1_TXE (1 << 1)
+#define FIR_CR1_RXE (1 << 0)
+
+/* FIR Control Register 2 (FIR_CR2) */
+
+#define FIR_CR2_SIPE (1 << 10)
+#define FIR_CR2_BCRC (1 << 9)
+#define FIR_CR2_TFLRS (1 << 8)
+#define FIR_CR2_ISS (1 << 7)
+#define FIR_CR2_LMS (1 << 6)
+#define FIR_CR2_TPPS (1 << 5)
+#define FIR_CR2_RPPS (1 << 4)
+#define FIR_CR2_TTRG_BIT 2
+#define FIR_CR2_TTRG_MASK (0x3 << FIR_CR2_TTRG_BIT)
+ #define FIR_CR2_TTRG_16 (0 << FIR_CR2_TTRG_BIT) /* Transmit Trigger Level is 16 */
+ #define FIR_CR2_TTRG_32 (1 << FIR_CR2_TTRG_BIT) /* Transmit Trigger Level is 32 */
+ #define FIR_CR2_TTRG_64 (2 << FIR_CR2_TTRG_BIT) /* Transmit Trigger Level is 64 */
+ #define FIR_CR2_TTRG_128 (3 << FIR_CR2_TTRG_BIT) /* Transmit Trigger Level is 128 */
+#define FIR_CR2_RTRG_BIT 0
+#define FIR_CR2_RTRG_MASK (0x3 << FIR_CR2_RTRG_BIT)
+ #define FIR_CR2_RTRG_16 (0 << FIR_CR2_RTRG_BIT) /* Receive Trigger Level is 16 */
+ #define FIR_CR2_RTRG_32 (1 << FIR_CR2_RTRG_BIT) /* Receive Trigger Level is 32 */
+ #define FIR_CR2_RTRG_64 (2 << FIR_CR2_RTRG_BIT) /* Receive Trigger Level is 64 */
+ #define FIR_CR2_RTRG_128 (3 << FIR_CR2_RTRG_BIT) /* Receive Trigger Level is 128 */
+
+/* FIR Status Register (FIR_SR) */
+
+#define FIR_SR_RFW (1 << 12)
+#define FIR_SR_RFA (1 << 11)
+#define FIR_SR_TFRTL (1 << 10)
+#define FIR_SR_RFRTL (1 << 9)
+#define FIR_SR_URUN (1 << 8)
+#define FIR_SR_RFTE (1 << 7)
+#define FIR_SR_ORUN (1 << 6)
+#define FIR_SR_CRCE (1 << 5)
+#define FIR_SR_FEND (1 << 4)
+#define FIR_SR_TFF (1 << 3)
+#define FIR_SR_RFE (1 << 2)
+#define FIR_SR_TIDLE (1 << 1)
+#define FIR_SR_RB (1 << 0)
+
+
+
+
+/*************************************************************************
+ * SCC
+ *************************************************************************/
+#define SCC_DR(base) ((base) + 0x000)
+#define SCC_FDR(base) ((base) + 0x004)
+#define SCC_CR(base) ((base) + 0x008)
+#define SCC1_CR(base) ((base) + 0x008)
+#define SCC_SR(base) ((base) + 0x00C)
+#define SCC_TFR(base) ((base) + 0x010)
+#define SCC_EGTR(base) ((base) + 0x014)
+#define SCC_ECR(base) ((base) + 0x018)
+#define SCC_RTOR(base) ((base) + 0x01C)
+
+#define REG_SCC_DR(base) REG8(SCC_DR(base))
+#define REG_SCC_FDR(base) REG8(SCC_FDR(base))
+#define REG_SCC_CR(base) REG32(SCC_CR(base))
+#define REG_SCC1_CR(base) REG32(SCC1_CR(base))
+#define REG_SCC_SR(base) REG16(SCC_SR(base))
+#define REG_SCC_TFR(base) REG16(SCC_TFR(base))
+#define REG_SCC_EGTR(base) REG8(SCC_EGTR(base))
+#define REG_SCC_ECR(base) REG32(SCC_ECR(base))
+#define REG_SCC_RTOR(base) REG8(SCC_RTOR(base))
+
+/* SCC FIFO Data Count Register (SCC_FDR) */
+
+#define SCC_FDR_EMPTY 0x00
+#define SCC_FDR_FULL 0x10
+
+/* SCC Control Register (SCC_CR) */
+
+#define SCC_CR_SCCE (1 << 31)
+#define SCC_CR_TRS (1 << 30)
+#define SCC_CR_T2R (1 << 29)
+#define SCC_CR_FDIV_BIT 24
+#define SCC_CR_FDIV_MASK (0x3 << SCC_CR_FDIV_BIT)
+ #define SCC_CR_FDIV_1 (0 << SCC_CR_FDIV_BIT) /* SCC_CLK frequency is the same as device clock */
+ #define SCC_CR_FDIV_2 (1 << SCC_CR_FDIV_BIT) /* SCC_CLK frequency is half of device clock */
+#define SCC_CR_FLUSH (1 << 23)
+#define SCC_CR_TRIG_BIT 16
+#define SCC_CR_TRIG_MASK (0x3 << SCC_CR_TRIG_BIT)
+ #define SCC_CR_TRIG_1 (0 << SCC_CR_TRIG_BIT) /* Receive/Transmit-FIFO Trigger is 1 */
+ #define SCC_CR_TRIG_4 (1 << SCC_CR_TRIG_BIT) /* Receive/Transmit-FIFO Trigger is 4 */
+ #define SCC_CR_TRIG_8 (2 << SCC_CR_TRIG_BIT) /* Receive/Transmit-FIFO Trigger is 8 */
+ #define SCC_CR_TRIG_14 (3 << SCC_CR_TRIG_BIT) /* Receive/Transmit-FIFO Trigger is 14 */
+#define SCC_CR_TP (1 << 15)
+#define SCC_CR_CONV (1 << 14)
+#define SCC_CR_TXIE (1 << 13)
+#define SCC_CR_RXIE (1 << 12)
+#define SCC_CR_TENDIE (1 << 11)
+#define SCC_CR_RTOIE (1 << 10)
+#define SCC_CR_ECIE (1 << 9)
+#define SCC_CR_EPIE (1 << 8)
+#define SCC_CR_RETIE (1 << 7)
+#define SCC_CR_EOIE (1 << 6)
+#define SCC_CR_TSEND (1 << 3)
+#define SCC_CR_PX_BIT 1
+#define SCC_CR_PX_MASK (0x3 << SCC_CR_PX_BIT)
+ #define SCC_CR_PX_NOT_SUPPORT (0 << SCC_CR_PX_BIT) /* SCC does not support clock stop */
+ #define SCC_CR_PX_STOP_LOW (1 << SCC_CR_PX_BIT) /* SCC_CLK stops at state low */
+ #define SCC_CR_PX_STOP_HIGH (2 << SCC_CR_PX_BIT) /* SCC_CLK stops at state high */
+#define SCC_CR_CLKSTP (1 << 0)
+
+/* SCC Status Register (SCC_SR) */
+
+#define SCC_SR_TRANS (1 << 15)
+#define SCC_SR_ORER (1 << 12)
+#define SCC_SR_RTO (1 << 11)
+#define SCC_SR_PER (1 << 10)
+#define SCC_SR_TFTG (1 << 9)
+#define SCC_SR_RFTG (1 << 8)
+#define SCC_SR_TEND (1 << 7)
+#define SCC_SR_RETR_3 (1 << 4)
+#define SCC_SR_ECNTO (1 << 0)
+
+
+
+
+/*************************************************************************
+ * ETH
+ *************************************************************************/
+#define ETH_BMR (ETH_BASE + 0x1000)
+#define ETH_TPDR (ETH_BASE + 0x1004)
+#define ETH_RPDR (ETH_BASE + 0x1008)
+#define ETH_RAR (ETH_BASE + 0x100C)
+#define ETH_TAR (ETH_BASE + 0x1010)
+#define ETH_SR (ETH_BASE + 0x1014)
+#define ETH_CR (ETH_BASE + 0x1018)
+#define ETH_IER (ETH_BASE + 0x101C)
+#define ETH_MFCR (ETH_BASE + 0x1020)
+#define ETH_CTAR (ETH_BASE + 0x1050)
+#define ETH_CRAR (ETH_BASE + 0x1054)
+#define ETH_MCR (ETH_BASE + 0x0000)
+#define ETH_MAHR (ETH_BASE + 0x0004)
+#define ETH_MALR (ETH_BASE + 0x0008)
+#define ETH_HTHR (ETH_BASE + 0x000C)
+#define ETH_HTLR (ETH_BASE + 0x0010)
+#define ETH_MIAR (ETH_BASE + 0x0014)
+#define ETH_MIDR (ETH_BASE + 0x0018)
+#define ETH_FCR (ETH_BASE + 0x001C)
+#define ETH_VTR1 (ETH_BASE + 0x0020)
+#define ETH_VTR2 (ETH_BASE + 0x0024)
+#define ETH_WKFR (ETH_BASE + 0x0028)
+#define ETH_PMTR (ETH_BASE + 0x002C)
+
+#define REG_ETH_BMR REG32(ETH_BMR)
+#define REG_ETH_TPDR REG32(ETH_TPDR)
+#define REG_ETH_RPDR REG32(ETH_RPDR)
+#define REG_ETH_RAR REG32(ETH_RAR)
+#define REG_ETH_TAR REG32(ETH_TAR)
+#define REG_ETH_SR REG32(ETH_SR)
+#define REG_ETH_CR REG32(ETH_CR)
+#define REG_ETH_IER REG32(ETH_IER)
+#define REG_ETH_MFCR REG32(ETH_MFCR)
+#define REG_ETH_CTAR REG32(ETH_CTAR)
+#define REG_ETH_CRAR REG32(ETH_CRAR)
+#define REG_ETH_MCR REG32(ETH_MCR)
+#define REG_ETH_MAHR REG32(ETH_MAHR)
+#define REG_ETH_MALR REG32(ETH_MALR)
+#define REG_ETH_HTHR REG32(ETH_HTHR)
+#define REG_ETH_HTLR REG32(ETH_HTLR)
+#define REG_ETH_MIAR REG32(ETH_MIAR)
+#define REG_ETH_MIDR REG32(ETH_MIDR)
+#define REG_ETH_FCR REG32(ETH_FCR)
+#define REG_ETH_VTR1 REG32(ETH_VTR1)
+#define REG_ETH_VTR2 REG32(ETH_VTR2)
+#define REG_ETH_WKFR REG32(ETH_WKFR)
+#define REG_ETH_PMTR REG32(ETH_PMTR)
+
+/* Bus Mode Register (ETH_BMR) */
+
+#define ETH_BMR_DBO (1 << 20)
+#define ETH_BMR_PBL_BIT 8
+#define ETH_BMR_PBL_MASK (0x3f << ETH_BMR_PBL_BIT)
+ #define ETH_BMR_PBL_1 (0x1 << ETH_BMR_PBL_BIT)
+ #define ETH_BMR_PBL_4 (0x4 << ETH_BMR_PBL_BIT)
+#define ETH_BMR_BLE (1 << 7)
+#define ETH_BMR_DSL_BIT 2
+#define ETH_BMR_DSL_MASK (0x1f << ETH_BMR_DSL_BIT)
+ #define ETH_BMR_DSL_0 (0x0 << ETH_BMR_DSL_BIT)
+ #define ETH_BMR_DSL_1 (0x1 << ETH_BMR_DSL_BIT)
+ #define ETH_BMR_DSL_2 (0x2 << ETH_BMR_DSL_BIT)
+ #define ETH_BMR_DSL_4 (0x4 << ETH_BMR_DSL_BIT)
+ #define ETH_BMR_DSL_8 (0x8 << ETH_BMR_DSL_BIT)
+#define ETH_BMR_SWR (1 << 0)
+
+/* DMA Status Register (ETH_SR) */
+
+#define ETH_SR_EB_BIT 23
+#define ETH_SR_EB_MASK (0x7 << ETH_SR_EB_BIT)
+ #define ETH_SR_EB_TX_ABORT (0x1 << ETH_SR_EB_BIT)
+ #define ETH_SR_EB_RX_ABORT (0x2 << ETH_SR_EB_BIT)
+#define ETH_SR_TS_BIT 20
+#define ETH_SR_TS_MASK (0x7 << ETH_SR_TS_BIT)
+ #define ETH_SR_TS_STOP (0x0 << ETH_SR_TS_BIT)
+ #define ETH_SR_TS_FTD (0x1 << ETH_SR_TS_BIT)
+ #define ETH_SR_TS_WEOT (0x2 << ETH_SR_TS_BIT)
+ #define ETH_SR_TS_QDAT (0x3 << ETH_SR_TS_BIT)
+ #define ETH_SR_TS_SUSPEND (0x6 << ETH_SR_TS_BIT)
+ #define ETH_SR_TS_CTD (0x7 << ETH_SR_TS_BIT)
+#define ETH_SR_RS_BIT 17
+#define ETH_SR_RS_MASK (0x7 << ETH_SR_RS_BIT)
+ #define ETH_SR_RS_STOP (0x0 << ETH_SR_RS_BIT)
+ #define ETH_SR_RS_FRD (0x1 << ETH_SR_RS_BIT)
+ #define ETH_SR_RS_CEOR (0x2 << ETH_SR_RS_BIT)
+ #define ETH_SR_RS_WRP (0x3 << ETH_SR_RS_BIT)
+ #define ETH_SR_RS_SUSPEND (0x4 << ETH_SR_RS_BIT)
+ #define ETH_SR_RS_CRD (0x5 << ETH_SR_RS_BIT)
+ #define ETH_SR_RS_FCF (0x6 << ETH_SR_RS_BIT)
+ #define ETH_SR_RS_QRF (0x7 << ETH_SR_RS_BIT)
+#define ETH_SR_NIS (1 << 16)
+#define ETH_SR_AIS (1 << 15)
+#define ETH_SR_ERI (1 << 14)
+#define ETH_SR_FBE (1 << 13)
+#define ETH_SR_ETI (1 << 10)
+#define ETH_SR_RWT (1 << 9)
+#define ETH_SR_RPS (1 << 8)
+#define ETH_SR_RU (1 << 7)
+#define ETH_SR_RI (1 << 6)
+#define ETH_SR_UNF (1 << 5)
+#define ETH_SR_TJT (1 << 3)
+#define ETH_SR_TU (1 << 2)
+#define ETH_SR_TPS (1 << 1)
+#define ETH_SR_TI (1 << 0)
+
+/* Control (Operation Mode) Register (ETH_CR) */
+
+#define ETH_CR_TTM (1 << 22)
+#define ETH_CR_SF (1 << 21)
+#define ETH_CR_TR_BIT 14
+#define ETH_CR_TR_MASK (0x3 << ETH_CR_TR_BIT)
+#define ETH_CR_ST (1 << 13)
+#define ETH_CR_OSF (1 << 2)
+#define ETH_CR_SR (1 << 1)
+
+/* Interrupt Enable Register (ETH_IER) */
+
+#define ETH_IER_NI (1 << 16)
+#define ETH_IER_AI (1 << 15)
+#define ETH_IER_ERE (1 << 14)
+#define ETH_IER_FBE (1 << 13)
+#define ETH_IER_ET (1 << 10)
+#define ETH_IER_RWE (1 << 9)
+#define ETH_IER_RS (1 << 8)
+#define ETH_IER_RU (1 << 7)
+#define ETH_IER_RI (1 << 6)
+#define ETH_IER_UN (1 << 5)
+#define ETH_IER_TJ (1 << 3)
+#define ETH_IER_TU (1 << 2)
+#define ETH_IER_TS (1 << 1)
+#define ETH_IER_TI (1 << 0)
+
+/* Missed Frame and Buffer Overflow Counter Register (ETH_MFCR) */
+
+#define ETH_MFCR_OVERFLOW_BIT 17
+#define ETH_MFCR_OVERFLOW_MASK (0x7ff << ETH_MFCR_OVERFLOW_BIT)
+#define ETH_MFCR_MFC_BIT 0
+#define ETH_MFCR_MFC_MASK (0xffff << ETH_MFCR_MFC_BIT)
+
+/* MAC Control Register (ETH_MCR) */
+
+#define ETH_MCR_RA (1 << 31)
+#define ETH_MCR_HBD (1 << 28)
+#define ETH_MCR_PS (1 << 27)
+#define ETH_MCR_DRO (1 << 23)
+#define ETH_MCR_OM_BIT 21
+#define ETH_MCR_OM_MASK (0x3 << ETH_MCR_OM_BIT)
+ #define ETH_MCR_OM_NORMAL (0x0 << ETH_MCR_OM_BIT)
+ #define ETH_MCR_OM_INTERNAL (0x1 << ETH_MCR_OM_BIT)
+ #define ETH_MCR_OM_EXTERNAL (0x2 << ETH_MCR_OM_BIT)
+#define ETH_MCR_F (1 << 20)
+#define ETH_MCR_PM (1 << 19)
+#define ETH_MCR_PR (1 << 18)
+#define ETH_MCR_IF (1 << 17)
+#define ETH_MCR_PB (1 << 16)
+#define ETH_MCR_HO (1 << 15)
+#define ETH_MCR_HP (1 << 13)
+#define ETH_MCR_LCC (1 << 12)
+#define ETH_MCR_DBF (1 << 11)
+#define ETH_MCR_DTRY (1 << 10)
+#define ETH_MCR_ASTP (1 << 8)
+#define ETH_MCR_BOLMT_BIT 6
+#define ETH_MCR_BOLMT_MASK (0x3 << ETH_MCR_BOLMT_BIT)
+ #define ETH_MCR_BOLMT_10 (0 << ETH_MCR_BOLMT_BIT)
+ #define ETH_MCR_BOLMT_8 (1 << ETH_MCR_BOLMT_BIT)
+ #define ETH_MCR_BOLMT_4 (2 << ETH_MCR_BOLMT_BIT)
+ #define ETH_MCR_BOLMT_1 (3 << ETH_MCR_BOLMT_BIT)
+#define ETH_MCR_DC (1 << 5)
+#define ETH_MCR_TE (1 << 3)
+#define ETH_MCR_RE (1 << 2)
+
+/* MII Address Register (ETH_MIAR) */
+
+#define ETH_MIAR_PHY_ADDR_BIT 11
+#define ETH_MIAR_PHY_ADDR_MASK (0x1f << ETH_MIAR_PHY_ADDR_BIT)
+#define ETH_MIAR_MII_REG_BIT 6
+#define ETH_MIAR_MII_REG_MASK (0x1f << ETH_MIAR_MII_REG_BIT)
+#define ETH_MIAR_MII_WRITE (1 << 1)
+#define ETH_MIAR_MII_BUSY (1 << 0)
+
+/* Flow Control Register (ETH_FCR) */
+
+#define ETH_FCR_PAUSE_TIME_BIT 16
+#define ETH_FCR_PAUSE_TIME_MASK (0xffff << ETH_FCR_PAUSE_TIME_BIT)
+#define ETH_FCR_PCF (1 << 2)
+#define ETH_FCR_FCE (1 << 1)
+#define ETH_FCR_BUSY (1 << 0)
+
+/* PMT Control and Status Register (ETH_PMTR) */
+
+#define ETH_PMTR_GU (1 << 9)
+#define ETH_PMTR_RF (1 << 6)
+#define ETH_PMTR_MF (1 << 5)
+#define ETH_PMTR_RWK (1 << 2)
+#define ETH_PMTR_MPK (1 << 1)
+
+/* Receive Descriptor 0 (ETH_RD0) Bits */
+
+#define ETH_RD0_OWN (1 << 31)
+#define ETH_RD0_FF (1 << 30)
+#define ETH_RD0_FL_BIT 16
+#define ETH_RD0_FL_MASK (0x3fff << ETH_RD0_FL_BIT)
+#define ETH_RD0_ES (1 << 15)
+#define ETH_RD0_DE (1 << 14)
+#define ETH_RD0_LE (1 << 12)
+#define ETH_RD0_RF (1 << 11)
+#define ETH_RD0_MF (1 << 10)
+#define ETH_RD0_FD (1 << 9)
+#define ETH_RD0_LD (1 << 8)
+#define ETH_RD0_TL (1 << 7)
+#define ETH_RD0_CS (1 << 6)
+#define ETH_RD0_FT (1 << 5)
+#define ETH_RD0_WT (1 << 4)
+#define ETH_RD0_ME (1 << 3)
+#define ETH_RD0_DB (1 << 2)
+#define ETH_RD0_CE (1 << 1)
+
+/* Receive Descriptor 1 (ETH_RD1) Bits */
+
+#define ETH_RD1_RER (1 << 25)
+#define ETH_RD1_RCH (1 << 24)
+#define ETH_RD1_RBS2_BIT 11
+#define ETH_RD1_RBS2_MASK (0x7ff << ETH_RD1_RBS2_BIT)
+#define ETH_RD1_RBS1_BIT 0
+#define ETH_RD1_RBS1_MASK (0x7ff << ETH_RD1_RBS1_BIT)
+
+/* Transmit Descriptor 0 (ETH_TD0) Bits */
+
+#define ETH_TD0_OWN (1 << 31)
+#define ETH_TD0_FA (1 << 15)
+#define ETH_TD0_LOC (1 << 11)
+#define ETH_TD0_NC (1 << 10)
+#define ETH_TD0_LC (1 << 9)
+#define ETH_TD0_EC (1 << 8)
+#define ETH_TD0_HBF (1 << 7)
+#define ETH_TD0_CC_BIT 3
+#define ETH_TD0_CC_MASK (0xf << ETH_TD0_CC_BIT)
+#define ETH_TD0_ED (1 << 2)
+#define ETH_TD0_UF (1 << 1)
+#define ETH_TD0_DF (1 << 0)
+
+/* Transmit Descriptor 1 (ETH_TD1) Bits */
+
+#define ETH_TD1_IC (1 << 31)
+#define ETH_TD1_LS (1 << 30)
+#define ETH_TD1_FS (1 << 29)
+#define ETH_TD1_AC (1 << 26)
+#define ETH_TD1_TER (1 << 25)
+#define ETH_TD1_TCH (1 << 24)
+#define ETH_TD1_DPD (1 << 23)
+#define ETH_TD1_TBS2_BIT 11
+#define ETH_TD1_TBS2_MASK (0x7ff << ETH_TD1_TBS2_BIT)
+#define ETH_TD1_TBS1_BIT 0
+#define ETH_TD1_TBS1_MASK (0x7ff << ETH_TD1_TBS1_BIT)
+
+
+
+
+/*************************************************************************
+ * WDT
+ *************************************************************************/
+#define WDT_WTCSR (WDT_BASE + 0x00)
+#define WDT_WTCNT (WDT_BASE + 0x04)
+
+#define REG_WDT_WTCSR REG8(WDT_WTCSR)
+#define REG_WDT_WTCNT REG32(WDT_WTCNT)
+
+#define WDT_WTCSR_START (1 << 4)
+
+
+
+
+/*************************************************************************
+ * OST
+ *************************************************************************/
+#define OST_TER (OST_BASE + 0x00)
+#define OST_TRDR(n) (OST_BASE + 0x10 + ((n) * 0x20))
+#define OST_TCNT(n) (OST_BASE + 0x14 + ((n) * 0x20))
+#define OST_TCSR(n) (OST_BASE + 0x18 + ((n) * 0x20))
+#define OST_TCRB(n) (OST_BASE + 0x1c + ((n) * 0x20))
+
+#define REG_OST_TER REG8(OST_TER)
+#define REG_OST_TRDR(n) REG32(OST_TRDR((n)))
+#define REG_OST_TCNT(n) REG32(OST_TCNT((n)))
+#define REG_OST_TCSR(n) REG16(OST_TCSR((n)))
+#define REG_OST_TCRB(n) REG32(OST_TCRB((n)))
+
+#define OST_TCSR_BUSY (1 << 7)
+#define OST_TCSR_UF (1 << 6)
+#define OST_TCSR_UIE (1 << 5)
+#define OST_TCSR_CKS_BIT 0
+#define OST_TCSR_CKS_MASK (0x07 << OST_TCSR_CKS_BIT)
+ #define OST_TCSR_CKS_PCLK_4 (0 << OST_TCSR_CKS_BIT)
+ #define OST_TCSR_CKS_PCLK_16 (1 << OST_TCSR_CKS_BIT)
+ #define OST_TCSR_CKS_PCLK_64 (2 << OST_TCSR_CKS_BIT)
+ #define OST_TCSR_CKS_PCLK_256 (3 << OST_TCSR_CKS_BIT)
+ #define OST_TCSR_CKS_RTCCLK (4 << OST_TCSR_CKS_BIT)
+ #define OST_TCSR_CKS_EXTAL (5 << OST_TCSR_CKS_BIT)
+
+#define OST_TCSR0 OST_TCSR(0)
+#define OST_TCSR1 OST_TCSR(1)
+#define OST_TCSR2 OST_TCSR(2)
+#define OST_TRDR0 OST_TRDR(0)
+#define OST_TRDR1 OST_TRDR(1)
+#define OST_TRDR2 OST_TRDR(2)
+#define OST_TCNT0 OST_TCNT(0)
+#define OST_TCNT1 OST_TCNT(1)
+#define OST_TCNT2 OST_TCNT(2)
+#define OST_TCRB0 OST_TCRB(0)
+#define OST_TCRB1 OST_TCRB(1)
+#define OST_TCRB2 OST_TCRB(2)
+
+/*************************************************************************
+ * UART
+ *************************************************************************/
+
+#define IRDA_BASE UART0_BASE
+#define UART_BASE UART0_BASE
+#define UART_OFF 0x1000
+
+/* register offset */
+#define OFF_RDR (0x00) /* R 8b H'xx */
+#define OFF_TDR (0x00) /* W 8b H'xx */
+#define OFF_DLLR (0x00) /* RW 8b H'00 */
+#define OFF_DLHR (0x04) /* RW 8b H'00 */
+#define OFF_IER (0x04) /* RW 8b H'00 */
+#define OFF_ISR (0x08) /* R 8b H'01 */
+#define OFF_FCR (0x08) /* W 8b H'00 */
+#define OFF_LCR (0x0C) /* RW 8b H'00 */
+#define OFF_MCR (0x10) /* RW 8b H'00 */
+#define OFF_LSR (0x14) /* R 8b H'00 */
+#define OFF_MSR (0x18) /* R 8b H'00 */
+#define OFF_SPR (0x1C) /* RW 8b H'00 */
+#define OFF_MCR (0x10) /* RW 8b H'00 */
+#define OFF_SIRCR (0x20) /* RW 8b H'00, UART0 */
+
+/* register address */
+#define UART0_RDR (UART0_BASE + OFF_RDR)
+#define UART0_TDR (UART0_BASE + OFF_TDR)
+#define UART0_DLLR (UART0_BASE + OFF_DLLR)
+#define UART0_DLHR (UART0_BASE + OFF_DLHR)
+#define UART0_IER (UART0_BASE + OFF_IER)
+#define UART0_ISR (UART0_BASE + OFF_ISR)
+#define UART0_FCR (UART0_BASE + OFF_FCR)
+#define UART0_LCR (UART0_BASE + OFF_LCR)
+#define UART0_MCR (UART0_BASE + OFF_MCR)
+#define UART0_LSR (UART0_BASE + OFF_LSR)
+#define UART0_MSR (UART0_BASE + OFF_MSR)
+#define UART0_SPR (UART0_BASE + OFF_SPR)
+#define UART0_SIRCR (UART0_BASE + OFF_SIRCR)
+
+#define UART1_RDR (UART1_BASE + OFF_RDR)
+#define UART1_TDR (UART1_BASE + OFF_TDR)
+#define UART1_DLLR (UART1_BASE + OFF_DLLR)
+#define UART1_DLHR (UART1_BASE + OFF_DLHR)
+#define UART1_IER (UART1_BASE + OFF_IER)
+#define UART1_ISR (UART1_BASE + OFF_ISR)
+#define UART1_FCR (UART1_BASE + OFF_FCR)
+#define UART1_LCR (UART1_BASE + OFF_LCR)
+#define UART1_MCR (UART1_BASE + OFF_MCR)
+#define UART1_LSR (UART1_BASE + OFF_LSR)
+#define UART1_MSR (UART1_BASE + OFF_MSR)
+#define UART1_SPR (UART1_BASE + OFF_SPR)
+#define UART1_SIRCR (UART1_BASE + OFF_SIRCR)
+
+#define UART2_RDR (UART2_BASE + OFF_RDR)
+#define UART2_TDR (UART2_BASE + OFF_TDR)
+#define UART2_DLLR (UART2_BASE + OFF_DLLR)
+#define UART2_DLHR (UART2_BASE + OFF_DLHR)
+#define UART2_IER (UART2_BASE + OFF_IER)
+#define UART2_ISR (UART2_BASE + OFF_ISR)
+#define UART2_FCR (UART2_BASE + OFF_FCR)
+#define UART2_LCR (UART2_BASE + OFF_LCR)
+#define UART2_MCR (UART2_BASE + OFF_MCR)
+#define UART2_LSR (UART2_BASE + OFF_LSR)
+#define UART2_MSR (UART2_BASE + OFF_MSR)
+#define UART2_SPR (UART2_BASE + OFF_SPR)
+#define UART2_SIRCR (UART2_BASE + OFF_SIRCR)
+
+#define UART3_RDR (UART3_BASE + OFF_RDR)
+#define UART3_TDR (UART3_BASE + OFF_TDR)
+#define UART3_DLLR (UART3_BASE + OFF_DLLR)
+#define UART3_DLHR (UART3_BASE + OFF_DLHR)
+#define UART3_IER (UART3_BASE + OFF_IER)
+#define UART3_ISR (UART3_BASE + OFF_ISR)
+#define UART3_FCR (UART3_BASE + OFF_FCR)
+#define UART3_LCR (UART3_BASE + OFF_LCR)
+#define UART3_MCR (UART3_BASE + OFF_MCR)
+#define UART3_LSR (UART3_BASE + OFF_LSR)
+#define UART3_MSR (UART3_BASE + OFF_MSR)
+#define UART3_SPR (UART3_BASE + OFF_SPR)
+#define UART3_SIRCR (UART3_BASE + OFF_SIRCR)
+
+/*
+ * Define macros for UARTIER
+ * UART Interrupt Enable Register
+ */
+#define UARTIER_RIE (1 << 0) /* 0: receive fifo "full" interrupt disable */
+#define UARTIER_TIE (1 << 1) /* 0: transmit fifo "empty" interrupt disable */
+#define UARTIER_RLIE (1 << 2) /* 0: receive line status interrupt disable */
+#define UARTIER_MIE (1 << 3) /* 0: modem status interrupt disable */
+#define UARTIER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */
+
+/*
+ * Define macros for UARTISR
+ * UART Interrupt Status Register
+ */
+#define UARTISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */
+#define UARTISR_IID (7 << 1) /* Source of Interrupt */
+#define UARTISR_IID_MSI (0 << 1) /* Modem status interrupt */
+#define UARTISR_IID_THRI (1 << 1) /* Transmitter holding register empty */
+#define UARTISR_IID_RDI (2 << 1) /* Receiver data interrupt */
+#define UARTISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */
+#define UARTISR_FFMS (3 << 6) /* FIFO mode select, set when UARTFCR.FE is set to 1 */
+#define UARTISR_FFMS_NO_FIFO (0 << 6)
+#define UARTISR_FFMS_FIFO_MODE (3 << 6)
+
+/*
+ * Define macros for UARTFCR
+ * UART FIFO Control Register
+ */
+#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */
+#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */
+#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */
+#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */
+#define UARTFCR_UUE (1 << 4) /* 0: disable UART */
+#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */
+#define UARTFCR_RTRG_1 (0 << 6)
+#define UARTFCR_RTRG_4 (1 << 6)
+#define UARTFCR_RTRG_8 (2 << 6)
+#define UARTFCR_RTRG_15 (3 << 6)
+
+/*
+ * Define macros for UARTLCR
+ * UART Line Control Register
+ */
+#define UARTLCR_WLEN (3 << 0) /* word length */
+#define UARTLCR_WLEN_5 (0 << 0)
+#define UARTLCR_WLEN_6 (1 << 0)
+#define UARTLCR_WLEN_7 (2 << 0)
+#define UARTLCR_WLEN_8 (3 << 0)
+#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8
+ 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */
+#define UARTLCR_PE (1 << 3) /* 0: parity disable */
+#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */
+#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */
+#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */
+#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */
+
+/*
+ * Define macros for UARTLSR
+ * UART Line Status Register
+ */
+#define UARTLSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */
+#define UARTLSR_ORER (1 << 1) /* 0: no overrun error */
+#define UARTLSR_PER (1 << 2) /* 0: no parity error */
+#define UARTLSR_FER (1 << 3) /* 0; no framing error */
+#define UARTLSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */
+#define UARTLSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */
+#define UARTLSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */
+#define UARTLSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */
+
+/*
+ * Define macros for UARTMCR
+ * UART Modem Control Register
+ */
+#define UARTMCR_DTR (1 << 0) /* 0: DTR_ ouput high */
+#define UARTMCR_RTS (1 << 1) /* 0: RTS_ output high */
+#define UARTMCR_OUT1 (1 << 2) /* 0: UARTMSR.RI is set to 0 and RI_ input high */
+#define UARTMCR_OUT2 (1 << 3) /* 0: UARTMSR.DCD is set to 0 and DCD_ input high */
+#define UARTMCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */
+#define UARTMCR_MCE (1 << 7) /* 0: modem function is disable */
+
+/*
+ * Define macros for UARTMSR
+ * UART Modem Status Register
+ */
+#define UARTMSR_DCTS (1 << 0) /* 0: no change on CTS_ pin since last read of UARTMSR */
+#define UARTMSR_DDSR (1 << 1) /* 0: no change on DSR_ pin since last read of UARTMSR */
+#define UARTMSR_DRI (1 << 2) /* 0: no change on RI_ pin since last read of UARTMSR */
+#define UARTMSR_DDCD (1 << 3) /* 0: no change on DCD_ pin since last read of UARTMSR */
+#define UARTMSR_CTS (1 << 4) /* 0: CTS_ pin is high */
+#define UARTMSR_DSR (1 << 5) /* 0: DSR_ pin is high */
+#define UARTMSR_RI (1 << 6) /* 0: RI_ pin is high */
+#define UARTMSR_DCD (1 << 7) /* 0: DCD_ pin is high */
+
+/*
+ * Define macros for SIRCR
+ * Slow IrDA Control Register
+ */
+#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: IrDA mode */
+#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: IrDA mode */
+#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length
+ 1: 0 pulse width is 1.6us for 115.2Kbps */
+#define SIRCR_TXPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */
+#define SIRCR_RXPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */
+
+
+
+/*************************************************************************
+ * INTC
+ *************************************************************************/
+#define INTC_ISR (INTC_BASE + 0x00)
+#define INTC_IMR (INTC_BASE + 0x04)
+#define INTC_IMSR (INTC_BASE + 0x08)
+#define INTC_IMCR (INTC_BASE + 0x0c)
+#define INTC_IPR (INTC_BASE + 0x10)
+
+#define REG_INTC_ISR REG32(INTC_ISR)
+#define REG_INTC_IMR REG32(INTC_IMR)
+#define REG_INTC_IMSR REG32(INTC_IMSR)
+#define REG_INTC_IMCR REG32(INTC_IMCR)
+#define REG_INTC_IPR REG32(INTC_IPR)
+
+#define IRQ_I2C 1
+#define IRQ_PS2 2
+#define IRQ_UPRT 3
+#define IRQ_CORE 4
+#define IRQ_UART3 6
+#define IRQ_UART2 7
+#define IRQ_UART1 8
+#define IRQ_UART0 9
+#define IRQ_SCC1 10
+#define IRQ_SCC0 11
+#define IRQ_UDC 12
+#define IRQ_UHC 13
+#define IRQ_MSC 14
+#define IRQ_RTC 15
+#define IRQ_FIR 16
+#define IRQ_SSI 17
+#define IRQ_CIM 18
+#define IRQ_ETH 19
+#define IRQ_AIC 20
+#define IRQ_DMAC 21
+#define IRQ_OST2 22
+#define IRQ_OST1 23
+#define IRQ_OST0 24
+#define IRQ_GPIO3 25
+#define IRQ_GPIO2 26
+#define IRQ_GPIO1 27
+#define IRQ_GPIO0 28
+#define IRQ_LCD 30
+
+
+
+
+/*************************************************************************
+ * CIM
+ *************************************************************************/
+#define CIM_CFG (CIM_BASE + 0x0000)
+#define CIM_CTRL (CIM_BASE + 0x0004)
+#define CIM_STATE (CIM_BASE + 0x0008)
+#define CIM_IID (CIM_BASE + 0x000C)
+#define CIM_RXFIFO (CIM_BASE + 0x0010)
+#define CIM_DA (CIM_BASE + 0x0020)
+#define CIM_FA (CIM_BASE + 0x0024)
+#define CIM_FID (CIM_BASE + 0x0028)
+#define CIM_CMD (CIM_BASE + 0x002C)
+
+#define REG_CIM_CFG REG32(CIM_CFG)
+#define REG_CIM_CTRL REG32(CIM_CTRL)
+#define REG_CIM_STATE REG32(CIM_STATE)
+#define REG_CIM_IID REG32(CIM_IID)
+#define REG_CIM_RXFIFO REG32(CIM_RXFIFO)
+#define REG_CIM_DA REG32(CIM_DA)
+#define REG_CIM_FA REG32(CIM_FA)
+#define REG_CIM_FID REG32(CIM_FID)
+#define REG_CIM_CMD REG32(CIM_CMD)
+
+/* CIM Configuration Register (CIM_CFG) */
+
+#define CIM_CFG_INV_DAT (1 << 15)
+#define CIM_CFG_VSP (1 << 14)
+#define CIM_CFG_HSP (1 << 13)
+#define CIM_CFG_PCP (1 << 12)
+#define CIM_CFG_DUMMY_ZERO (1 << 9)
+#define CIM_CFG_EXT_VSYNC (1 << 8)
+#define CIM_CFG_PACK_BIT 4
+#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT)
+#define CIM_CFG_DSM_BIT 0
+#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT)
+ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */
+ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */
+ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */
+ #define CIM_CFG_DSM_NGCM (3 << CIM_CFG_DSM_BIT) /* Non-Gated Clock Mode */
+
+/* CIM Control Register (CIM_CTRL) */
+
+#define CIM_CTRL_MCLKDIV_BIT 24
+#define CIM_CTRL_MCLKDIV_MASK (0xff << CIM_CTRL_MCLKDIV_BIT)
+#define CIM_CTRL_FRC_BIT 16
+#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT)
+ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */
+ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */
+ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */
+ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */
+ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */
+ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */
+ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */
+ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */
+ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */
+ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */
+ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */
+ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */
+ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */
+ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */
+ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */
+ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */
+#define CIM_CTRL_VDDM (1 << 13)
+#define CIM_CTRL_DMA_SOFM (1 << 12)
+#define CIM_CTRL_DMA_EOFM (1 << 11)
+#define CIM_CTRL_DMA_STOPM (1 << 10)
+#define CIM_CTRL_RXF_TRIGM (1 << 9)
+#define CIM_CTRL_RXF_OFM (1 << 8)
+#define CIM_CTRL_RXF_TRIG_BIT 4
+#define CIM_CTRL_RXF_TRIG_MASK (0x7 << CIM_CTRL_RXF_TRIG_BIT)
+ #define CIM_CTRL_RXF_TRIG_4 (0 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 4 */
+ #define CIM_CTRL_RXF_TRIG_8 (1 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 8 */
+ #define CIM_CTRL_RXF_TRIG_12 (2 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 12 */
+ #define CIM_CTRL_RXF_TRIG_16 (3 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 16 */
+ #define CIM_CTRL_RXF_TRIG_20 (4 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 20 */
+ #define CIM_CTRL_RXF_TRIG_24 (5 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 24 */
+ #define CIM_CTRL_RXF_TRIG_28 (6 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 28 */
+ #define CIM_CTRL_RXF_TRIG_32 (7 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 32 */
+#define CIM_CTRL_DMA_EN (1 << 2)
+#define CIM_CTRL_RXF_RST (1 << 1)
+#define CIM_CTRL_ENA (1 << 0)
+
+/* CIM State Register (CIM_STATE) */
+
+#define CIM_STATE_DMA_SOF (1 << 6)
+#define CIM_STATE_DMA_EOF (1 << 5)
+#define CIM_STATE_DMA_STOP (1 << 4)
+#define CIM_STATE_RXF_OF (1 << 3)
+#define CIM_STATE_RXF_TRIG (1 << 2)
+#define CIM_STATE_RXF_EMPTY (1 << 1)
+#define CIM_STATE_VDD (1 << 0)
+
+/* CIM DMA Command Register (CIM_CMD) */
+
+#define CIM_CMD_SOFINT (1 << 31)
+#define CIM_CMD_EOFINT (1 << 30)
+#define CIM_CMD_STOP (1 << 28)
+#define CIM_CMD_LEN_BIT 0
+#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT)
+
+
+
+
+/*************************************************************************
+ * PWM
+ *************************************************************************/
+#define PWM_CTR(n) (PWM##n##_BASE + 0x000)
+#define PWM_PER(n) (PWM##n##_BASE + 0x004)
+#define PWM_DUT(n) (PWM##n##_BASE + 0x008)
+
+#define REG_PWM_CTR(n) REG8(PWM_CTR(n))
+#define REG_PWM_PER(n) REG16(PWM_PER(n))
+#define REG_PWM_DUT(n) REG16(PWM_DUT(n))
+
+/* PWM Control Register (PWM_CTR) */
+
+#define PWM_CTR_EN (1 << 7)
+#define PWM_CTR_SD (1 << 6)
+#define PWM_CTR_PRESCALE_BIT 0
+#define PWM_CTR_PRESCALE_MASK (0x3f << PWM_CTR_PRESCALE_BIT)
+
+/* PWM Period Register (PWM_PER) */
+
+#define PWM_PER_PERIOD_BIT 0
+#define PWM_PER_PERIOD_MASK (0x3ff << PWM_PER_PERIOD_BIT)
+
+/* PWM Duty Register (PWM_DUT) */
+
+#define PWM_DUT_FDUTY (1 << 10)
+#define PWM_DUT_DUTY_BIT 0
+#define PWM_DUT_DUTY_MASK (0x3ff << PWM_DUT_DUTY_BIT)
+
+
+
+
+/*************************************************************************
+ * EMC
+ *************************************************************************/
+#define EMC_BCR (EMC_BASE + 0x00)
+#define EMC_SMCR0 (EMC_BASE + 0x10)
+#define EMC_SMCR1 (EMC_BASE + 0x14)
+#define EMC_SMCR2 (EMC_BASE + 0x18)
+#define EMC_SMCR3 (EMC_BASE + 0x1c)
+#define EMC_SMCR4 (EMC_BASE + 0x20)
+#define EMC_SMCR5 (EMC_BASE + 0x24)
+#define EMC_SMCR6 (EMC_BASE + 0x28)
+#define EMC_SMCR7 (EMC_BASE + 0x2c)
+#define EMC_SACR0 (EMC_BASE + 0x30)
+#define EMC_SACR1 (EMC_BASE + 0x34)
+#define EMC_SACR2 (EMC_BASE + 0x38)
+#define EMC_SACR3 (EMC_BASE + 0x3c)
+#define EMC_SACR4 (EMC_BASE + 0x40)
+#define EMC_SACR5 (EMC_BASE + 0x44)
+#define EMC_SACR6 (EMC_BASE + 0x48)
+#define EMC_SACR7 (EMC_BASE + 0x4c)
+#define EMC_NFCSR (EMC_BASE + 0x50)
+#define EMC_NFECC (EMC_BASE + 0x54)
+#define EMC_PCCR1 (EMC_BASE + 0x60)
+#define EMC_PCCR2 (EMC_BASE + 0x64)
+#define EMC_PCCR3 (EMC_BASE + 0x68)
+#define EMC_PCCR4 (EMC_BASE + 0x6c)
+#define EMC_DMCR (EMC_BASE + 0x80)
+#define EMC_RTCSR (EMC_BASE + 0x84)
+#define EMC_RTCNT (EMC_BASE + 0x88)
+#define EMC_RTCOR (EMC_BASE + 0x8c)
+#define EMC_DMAR1 (EMC_BASE + 0x90)
+#define EMC_DMAR2 (EMC_BASE + 0x94)
+#define EMC_DMAR3 (EMC_BASE + 0x98)
+#define EMC_DMAR4 (EMC_BASE + 0x9c)
+
+#define EMC_SDMR0 (EMC_BASE + 0xa000)
+#define EMC_SDMR1 (EMC_BASE + 0xb000)
+#define EMC_SDMR2 (EMC_BASE + 0xc000)
+#define EMC_SDMR3 (EMC_BASE + 0xd000)
+
+#define REG_EMC_BCR REG32(EMC_BCR)
+#define REG_EMC_SMCR0 REG32(EMC_SMCR0)
+#define REG_EMC_SMCR1 REG32(EMC_SMCR1)
+#define REG_EMC_SMCR2 REG32(EMC_SMCR2)
+#define REG_EMC_SMCR3 REG32(EMC_SMCR3)
+#define REG_EMC_SMCR4 REG32(EMC_SMCR4)
+#define REG_EMC_SMCR5 REG32(EMC_SMCR5)
+#define REG_EMC_SMCR6 REG32(EMC_SMCR6)
+#define REG_EMC_SMCR7 REG32(EMC_SMCR7)
+#define REG_EMC_SACR0 REG32(EMC_SACR0)
+#define REG_EMC_SACR1 REG32(EMC_SACR1)
+#define REG_EMC_SACR2 REG32(EMC_SACR2)
+#define REG_EMC_SACR3 REG32(EMC_SACR3)
+#define REG_EMC_SACR4 REG32(EMC_SACR4)
+#define REG_EMC_SACR5 REG32(EMC_SACR5)
+#define REG_EMC_SACR6 REG32(EMC_SACR6)
+#define REG_EMC_SACR7 REG32(EMC_SACR7)
+#define REG_EMC_NFCSR REG32(EMC_NFCSR)
+#define REG_EMC_NFECC REG32(EMC_NFECC)
+#define REG_EMC_DMCR REG32(EMC_DMCR)
+#define REG_EMC_RTCSR REG16(EMC_RTCSR)
+#define REG_EMC_RTCNT REG16(EMC_RTCNT)
+#define REG_EMC_RTCOR REG16(EMC_RTCOR)
+#define REG_EMC_DMAR1 REG32(EMC_DMAR1)
+#define REG_EMC_DMAR2 REG32(EMC_DMAR2)
+#define REG_EMC_DMAR3 REG32(EMC_DMAR3)
+#define REG_EMC_DMAR4 REG32(EMC_DMAR4)
+#define REG_EMC_PCCR1 REG32(EMC_PCCR1)
+#define REG_EMC_PCCR2 REG32(EMC_PCCR2)
+#define REG_EMC_PCCR3 REG32(EMC_PCCR3)
+#define REG_EMC_PCCR4 REG32(EMC_PCCR4)
+
+
+#define EMC_BCR_BRE (1 << 1)
+
+#define EMC_SMCR_STRV_BIT 24
+#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT)
+#define EMC_SMCR_TAW_BIT 20
+#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT)
+#define EMC_SMCR_TBP_BIT 16
+#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT)
+#define EMC_SMCR_TAH_BIT 12
+#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT)
+#define EMC_SMCR_TAS_BIT 8
+#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT)
+#define EMC_SMCR_BW_BIT 6
+#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT)
+#define EMC_SMCR_BCM (1 << 3)
+#define EMC_SMCR_BL_BIT 1
+#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT)
+#define EMC_SMCR_SMT (1 << 0)
+
+#define EMC_SACR_BASE_BIT 8
+#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT)
+#define EMC_SACR_MASK_BIT 0
+#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT)
+
+#define EMC_NFCSR_RB (1 << 7)
+#define EMC_NFCSR_BOOT_SEL_BIT 4
+#define EMC_NFCSR_BOOT_SEL_MASK (0x07 << EMC_NFCSR_BOOT_SEL_BIT)
+#define EMC_NFCSR_ERST (1 << 3)
+#define EMC_NFCSR_ECCE (1 << 2)
+#define EMC_NFCSR_FCE (1 << 1)
+#define EMC_NFCSR_NFE (1 << 0)
+
+#define EMC_NFECC_ECC2_BIT 16
+#define EMC_NFECC_ECC2_MASK (0xff << EMC_NFECC_ECC2_BIT)
+#define EMC_NFECC_ECC1_BIT 8
+#define EMC_NFECC_ECC1_MASK (0xff << EMC_NFECC_ECC1_BIT)
+#define EMC_NFECC_ECC0_BIT 0
+#define EMC_NFECC_ECC0_MASK (0xff << EMC_NFECC_ECC0_BIT)
+
+#define EMC_DMCR_BW_BIT 31
+#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT)
+#define EMC_DMCR_CA_BIT 26
+#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT)
+#define EMC_DMCR_RMODE (1 << 25)
+#define EMC_DMCR_RFSH (1 << 24)
+#define EMC_DMCR_MRSET (1 << 23)
+#define EMC_DMCR_RA_BIT 20
+#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT)
+#define EMC_DMCR_BA_BIT 19
+#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT)
+#define EMC_DMCR_PDM (1 << 18)
+#define EMC_DMCR_EPIN (1 << 17)
+#define EMC_DMCR_TRAS_BIT 13
+#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT)
+#define EMC_DMCR_RCD_BIT 11
+#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT)
+#define EMC_DMCR_TPC_BIT 8
+#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT)
+#define EMC_DMCR_TRWL_BIT 5
+#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT)
+#define EMC_DMCR_TRC_BIT 2
+#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT)
+#define EMC_DMCR_TCL_BIT 0
+#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT)
+
+#define EMC_RTCSR_CMF (1 << 7)
+#define EMC_RTCSR_CKS_BIT 0
+#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT)
+
+#define EMC_DMAR_BASE_BIT 8
+#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT)
+#define EMC_DMAR_MASK_BIT 0
+#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT)
+
+#define EMC_SDMR_BM (1 << 9)
+#define EMC_SDMR_OM_BIT 7
+#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT)
+ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT)
+#define EMC_SDMR_CAS_BIT 4
+#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT)
+#define EMC_SDMR_BT_BIT 3
+#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT)
+ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT)
+ #define EMC_SDMR_BT_INTR (1 << EMC_SDMR_BT_BIT)
+#define EMC_SDMR_BL_BIT 0
+#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT)
+
+#define EMC_SDMR_CAS2_16BIT \
+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2)
+#define EMC_SDMR_CAS2_32BIT \
+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4)
+#define EMC_SDMR_CAS3_16BIT \
+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2)
+#define EMC_SDMR_CAS3_32BIT \
+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4)
+
+#define EMC_PCCR12_AMW (1 << 31)
+#define EMC_PCCR12_AMAS_BIT 28
+#define EMC_PCCR12_AMAS_MASK (0x07 << EMC_PCCR12_AMAS_BIT)
+#define EMC_PCCR12_AMAH_BIT 24
+#define EMC_PCCR12_AMAH_MASK (0x07 << EMC_PCCR12_AMAH_BIT)
+#define EMC_PCCR12_AMPW_BIT 20
+#define EMC_PCCR12_AMPW_MASK (0x0f << EMC_PCCR12_AMPW_BIT)
+#define EMC_PCCR12_AMRT_BIT 16
+#define EMC_PCCR12_AMRT_MASK (0x0f << EMC_PCCR12_AMRT_BIT)
+#define EMC_PCCR12_CMW (1 << 15)
+#define EMC_PCCR12_CMAS_BIT 12
+#define EMC_PCCR12_CMAS_MASK (0x07 << EMC_PCCR12_CMAS_BIT)
+#define EMC_PCCR12_CMAH_BIT 8
+#define EMC_PCCR12_CMAH_MASK (0x07 << EMC_PCCR12_CMAH_BIT)
+#define EMC_PCCR12_CMPW_BIT 4
+#define EMC_PCCR12_CMPW_MASK (0x0f << EMC_PCCR12_CMPW_BIT)
+#define EMC_PCCR12_CMRT_BIT 0
+#define EMC_PCCR12_CMRT_MASK (0x07 << EMC_PCCR12_CMRT_BIT)
+
+#define EMC_PCCR34_DRS_BIT 16
+#define EMC_PCCR34_DRS_MASK (0x03 << EMC_PCCR34_DRS_BIT)
+ #define EMC_PCCR34_DRS_SPKR (1 << EMC_PCCR34_DRS_BIT)
+ #define EMC_PCCR34_DRS_IOIS16 (2 << EMC_PCCR34_DRS_BIT)
+ #define EMC_PCCR34_DRS_INPACK (3 << EMC_PCCR34_DRS_BIT)
+#define EMC_PCCR34_IOIS16 (1 << 15)
+#define EMC_PCCR34_IOW (1 << 14)
+#define EMC_PCCR34_TCB_BIT 12
+#define EMC_PCCR34_TCB_MASK (0x03 << EMC_PCCR34_TCB_BIT)
+#define EMC_PCCR34_IORT_BIT 8
+#define EMC_PCCR34_IORT_MASK (0x07 << EMC_PCCR34_IORT_BIT)
+#define EMC_PCCR34_IOAE_BIT 6
+#define EMC_PCCR34_IOAE_MASK (0x03 << EMC_PCCR34_IOAE_BIT)
+ #define EMC_PCCR34_IOAE_NONE (0 << EMC_PCCR34_IOAE_BIT)
+ #define EMC_PCCR34_IOAE_1 (1 << EMC_PCCR34_IOAE_BIT)
+ #define EMC_PCCR34_IOAE_2 (2 << EMC_PCCR34_IOAE_BIT)
+ #define EMC_PCCR34_IOAE_5 (3 << EMC_PCCR34_IOAE_BIT)
+#define EMC_PCCR34_IOAH_BIT 4
+#define EMC_PCCR34_IOAH_MASK (0x03 << EMC_PCCR34_IOAH_BIT)
+ #define EMC_PCCR34_IOAH_NONE (0 << EMC_PCCR34_IOAH_BIT)
+ #define EMC_PCCR34_IOAH_1 (1 << EMC_PCCR34_IOAH_BIT)
+ #define EMC_PCCR34_IOAH_2 (2 << EMC_PCCR34_IOAH_BIT)
+ #define EMC_PCCR34_IOAH_5 (3 << EMC_PCCR34_IOAH_BIT)
+#define EMC_PCCR34_IOPW_BIT 0
+#define EMC_PCCR34_IOPW_MASK (0x0f << EMC_PCCR34_IOPW_BIT)
+
+
+
+
+/*************************************************************************
+ * GPIO
+ *************************************************************************/
+#define GPIO_GPDR(n) (GPIO_BASE + (0x00 + (n)*0x30))
+#define GPIO_GPDIR(n) (GPIO_BASE + (0x04 + (n)*0x30))
+#define GPIO_GPODR(n) (GPIO_BASE + (0x08 + (n)*0x30))
+#define GPIO_GPPUR(n) (GPIO_BASE + (0x0c + (n)*0x30))
+#define GPIO_GPALR(n) (GPIO_BASE + (0x10 + (n)*0x30))
+#define GPIO_GPAUR(n) (GPIO_BASE + (0x14 + (n)*0x30))
+#define GPIO_GPIDLR(n) (GPIO_BASE + (0x18 + (n)*0x30))
+#define GPIO_GPIDUR(n) (GPIO_BASE + (0x1c + (n)*0x30))
+#define GPIO_GPIER(n) (GPIO_BASE + (0x20 + (n)*0x30))
+#define GPIO_GPIMR(n) (GPIO_BASE + (0x24 + (n)*0x30))
+#define GPIO_GPFR(n) (GPIO_BASE + (0x28 + (n)*0x30))
+
+#define REG_GPIO_GPDR(n) REG32(GPIO_GPDR((n)))
+#define REG_GPIO_GPDIR(n) REG32(GPIO_GPDIR((n)))
+#define REG_GPIO_GPODR(n) REG32(GPIO_GPODR((n)))
+#define REG_GPIO_GPPUR(n) REG32(GPIO_GPPUR((n)))
+#define REG_GPIO_GPALR(n) REG32(GPIO_GPALR((n)))
+#define REG_GPIO_GPAUR(n) REG32(GPIO_GPAUR((n)))
+#define REG_GPIO_GPIDLR(n) REG32(GPIO_GPIDLR((n)))
+#define REG_GPIO_GPIDUR(n) REG32(GPIO_GPIDUR((n)))
+#define REG_GPIO_GPIER(n) REG32(GPIO_GPIER((n)))
+#define REG_GPIO_GPIMR(n) REG32(GPIO_GPIMR((n)))
+#define REG_GPIO_GPFR(n) REG32(GPIO_GPFR((n)))
+
+#define GPIO_IRQ_LOLEVEL 0
+#define GPIO_IRQ_HILEVEL 1
+#define GPIO_IRQ_FALLEDG 2
+#define GPIO_IRQ_RAISEDG 3
+
+#define IRQ_GPIO_0 48
+#define NUM_GPIO 128
+
+#define GPIO_GPDR0 GPIO_GPDR(0)
+#define GPIO_GPDR1 GPIO_GPDR(1)
+#define GPIO_GPDR2 GPIO_GPDR(2)
+#define GPIO_GPDR3 GPIO_GPDR(3)
+#define GPIO_GPDIR0 GPIO_GPDIR(0)
+#define GPIO_GPDIR1 GPIO_GPDIR(1)
+#define GPIO_GPDIR2 GPIO_GPDIR(2)
+#define GPIO_GPDIR3 GPIO_GPDIR(3)
+#define GPIO_GPODR0 GPIO_GPODR(0)
+#define GPIO_GPODR1 GPIO_GPODR(1)
+#define GPIO_GPODR2 GPIO_GPODR(2)
+#define GPIO_GPODR3 GPIO_GPODR(3)
+#define GPIO_GPPUR0 GPIO_GPPUR(0)
+#define GPIO_GPPUR1 GPIO_GPPUR(1)
+#define GPIO_GPPUR2 GPIO_GPPUR(2)
+#define GPIO_GPPUR3 GPIO_GPPUR(3)
+#define GPIO_GPALR0 GPIO_GPALR(0)
+#define GPIO_GPALR1 GPIO_GPALR(1)
+#define GPIO_GPALR2 GPIO_GPALR(2)
+#define GPIO_GPALR3 GPIO_GPALR(3)
+#define GPIO_GPAUR0 GPIO_GPAUR(0)
+#define GPIO_GPAUR1 GPIO_GPAUR(1)
+#define GPIO_GPAUR2 GPIO_GPAUR(2)
+#define GPIO_GPAUR3 GPIO_GPAUR(3)
+#define GPIO_GPIDLR0 GPIO_GPIDLR(0)
+#define GPIO_GPIDLR1 GPIO_GPIDLR(1)
+#define GPIO_GPIDLR2 GPIO_GPIDLR(2)
+#define GPIO_GPIDLR3 GPIO_GPIDLR(3)
+#define GPIO_GPIDUR0 GPIO_GPIDUR(0)
+#define GPIO_GPIDUR1 GPIO_GPIDUR(1)
+#define GPIO_GPIDUR2 GPIO_GPIDUR(2)
+#define GPIO_GPIDUR3 GPIO_GPIDUR(3)
+#define GPIO_GPIER0 GPIO_GPIER(0)
+#define GPIO_GPIER1 GPIO_GPIER(1)
+#define GPIO_GPIER2 GPIO_GPIER(2)
+#define GPIO_GPIER3 GPIO_GPIER(3)
+#define GPIO_GPIMR0 GPIO_GPIMR(0)
+#define GPIO_GPIMR1 GPIO_GPIMR(1)
+#define GPIO_GPIMR2 GPIO_GPIMR(2)
+#define GPIO_GPIMR3 GPIO_GPIMR(3)
+#define GPIO_GPFR0 GPIO_GPFR(0)
+#define GPIO_GPFR1 GPIO_GPFR(1)
+#define GPIO_GPFR2 GPIO_GPFR(2)
+#define GPIO_GPFR3 GPIO_GPFR(3)
+
+
+/*************************************************************************
+ * HARB
+ *************************************************************************/
+#define HARB_HAPOR (HARB_BASE + 0x000)
+#define HARB_HMCTR (HARB_BASE + 0x010)
+#define HARB_HME8H (HARB_BASE + 0x014)
+#define HARB_HMCR1 (HARB_BASE + 0x018)
+#define HARB_HMER2 (HARB_BASE + 0x01C)
+#define HARB_HMER3 (HARB_BASE + 0x020)
+#define HARB_HMLTR (HARB_BASE + 0x024)
+
+#define REG_HARB_HAPOR REG32(HARB_HAPOR)
+#define REG_HARB_HMCTR REG32(HARB_HMCTR)
+#define REG_HARB_HME8H REG32(HARB_HME8H)
+#define REG_HARB_HMCR1 REG32(HARB_HMCR1)
+#define REG_HARB_HMER2 REG32(HARB_HMER2)
+#define REG_HARB_HMER3 REG32(HARB_HMER3)
+#define REG_HARB_HMLTR REG32(HARB_HMLTR)
+
+/* HARB Priority Order Register (HARB_HAPOR) */
+
+#define HARB_HAPOR_UCHSEL (1 << 7)
+#define HARB_HAPOR_PRIO_BIT 0
+#define HARB_HAPOR_PRIO_MASK (0xf << HARB_HAPOR_PRIO_BIT)
+
+/* AHB Monitor Control Register (HARB_HMCTR) */
+
+#define HARB_HMCTR_HET3_BIT 20
+#define HARB_HMCTR_HET3_MASK (0xf << HARB_HMCTR_HET3_BIT)
+#define HARB_HMCTR_HMS3_BIT 16
+#define HARB_HMCTR_HMS3_MASK (0xf << HARB_HMCTR_HMS3_BIT)
+#define HARB_HMCTR_HET2_BIT 12
+#define HARB_HMCTR_HET2_MASK (0xf << HARB_HMCTR_HET2_BIT)
+#define HARB_HMCTR_HMS2_BIT 8
+#define HARB_HMCTR_HMS2_MASK (0xf << HARB_HMCTR_HMS2_BIT)
+#define HARB_HMCTR_HOVF3 (1 << 7)
+#define HARB_HMCTR_HOVF2 (1 << 6)
+#define HARB_HMCTR_HOVF1 (1 << 5)
+#define HARB_HMCTR_HRST (1 << 4)
+#define HARB_HMCTR_HEE3 (1 << 2)
+#define HARB_HMCTR_HEE2 (1 << 1)
+#define HARB_HMCTR_HEE1 (1 << 0)
+
+/* AHB Monitor Event 8bits High Register (HARB_HME8H) */
+
+#define HARB_HME8H_HC8H1_BIT 16
+#define HARB_HME8H_HC8H1_MASK (0xff << HARB_HME8H_HC8H1_BIT)
+#define HARB_HME8H_HC8H2_BIT 8
+#define HARB_HME8H_HC8H2_MASK (0xff << HARB_HME8H_HC8H2_BIT)
+#define HARB_HME8H_HC8H3_BIT 0
+#define HARB_HME8H_HC8H3_MASK (0xff << HARB_HME8H_HC8H3_BIT)
+
+/* AHB Monitor Latency Register (HARB_HMLTR) */
+
+#define HARB_HMLTR_HLT2_BIT 16
+#define HARB_HMLTR_HLT2_MASK (0xffff << HARB_HMLTR_HLT2_BIT)
+#define HARB_HMLTR_HLT3_BIT 0
+#define HARB_HMLTR_HLT3_MASK (0xffff << HARB_HMLTR_HLT3_BIT)
+
+
+
+
+/*************************************************************************
+ * I2C
+ *************************************************************************/
+#define I2C_DR (I2C_BASE + 0x000)
+#define I2C_CR (I2C_BASE + 0x004)
+#define I2C_SR (I2C_BASE + 0x008)
+#define I2C_GR (I2C_BASE + 0x00C)
+
+#define REG_I2C_DR REG8(I2C_DR)
+#define REG_I2C_CR REG8(I2C_CR)
+#define REG_I2C_SR REG8(I2C_SR)
+#define REG_I2C_GR REG16(I2C_GR)
+
+/* I2C Control Register (I2C_CR) */
+
+#define I2C_CR_IEN (1 << 4)
+#define I2C_CR_STA (1 << 3)
+#define I2C_CR_STO (1 << 2)
+#define I2C_CR_AC (1 << 1)
+#define I2C_CR_I2CE (1 << 0)
+
+/* I2C Status Register (I2C_SR) */
+
+#define I2C_SR_STX (1 << 4)
+#define I2C_SR_BUSY (1 << 3)
+#define I2C_SR_TEND (1 << 2)
+#define I2C_SR_DRF (1 << 1)
+#define I2C_SR_ACKF (1 << 0)
+
+
+
+
+/*************************************************************************
+ * UDC
+ *************************************************************************/
+#define UDC_EP0InCR (UDC_BASE + 0x00)
+#define UDC_EP0InSR (UDC_BASE + 0x04)
+#define UDC_EP0InBSR (UDC_BASE + 0x08)
+#define UDC_EP0InMPSR (UDC_BASE + 0x0c)
+#define UDC_EP0InDesR (UDC_BASE + 0x14)
+#define UDC_EP1InCR (UDC_BASE + 0x20)
+#define UDC_EP1InSR (UDC_BASE + 0x24)
+#define UDC_EP1InBSR (UDC_BASE + 0x28)
+#define UDC_EP1InMPSR (UDC_BASE + 0x2c)
+#define UDC_EP1InDesR (UDC_BASE + 0x34)
+#define UDC_EP2InCR (UDC_BASE + 0x40)
+#define UDC_EP2InSR (UDC_BASE + 0x44)
+#define UDC_EP2InBSR (UDC_BASE + 0x48)
+#define UDC_EP2InMPSR (UDC_BASE + 0x4c)
+#define UDC_EP2InDesR (UDC_BASE + 0x54)
+#define UDC_EP3InCR (UDC_BASE + 0x60)
+#define UDC_EP3InSR (UDC_BASE + 0x64)
+#define UDC_EP3InBSR (UDC_BASE + 0x68)
+#define UDC_EP3InMPSR (UDC_BASE + 0x6c)
+#define UDC_EP3InDesR (UDC_BASE + 0x74)
+#define UDC_EP4InCR (UDC_BASE + 0x80)
+#define UDC_EP4InSR (UDC_BASE + 0x84)
+#define UDC_EP4InBSR (UDC_BASE + 0x88)
+#define UDC_EP4InMPSR (UDC_BASE + 0x8c)
+#define UDC_EP4InDesR (UDC_BASE + 0x94)
+
+#define UDC_EP0OutCR (UDC_BASE + 0x200)
+#define UDC_EP0OutSR (UDC_BASE + 0x204)
+#define UDC_EP0OutPFNR (UDC_BASE + 0x208)
+#define UDC_EP0OutMPSR (UDC_BASE + 0x20c)
+#define UDC_EP0OutSBPR (UDC_BASE + 0x210)
+#define UDC_EP0OutDesR (UDC_BASE + 0x214)
+#define UDC_EP5OutCR (UDC_BASE + 0x2a0)
+#define UDC_EP5OutSR (UDC_BASE + 0x2a4)
+#define UDC_EP5OutPFNR (UDC_BASE + 0x2a8)
+#define UDC_EP5OutMPSR (UDC_BASE + 0x2ac)
+#define UDC_EP5OutDesR (UDC_BASE + 0x2b4)
+#define UDC_EP6OutCR (UDC_BASE + 0x2c0)
+#define UDC_EP6OutSR (UDC_BASE + 0x2c4)
+#define UDC_EP6OutPFNR (UDC_BASE + 0x2c8)
+#define UDC_EP6OutMPSR (UDC_BASE + 0x2cc)
+#define UDC_EP6OutDesR (UDC_BASE + 0x2d4)
+#define UDC_EP7OutCR (UDC_BASE + 0x2e0)
+#define UDC_EP7OutSR (UDC_BASE + 0x2e4)
+#define UDC_EP7OutPFNR (UDC_BASE + 0x2e8)
+#define UDC_EP7OutMPSR (UDC_BASE + 0x2ec)
+#define UDC_EP7OutDesR (UDC_BASE + 0x2f4)
+
+#define UDC_DevCFGR (UDC_BASE + 0x400)
+#define UDC_DevCR (UDC_BASE + 0x404)
+#define UDC_DevSR (UDC_BASE + 0x408)
+#define UDC_DevIntR (UDC_BASE + 0x40c)
+#define UDC_DevIntMR (UDC_BASE + 0x410)
+#define UDC_EPIntR (UDC_BASE + 0x414)
+#define UDC_EPIntMR (UDC_BASE + 0x418)
+
+#define UDC_STCMAR (UDC_BASE + 0x500)
+#define UDC_EP0InfR (UDC_BASE + 0x504)
+#define UDC_EP1InfR (UDC_BASE + 0x508)
+#define UDC_EP2InfR (UDC_BASE + 0x50c)
+#define UDC_EP3InfR (UDC_BASE + 0x510)
+#define UDC_EP4InfR (UDC_BASE + 0x514)
+#define UDC_EP5InfR (UDC_BASE + 0x518)
+#define UDC_EP6InfR (UDC_BASE + 0x51c)
+#define UDC_EP7InfR (UDC_BASE + 0x520)
+
+#define UDC_TXCONFIRM (UDC_BASE + 0x41C)
+#define UDC_TXZLP (UDC_BASE + 0x420)
+#define UDC_RXCONFIRM (UDC_BASE + 0x41C)
+
+#define UDC_RXFIFO (UDC_BASE + 0x800)
+#define UDC_TXFIFOEP0 (UDC_BASE + 0x840)
+
+#define REG_UDC_EP0InCR REG32(UDC_EP0InCR)
+#define REG_UDC_EP0InSR REG32(UDC_EP0InSR)
+#define REG_UDC_EP0InBSR REG32(UDC_EP0InBSR)
+#define REG_UDC_EP0InMPSR REG32(UDC_EP0InMPSR)
+#define REG_UDC_EP0InDesR REG32(UDC_EP0InDesR)
+#define REG_UDC_EP1InCR REG32(UDC_EP1InCR)
+#define REG_UDC_EP1InSR REG32(UDC_EP1InSR)
+#define REG_UDC_EP1InBSR REG32(UDC_EP1InBSR)
+#define REG_UDC_EP1InMPSR REG32(UDC_EP1InMPSR)
+#define REG_UDC_EP1InDesR REG32(UDC_EP1InDesR)
+#define REG_UDC_EP2InCR REG32(UDC_EP2InCR)
+#define REG_UDC_EP2InSR REG32(UDC_EP2InSR)
+#define REG_UDC_EP2InBSR REG32(UDC_EP2InBSR)
+#define REG_UDC_EP2InMPSR REG32(UDC_EP2InMPSR)
+#define REG_UDC_EP2InDesR REG32(UDC_EP2InDesR)
+#define REG_UDC_EP3InCR REG32(UDC_EP3InCR)
+#define REG_UDC_EP3InSR REG32(UDC_EP3InSR)
+#define REG_UDC_EP3InBSR REG32(UDC_EP3InBSR)
+#define REG_UDC_EP3InMPSR REG32(UDC_EP3InMPSR)
+#define REG_UDC_EP3InDesR REG32(UDC_EP3InDesR)
+#define REG_UDC_EP4InCR REG32(UDC_EP4InCR)
+#define REG_UDC_EP4InSR REG32(UDC_EP4InSR)
+#define REG_UDC_EP4InBSR REG32(UDC_EP4InBSR)
+#define REG_UDC_EP4InMPSR REG32(UDC_EP4InMPSR)
+#define REG_UDC_EP4InDesR REG32(UDC_EP4InDesR)
+
+#define REG_UDC_EP0OutCR REG32(UDC_EP0OutCR)
+#define REG_UDC_EP0OutSR REG32(UDC_EP0OutSR)
+#define REG_UDC_EP0OutPFNR REG32(UDC_EP0OutPFNR)
+#define REG_UDC_EP0OutMPSR REG32(UDC_EP0OutMPSR)
+#define REG_UDC_EP0OutSBPR REG32(UDC_EP0OutSBPR)
+#define REG_UDC_EP0OutDesR REG32(UDC_EP0OutDesR)
+#define REG_UDC_EP5OutCR REG32(UDC_EP5OutCR)
+#define REG_UDC_EP5OutSR REG32(UDC_EP5OutSR)
+#define REG_UDC_EP5OutPFNR REG32(UDC_EP5OutPFNR)
+#define REG_UDC_EP5OutMPSR REG32(UDC_EP5OutMPSR)
+#define REG_UDC_EP5OutDesR REG32(UDC_EP5OutDesR)
+#define REG_UDC_EP6OutCR REG32(UDC_EP6OutCR)
+#define REG_UDC_EP6OutSR REG32(UDC_EP6OutSR)
+#define REG_UDC_EP6OutPFNR REG32(UDC_EP6OutPFNR)
+#define REG_UDC_EP6OutMPSR REG32(UDC_EP6OutMPSR)
+#define REG_UDC_EP6OutDesR REG32(UDC_EP6OutDesR)
+#define REG_UDC_EP7OutCR REG32(UDC_EP7OutCR)
+#define REG_UDC_EP7OutSR REG32(UDC_EP7OutSR)
+#define REG_UDC_EP7OutPFNR REG32(UDC_EP7OutPFNR)
+#define REG_UDC_EP7OutMPSR REG32(UDC_EP7OutMPSR)
+#define REG_UDC_EP7OutDesR REG32(UDC_EP7OutDesR)
+
+#define REG_UDC_DevCFGR REG32(UDC_DevCFGR)
+#define REG_UDC_DevCR REG32(UDC_DevCR)
+#define REG_UDC_DevSR REG32(UDC_DevSR)
+#define REG_UDC_DevIntR REG32(UDC_DevIntR)
+#define REG_UDC_DevIntMR REG32(UDC_DevIntMR)
+#define REG_UDC_EPIntR REG32(UDC_EPIntR)
+#define REG_UDC_EPIntMR REG32(UDC_EPIntMR)
+
+#define REG_UDC_STCMAR REG32(UDC_STCMAR)
+#define REG_UDC_EP0InfR REG32(UDC_EP0InfR)
+#define REG_UDC_EP1InfR REG32(UDC_EP1InfR)
+#define REG_UDC_EP2InfR REG32(UDC_EP2InfR)
+#define REG_UDC_EP3InfR REG32(UDC_EP3InfR)
+#define REG_UDC_EP4InfR REG32(UDC_EP4InfR)
+#define REG_UDC_EP5InfR REG32(UDC_EP5InfR)
+#define REG_UDC_EP6InfR REG32(UDC_EP6InfR)
+#define REG_UDC_EP7InfR REG32(UDC_EP7InfR)
+
+#define UDC_DevCFGR_PI (1 << 5)
+#define UDC_DevCFGR_SS (1 << 4)
+#define UDC_DevCFGR_SP (1 << 3)
+#define UDC_DevCFGR_RW (1 << 2)
+#define UDC_DevCFGR_SPD_BIT 0
+#define UDC_DevCFGR_SPD_MASK (0x03 << UDC_DevCFGR_SPD_BIT)
+ #define UDC_DevCFGR_SPD_HS (0 << UDC_DevCFGR_SPD_BIT)
+ #define UDC_DevCFGR_SPD_LS (2 << UDC_DevCFGR_SPD_BIT)
+ #define UDC_DevCFGR_SPD_FS (3 << UDC_DevCFGR_SPD_BIT)
+
+#define UDC_DevCR_DM (1 << 9)
+#define UDC_DevCR_BE (1 << 5)
+#define UDC_DevCR_RES (1 << 0)
+
+#define UDC_DevSR_ENUMSPD_BIT 13
+#define UDC_DevSR_ENUMSPD_MASK (0x03 << UDC_DevSR_ENUMSPD_BIT)
+ #define UDC_DevSR_ENUMSPD_HS (0 << UDC_DevSR_ENUMSPD_BIT)
+ #define UDC_DevSR_ENUMSPD_LS (2 << UDC_DevSR_ENUMSPD_BIT)
+ #define UDC_DevSR_ENUMSPD_FS (3 << UDC_DevSR_ENUMSPD_BIT)
+#define UDC_DevSR_SUSP (1 << 12)
+#define UDC_DevSR_ALT_BIT 8
+#define UDC_DevSR_ALT_MASK (0x0f << UDC_DevSR_ALT_BIT)
+#define UDC_DevSR_INTF_BIT 4
+#define UDC_DevSR_INTF_MASK (0x0f << UDC_DevSR_INTF_BIT)
+#define UDC_DevSR_CFG_BIT 0
+#define UDC_DevSR_CFG_MASK (0x0f << UDC_DevSR_CFG_BIT)
+
+#define UDC_DevIntR_ENUM (1 << 6)
+#define UDC_DevIntR_SOF (1 << 5)
+#define UDC_DevIntR_US (1 << 4)
+#define UDC_DevIntR_UR (1 << 3)
+#define UDC_DevIntR_SI (1 << 1)
+#define UDC_DevIntR_SC (1 << 0)
+
+#define UDC_EPIntR_OUTEP_BIT 16
+#define UDC_EPIntR_OUTEP_MASK (0xffff << UDC_EPIntR_OUTEP_BIT)
+#define UDC_EPIntR_OUTEP0 0x00010000
+#define UDC_EPIntR_OUTEP5 0x00200000
+#define UDC_EPIntR_OUTEP6 0x00400000
+#define UDC_EPIntR_OUTEP7 0x00800000
+#define UDC_EPIntR_INEP_BIT 0
+#define UDC_EPIntR_INEP_MASK (0xffff << UDC_EPIntR_INEP_BIT)
+#define UDC_EPIntR_INEP0 0x00000001
+#define UDC_EPIntR_INEP1 0x00000002
+#define UDC_EPIntR_INEP2 0x00000004
+#define UDC_EPIntR_INEP3 0x00000008
+#define UDC_EPIntR_INEP4 0x00000010
+
+
+#define UDC_EPIntMR_OUTEP_BIT 16
+#define UDC_EPIntMR_OUTEP_MASK (0xffff << UDC_EPIntMR_OUTEP_BIT)
+#define UDC_EPIntMR_INEP_BIT 0
+#define UDC_EPIntMR_INEP_MASK (0xffff << UDC_EPIntMR_INEP_BIT)
+
+#define UDC_EPCR_ET_BIT 4
+#define UDC_EPCR_ET_MASK (0x03 << UDC_EPCR_ET_BIT)
+ #define UDC_EPCR_ET_CTRL (0 << UDC_EPCR_ET_BIT)
+ #define UDC_EPCR_ET_ISO (1 << UDC_EPCR_ET_BIT)
+ #define UDC_EPCR_ET_BULK (2 << UDC_EPCR_ET_BIT)
+ #define UDC_EPCR_ET_INTR (3 << UDC_EPCR_ET_BIT)
+#define UDC_EPCR_SN (1 << 2)
+#define UDC_EPCR_F (1 << 1)
+#define UDC_EPCR_S (1 << 0)
+
+#define UDC_EPSR_RXPKTSIZE_BIT 11
+#define UDC_EPSR_RXPKTSIZE_MASK (0x7ff << UDC_EPSR_RXPKTSIZE_BIT)
+#define UDC_EPSR_IN (1 << 6)
+#define UDC_EPSR_OUT_BIT 4
+#define UDC_EPSR_OUT_MASK (0x03 << UDC_EPSR_OUT_BIT)
+ #define UDC_EPSR_OUT_NONE (0 << UDC_EPSR_OUT_BIT)
+ #define UDC_EPSR_OUT_RCVDATA (1 << UDC_EPSR_OUT_BIT)
+ #define UDC_EPSR_OUT_RCVSETUP (2 << UDC_EPSR_OUT_BIT)
+#define UDC_EPSR_PID_BIT 0
+#define UDC_EPSR_PID_MASK (0x0f << UDC_EPSR_PID_BIT)
+
+#define UDC_EPInfR_MPS_BIT 19
+#define UDC_EPInfR_MPS_MASK (0x3ff << UDC_EPInfR_MPS_BIT)
+#define UDC_EPInfR_ALTS_BIT 15
+#define UDC_EPInfR_ALTS_MASK (0x0f << UDC_EPInfR_ALTS_BIT)
+#define UDC_EPInfR_IFN_BIT 11
+#define UDC_EPInfR_IFN_MASK (0x0f << UDC_EPInfR_IFN_BIT)
+#define UDC_EPInfR_CGN_BIT 7
+#define UDC_EPInfR_CGN_MASK (0x0f << UDC_EPInfR_CGN_BIT)
+#define UDC_EPInfR_EPT_BIT 5
+#define UDC_EPInfR_EPT_MASK (0x03 << UDC_EPInfR_EPT_BIT)
+ #define UDC_EPInfR_EPT_CTRL (0 << UDC_EPInfR_EPT_BIT)
+ #define UDC_EPInfR_EPT_ISO (1 << UDC_EPInfR_EPT_BIT)
+ #define UDC_EPInfR_EPT_BULK (2 << UDC_EPInfR_EPT_BIT)
+ #define UDC_EPInfR_EPT_INTR (3 << UDC_EPInfR_EPT_BIT)
+#define UDC_EPInfR_EPD (1 << 4)
+ #define UDC_EPInfR_EPD_OUT (0 << 4)
+ #define UDC_EPInfR_EPD_IN (1 << 4)
+
+#define UDC_EPInfR_EPN_BIT 0
+#define UDC_EPInfR_EPN_MASK (0xf << UDC_EPInfR_EPN_BIT)
+
+
+
+
+/*************************************************************************
+ * DMAC
+ *************************************************************************/
+#define DMAC_DSAR(n) (DMAC_BASE + (0x00 + (n) * 0x20))
+#define DMAC_DDAR(n) (DMAC_BASE + (0x04 + (n) * 0x20))
+#define DMAC_DTCR(n) (DMAC_BASE + (0x08 + (n) * 0x20))
+#define DMAC_DRSR(n) (DMAC_BASE + (0x0c + (n) * 0x20))
+#define DMAC_DCCSR(n) (DMAC_BASE + (0x10 + (n) * 0x20))
+#define DMAC_DMAIPR (DMAC_BASE + 0xf8)
+#define DMAC_DMACR (DMAC_BASE + 0xfc)
+
+#define REG_DMAC_DSAR(n) REG32(DMAC_DSAR((n)))
+#define REG_DMAC_DDAR(n) REG32(DMAC_DDAR((n)))
+#define REG_DMAC_DTCR(n) REG32(DMAC_DTCR((n)))
+#define REG_DMAC_DRSR(n) REG32(DMAC_DRSR((n)))
+#define REG_DMAC_DCCSR(n) REG32(DMAC_DCCSR((n)))
+#define REG_DMAC_DMAIPR REG32(DMAC_DMAIPR)
+#define REG_DMAC_DMACR REG32(DMAC_DMACR)
+
+#define DMAC_DRSR_RS_BIT 0
+#define DMAC_DRSR_RS_MASK (0x1f << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_EXTREXTR (0 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_PCMCIAOUT (4 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_PCMCIAIN (5 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_DESOUT (10 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_DESIN (11 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART3OUT (14 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART3IN (15 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART2OUT (16 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART2IN (17 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART1OUT (18 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART1IN (19 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSIOUT (22 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSIIN (23 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSCOUT (26 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSCIN (27 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_OST2 (28 << DMAC_DRSR_RS_BIT)
+
+#define DMAC_DCCSR_EACKS (1 << 31)
+#define DMAC_DCCSR_EACKM (1 << 30)
+#define DMAC_DCCSR_ERDM_BIT 28
+#define DMAC_DCCSR_ERDM_MASK (0x03 << DMAC_DCCSR_ERDM_BIT)
+ #define DMAC_DCCSR_ERDM_LLEVEL (0 << DMAC_DCCSR_ERDM_BIT)
+ #define DMAC_DCCSR_ERDM_FEDGE (1 << DMAC_DCCSR_ERDM_BIT)
+ #define DMAC_DCCSR_ERDM_HLEVEL (2 << DMAC_DCCSR_ERDM_BIT)
+ #define DMAC_DCCSR_ERDM_REDGE (3 << DMAC_DCCSR_ERDM_BIT)
+#define DMAC_DCCSR_EOPM (1 << 27)
+#define DMAC_DCCSR_SAM (1 << 23)
+#define DMAC_DCCSR_DAM (1 << 22)
+#define DMAC_DCCSR_RDIL_BIT 16
+#define DMAC_DCCSR_RDIL_MASK (0x0f << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_IGN (0 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_2 (1 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_4 (2 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_8 (3 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_12 (4 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_16 (5 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_20 (6 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_24 (7 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_28 (8 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_32 (9 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_48 (10 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_60 (11 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_64 (12 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_124 (13 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_128 (14 << DMAC_DCCSR_RDIL_BIT)
+ #define DMAC_DCCSR_RDIL_200 (15 << DMAC_DCCSR_RDIL_BIT)
+#define DMAC_DCCSR_SWDH_BIT 14
+#define DMAC_DCCSR_SWDH_MASK (0x03 << DMAC_DCCSR_SWDH_BIT)
+ #define DMAC_DCCSR_SWDH_32 (0 << DMAC_DCCSR_SWDH_BIT)
+ #define DMAC_DCCSR_SWDH_8 (1 << DMAC_DCCSR_SWDH_BIT)
+ #define DMAC_DCCSR_SWDH_16 (2 << DMAC_DCCSR_SWDH_BIT)
+#define DMAC_DCCSR_DWDH_BIT 12
+#define DMAC_DCCSR_DWDH_MASK (0x03 << DMAC_DCCSR_DWDH_BIT)
+ #define DMAC_DCCSR_DWDH_32 (0 << DMAC_DCCSR_DWDH_BIT)
+ #define DMAC_DCCSR_DWDH_8 (1 << DMAC_DCCSR_DWDH_BIT)
+ #define DMAC_DCCSR_DWDH_16 (2 << DMAC_DCCSR_DWDH_BIT)
+#define DMAC_DCCSR_DS_BIT 8
+#define DMAC_DCCSR_DS_MASK (0x07 << DMAC_DCCSR_DS_BIT)
+ #define DMAC_DCCSR_DS_32b (0 << DMAC_DCCSR_DS_BIT)
+ #define DMAC_DCCSR_DS_8b (1 << DMAC_DCCSR_DS_BIT)
+ #define DMAC_DCCSR_DS_16b (2 << DMAC_DCCSR_DS_BIT)
+ #define DMAC_DCCSR_DS_16B (3 << DMAC_DCCSR_DS_BIT)
+ #define DMAC_DCCSR_DS_32B (4 << DMAC_DCCSR_DS_BIT)
+#define DMAC_DCCSR_TM (1 << 7)
+#define DMAC_DCCSR_AR (1 << 4)
+#define DMAC_DCCSR_TC (1 << 3)
+#define DMAC_DCCSR_HLT (1 << 2)
+#define DMAC_DCCSR_TCIE (1 << 1)
+#define DMAC_DCCSR_CHDE (1 << 0)
+
+#define DMAC_DMAIPR_CINT_BIT 8
+#define DMAC_DMAIPR_CINT_MASK (0xff << DMAC_DMAIPR_CINT_BIT)
+
+#define DMAC_DMACR_PR_BIT 8
+#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_01234567 (0 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_02314675 (1 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_20136457 (2 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_ROUNDROBIN (3 << DMAC_DMACR_PR_BIT)
+#define DMAC_DMACR_HTR (1 << 3)
+#define DMAC_DMACR_AER (1 << 2)
+#define DMAC_DMACR_DME (1 << 0)
+
+#define IRQ_DMA_0 32
+#define NUM_DMA 6
+
+#define DMAC_DSAR0 DMAC_DSAR(0)
+#define DMAC_DDAR0 DMAC_DDAR(0)
+#define DMAC_DTCR0 DMAC_DTCR(0)
+#define DMAC_DRSR0 DMAC_DRSR(0)
+#define DMAC_DCCSR0 DMAC_DCCSR(0)
+
+#define DMAC_DSAR1 DMAC_DSAR(1)
+#define DMAC_DDAR1 DMAC_DDAR(1)
+#define DMAC_DTCR1 DMAC_DTCR(1)
+#define DMAC_DRSR1 DMAC_DRSR(1)
+#define DMAC_DCCSR1 DMAC_DCCSR(1)
+
+#define DMAC_DSAR2 DMAC_DSAR(2)
+#define DMAC_DDAR2 DMAC_DDAR(2)
+#define DMAC_DTCR2 DMAC_DTCR(2)
+#define DMAC_DRSR2 DMAC_DRSR(2)
+#define DMAC_DCCSR2 DMAC_DCCSR(2)
+
+#define DMAC_DSAR3 DMAC_DSAR(3)
+#define DMAC_DDAR3 DMAC_DDAR(3)
+#define DMAC_DTCR3 DMAC_DTCR(3)
+#define DMAC_DRSR3 DMAC_DRSR(3)
+#define DMAC_DCCSR3 DMAC_DCCSR(3)
+
+#define DMAC_DSAR4 DMAC_DSAR(4)
+#define DMAC_DDAR4 DMAC_DDAR(4)
+#define DMAC_DTCR4 DMAC_DTCR(4)
+#define DMAC_DRSR4 DMAC_DRSR(4)
+#define DMAC_DCCSR4 DMAC_DCCSR(4)
+
+#define DMAC_DSAR5 DMAC_DSAR(5)
+#define DMAC_DDAR5 DMAC_DDAR(5)
+#define DMAC_DTCR5 DMAC_DTCR(5)
+#define DMAC_DRSR5 DMAC_DRSR(5)
+#define DMAC_DCCSR5 DMAC_DCCSR(5)
+
+#define DMAC_DSAR6 DMAC_DSAR(6)
+#define DMAC_DDAR6 DMAC_DDAR(6)
+#define DMAC_DTCR6 DMAC_DTCR(6)
+#define DMAC_DRSR6 DMAC_DRSR(6)
+#define DMAC_DCCSR6 DMAC_DCCSR(6)
+
+#define DMAC_DSAR7 DMAC_DSAR(7)
+#define DMAC_DDAR7 DMAC_DDAR(7)
+#define DMAC_DTCR7 DMAC_DTCR(7)
+#define DMAC_DRSR7 DMAC_DRSR(7)
+#define DMAC_DCCSR7 DMAC_DCCSR(7)
+
+
+
+/*************************************************************************
+ * AIC
+ *************************************************************************/
+#define AIC_FR (AIC_BASE + 0x000)
+#define AIC_CR (AIC_BASE + 0x004)
+#define AIC_ACCR1 (AIC_BASE + 0x008)
+#define AIC_ACCR2 (AIC_BASE + 0x00C)
+#define AIC_I2SCR (AIC_BASE + 0x010)
+#define AIC_SR (AIC_BASE + 0x014)
+#define AIC_ACSR (AIC_BASE + 0x018)
+#define AIC_I2SSR (AIC_BASE + 0x01C)
+#define AIC_ACCAR (AIC_BASE + 0x020)
+#define AIC_ACCDR (AIC_BASE + 0x024)
+#define AIC_ACSAR (AIC_BASE + 0x028)
+#define AIC_ACSDR (AIC_BASE + 0x02C)
+#define AIC_I2SDIV (AIC_BASE + 0x030)
+#define AIC_DR (AIC_BASE + 0x034)
+
+#define REG_AIC_FR REG32(AIC_FR)
+#define REG_AIC_CR REG32(AIC_CR)
+#define REG_AIC_ACCR1 REG32(AIC_ACCR1)
+#define REG_AIC_ACCR2 REG32(AIC_ACCR2)
+#define REG_AIC_I2SCR REG32(AIC_I2SCR)
+#define REG_AIC_SR REG32(AIC_SR)
+#define REG_AIC_ACSR REG32(AIC_ACSR)
+#define REG_AIC_I2SSR REG32(AIC_I2SSR)
+#define REG_AIC_ACCAR REG32(AIC_ACCAR)
+#define REG_AIC_ACCDR REG32(AIC_ACCDR)
+#define REG_AIC_ACSAR REG32(AIC_ACSAR)
+#define REG_AIC_ACSDR REG32(AIC_ACSDR)
+#define REG_AIC_I2SDIV REG32(AIC_I2SDIV)
+#define REG_AIC_DR REG32(AIC_DR)
+
+/* AIC Controller Configuration Register (AIC_FR) */
+
+#define AIC_FR_RFTH_BIT 12
+#define AIC_FR_RFTH_MASK (0xf << AIC_FR_RFTH_BIT)
+#define AIC_FR_TFTH_BIT 8
+#define AIC_FR_TFTH_MASK (0xf << AIC_FR_TFTH_BIT)
+#define AIC_FR_AUSEL (1 << 4)
+#define AIC_FR_RST (1 << 3)
+#define AIC_FR_BCKD (1 << 2)
+#define AIC_FR_SYNCD (1 << 1)
+#define AIC_FR_ENB (1 << 0)
+
+/* AIC Controller Common Control Register (AIC_CR) */
+
+#define AIC_CR_RDMS (1 << 15)
+#define AIC_CR_TDMS (1 << 14)
+#define AIC_CR_FLUSH (1 << 8)
+#define AIC_CR_EROR (1 << 6)
+#define AIC_CR_ETUR (1 << 5)
+#define AIC_CR_ERFS (1 << 4)
+#define AIC_CR_ETFS (1 << 3)
+#define AIC_CR_ENLBF (1 << 2)
+#define AIC_CR_ERPL (1 << 1)
+#define AIC_CR_EREC (1 << 0)
+
+/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */
+
+#define AIC_ACCR1_RS_BIT 16
+#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT)
+ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */
+ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */
+ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */
+ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit */
+ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit */
+ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit */
+ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit */
+ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */
+ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit */
+ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit */
+#define AIC_ACCR1_XS_BIT 0
+#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT)
+ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */
+ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */
+ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */
+ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit */
+ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit */
+ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit */
+ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit */
+ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */
+ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit */
+ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit */
+
+/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */
+
+#define AIC_ACCR2_ERSTO (1 << 18)
+#define AIC_ACCR2_ESADR (1 << 17)
+#define AIC_ACCR2_ECADT (1 << 16)
+#define AIC_ACCR2_OASS_BIT 8
+#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT)
+ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */
+ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */
+ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */
+ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */
+#define AIC_ACCR2_IASS_BIT 6
+#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT)
+ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */
+ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */
+ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */
+ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */
+#define AIC_ACCR2_SO (1 << 3)
+#define AIC_ACCR2_SR (1 << 2)
+#define AIC_ACCR2_SS (1 << 1)
+#define AIC_ACCR2_SA (1 << 0)
+
+/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */
+
+#define AIC_I2SCR_STPBK (1 << 12)
+#define AIC_I2SCR_WL_BIT 1
+#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT)
+ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */
+ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */
+ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */
+ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */
+ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */
+#define AIC_I2SCR_AMSL (1 << 0)
+
+/* AIC Controller FIFO Status Register (AIC_SR) */
+
+#define AIC_SR_RFL_BIT 24
+#define AIC_SR_RFL_MASK (0x1f << AIC_SR_RFL_BIT)
+#define AIC_SR_TFL_BIT 8
+#define AIC_SR_TFL_MASK (0x1f << AIC_SR_TFL_BIT)
+#define AIC_SR_ROR (1 << 6)
+#define AIC_SR_TUR (1 << 5)
+#define AIC_SR_RFS (1 << 4)
+#define AIC_SR_TFS (1 << 3)
+
+/* AIC Controller AC-link Status Register (AIC_ACSR) */
+
+#define AIC_ACSR_CRDY (1 << 20)
+#define AIC_ACSR_CLPM (1 << 19)
+#define AIC_ACSR_RSTO (1 << 18)
+#define AIC_ACSR_SADR (1 << 17)
+#define AIC_ACSR_CADT (1 << 16)
+
+/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */
+
+#define AIC_I2SSR_BSY (1 << 2)
+
+/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */
+
+#define AIC_ACCAR_CAR_BIT 0
+#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT)
+
+/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */
+
+#define AIC_ACCDR_CDR_BIT 0
+#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT)
+
+/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */
+
+#define AIC_ACSAR_SAR_BIT 0
+#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT)
+
+/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */
+
+#define AIC_ACSDR_SDR_BIT 0
+#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT)
+
+/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */
+
+#define AIC_I2SDIV_DIV_BIT 0
+#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT)
+ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */
+ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */
+ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */
+ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */
+ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */
+ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */
+
+
+
+
+/*************************************************************************
+ * LCD
+ *************************************************************************/
+#define LCD_CFG (LCD_BASE + 0x00)
+#define LCD_VSYNC (LCD_BASE + 0x04)
+#define LCD_HSYNC (LCD_BASE + 0x08)
+#define LCD_VAT (LCD_BASE + 0x0c)
+#define LCD_DAH (LCD_BASE + 0x10)
+#define LCD_DAV (LCD_BASE + 0x14)
+#define LCD_PS (LCD_BASE + 0x18)
+#define LCD_CLS (LCD_BASE + 0x1c)
+#define LCD_SPL (LCD_BASE + 0x20)
+#define LCD_REV (LCD_BASE + 0x24)
+#define LCD_CTRL (LCD_BASE + 0x30)
+#define LCD_STATE (LCD_BASE + 0x34)
+#define LCD_IID (LCD_BASE + 0x38)
+#define LCD_DA0 (LCD_BASE + 0x40)
+#define LCD_SA0 (LCD_BASE + 0x44)
+#define LCD_FID0 (LCD_BASE + 0x48)
+#define LCD_CMD0 (LCD_BASE + 0x4c)
+#define LCD_DA1 (LCD_BASE + 0x50)
+#define LCD_SA1 (LCD_BASE + 0x54)
+#define LCD_FID1 (LCD_BASE + 0x58)
+#define LCD_CMD1 (LCD_BASE + 0x5c)
+
+#define REG_LCD_CFG REG32(LCD_CFG)
+#define REG_LCD_VSYNC REG32(LCD_VSYNC)
+#define REG_LCD_HSYNC REG32(LCD_HSYNC)
+#define REG_LCD_VAT REG32(LCD_VAT)
+#define REG_LCD_DAH REG32(LCD_DAH)
+#define REG_LCD_DAV REG32(LCD_DAV)
+#define REG_LCD_PS REG32(LCD_PS)
+#define REG_LCD_CLS REG32(LCD_CLS)
+#define REG_LCD_SPL REG32(LCD_SPL)
+#define REG_LCD_REV REG32(LCD_REV)
+#define REG_LCD_CTRL REG32(LCD_CTRL)
+#define REG_LCD_STATE REG32(LCD_STATE)
+#define REG_LCD_IID REG32(LCD_IID)
+#define REG_LCD_DA0 REG32(LCD_DA0)
+#define REG_LCD_SA0 REG32(LCD_SA0)
+#define REG_LCD_FID0 REG32(LCD_FID0)
+#define REG_LCD_CMD0 REG32(LCD_CMD0)
+#define REG_LCD_DA1 REG32(LCD_DA1)
+#define REG_LCD_SA1 REG32(LCD_SA1)
+#define REG_LCD_FID1 REG32(LCD_FID1)
+#define REG_LCD_CMD1 REG32(LCD_CMD1)
+
+#define LCD_CFG_PDW_BIT 4
+#define LCD_CFG_PDW_MASK (0x03 << LCD_DEV_PDW_BIT)
+ #define LCD_CFG_PDW_1 (0 << LCD_DEV_PDW_BIT)
+ #define LCD_CFG_PDW_2 (1 << LCD_DEV_PDW_BIT)
+ #define LCD_CFG_PDW_4 (2 << LCD_DEV_PDW_BIT)
+ #define LCD_CFG_PDW_8 (3 << LCD_DEV_PDW_BIT)
+#define LCD_CFG_MODE_BIT 0
+#define LCD_CFG_MODE_MASK (0x0f << LCD_DEV_MODE_BIT)
+ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_DEV_MODE_BIT)
+ #define LCD_CFG_MODE_SHARP_HR (1 << LCD_DEV_MODE_BIT)
+ #define LCD_CFG_MODE_CASIO_TFT (2 << LCD_DEV_MODE_BIT)
+ #define LCD_CFG_MODE_SAMSUNG_ALPHA (3 << LCD_DEV_MODE_BIT)
+ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_DEV_MODE_BIT)
+ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_DEV_MODE_BIT)
+ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_DEV_MODE_BIT)
+ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_DEV_MODE_BIT)
+ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_DEV_MODE_BIT)
+ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_DEV_MODE_BIT)
+
+#define LCD_VSYNC_VPS_BIT 16
+#define LCD_VSYNC_VPS_MASK (0xffff << LCD_VSYNC_VPS_BIT)
+#define LCD_VSYNC_VPE_BIT 0
+#define LCD_VSYNC_VPE_MASK (0xffff << LCD_VSYNC_VPS_BIT)
+
+#define LCD_HSYNC_HPS_BIT 16
+#define LCD_HSYNC_HPS_MASK (0xffff << LCD_HSYNC_HPS_BIT)
+#define LCD_HSYNC_HPE_BIT 0
+#define LCD_HSYNC_HPE_MASK (0xffff << LCD_HSYNC_HPE_BIT)
+
+#define LCD_VAT_HT_BIT 16
+#define LCD_VAT_HT_MASK (0xffff << LCD_VAT_HT_BIT)
+#define LCD_VAT_VT_BIT 0
+#define LCD_VAT_VT_MASK (0xffff << LCD_VAT_VT_BIT)
+
+#define LCD_DAH_HDS_BIT 16
+#define LCD_DAH_HDS_MASK (0xffff << LCD_DAH_HDS_BIT)
+#define LCD_DAH_HDE_BIT 0
+#define LCD_DAH_HDE_MASK (0xffff << LCD_DAH_HDE_BIT)
+
+#define LCD_DAV_VDS_BIT 16
+#define LCD_DAV_VDS_MASK (0xffff << LCD_DAV_VDS_BIT)
+#define LCD_DAV_VDE_BIT 0
+#define LCD_DAV_VDE_MASK (0xffff << LCD_DAV_VDE_BIT)
+
+#define LCD_CTRL_BST_BIT 28
+#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT)
+ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT)
+ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT)
+ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT)
+#define LCD_CTRL_RGB555 (1 << 27)
+#define LCD_CTRL_OFUP (1 << 26)
+#define LCD_CTRL_FRC_BIT 24
+#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT)
+ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT)
+ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT)
+ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT)
+#define LCD_CTRL_PDD_BIT 16
+#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT)
+#define LCD_CTRL_EOFM (1 << 13)
+#define LCD_CTRL_SOFM (1 << 12)
+#define LCD_CTRL_OFUM (1 << 11)
+#define LCD_CTRL_IFUM0 (1 << 10)
+#define LCD_CTRL_IFUM1 (1 << 9)
+#define LCD_CTRL_LDDM (1 << 8)
+#define LCD_CTRL_QDM (1 << 7)
+#define LCD_CTRL_BEDN (1 << 6)
+#define LCD_CTRL_PEDN (1 << 5)
+#define LCD_CTRL_DIS (1 << 4)
+#define LCD_CTRL_ENA (1 << 3)
+#define LCD_CTRL_BPP_BIT 0
+#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT)
+ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT)
+ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT)
+ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT)
+ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT)
+ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT)
+
+#define LCD_STATE_QD (1 << 7)
+#define LCD_STATE_EOF (1 << 5)
+#define LCD_STATE_SOF (1 << 4)
+#define LCD_STATE_OFU (1 << 3)
+#define LCD_STATE_IFU0 (1 << 2)
+#define LCD_STATE_IFU1 (1 << 1)
+#define LCD_STATE_LDD (1 << 0)
+
+#define LCD_CMD_SOFINT (1 << 31)
+#define LCD_CMD_EOFINT (1 << 30)
+#define LCD_CMD_PAL (1 << 28)
+#define LCD_CMD_LEN_BIT 0
+#define LCD_CMD_LEN_MASK (0xffffff << LCD_CMD_LEN_BIT)
+
+
+
+
+/*************************************************************************
+ * DES
+ *************************************************************************/
+#define DES_CR1 (DES_BASE + 0x000)
+#define DES_CR2 (DES_BASE + 0x004)
+#define DES_SR (DES_BASE + 0x008)
+#define DES_K1L (DES_BASE + 0x010)
+#define DES_K1R (DES_BASE + 0x014)
+#define DES_K2L (DES_BASE + 0x018)
+#define DES_K2R (DES_BASE + 0x01C)
+#define DES_K3L (DES_BASE + 0x020)
+#define DES_K3R (DES_BASE + 0x024)
+#define DES_IVL (DES_BASE + 0x028)
+#define DES_IVR (DES_BASE + 0x02C)
+#define DES_DIN (DES_BASE + 0x030)
+#define DES_DOUT (DES_BASE + 0x034)
+
+#define REG_DES_CR1 REG32(DES_CR1)
+#define REG_DES_CR2 REG32(DES_CR2)
+#define REG_DES_SR REG32(DES_SR)
+#define REG_DES_K1L REG32(DES_K1L)
+#define REG_DES_K1R REG32(DES_K1R)
+#define REG_DES_K2L REG32(DES_K2L)
+#define REG_DES_K2R REG32(DES_K2R)
+#define REG_DES_K3L REG32(DES_K3L)
+#define REG_DES_K3R REG32(DES_K3R)
+#define REG_DES_IVL REG32(DES_IVL)
+#define REG_DES_IVR REG32(DES_IVR)
+#define REG_DES_DIN REG32(DES_DIN)
+#define REG_DES_DOUT REG32(DES_DOUT)
+
+/* DES Control Register 1 (DES_CR1) */
+
+#define DES_CR1_EN (1 << 0)
+
+/* DES Control Register 2 (DES_CR2) */
+
+#define DES_CR2_ENDEC (1 << 3)
+#define DES_CR2_MODE (1 << 2)
+#define DES_CR2_ALG (1 << 1)
+#define DES_CR2_DMAE (1 << 0)
+
+/* DES State Register (DES_SR) */
+
+#define DES_SR_IN_FULL (1 << 5)
+#define DES_SR_IN_LHF (1 << 4)
+#define DES_SR_IN_EMPTY (1 << 3)
+#define DES_SR_OUT_FULL (1 << 2)
+#define DES_SR_OUT_GHF (1 << 1)
+#define DES_SR_OUT_EMPTY (1 << 0)
+
+
+
+
+/*************************************************************************
+ * CPM
+ *************************************************************************/
+#define CPM_CFCR (CPM_BASE+0x00)
+#define CPM_PLCR1 (CPM_BASE+0x10)
+#define CPM_OCR (CPM_BASE+0x1c)
+#define CPM_CFCR2 (CPM_BASE+0x60)
+#define CPM_LPCR (CPM_BASE+0x04)
+#define CPM_RSTR (CPM_BASE+0x08)
+#define CPM_MSCR (CPM_BASE+0x20)
+#define CPM_SCR (CPM_BASE+0x24)
+#define CPM_WRER (CPM_BASE+0x28)
+#define CPM_WFER (CPM_BASE+0x2c)
+#define CPM_WER (CPM_BASE+0x30)
+#define CPM_WSR (CPM_BASE+0x34)
+#define CPM_GSR0 (CPM_BASE+0x38)
+#define CPM_GSR1 (CPM_BASE+0x3c)
+#define CPM_GSR2 (CPM_BASE+0x40)
+#define CPM_SPR (CPM_BASE+0x44)
+#define CPM_GSR3 (CPM_BASE+0x48)
+
+#define REG_CPM_CFCR REG32(CPM_CFCR)
+#define REG_CPM_PLCR1 REG32(CPM_PLCR1)
+#define REG_CPM_OCR REG32(CPM_OCR)
+#define REG_CPM_CFCR2 REG32(CPM_CFCR2)
+#define REG_CPM_LPCR REG32(CPM_LPCR)
+#define REG_CPM_RSTR REG32(CPM_RSTR)
+#define REG_CPM_MSCR REG32(CPM_MSCR)
+#define REG_CPM_SCR REG32(CPM_SCR)
+#define REG_CPM_WRER REG32(CPM_WRER)
+#define REG_CPM_WFER REG32(CPM_WFER)
+#define REG_CPM_WER REG32(CPM_WER)
+#define REG_CPM_WSR REG32(CPM_WSR)
+#define REG_CPM_GSR0 REG32(CPM_GSR0)
+#define REG_CPM_GSR1 REG32(CPM_GSR1)
+#define REG_CPM_GSR2 REG32(CPM_GSR2)
+#define REG_CPM_SPR REG32(CPM_SPR)
+#define REG_CPM_GSR3 REG32(CPM_GSR3)
+
+#define CPM_CFCR_SSI (1 << 31)
+#define CPM_CFCR_LCD (1 << 30)
+#define CPM_CFCR_I2S (1 << 29)
+#define CPM_CFCR_UCS (1 << 28)
+#define CPM_CFCR_UFR_BIT 25
+#define CPM_CFCR_UFR_MASK (0x07 << CPM_CFCR_UFR_BIT)
+#define CPM_CFCR_MSC (1 << 24)
+#define CPM_CFCR_CKOEN2 (1 << 23)
+#define CPM_CFCR_CKOEN1 (1 << 22)
+#define CPM_CFCR_UPE (1 << 20)
+#define CPM_CFCR_MFR_BIT 16
+#define CPM_CFCR_MFR_MASK (0x0f << CPM_CFCR_MFR_BIT)
+#define CPM_CFCR_LFR_BIT 12
+#define CPM_CFCR_LFR_MASK (0x0f << CPM_CFCR_LFR_BIT)
+#define CPM_CFCR_PFR_BIT 8
+#define CPM_CFCR_PFR_MASK (0x0f << CPM_CFCR_PFR_BIT)
+#define CPM_CFCR_SFR_BIT 4
+#define CPM_CFCR_SFR_MASK (0x0f << CPM_CFCR_SFR_BIT)
+#define CPM_CFCR_IFR_BIT 0
+#define CPM_CFCR_IFR_MASK (0x0f << CPM_CFCR_IFR_BIT)
+
+#define CPM_PLCR1_PLL1FD_BIT 23
+#define CPM_PLCR1_PLL1FD_MASK (0x1ff << CPM_PLCR1_PLL1FD_BIT)
+#define CPM_PLCR1_PLL1RD_BIT 18
+#define CPM_PLCR1_PLL1RD_MASK (0x1f << CPM_PLCR1_PLL1RD_BIT)
+#define CPM_PLCR1_PLL1OD_BIT 16
+#define CPM_PLCR1_PLL1OD_MASK (0x03 << CPM_PLCR1_PLL1OD_BIT)
+#define CPM_PLCR1_PLL1S (1 << 10)
+#define CPM_PLCR1_PLL1BP (1 << 9)
+#define CPM_PLCR1_PLL1EN (1 << 8)
+#define CPM_PLCR1_PLL1ST_BIT 0
+#define CPM_PLCR1_PLL1ST_MASK (0xff << CPM_PLCR1_PLL1ST_BIT)
+
+#define CPM_OCR_O1ST_BIT 16
+#define CPM_OCR_O1ST_MASK (0xff << CPM_OCR_O1ST_BIT)
+#define CPM_OCR_EXT_RTC_CLK (1<<8)
+#define CPM_OCR_SUSPEND_PHY1 (1<<7)
+#define CPM_OCR_SUSPEND_PHY0 (1<<6)
+
+#define CPM_CFCR2_PXFR_BIT 0
+#define CPM_CFCR2_PXFR_MASK (0x1ff << CPM_CFCR2_PXFR_BIT)
+
+#define CPM_LPCR_DUTY_BIT 3
+#define CPM_LPCR_DUTY_MASK (0x1f << CPM_LPCR_DUTY_BIT)
+#define CPM_LPCR_DOZE (1 << 2)
+#define CPM_LPCR_LPM_BIT 0
+#define CPM_LPCR_LPM_MASK (0x03 << CPM_LPCR_LPM_BIT)
+ #define CPM_LPCR_LPM_IDLE (0 << CPM_LPCR_LPM_BIT)
+ #define CPM_LPCR_LPM_SLEEP (1 << CPM_LPCR_LPM_BIT)
+ #define CPM_LPCR_LPM_HIBERNATE (2 << CPM_LPCR_LPM_BIT)
+
+#define CPM_RSTR_SR (1 << 2)
+#define CPM_RSTR_WR (1 << 1)
+#define CPM_RSTR_HR (1 << 0)
+
+#define CPM_MSCR_MSTP_BIT 0
+#define CPM_MSCR_MSTP_MASK (0x1ffffff << CPM_MSCR_MSTP_BIT)
+ #define CPM_MSCR_MSTP_UART0 0
+ #define CPM_MSCR_MSTP_UART1 1
+ #define CPM_MSCR_MSTP_UART2 2
+ #define CPM_MSCR_MSTP_OST 3
+ #define CPM_MSCR_MSTP_DMAC 5
+ #define CPM_MSCR_MSTP_UHC 6
+ #define CPM_MSCR_MSTP_LCD 7
+ #define CPM_MSCR_MSTP_I2C 8
+ #define CPM_MSCR_MSTP_AICPCLK 9
+ #define CPM_MSCR_MSTP_PWM0 10
+ #define CPM_MSCR_MSTP_PWM1 11
+ #define CPM_MSCR_MSTP_SSI 12
+ #define CPM_MSCR_MSTP_MSC 13
+ #define CPM_MSCR_MSTP_SCC 14
+ #define CPM_MSCR_MSTP_AICBCLK 18
+ #define CPM_MSCR_MSTP_UART3 20
+ #define CPM_MSCR_MSTP_ETH 21
+ #define CPM_MSCR_MSTP_KBC 22
+ #define CPM_MSCR_MSTP_CIM 23
+ #define CPM_MSCR_MSTP_UDC 24
+ #define CPM_MSCR_MSTP_UPRT 25
+
+#define CPM_SCR_O1SE (1 << 4)
+#define CPM_SCR_HGP (1 << 3)
+#define CPM_SCR_HZP (1 << 2)
+#define CPM_SCR_HZM (1 << 1)
+
+#define CPM_WRER_RE_BIT 0
+#define CPM_WRER_RE_MASK (0xffff << CPM_WRER_RE_BIT)
+
+#define CPM_WFER_FE_BIT 0
+#define CPM_WFER_FE_MASK (0xffff << CPM_WFER_FE_BIT)
+
+#define CPM_WER_WERTC (1 << 31)
+#define CPM_WER_WEETH (1 << 30)
+#define CPM_WER_WE_BIT 0
+#define CPM_WER_WE_MASK (0xffff << CPM_WER_WE_BIT)
+
+#define CPM_WSR_WSRTC (1 << 31)
+#define CPM_WSR_WSETH (1 << 30)
+#define CPM_WSR_WS_BIT 0
+#define CPM_WSR_WS_MASK (0xffff << CPM_WSR_WS_BIT)
+
+
+
+
+/*************************************************************************
+ * SSI
+ *************************************************************************/
+#define SSI_DR (SSI_BASE + 0x000)
+#define SSI_CR0 (SSI_BASE + 0x004)
+#define SSI_CR1 (SSI_BASE + 0x008)
+#define SSI_SR (SSI_BASE + 0x00C)
+#define SSI_ITR (SSI_BASE + 0x010)
+#define SSI_ICR (SSI_BASE + 0x014)
+#define SSI_GR (SSI_BASE + 0x018)
+
+#define REG_SSI_DR REG32(SSI_DR)
+#define REG_SSI_CR0 REG16(SSI_CR0)
+#define REG_SSI_CR1 REG32(SSI_CR1)
+#define REG_SSI_SR REG32(SSI_SR)
+#define REG_SSI_ITR REG16(SSI_ITR)
+#define REG_SSI_ICR REG8(SSI_ICR)
+#define REG_SSI_GR REG16(SSI_GR)
+
+/* SSI Data Register (SSI_DR) */
+
+#define SSI_DR_GPC_BIT 0
+#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT)
+
+/* SSI Control Register 0 (SSI_CR0) */
+
+#define SSI_CR0_SSIE (1 << 15)
+#define SSI_CR0_TIE (1 << 14)
+#define SSI_CR0_RIE (1 << 13)
+#define SSI_CR0_TEIE (1 << 12)
+#define SSI_CR0_REIE (1 << 11)
+#define SSI_CR0_LOOP (1 << 10)
+#define SSI_CR0_RFINE (1 << 9)
+#define SSI_CR0_RFINC (1 << 8)
+#define SSI_CR0_FSEL (1 << 6)
+#define SSI_CR0_TFLUSH (1 << 2)
+#define SSI_CR0_RFLUSH (1 << 1)
+#define SSI_CR0_DISREV (1 << 0)
+
+/* SSI Control Register 1 (SSI_CR1) */
+
+#define SSI_CR1_FRMHL_BIT 30
+#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT)
+ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */
+ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */
+ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */
+ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */
+#define SSI_CR1_TFVCK_BIT 28
+#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT)
+#define SSI_CR1_TCKFI_BIT 26
+#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT)
+#define SSI_CR1_LFST (1 << 25)
+#define SSI_CR1_ITFRM (1 << 24)
+#define SSI_CR1_UNFIN (1 << 23)
+#define SSI_CR1_MULTS (1 << 22)
+#define SSI_CR1_FMAT_BIT 20
+#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT)
+ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */
+ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */
+ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */
+ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */
+#define SSI_CR1_MCOM_BIT 12
+#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT)
+ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */
+ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */
+ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */
+ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */
+ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */
+ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */
+ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */
+ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */
+ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */
+ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */
+ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */
+ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */
+ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */
+ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */
+ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */
+ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */
+#define SSI_CR1_TTRG_BIT 10
+#define SSI_CR1_TTRG_MASK (0x3 << SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_1 (0 << SSI_CR1_TTRG_BIT)/* Less than or equal to 1 */
+ #define SSI_CR1_TTRG_4 (1 << SSI_CR1_TTRG_BIT) /* Less than or equal to 4 */
+ #define SSI_CR1_TTRG_8 (2 << SSI_CR1_TTRG_BIT) /* Less than or equal to 8 */
+ #define SSI_CR1_TTRG_14 (3 << SSI_CR1_TTRG_BIT) /* Less than or equal to 14 */
+#define SSI_CR1_RTRG_BIT 8
+#define SSI_CR1_RTRG_MASK (0x3 << SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_1 (0 << SSI_CR1_RTRG_BIT) /* More than or equal to 1 */
+ #define SSI_CR1_RTRG_4 (1 << SSI_CR1_RTRG_BIT) /* More than or equal to 4 */
+ #define SSI_CR1_RTRG_8 (2 << SSI_CR1_RTRG_BIT) /* More than or equal to 8 */
+ #define SSI_CR1_RTRG_14 (3 << SSI_CR1_RTRG_BIT) /* More than or equal to 14 */
+#define SSI_CR1_FLEN_BIT 4
+#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT)
+#define SSI_CR1_PHA (1 << 1)
+#define SSI_CR1_POL (1 << 0)
+
+/* SSI Status Register (SSI_SR) */
+
+#define SSI_SR_TFIFONUM_BIT 13
+#define SSI_SR_TFIFONUM_MASK (0x1f << SSI_SR_TFIFONUM_BIT)
+#define SSI_SR_RFIFONUM_BIT 8
+#define SSI_SR_RFIFONUM_MASK (0x1f << SSI_SR_RFIFONUM_BIT)
+#define SSI_SR_END (1 << 7)
+#define SSI_SR_BUSY (1 << 6)
+#define SSI_SR_TFF (1 << 5)
+#define SSI_SR_RFE (1 << 4)
+#define SSI_SR_TFHE (1 << 3)
+#define SSI_SR_RFHF (1 << 2)
+#define SSI_SR_UNDR (1 << 1)
+#define SSI_SR_OVER (1 << 0)
+
+/* SSI Interval Time Control Register (SSI_ITR) */
+
+#define SSI_ITR_CNTCLK (1 << 15)
+#define SSI_ITR_IVLTM_BIT 0
+#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT)
+
+#endif /* __ASM_JZ4730_REGS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4730/serial.h b/arch/mips/include/asm/mach-jz4730/serial.h
new file mode 100644
index 00000000000..4a0afc3fe6d
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4730/serial.h
@@ -0,0 +1,33 @@
+/*
+ * linux/include/asm-mips/mach-jz4730/serial.h
+ *
+ * JZ4730 serial port definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4730_SERIAL_H__
+#define __ASM_JZ4730_SERIAL_H__
+
+#define JZ_BASE_BAUD (JZ_EXTAL/16)
+#define JZ_SERIAL_PORT_DEFNS \
+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \
+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \
+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, \
+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART1, \
+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART1_BASE, \
+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, \
+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART2, \
+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART2_BASE, \
+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, \
+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART3, \
+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART3_BASE, \
+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM },
+
+#endif /* __ASM_JZ4730_SERIAL_H__ */
diff --git a/arch/mips/include/asm/mach-jz4730/war.h b/arch/mips/include/asm/mach-jz4730/war.h
new file mode 100644
index 00000000000..3a5bc17e28f
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4730/war.h
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H
+#define __ASM_MIPS_MACH_JZ4740_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR 0
+#define R4600_V1_HIT_CACHEOP_WAR 0
+#define R4600_V2_HIT_CACHEOP_WAR 0
+#define R5432_CP0_INTERRUPT_WAR 0
+#define BCM1250_M3_WAR 0
+#define SIBYTE_1956_WAR 0
+#define MIPS4K_ICACHE_REFILL_WAR 0
+#define MIPS_CACHE_SYNC_WAR 0
+#define TX49XX_ICACHE_INDEX_INV_WAR 0
+#define RM9000_CDEX_SMP_WAR 0
+#define ICACHE_REFILLS_WORKAROUND_WAR 0
+#define R10000_LLSC_WAR 0
+#define MIPS34K_MISSED_ITLB_WAR 0
+
+#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */
diff --git a/arch/mips/include/asm/mach-jz4740/board-dipper.h b/arch/mips/include/asm/mach-jz4740/board-dipper.h
new file mode 100644
index 00000000000..ae84f24d5f9
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/board-dipper.h
@@ -0,0 +1,69 @@
+/*
+ * linux/include/asm-mips/mach-jz4740/board-dipper.h
+ *
+ * JZ4725-based (16bit) Dipper board ver 1.x definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4725_DIPPER_H__
+#define __ASM_JZ4725_DIPPER_H__
+
+/*======================================================================
+ * Frequencies of on-board oscillators
+ */
+#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */
+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
+
+/*======================================================================
+ * GPIO JZ4725
+ */
+#define GPIO_SD_VCC_EN_N 85 /* GPC21 */
+#define GPIO_SD_CD_N 91 /* GPC27 */
+#define GPIO_SD_WP 112 /* GPD16 */
+#define GPIO_USB_DETE 124 /* GPD28 */
+#define GPIO_DC_DETE_N 103 /* GPD7 */
+#define GPIO_CHARG_STAT_N 86 /* GPC22 */
+#define GPIO_DISP_OFF_N 118 /* GPD22 */
+
+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
+
+/*======================================================================
+ * MMC/SD
+ */
+
+#define MSC_WP_PIN GPIO_SD_WP
+#define MSC_HOTPLUG_PIN GPIO_SD_CD_N
+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N)
+
+#define __msc_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD_VCC_EN_N); \
+ __gpio_as_input(GPIO_SD_CD_N); \
+} while (0)
+
+#define __msc_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \
+} while (0)
+
+#define __msc_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD_VCC_EN_N); \
+} while (0)
+
+#define __msc_card_detected(s) \
+({ \
+ int detected = 1; \
+ if (__gpio_get_pin(GPIO_SD_CD_N)) \
+ detected = 0; \
+ detected; \
+})
+
+#endif /* __ASM_JZ4740_DIPPER_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/board-leo.h b/arch/mips/include/asm/mach-jz4740/board-leo.h
new file mode 100644
index 00000000000..4b883e28834
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/board-leo.h
@@ -0,0 +1,56 @@
+#ifndef __ASM_JZ4740_LEO_H__
+#define __ASM_JZ4740_LEO_H__
+
+/*
+ * Define your board specific codes here !!!
+ */
+
+/*======================================================================
+ * Frequencies of on-board oscillators
+ */
+#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */
+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
+
+
+/*======================================================================
+ * GPIO
+ */
+#define GPIO_DISP_OFF_N 100
+#define GPIO_SD_VCC_EN_N 119
+#define GPIO_SD_CD_N 120
+#define GPIO_SD_WP 111
+
+/*======================================================================
+ * MMC/SD
+ */
+
+#define MSC_WP_PIN GPIO_SD_WP
+#define MSC_HOTPLUG_PIN GPIO_SD_CD_N
+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N)
+
+#define __msc_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD_VCC_EN_N); \
+ __gpio_as_input(GPIO_SD_CD_N); \
+} while (0)
+
+#define __msc_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \
+} while (0)
+
+#define __msc_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD_VCC_EN_N); \
+} while (0)
+
+#define __msc_card_detected(s) \
+({ \
+ int detected = 1; \
+ __gpio_as_input(GPIO_SD_CD_N); \
+ if (__gpio_get_pin(GPIO_SD_CD_N)) \
+ detected = 0; \
+ detected; \
+})
+
+#endif /* __ASM_JZ4740_BOARD_LEO_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/board-lyra.h b/arch/mips/include/asm/mach-jz4740/board-lyra.h
new file mode 100644
index 00000000000..29e0ce00fcc
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/board-lyra.h
@@ -0,0 +1,70 @@
+/*
+ * linux/include/asm-mips/mach-jz4740/board-lyra.h
+ *
+ * JZ4740-based LYRA board ver 2.x definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4740_LYRA_H__
+#define __ASM_JZ4740_LYRA_H__
+
+/*======================================================================
+ * Frequencies of on-board oscillators
+ */
+#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */
+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
+
+
+/*======================================================================
+ * GPIO
+ */
+#define GPIO_SD_VCC_EN_N 113 /* GPD17 */
+#define GPIO_SD_CD_N 110 /* GPD14 */
+#define GPIO_SD_WP 112 /* GPD16 */
+#define GPIO_USB_DETE 102 /* GPD6 */
+#define GPIO_DC_DETE_N 103 /* GPD7 */
+#define GPIO_CHARG_STAT_N 111 /* GPD15 */
+#define GPIO_DISP_OFF_N 118 /* GPD22 */
+#define GPIO_LED_EN 124 /* GPD28 */
+
+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
+/*======================================================================
+ * MMC/SD
+ */
+
+#define MSC_WP_PIN GPIO_SD_WP
+#define MSC_HOTPLUG_PIN GPIO_SD_CD_N
+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N)
+
+#define __msc_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD_VCC_EN_N); \
+ __gpio_as_input(GPIO_SD_CD_N); \
+} while (0)
+
+#define __msc_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \
+} while (0)
+
+#define __msc_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD_VCC_EN_N); \
+} while (0)
+
+#define __msc_card_detected(s) \
+({ \
+ int detected = 1; \
+ if (!(__gpio_get_pin(GPIO_SD_CD_N))) \
+ detected = 0; \
+ detected; \
+})
+
+#endif /* __ASM_JZ4740_LYRA_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/board-pavo.h b/arch/mips/include/asm/mach-jz4740/board-pavo.h
new file mode 100644
index 00000000000..602503c385e
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/board-pavo.h
@@ -0,0 +1,70 @@
+/*
+ * linux/include/asm-mips/mach-jz4740/board-pavo.h
+ *
+ * JZ4730-based PAVO board ver 2.x definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4740_PAVO_H__
+#define __ASM_JZ4740_PAVO_H__
+
+/*======================================================================
+ * Frequencies of on-board oscillators
+ */
+#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */
+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
+
+#define CFG_PBAT_DIV 4 //add for touchscreen
+/*======================================================================
+ * GPIO
+ */
+#define GPIO_SD_VCC_EN_N 113 /* GPD17 */
+#define GPIO_SD_CD_N 110 /* GPD14 */
+#define GPIO_SD_WP 112 /* GPD16 */
+#define GPIO_USB_DETE 102 /* GPD6 */
+#define GPIO_DC_DETE_N 103 /* GPD7 */
+#define GPIO_CHARG_STAT_N 111 /* GPD15 */
+#define GPIO_DISP_OFF_N 118 /* GPD22 */
+#define GPIO_LED_EN 124 /* GPD28 */
+
+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
+/*======================================================================
+ * MMC/SD
+ */
+
+#define MSC_WP_PIN GPIO_SD_WP
+#define MSC_HOTPLUG_PIN GPIO_SD_CD_N
+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N)
+
+#define __msc_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD_VCC_EN_N); \
+ __gpio_as_input(GPIO_SD_CD_N); \
+} while (0)
+
+#define __msc_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \
+} while (0)
+
+#define __msc_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD_VCC_EN_N); \
+} while (0)
+
+#define __msc_card_detected(s) \
+({ \
+ int detected = 1; \
+ if (__gpio_get_pin(GPIO_SD_CD_N)) \
+ detected = 0; \
+ detected; \
+})
+
+#endif /* __ASM_JZ4740_PAVO_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/board-virgo.h b/arch/mips/include/asm/mach-jz4740/board-virgo.h
new file mode 100644
index 00000000000..acd7bb71719
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/board-virgo.h
@@ -0,0 +1,67 @@
+/*
+ * linux/include/asm-mips/mach-jz4740/board-virgo.h
+ *
+ * JZ4720-based VIRGO board ver 1.x definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4720_VIRGO_H__
+#define __ASM_JZ4720_VIRGO_H__
+
+/*======================================================================
+ * Frequencies of on-board oscillators
+ */
+#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */
+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
+
+/*======================================================================
+ * GPIO VIRGO(JZ4720)
+ */
+#define GPIO_SD_VCC_EN_N 115 /* GPD19 */
+#define GPIO_SD_CD_N 116 /* GPD20 */
+#define GPIO_USB_DETE 114 /* GPD18 */
+#define GPIO_DC_DETE_N 120 /* GPD24 */
+#define GPIO_DISP_OFF_N 118 /* GPD22 */
+#define GPIO_LED_EN 117 /* GPD21 */
+
+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
+
+/*======================================================================
+ * MMC/SD
+ */
+
+#define MSC_HOTPLUG_PIN GPIO_SD_CD_N
+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N)
+
+#define __msc_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD_VCC_EN_N); \
+ __gpio_as_input(GPIO_SD_CD_N); \
+} while (0)
+
+#define __msc_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \
+} while (0)
+
+#define __msc_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD_VCC_EN_N); \
+} while (0)
+
+#define __msc_card_detected(s) \
+({ \
+ int detected = 1; \
+ if (__gpio_get_pin(GPIO_SD_CD_N)) \
+ detected = 0; \
+ detected; \
+})
+
+#endif /* __ASM_JZ4720_VIRGO_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/clock.h b/arch/mips/include/asm/mach-jz4740/clock.h
new file mode 100644
index 00000000000..11ffe8894de
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/clock.h
@@ -0,0 +1,173 @@
+/*
+ * linux/include/asm-mips/mach-jz4740/clock.h
+ *
+ * JZ4740 clocks definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4740_CLOCK_H__
+#define __ASM_JZ4740_CLOCK_H__
+
+#ifndef JZ_EXTAL
+//#define JZ_EXTAL 3686400 /* 3.6864 MHz */
+#define JZ_EXTAL 12000000 /* 3.6864 MHz */
+#endif
+#ifndef JZ_EXTAL2
+#define JZ_EXTAL2 32768 /* 32.768 KHz */
+#endif
+
+/*
+ * JZ4740 clocks structure
+ */
+typedef struct {
+ unsigned int cclk; /* CPU clock */
+ unsigned int hclk; /* System bus clock */
+ unsigned int pclk; /* Peripheral bus clock */
+ unsigned int mclk; /* Flash/SRAM/SDRAM clock */
+ unsigned int lcdclk; /* LCDC module clock */
+ unsigned int pixclk; /* LCD pixel clock */
+ unsigned int i2sclk; /* AIC module clock */
+ unsigned int usbclk; /* USB module clock */
+ unsigned int mscclk; /* MSC module clock */
+ unsigned int extalclk; /* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */
+ unsigned int rtcclk; /* RTC clock for CPM,INTC,RTC,TCU,WDT */
+} jz_clocks_t;
+
+extern jz_clocks_t jz_clocks;
+
+
+/* PLL output frequency */
+static __inline__ unsigned int __cpm_get_pllout(void)
+{
+ unsigned long m, n, no, pllout;
+ unsigned long cppcr = REG_CPM_CPPCR;
+ unsigned long od[4] = {1, 2, 2, 4};
+ if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) {
+ m = __cpm_get_pllm() + 2;
+ n = __cpm_get_plln() + 2;
+ no = od[__cpm_get_pllod()];
+ pllout = ((JZ_EXTAL) / (n * no)) * m;
+ } else
+ pllout = JZ_EXTAL;
+ return pllout;
+}
+
+/* PLL output frequency for MSC/I2S/LCD/USB */
+static __inline__ unsigned int __cpm_get_pllout2(void)
+{
+ if (REG_CPM_CPCCR & CPM_CPCCR_PCS)
+ return __cpm_get_pllout();
+ else
+ return __cpm_get_pllout()/2;
+}
+
+/* CPU core clock */
+static __inline__ unsigned int __cpm_get_cclk(void)
+{
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_cdiv()];
+}
+
+/* AHB system bus clock */
+static __inline__ unsigned int __cpm_get_hclk(void)
+{
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_hdiv()];
+}
+
+/* Memory bus clock */
+static __inline__ unsigned int __cpm_get_mclk(void)
+{
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_mdiv()];
+}
+
+/* APB peripheral bus clock */
+static __inline__ unsigned int __cpm_get_pclk(void)
+{
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_pdiv()];
+}
+
+/* LCDC module clock */
+static __inline__ unsigned int __cpm_get_lcdclk(void)
+{
+ return __cpm_get_pllout2() / (__cpm_get_ldiv() + 1);
+}
+
+/* LCD pixel clock */
+static __inline__ unsigned int __cpm_get_pixclk(void)
+{
+ return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1);
+}
+
+/* I2S clock */
+static __inline__ unsigned int __cpm_get_i2sclk(void)
+{
+ if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) {
+ return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1);
+ }
+ else {
+ return JZ_EXTAL;
+ }
+}
+
+/* USB clock */
+static __inline__ unsigned int __cpm_get_usbclk(void)
+{
+ if (REG_CPM_CPCCR & CPM_CPCCR_UCS) {
+ return __cpm_get_pllout2() / (__cpm_get_udiv() + 1);
+ }
+ else {
+ return JZ_EXTAL;
+ }
+}
+
+/* MSC clock */
+static __inline__ unsigned int __cpm_get_mscclk(void)
+{
+ return __cpm_get_pllout2() / (__cpm_get_mscdiv() + 1);
+}
+
+/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */
+static __inline__ unsigned int __cpm_get_extalclk(void)
+{
+ return JZ_EXTAL;
+}
+
+/* RTC clock for CPM,INTC,RTC,TCU,WDT */
+static __inline__ unsigned int __cpm_get_rtcclk(void)
+{
+ return JZ_EXTAL2;
+}
+
+/*
+ * Output 24MHz for SD and 16MHz for MMC.
+ */
+static inline void __cpm_select_msc_clk(int sd)
+{
+ unsigned int pllout2 = __cpm_get_pllout2();
+ unsigned int div = 0;
+
+ if (sd) {
+ div = pllout2 / 24000000;
+ }
+ else {
+ div = pllout2 / 16000000;
+ }
+
+ REG_CPM_MSCCDR = div - 1;
+}
+
+#endif /* __ASM_JZ4740_CLOCK_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/dma.h b/arch/mips/include/asm/mach-jz4740/dma.h
new file mode 100644
index 00000000000..b82b984ea94
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/dma.h
@@ -0,0 +1,265 @@
+/*
+ * linux/include/asm-mips/mach-jz4740/dma.h
+ *
+ * JZ4740 DMA definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4740_DMA_H__
+#define __ASM_JZ4740_DMA_H__
+
+#include <linux/interrupt.h>
+#include <asm/io.h> /* need byte IO */
+#include <linux/spinlock.h> /* And spinlocks */
+#include <linux/delay.h>
+#include <asm/system.h>
+
+/*
+ * Descriptor structure for JZ4740 DMA engine
+ * Note: this structure must always be aligned to a 16-bytes boundary.
+ */
+
+typedef struct {
+ volatile u32 dcmd; /* DCMD value for the current transfer */
+ volatile u32 dsadr; /* DSAR value for the current transfer */
+ volatile u32 dtadr; /* DTAR value for the current transfer */
+ volatile u32 ddadr; /* Points to the next descriptor + transfer count */
+} jz_dma_desc;
+
+
+/* DMA Device ID's follow */
+enum {
+ DMA_ID_UART0_TX = 0,
+ DMA_ID_UART0_RX,
+ DMA_ID_SSI_TX,
+ DMA_ID_SSI_RX,
+ DMA_ID_AIC_TX,
+ DMA_ID_AIC_RX,
+ DMA_ID_MSC_TX,
+ DMA_ID_MSC_RX,
+ DMA_ID_TCU_OVERFLOW,
+ DMA_ID_AUTO,
+ DMA_ID_RAW_SET,
+ DMA_ID_MAX
+};
+
+/* DMA modes, simulated by sw */
+#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */
+#define DMA_AUTOINIT 0x2
+#define DMA_MODE_MASK 0x3
+
+struct jz_dma_chan {
+ int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */
+ unsigned int io; /* DMA channel number */
+ const char *dev_str; /* string describes the DMA channel */
+ int irq; /* DMA irq number */
+ void *irq_dev; /* DMA private device structure */
+ unsigned int fifo_addr; /* physical fifo address of the requested device */
+ unsigned int cntl; /* DMA controll */
+ unsigned int mode; /* DMA configuration */
+ unsigned int source; /* DMA request source */
+};
+
+extern struct jz_dma_chan jz_dma_table[];
+
+
+#define DMA_8BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_8BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_32_16BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_32_16BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+extern int jz_request_dma(int dev_id,
+ const char *dev_str,
+ irqreturn_t (*irqhandler)(int, void *),
+ unsigned long irqflags,
+ void *irq_dev_id);
+extern void jz_free_dma(unsigned int dmanr);
+
+extern int jz_dma_read_proc(char *buf, char **start, off_t fpos,
+ int length, int *eof, void *data);
+extern void dump_jz_dma_channel(unsigned int dmanr);
+
+extern void enable_dma(unsigned int dmanr);
+extern void disable_dma(unsigned int dmanr);
+extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr);
+extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt);
+extern void set_dma_mode(unsigned int dmanr, unsigned int mode);
+extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
+extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
+extern unsigned int get_dma_residue(unsigned int dmanr);
+
+extern spinlock_t dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dma_spin_lock, flags);
+ return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+ spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ */
+#define clear_dma_ff(channel)
+
+static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr)
+{
+ if (dmanr > MAX_DMA_NUM
+ || jz_dma_table[dmanr].dev_id < 0)
+ return NULL;
+ return &jz_dma_table[dmanr];
+}
+
+static __inline__ int dma_halted(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 1;
+ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0;
+}
+
+static __inline__ unsigned int get_dma_mode(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+ return chan->mode;
+}
+
+static __inline__ void clear_dma_done(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+}
+
+static __inline__ void clear_dma_halt(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT);
+ REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT);
+}
+
+static __inline__ void clear_dma_flag(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+ REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR);
+}
+
+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
+{
+}
+
+static __inline__ unsigned int get_dma_done_status(unsigned int dmanr)
+{
+ unsigned long dccsr;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+ dccsr = REG_DMAC_DCCSR(chan->io);
+ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+}
+
+static __inline__ int get_dma_done_irq(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return -1;
+ return chan->irq;
+}
+
+#endif /* __ASM_JZ4740_DMA_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/jz4740.h b/arch/mips/include/asm/mach-jz4740/jz4740.h
new file mode 100644
index 00000000000..117af54ec32
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/jz4740.h
@@ -0,0 +1,58 @@
+/*
+ * linux/include/asm-mips/mach-jz4740/jz4740.h
+ *
+ * JZ4740 common definition.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4740_H__
+#define __ASM_JZ4740_H__
+
+#include <asm/mach-jz4740/regs.h>
+#include <asm/mach-jz4740/ops.h>
+#include <asm/mach-jz4740/dma.h>
+#include <asm/mach-jz4740/misc.h>
+
+/*------------------------------------------------------------------
+ * Platform definitions
+ */
+#define JZ_SOC_NAME "JZ4740"
+
+#ifdef CONFIG_JZ4740_PAVO
+#include <asm/mach-jz4740/board-pavo.h>
+#endif
+
+#ifdef CONFIG_JZ4740_LEO
+#include <asm/mach-jz4740/board-leo.h>
+#endif
+
+#ifdef CONFIG_JZ4740_LYRA
+#include <asm/mach-jz4740/board-lyra.h>
+#endif
+
+#ifdef CONFIG_JZ4725_DIPPER
+#include <asm/mach-jz4740/board-dipper.h>
+#endif
+
+#ifdef CONFIG_JZ4720_VIRGO
+#include <asm/mach-jz4740/board-virgo.h>
+#endif
+
+/* Add other platform definition here ... */
+
+
+/*------------------------------------------------------------------
+ * Follows are related to platform definitions
+ */
+
+#include <asm/mach-jz4740/clock.h>
+#include <asm/mach-jz4740/serial.h>
+
+#endif /* __ASM_JZ4740_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/misc.h b/arch/mips/include/asm/mach-jz4740/misc.h
new file mode 100644
index 00000000000..8f14a5aced2
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/misc.h
@@ -0,0 +1,43 @@
+/*
+ * linux/include/asm-mips/mach-jz4740/misc.h
+ *
+ * Ingenic's JZ4740 common include.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <yliu@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4740_MISC_H__
+#define __ASM_JZ4740_MISC_H__
+
+/*==========================================================
+ * I2C
+ *===========================================================*/
+
+#define I2C_EEPROM_DEV 0xA /* b'1010 */
+#define I2C_RTC_DEV 0xD /* b'1101 */
+#define DIMM0_SPD_ADDR 0
+#define DIMM1_SPD_ADDR 1
+#define DIMM2_SPD_ADDR 2
+#define DIMM3_SPD_ADDR 3
+#define JZ_HCI_ADDR 7
+
+#define DIMM_SPD_LEN 128
+#define JZ_HCI_LEN 512 /* 4K bits E2PROM */
+#define I2C_RTC_LEN 16
+#define HCI_MAC_OFFSET 64
+
+extern void i2c_open(void);
+extern void i2c_close(void);
+extern void i2c_setclk(unsigned int i2cclk);
+extern int i2c_read(unsigned char device, unsigned char *buf,
+ unsigned char address, int count);
+extern int i2c_write(unsigned char device, unsigned char *buf,
+ unsigned char address, int count);
+
+#endif /* __ASM_JZ4740_MISC_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/ops.h b/arch/mips/include/asm/mach-jz4740/ops.h
new file mode 100644
index 00000000000..6ff050a637e
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/ops.h
@@ -0,0 +1,2224 @@
+/*
+ * linux/include/asm-mips/mach-jz4740/ops.h
+ *
+ * Ingenic's JZ4740 common include.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <yliu@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#ifndef __JZ4740_OPS_H__
+#define __JZ4740_OPS_H__
+
+/*
+ * Definition of Module Operations
+ */
+
+/***************************************************************************
+ * GPIO
+ ***************************************************************************/
+
+//------------------------------------------------------
+// GPIO Pins Description
+//
+// PORT 0:
+//
+// PIN/BIT N FUNC0 FUNC1
+// 0 D0 -
+// 1 D1 -
+// 2 D2 -
+// 3 D3 -
+// 4 D4 -
+// 5 D5 -
+// 6 D6 -
+// 7 D7 -
+// 8 D8 -
+// 9 D9 -
+// 10 D10 -
+// 11 D11 -
+// 12 D12 -
+// 13 D13 -
+// 14 D14 -
+// 15 D15 -
+// 16 D16 -
+// 17 D17 -
+// 18 D18 -
+// 19 D19 -
+// 20 D20 -
+// 21 D21 -
+// 22 D22 -
+// 23 D23 -
+// 24 D24 -
+// 25 D25 -
+// 26 D26 -
+// 27 D27 -
+// 28 D28 -
+// 29 D29 -
+// 30 D30 -
+// 31 D31 -
+//
+//------------------------------------------------------
+// PORT 1:
+//
+// PIN/BIT N FUNC0 FUNC1
+// 0 A0 -
+// 1 A1 -
+// 2 A2 -
+// 3 A3 -
+// 4 A4 -
+// 5 A5 -
+// 6 A6 -
+// 7 A7 -
+// 8 A8 -
+// 9 A9 -
+// 10 A10 -
+// 11 A11 -
+// 12 A12 -
+// 13 A13 -
+// 14 A14 -
+// 15 A15/CL -
+// 16 A16/AL -
+// 17 LCD_CLS A21
+// 18 LCD_SPL A22
+// 19 DCS# -
+// 20 RAS# -
+// 21 CAS# -
+// 22 RDWE#/BUFD# -
+// 23 CKE -
+// 24 CKO -
+// 25 CS1# -
+// 26 CS2# -
+// 27 CS3# -
+// 28 CS4# -
+// 29 RD# -
+// 30 WR# -
+// 31 WE0# -
+//
+// Note: PIN15&16 are CL&AL when connecting to NAND flash.
+//------------------------------------------------------
+// PORT 2:
+//
+// PIN/BIT N FUNC0 FUNC1
+// 0 LCD_D0 -
+// 1 LCD_D1 -
+// 2 LCD_D2 -
+// 3 LCD_D3 -
+// 4 LCD_D4 -
+// 5 LCD_D5 -
+// 6 LCD_D6 -
+// 7 LCD_D7 -
+// 8 LCD_D8 -
+// 9 LCD_D9 -
+// 10 LCD_D10 -
+// 11 LCD_D11 -
+// 12 LCD_D12 -
+// 13 LCD_D13 -
+// 14 LCD_D14 -
+// 15 LCD_D15 -
+// 16 LCD_D16 -
+// 17 LCD_D17 -
+// 18 LCD_PCLK -
+// 19 LCD_HSYNC -
+// 20 LCD_VSYNC -
+// 21 LCD_DE -
+// 22 LCD_PS A19
+// 23 LCD_REV A20
+// 24 WE1# -
+// 25 WE2# -
+// 26 WE3# -
+// 27 WAIT# -
+// 28 FRE# -
+// 29 FWE# -
+// 30(NOTE:FRB#) - -
+// 31 - -
+//
+// NOTE(1): PIN30 is used for FRB# when connecting to NAND flash.
+//------------------------------------------------------
+// PORT 3:
+//
+// PIN/BIT N FUNC0 FUNC1
+// 0 CIM_D0 -
+// 1 CIM_D1 -
+// 2 CIM_D2 -
+// 3 CIM_D3 -
+// 4 CIM_D4 -
+// 5 CIM_D5 -
+// 6 CIM_D6 -
+// 7 CIM_D7 -
+// 8 MSC_CMD -
+// 9 MSC_CLK -
+// 10 MSC_D0 -
+// 11 MSC_D1 -
+// 12 MSC_D2 -
+// 13 MSC_D3 -
+// 14 CIM_MCLK -
+// 15 CIM_PCLK -
+// 16 CIM_VSYNC -
+// 17 CIM_HSYNC -
+// 18 SSI_CLK SCLK_RSTN
+// 19 SSI_CE0# BIT_CLK(AIC)
+// 20 SSI_DT SDATA_OUT(AIC)
+// 21 SSI_DR SDATA_IN(AIC)
+// 22 SSI_CE1#&GPC SYNC(AIC)
+// 23 PWM0 I2C_SDA
+// 24 PWM1 I2C_SCK
+// 25 PWM2 UART0_TxD
+// 26 PWM3 UART0_RxD
+// 27 PWM4 A17
+// 28 PWM5 A18
+// 29 - -
+// 30 PWM6 UART0_CTS/UART1_RxD
+// 31 PWM7 UART0_RTS/UART1_TxD
+//
+//////////////////////////////////////////////////////////
+
+/*
+ * p is the port number (0,1,2,3)
+ * o is the pin offset (0-31) inside the port
+ * n is the absolute number of a pin (0-127), regardless of the port
+ */
+
+//-------------------------------------------
+// Function Pins Mode
+
+#define __gpio_as_func0(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFUNS(p) = (1 << o); \
+ REG_GPIO_PXSELC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_func1(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFUNS(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+} while (0)
+
+/*
+ * D0 ~ D31, A0 ~ A16, DCS#, RAS#, CAS#, CKE#,
+ * RDWE#, CKO#, WE0#, WE1#, WE2#, WE3#
+ */
+#define __gpio_as_sdram_32bit() \
+do { \
+ REG_GPIO_PXFUNS(0) = 0xffffffff; \
+ REG_GPIO_PXSELC(0) = 0xffffffff; \
+ REG_GPIO_PXPES(0) = 0xffffffff; \
+ REG_GPIO_PXFUNS(1) = 0x81f9ffff; \
+ REG_GPIO_PXSELC(1) = 0x81f9ffff; \
+ REG_GPIO_PXPES(1) = 0x81f9ffff; \
+ REG_GPIO_PXFUNS(2) = 0x07000000; \
+ REG_GPIO_PXSELC(2) = 0x07000000; \
+ REG_GPIO_PXPES(2) = 0x07000000; \
+} while (0)
+
+/*
+ * D0 ~ D15, A0 ~ A16, DCS#, RAS#, CAS#, CKE#,
+ * RDWE#, CKO#, WE0#, WE1#
+ */
+#define __gpio_as_sdram_16bit() \
+do { \
+ REG_GPIO_PXFUNS(0) = 0x5442bfaa; \
+ REG_GPIO_PXSELC(0) = 0x5442bfaa; \
+ REG_GPIO_PXPES(0) = 0x5442bfaa; \
+ REG_GPIO_PXFUNS(1) = 0x81f9ffff; \
+ REG_GPIO_PXSELC(1) = 0x81f9ffff; \
+ REG_GPIO_PXPES(1) = 0x81f9ffff; \
+ REG_GPIO_PXFUNS(2) = 0x01000000; \
+ REG_GPIO_PXSELC(2) = 0x01000000; \
+ REG_GPIO_PXPES(2) = 0x01000000; \
+} while (0)
+
+/*
+ * CS1#, CLE, ALE, FRE#, FWE#, FRB#, RDWE#/BUFD#
+ */
+#define __gpio_as_nand() \
+do { \
+ REG_GPIO_PXFUNS(1) = 0x02018000; \
+ REG_GPIO_PXSELC(1) = 0x02018000; \
+ REG_GPIO_PXPES(1) = 0x02018000; \
+ REG_GPIO_PXFUNS(2) = 0x30000000; \
+ REG_GPIO_PXSELC(2) = 0x30000000; \
+ REG_GPIO_PXPES(2) = 0x30000000; \
+ REG_GPIO_PXFUNC(2) = 0x40000000; \
+ REG_GPIO_PXSELC(2) = 0x40000000; \
+ REG_GPIO_PXDIRC(2) = 0x40000000; \
+ REG_GPIO_PXPES(2) = 0x40000000; \
+ REG_GPIO_PXFUNS(1) = 0x00400000; \
+ REG_GPIO_PXSELC(1) = 0x00400000; \
+} while (0)
+
+/*
+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D7
+ */
+#define __gpio_as_nor_8bit() \
+do { \
+ REG_GPIO_PXFUNS(0) = 0x000000ff; \
+ REG_GPIO_PXSELC(0) = 0x000000ff; \
+ REG_GPIO_PXPES(0) = 0x000000ff; \
+ REG_GPIO_PXFUNS(1) = 0x7041ffff; \
+ REG_GPIO_PXSELC(1) = 0x7041ffff; \
+ REG_GPIO_PXPES(1) = 0x7041ffff; \
+ REG_GPIO_PXFUNS(1) = 0x00060000; \
+ REG_GPIO_PXSELS(1) = 0x00060000; \
+ REG_GPIO_PXPES(1) = 0x00060000; \
+ REG_GPIO_PXFUNS(2) = 0x08000000; \
+ REG_GPIO_PXSELC(2) = 0x08000000; \
+ REG_GPIO_PXPES(2) = 0x08000000; \
+ REG_GPIO_PXFUNS(2) = 0x00c00000; \
+ REG_GPIO_PXSELS(2) = 0x00c00000; \
+ REG_GPIO_PXPES(2) = 0x00c00000; \
+ REG_GPIO_PXFUNS(3) = 0x18000000; \
+ REG_GPIO_PXSELS(3) = 0x18000000; \
+ REG_GPIO_PXPES(3) = 0x18000000; \
+} while (0)
+
+/*
+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D15
+ */
+#define __gpio_as_nor_16bit() \
+do { \
+ REG_GPIO_PXFUNS(0) = 0x0000ffff; \
+ REG_GPIO_PXSELC(0) = 0x0000ffff; \
+ REG_GPIO_PXPES(0) = 0x0000ffff; \
+ REG_GPIO_PXFUNS(1) = 0x7041ffff; \
+ REG_GPIO_PXSELC(1) = 0x7041ffff; \
+ REG_GPIO_PXPES(1) = 0x7041ffff; \
+ REG_GPIO_PXFUNS(1) = 0x00060000; \
+ REG_GPIO_PXSELS(1) = 0x00060000; \
+ REG_GPIO_PXPES(1) = 0x00060000; \
+ REG_GPIO_PXFUNS(2) = 0x08000000; \
+ REG_GPIO_PXSELC(2) = 0x08000000; \
+ REG_GPIO_PXPES(2) = 0x08000000; \
+ REG_GPIO_PXFUNS(2) = 0x00c00000; \
+ REG_GPIO_PXSELS(2) = 0x00c00000; \
+ REG_GPIO_PXPES(2) = 0x00c00000; \
+ REG_GPIO_PXFUNS(3) = 0x18000000; \
+ REG_GPIO_PXSELS(3) = 0x18000000; \
+ REG_GPIO_PXPES(3) = 0x18000000; \
+} while (0)
+
+/*
+ * UART0_TxD, UART_RxD0
+ */
+#define __gpio_as_uart0() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x06000000; \
+ REG_GPIO_PXSELS(3) = 0x06000000; \
+ REG_GPIO_PXPES(3) = 0x06000000; \
+} while (0)
+
+/*
+ * UART0_CTS, UART0_RTS
+ */
+#define __gpio_as_ctsrts() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0xc0000000; \
+ REG_GPIO_PXSELS(3) = 0xc0000000; \
+ REG_GPIO_PXTRGC(3) = 0xc0000000; \
+ REG_GPIO_PXPES(3) = 0xc0000000; \
+} while (0)
+
+/*
+ * UART1_TxD, UART1_RxD1
+ */
+#define __gpio_as_uart1() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0xc0000000; \
+ REG_GPIO_PXSELC(3) = 0xc0000000; \
+ REG_GPIO_PXTRGS(3) = 0xc0000000; \
+ REG_GPIO_PXPES(3) = 0xc0000000; \
+} while (0)
+
+/*
+ * LCD_D0~LCD_D15, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_16bit() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x003cffff; \
+ REG_GPIO_PXSELC(2) = 0x003cffff; \
+ REG_GPIO_PXPES(2) = 0x003cffff; \
+} while (0)
+
+/*
+ * LCD_D0~LCD_D17, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_18bit() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x003fffff; \
+ REG_GPIO_PXSELC(2) = 0x003fffff; \
+ REG_GPIO_PXPES(2) = 0x003fffff; \
+} while (0)
+
+/*
+ * LCD_PS, LCD_REV, LCD_CLS, LCD_SPL
+ */
+#define __gpio_as_lcd_special() \
+do { \
+ REG_GPIO_PXFUNS(1) = 0x00060000; \
+ REG_GPIO_PXSELC(1) = 0x00060000; \
+ REG_GPIO_PXPES(1) = 0x00060000; \
+ REG_GPIO_PXFUNS(2) = 0x00c00000; \
+ REG_GPIO_PXSELC(2) = 0x00c00000; \
+ REG_GPIO_PXPES(2) = 0x00c00000; \
+} while (0)
+
+/* LCD_D0~LCD_D7, SLCD_RS, SLCD_CS */
+#define __gpio_as_slcd_8bit() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x001800ff; \
+ REG_GPIO_PXSELC(2) = 0x001800ff; \
+} while (0)
+
+/* LCD_D0~LCD_D7, SLCD_RS, SLCD_CS */
+#define __gpio_as_slcd_9bit() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x001801ff; \
+ REG_GPIO_PXSELC(2) = 0x001801ff; \
+} while (0)
+
+/* LCD_D0~LCD_D15, SLCD_RS, SLCD_CS */
+#define __gpio_as_slcd_16bit() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x0018ffff; \
+ REG_GPIO_PXSELC(2) = 0x0018ffff; \
+} while (0)
+
+/* LCD_D0~LCD_D17, SLCD_RS, SLCD_CS */
+#define __gpio_as_slcd_18bit() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x001bffff; \
+ REG_GPIO_PXSELC(2) = 0x001bffff; \
+} while (0)
+
+/*
+ * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC
+ */
+#define __gpio_as_cim() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x0003c0ff; \
+ REG_GPIO_PXSELC(3) = 0x0003c0ff; \
+ REG_GPIO_PXPES(3) = 0x0003c0ff; \
+} while (0)
+
+/*
+ * SDATA_OUT, SDATA_IN, BIT_CLK, SYNC, SCLK_RESET
+ */
+#define __gpio_as_aic() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x007c0000; \
+ REG_GPIO_PXSELS(3) = 0x007c0000; \
+ REG_GPIO_PXPES(3) = 0x007c0000; \
+} while (0)
+
+/*
+ * MSC_CMD, MSC_CLK, MSC_D0 ~ MSC_D3
+ */
+#define __gpio_as_msc() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x00003f00; \
+ REG_GPIO_PXSELC(3) = 0x00003f00; \
+ REG_GPIO_PXPES(3) = 0x00003f00; \
+} while (0)
+
+/*
+ * SSI_CS0, SSI_CLK, SSI_DT, SSI_DR
+ */
+#define __gpio_as_ssi() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x003c0000; \
+ REG_GPIO_PXSELC(3) = 0x003c0000; \
+ REG_GPIO_PXPES(3) = 0x003c0000; \
+} while (0)
+
+/*
+ * I2C_SCK, I2C_SDA
+ */
+#define __gpio_as_i2c() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x01800000; \
+ REG_GPIO_PXSELS(3) = 0x01800000; \
+ REG_GPIO_PXPES(3) = 0x01800000; \
+} while (0)
+
+/*
+ * PWM0
+ */
+#define __gpio_as_pwm0() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x00800000; \
+ REG_GPIO_PXSELC(3) = 0x00800000; \
+ REG_GPIO_PXPES(3) = 0x00800000; \
+} while (0)
+
+/*
+ * PWM1
+ */
+#define __gpio_as_pwm1() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x01000000; \
+ REG_GPIO_PXSELC(3) = 0x01000000; \
+ REG_GPIO_PXPES(3) = 0x01000000; \
+} while (0)
+
+/*
+ * PWM2
+ */
+#define __gpio_as_pwm2() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x02000000; \
+ REG_GPIO_PXSELC(3) = 0x02000000; \
+ REG_GPIO_PXPES(3) = 0x02000000; \
+} while (0)
+
+/*
+ * PWM3
+ */
+#define __gpio_as_pwm3() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x04000000; \
+ REG_GPIO_PXSELC(3) = 0x04000000; \
+ REG_GPIO_PXPES(3) = 0x04000000; \
+} while (0)
+
+/*
+ * PWM4
+ */
+#define __gpio_as_pwm4() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x08000000; \
+ REG_GPIO_PXSELC(3) = 0x08000000; \
+ REG_GPIO_PXPES(3) = 0x08000000; \
+} while (0)
+
+/*
+ * PWM5
+ */
+#define __gpio_as_pwm5() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x10000000; \
+ REG_GPIO_PXSELC(3) = 0x10000000; \
+ REG_GPIO_PXPES(3) = 0x10000000; \
+} while (0)
+
+/*
+ * PWM6
+ */
+#define __gpio_as_pwm6() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x40000000; \
+ REG_GPIO_PXSELC(3) = 0x40000000; \
+ REG_GPIO_PXPES(3) = 0x40000000; \
+} while (0)
+
+/*
+ * PWM7
+ */
+#define __gpio_as_pwm7() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x80000000; \
+ REG_GPIO_PXSELC(3) = 0x80000000; \
+ REG_GPIO_PXPES(3) = 0x80000000; \
+} while (0)
+
+/*
+ * n = 0 ~ 7
+ */
+#define __gpio_as_pwm(n) __gpio_as_pwm##n()
+
+//-------------------------------------------
+// GPIO or Interrupt Mode
+
+#define __gpio_get_port(p) (REG_GPIO_PXPIN(p))
+
+#define __gpio_port_as_output(p, o) \
+do { \
+ REG_GPIO_PXFUNC(p) = (1 << (o)); \
+ REG_GPIO_PXSELC(p) = (1 << (o)); \
+ REG_GPIO_PXDIRS(p) = (1 << (o)); \
+} while (0)
+
+#define __gpio_port_as_input(p, o) \
+do { \
+ REG_GPIO_PXFUNC(p) = (1 << (o)); \
+ REG_GPIO_PXSELC(p) = (1 << (o)); \
+ REG_GPIO_PXDIRC(p) = (1 << (o)); \
+} while (0)
+
+#define __gpio_as_output(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_as_output(p, o); \
+} while (0)
+
+#define __gpio_as_input(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_as_input(p, o); \
+} while (0)
+
+#define __gpio_set_pin(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXDATS(p) = (1 << o); \
+} while (0)
+
+#define __gpio_clear_pin(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXDATC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_get_pin(n) \
+({ \
+ unsigned int p, o, v; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ if (__gpio_get_port(p) & (1 << o)) \
+ v = 1; \
+ else \
+ v = 0; \
+ v; \
+})
+
+#define __gpio_as_irq_high_level(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGC(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRS(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_irq_low_level(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGC(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRC(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_irq_rise_edge(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGS(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRS(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_irq_fall_edge(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGS(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRC(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_mask_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+} while (0)
+
+#define __gpio_unmask_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_ack_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_get_irq() \
+({ \
+ unsigned int p, i, tmp, v = 0; \
+ for (p = 3; p >= 0; p--) { \
+ tmp = REG_GPIO_PXFLG(p); \
+ for (i = 0; i < 32; i++) \
+ if (tmp & (1 << i)) \
+ v = (32*p + i); \
+ } \
+ v; \
+})
+
+#define __gpio_group_irq(n) \
+({ \
+ register int tmp, i; \
+ tmp = REG_GPIO_PXFLG((n)); \
+ for (i=31;i>=0;i--) \
+ if (tmp & (1 << i)) \
+ break; \
+ i; \
+})
+
+#define __gpio_enable_pull(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXPEC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_disable_pull(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXPES(p) = (1 << o); \
+} while (0)
+
+
+/***************************************************************************
+ * CPM
+ ***************************************************************************/
+#define __cpm_get_pllm() \
+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLM_MASK) >> CPM_CPPCR_PLLM_BIT)
+#define __cpm_get_plln() \
+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLN_MASK) >> CPM_CPPCR_PLLN_BIT)
+#define __cpm_get_pllod() \
+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLOD_MASK) >> CPM_CPPCR_PLLOD_BIT)
+
+#define __cpm_get_cdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_CDIV_MASK) >> CPM_CPCCR_CDIV_BIT)
+#define __cpm_get_hdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_HDIV_MASK) >> CPM_CPCCR_HDIV_BIT)
+#define __cpm_get_pdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_PDIV_MASK) >> CPM_CPCCR_PDIV_BIT)
+#define __cpm_get_mdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT)
+#define __cpm_get_ldiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_LDIV_MASK) >> CPM_CPCCR_LDIV_BIT)
+#define __cpm_get_udiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_UDIV_MASK) >> CPM_CPCCR_UDIV_BIT)
+#define __cpm_get_i2sdiv() \
+ ((REG_CPM_I2SCDR & CPM_I2SCDR_I2SDIV_MASK) >> CPM_I2SCDR_I2SDIV_BIT)
+#define __cpm_get_pixdiv() \
+ ((REG_CPM_LPCDR & CPM_LPCDR_PIXDIV_MASK) >> CPM_LPCDR_PIXDIV_BIT)
+#define __cpm_get_mscdiv() \
+ ((REG_CPM_MSCCDR & CPM_MSCCDR_MSCDIV_MASK) >> CPM_MSCCDR_MSCDIV_BIT)
+#define __cpm_get_uhcdiv() \
+ ((REG_CPM_UHCCDR & CPM_UHCCDR_UHCDIV_MASK) >> CPM_UHCCDR_UHCDIV_BIT)
+#define __cpm_get_ssidiv() \
+ ((REG_CPM_SSICCDR & CPM_SSICDR_SSICDIV_MASK) >> CPM_SSICDR_SSIDIV_BIT)
+
+#define __cpm_set_cdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_CDIV_MASK) | ((v) << (CPM_CPCCR_CDIV_BIT)))
+#define __cpm_set_hdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_HDIV_MASK) | ((v) << (CPM_CPCCR_HDIV_BIT)))
+#define __cpm_set_pdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_PDIV_MASK) | ((v) << (CPM_CPCCR_PDIV_BIT)))
+#define __cpm_set_mdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_MDIV_MASK) | ((v) << (CPM_CPCCR_MDIV_BIT)))
+#define __cpm_set_ldiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_LDIV_MASK) | ((v) << (CPM_CPCCR_LDIV_BIT)))
+#define __cpm_set_udiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_UDIV_MASK) | ((v) << (CPM_CPCCR_UDIV_BIT)))
+#define __cpm_set_i2sdiv(v) \
+ (REG_CPM_I2SCDR = (REG_CPM_I2SCDR & ~CPM_I2SCDR_I2SDIV_MASK) | ((v) << (CPM_I2SCDR_I2SDIV_BIT)))
+#define __cpm_set_pixdiv(v) \
+ (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT)))
+#define __cpm_set_mscdiv(v) \
+ (REG_CPM_MSCCDR = (REG_CPM_MSCCDR & ~CPM_MSCCDR_MSCDIV_MASK) | ((v) << (CPM_MSCCDR_MSCDIV_BIT)))
+#define __cpm_set_uhcdiv(v) \
+ (REG_CPM_UHCCDR = (REG_CPM_UHCCDR & ~CPM_UHCCDR_UHCDIV_MASK) | ((v) << (CPM_UHCCDR_UHCDIV_BIT)))
+#define __cpm_ssiclk_select_exclk() \
+ (REG_CPM_SSICDR &= ~CPM_SSICDR_SCS)
+#define __cpm_ssiclk_select_pllout() \
+ (REG_CPM_SSICDR |= CPM_SSICDR_SCS)
+#define __cpm_set_ssidiv(v) \
+ (REG_CPM_SSICDR = (REG_CPM_SSICDR & ~CPM_SSICDR_SSIDIV_MASK) | ((v) << (CPM_SSICDR_SSIDIV_BIT)))
+
+#define __cpm_select_i2sclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_I2CS)
+#define __cpm_select_i2sclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_I2CS)
+#define __cpm_enable_cko() (REG_CPM_CPCCR |= CPM_CPCCR_CLKOEN)
+#define __cpm_select_usbclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_UCS)
+#define __cpm_select_usbclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_UCS)
+#define __cpm_enable_pll_change() (REG_CPM_CPCCR |= CPM_CPCCR_CE)
+#define __cpm_pllout_direct() (REG_CPM_CPCCR |= CPM_CPCCR_PCS)
+#define __cpm_pllout_div2() (REG_CPM_CPCCR &= ~CPM_CPCCR_PCS)
+
+#define __cpm_pll_is_on() (REG_CPM_CPPCR & CPM_CPPCR_PLLS)
+#define __cpm_pll_bypass() (REG_CPM_CPPCR |= CPM_CPPCR_PLLBP)
+#define __cpm_pll_enable() (REG_CPM_CPPCR |= CPM_CPPCR_PLLEN)
+
+#define __cpm_get_cclk_doze_duty() \
+ ((REG_CPM_LCR & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT)
+#define __cpm_set_cclk_doze_duty(v) \
+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_DOZE_DUTY_MASK) | ((v) << (CPM_LCR_DOZE_DUTY_BIT)))
+
+#define __cpm_doze_mode() (REG_CPM_LCR |= CPM_LCR_DOZE_ON)
+#define __cpm_idle_mode() \
+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_IDLE)
+#define __cpm_sleep_mode() \
+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_SLEEP)
+
+#define __cpm_stop_all() (REG_CPM_CLKGR = 0x7fff)
+#define __cpm_stop_uart1() (REG_CPM_CLKGR |= CPM_CLKGR_UART1)
+#define __cpm_stop_uhc() (REG_CPM_CLKGR |= CPM_CLKGR_UHC)
+#define __cpm_stop_ipu() (REG_CPM_CLKGR |= CPM_CLKGR_IPU)
+#define __cpm_stop_dmac() (REG_CPM_CLKGR |= CPM_CLKGR_DMAC)
+#define __cpm_stop_udc() (REG_CPM_CLKGR |= CPM_CLKGR_UDC)
+#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD)
+#define __cpm_stop_cim() (REG_CPM_CLKGR |= CPM_CLKGR_CIM)
+#define __cpm_stop_sadc() (REG_CPM_CLKGR |= CPM_CLKGR_SADC)
+#define __cpm_stop_msc() (REG_CPM_CLKGR |= CPM_CLKGR_MSC)
+#define __cpm_stop_aic1() (REG_CPM_CLKGR |= CPM_CLKGR_AIC1)
+#define __cpm_stop_aic2() (REG_CPM_CLKGR |= CPM_CLKGR_AIC2)
+#define __cpm_stop_ssi() (REG_CPM_CLKGR |= CPM_CLKGR_SSI)
+#define __cpm_stop_i2c() (REG_CPM_CLKGR |= CPM_CLKGR_I2C)
+#define __cpm_stop_rtc() (REG_CPM_CLKGR |= CPM_CLKGR_RTC)
+#define __cpm_stop_tcu() (REG_CPM_CLKGR |= CPM_CLKGR_TCU)
+#define __cpm_stop_uart0() (REG_CPM_CLKGR |= CPM_CLKGR_UART0)
+
+#define __cpm_start_all() (REG_CPM_CLKGR = 0x0)
+#define __cpm_start_uart1() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART1)
+#define __cpm_start_uhc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UHC)
+#define __cpm_start_ipu() (REG_CPM_CLKGR &= ~CPM_CLKGR_IPU)
+#define __cpm_start_dmac() (REG_CPM_CLKGR &= ~CPM_CLKGR_DMAC)
+#define __cpm_start_udc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UDC)
+#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD)
+#define __cpm_start_cim() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIM)
+#define __cpm_start_sadc() (REG_CPM_CLKGR &= ~CPM_CLKGR_SADC)
+#define __cpm_start_msc() (REG_CPM_CLKGR &= ~CPM_CLKGR_MSC)
+#define __cpm_start_aic1() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC1)
+#define __cpm_start_aic2() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC2)
+#define __cpm_start_ssi() (REG_CPM_CLKGR &= ~CPM_CLKGR_SSI)
+#define __cpm_start_i2c() (REG_CPM_CLKGR &= ~CPM_CLKGR_I2C)
+#define __cpm_start_rtc() (REG_CPM_CLKGR &= ~CPM_CLKGR_RTC)
+#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU)
+#define __cpm_start_uart0() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART0)
+
+#define __cpm_get_o1st() \
+ ((REG_CPM_SCR & CPM_SCR_O1ST_MASK) >> CPM_SCR_O1ST_BIT)
+#define __cpm_set_o1st(v) \
+ (REG_CPM_SCR = (REG_CPM_SCR & ~CPM_SCR_O1ST_MASK) | ((v) << (CPM_SCR_O1ST_BIT)))
+#define __cpm_suspend_usbphy() (REG_CPM_SCR |= CPM_SCR_USBPHY_SUSPEND)
+#define __cpm_enable_osc_in_sleep() (REG_CPM_SCR |= CPM_SCR_OSC_ENABLE)
+
+
+/***************************************************************************
+ * TCU
+ ***************************************************************************/
+// where 'n' is the TCU channel
+#define __tcu_select_extalclk(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_EXT_EN)
+#define __tcu_select_rtcclk(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_RTC_EN)
+#define __tcu_select_pclk(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_PCK_EN)
+
+#define __tcu_select_clk_div1(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1)
+#define __tcu_select_clk_div4(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE4)
+#define __tcu_select_clk_div16(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE16)
+#define __tcu_select_clk_div64(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE64)
+#define __tcu_select_clk_div256(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE256)
+#define __tcu_select_clk_div1024(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1024)
+
+#define __tcu_enable_pwm_output(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_EN )
+#define __tcu_disable_pwm_output(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_EN )
+
+#define __tcu_init_pwm_output_high(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_INITL_HIGH )
+#define __tcu_init_pwm_output_low(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_INITL_HIGH )
+
+#define __tcu_set_pwm_output_shutdown_graceful(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_SD )
+#define __tcu_set_pwm_output_shutdown_abrupt(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_SD )
+
+#define __tcu_start_counter(n) ( REG_TCU_TESR |= (1 << (n)) )
+#define __tcu_stop_counter(n) ( REG_TCU_TECR |= (1 << (n)) )
+
+#define __tcu_half_match_flag(n) ( REG_TCU_TFR & (1 << ((n) + 16)) )
+#define __tcu_full_match_flag(n) ( REG_TCU_TFR & (1 << (n)) )
+#define __tcu_set_half_match_flag(n) ( REG_TCU_TFSR = (1 << ((n) + 16)) )
+#define __tcu_set_full_match_flag(n) ( REG_TCU_TFSR = (1 << (n)) )
+#define __tcu_clear_half_match_flag(n) ( REG_TCU_TFCR = (1 << ((n) + 16)) )
+#define __tcu_clear_full_match_flag(n) ( REG_TCU_TFCR = (1 << (n)) )
+#define __tcu_mask_half_match_irq(n) ( REG_TCU_TMSR = (1 << ((n) + 16)) )
+#define __tcu_mask_full_match_irq(n) ( REG_TCU_TMSR = (1 << (n)) )
+#define __tcu_unmask_half_match_irq(n) ( REG_TCU_TMCR = (1 << ((n) + 16)) )
+#define __tcu_unmask_full_match_irq(n) ( REG_TCU_TMCR = (1 << (n)) )
+
+#define __tcu_wdt_clock_stopped() ( REG_TCU_TSR & TCU_TSSR_WDTSC )
+#define __tcu_timer_clock_stopped(n) ( REG_TCU_TSR & (1 << (n)) )
+
+#define __tcu_start_wdt_clock() ( REG_TCU_TSCR = TCU_TSSR_WDTSC )
+#define __tcu_start_timer_clock(n) ( REG_TCU_TSCR = (1 << (n)) )
+
+#define __tcu_stop_wdt_clock() ( REG_TCU_TSSR = TCU_TSSR_WDTSC )
+#define __tcu_stop_timer_clock(n) ( REG_TCU_TSSR = (1 << (n)) )
+
+#define __tcu_get_count(n) ( REG_TCU_TCNT((n)) )
+#define __tcu_set_count(n,v) ( REG_TCU_TCNT((n)) = (v) )
+#define __tcu_set_full_data(n,v) ( REG_TCU_TDFR((n)) = (v) )
+#define __tcu_set_half_data(n,v) ( REG_TCU_TDHR((n)) = (v) )
+
+
+/***************************************************************************
+ * WDT
+ ***************************************************************************/
+#define __wdt_start() ( REG_WDT_TCER |= WDT_TCER_TCEN )
+#define __wdt_stop() ( REG_WDT_TCER &= ~WDT_TCER_TCEN )
+#define __wdt_set_count(v) ( REG_WDT_TCNT = (v) )
+#define __wdt_set_data(v) ( REG_WDT_TDR = (v) )
+
+#define __wdt_select_extalclk() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_EXT_EN)
+#define __wdt_select_rtcclk() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_RTC_EN)
+#define __wdt_select_pclk() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_PCK_EN)
+
+#define __wdt_select_clk_div1() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1)
+#define __wdt_select_clk_div4() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE4)
+#define __wdt_select_clk_div16() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE16)
+#define __wdt_select_clk_div64() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE64)
+#define __wdt_select_clk_div256() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE256)
+#define __wdt_select_clk_div1024() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1024)
+
+
+/***************************************************************************
+ * UART
+ ***************************************************************************/
+
+#define __uart_enable(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE )
+#define __uart_disable(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE )
+
+#define __uart_enable_transmit_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE )
+#define __uart_disable_transmit_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE )
+
+#define __uart_enable_receive_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE )
+#define __uart_disable_receive_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) )
+
+#define __uart_enable_loopback(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP )
+#define __uart_disable_loopback(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP )
+
+#define __uart_set_8n1(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 )
+
+#define __uart_set_baud(n, devclk, baud) \
+ do { \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \
+ } while (0)
+
+#define __uart_parity_error(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 )
+
+#define __uart_clear_errors(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) )
+
+#define __uart_transmit_fifo_empty(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 )
+
+#define __uart_transmit_end(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 )
+
+#define __uart_transmit_char(n, ch) \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch)
+
+#define __uart_receive_fifo_full(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 )
+
+#define __uart_receive_ready(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 )
+
+#define __uart_receive_char(n) \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR)
+
+#define __uart_disable_irda() \
+ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) )
+#define __uart_enable_irda() \
+ /* Tx high pulse as 0, Rx low pulse as 0 */ \
+ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS )
+
+
+/***************************************************************************
+ * DMAC
+ ***************************************************************************/
+
+/* n is the DMA channel (0 - 5) */
+
+#define __dmac_enable_module() \
+ ( REG_DMAC_DMACR |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_RR )
+#define __dmac_disable_module() \
+ ( REG_DMAC_DMACR &= ~DMAC_DMACR_DMAE )
+
+/* p=0,1,2,3 */
+#define __dmac_set_priority(p) \
+do { \
+ REG_DMAC_DMACR &= ~DMAC_DMACR_PR_MASK; \
+ REG_DMAC_DMACR |= ((p) << DMAC_DMACR_PR_BIT); \
+} while (0)
+
+#define __dmac_test_halt_error() ( REG_DMAC_DMACR & DMAC_DMACR_HLT )
+#define __dmac_test_addr_error() ( REG_DMAC_DMACR & DMAC_DMACR_AR )
+
+#define __dmac_enable_descriptor(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES )
+#define __dmac_disable_descriptor(n) \
+ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES )
+
+#define __dmac_enable_channel(n) \
+ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN )
+#define __dmac_disable_channel(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN )
+#define __dmac_channel_enabled(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN )
+
+#define __dmac_channel_enable_irq(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE )
+#define __dmac_channel_disable_irq(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE )
+
+#define __dmac_channel_transmit_halt_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT )
+#define __dmac_channel_transmit_end_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT )
+#define __dmac_channel_address_error_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR )
+#define __dmac_channel_count_terminated_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT )
+#define __dmac_channel_descriptor_invalid_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV )
+
+#define __dmac_channel_clear_transmit_halt(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT )
+#define __dmac_channel_clear_transmit_end(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT )
+#define __dmac_channel_clear_address_error(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR )
+#define __dmac_channel_clear_count_terminated(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT )
+#define __dmac_channel_clear_descriptor_invalid(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV )
+
+#define __dmac_channel_set_single_mode(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TM )
+#define __dmac_channel_set_block_mode(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TM )
+
+#define __dmac_channel_set_transfer_unit_32bit(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_16bit(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_8bit(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_16byte(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_32byte(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \
+} while (0)
+
+/* w=8,16,32 */
+#define __dmac_channel_set_dest_port_width(n,w) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \
+} while (0)
+
+/* w=8,16,32 */
+#define __dmac_channel_set_src_port_width(n,w) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \
+} while (0)
+
+/* v=0-15 */
+#define __dmac_channel_set_rdil(n,v) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \
+ REG_DMAC_DCMD((n) |= ((v) << DMAC_DCMD_RDIL_BIT); \
+} while (0)
+
+#define __dmac_channel_dest_addr_fixed(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI )
+#define __dmac_channel_dest_addr_increment(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI )
+
+#define __dmac_channel_src_addr_fixed(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI )
+#define __dmac_channel_src_addr_increment(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI )
+
+#define __dmac_channel_set_doorbell(n) \
+ ( REG_DMAC_DMADBSR = (1 << (n)) )
+
+#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR & (1 << (n)) )
+#define __dmac_channel_ack_irq(n) ( REG_DMAC_DMAIPR &= ~(1 << (n)) )
+
+static __inline__ int __dmac_get_irq(void)
+{
+ int i;
+ for (i = 0; i < MAX_DMA_NUM; i++)
+ if (__dmac_channel_irq_detected(i))
+ return i;
+ return -1;
+}
+
+
+/***************************************************************************
+ * AIC (AC'97 & I2S Controller)
+ ***************************************************************************/
+
+#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB )
+#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB )
+
+#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL )
+#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL )
+
+#define __aic_play_zero() ( REG_AIC_FR &= ~AIC_FR_LSMP )
+#define __aic_play_lastsample() ( REG_AIC_FR |= AIC_FR_LSMP )
+
+#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD )
+#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) )
+#define __aic_reset_status() ( REG_AIC_FR & AIC_FR_RST )
+
+#define __aic_reset() \
+do { \
+ REG_AIC_FR |= AIC_FR_RST; \
+} while(0)
+
+
+#define __aic_set_transmit_trigger(n) \
+do { \
+ REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \
+ REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \
+} while(0)
+
+#define __aic_set_receive_trigger(n) \
+do { \
+ REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \
+ REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \
+} while(0)
+
+#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC )
+#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC )
+#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL )
+#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL )
+#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF )
+#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF )
+
+#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH )
+#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH )
+
+#define __aic_enable_transmit_intr() \
+ ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) )
+#define __aic_disable_transmit_intr() \
+ ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) )
+#define __aic_enable_receive_intr() \
+ ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) )
+#define __aic_disable_receive_intr() \
+ ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) )
+
+#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS )
+#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS )
+#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS )
+#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS )
+
+#define __aic_enable_mono2stereo() ( REG_AIC_CR |= AIC_CR_M2S )
+#define __aic_disable_mono2stereo() ( REG_AIC_CR &= ~AIC_CR_M2S )
+#define __aic_enable_byteswap() ( REG_AIC_CR |= AIC_CR_ENDSW )
+#define __aic_disable_byteswap() ( REG_AIC_CR &= ~AIC_CR_ENDSW )
+#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU )
+#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU )
+
+#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3
+#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4
+#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6
+#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7
+#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8
+#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9
+
+#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3
+#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4
+#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6
+#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7
+#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8
+#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9
+
+#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK )
+#define __ac97_set_xs_mono() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \
+} while(0)
+#define __ac97_set_xs_stereo() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \
+} while(0)
+
+/* In fact, only stereo is support now. */
+#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK )
+#define __ac97_set_rs_mono() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \
+} while(0)
+#define __ac97_set_rs_stereo() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \
+} while(0)
+
+#define __ac97_warm_reset_codec() \
+ do { \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SA; \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SS; \
+ udelay(2); \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \
+ } while (0)
+
+#define __ac97_cold_reset_codec() \
+ do { \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SR; \
+ udelay(2); \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \
+ } while (0)
+
+/* n=8,16,18,20 */
+#define __ac97_set_iass(n) \
+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT )
+#define __ac97_set_oass(n) \
+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT )
+
+#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL )
+#define __i2s_select_msbjustified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL )
+
+/* n=8,16,18,20,24 */
+/*#define __i2s_set_sample_size(n) \
+ ( REG_AIC_I2SCR |= (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )*/
+
+#define __i2s_set_oss_sample_size(n) \
+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT )
+#define __i2s_set_iss_sample_size(n) \
+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT )
+
+#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK )
+#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK )
+
+#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS )
+#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS )
+#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR )
+#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR )
+
+#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) )
+
+#define __aic_get_transmit_resident() \
+ ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT )
+#define __aic_get_receive_count() \
+ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT )
+
+#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT )
+#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR )
+#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO )
+#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM )
+#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY )
+#define __ac97_slot_error_detected() ( REG_AIC_ACSR & AIC_ACSR_SLTERR )
+#define __ac97_clear_slot_error() ( REG_AIC_ACSR &= ~AIC_ACSR_SLTERR )
+
+#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY )
+
+#define CODEC_READ_CMD (1 << 19)
+#define CODEC_WRITE_CMD (0 << 19)
+#define CODEC_REG_INDEX_BIT 12
+#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */
+#define CODEC_REG_DATA_BIT 4
+#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */
+
+#define __ac97_out_rcmd_addr(reg) \
+do { \
+ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \
+} while (0)
+
+#define __ac97_out_wcmd_addr(reg) \
+do { \
+ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \
+} while (0)
+
+#define __ac97_out_data(value) \
+do { \
+ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \
+} while (0)
+
+#define __ac97_in_data() \
+ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT )
+
+#define __ac97_in_status_addr() \
+ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT )
+
+#define __i2s_set_sample_rate(i2sclk, sync) \
+ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) )
+
+#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) )
+#define __aic_read_rfifo() ( REG_AIC_DR )
+
+#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC )
+#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC )
+
+//
+// Define next ops for AC97 compatible
+//
+
+#define AC97_ACSR AIC_ACSR
+
+#define __ac97_enable() __aic_enable(); __aic_select_ac97()
+#define __ac97_disable() __aic_disable()
+#define __ac97_reset() __aic_reset()
+
+#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n)
+#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n)
+
+#define __ac97_enable_record() __aic_enable_record()
+#define __ac97_disable_record() __aic_disable_record()
+#define __ac97_enable_replay() __aic_enable_replay()
+#define __ac97_disable_replay() __aic_disable_replay()
+#define __ac97_enable_loopback() __aic_enable_loopback()
+#define __ac97_disable_loopback() __aic_disable_loopback()
+
+#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma()
+#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma()
+#define __ac97_enable_receive_dma() __aic_enable_receive_dma()
+#define __ac97_disable_receive_dma() __aic_disable_receive_dma()
+
+#define __ac97_transmit_request() __aic_transmit_request()
+#define __ac97_receive_request() __aic_receive_request()
+#define __ac97_transmit_underrun() __aic_transmit_underrun()
+#define __ac97_receive_overrun() __aic_receive_overrun()
+
+#define __ac97_clear_errors() __aic_clear_errors()
+
+#define __ac97_get_transmit_resident() __aic_get_transmit_resident()
+#define __ac97_get_receive_count() __aic_get_receive_count()
+
+#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr()
+#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr()
+#define __ac97_enable_receive_intr() __aic_enable_receive_intr()
+#define __ac97_disable_receive_intr() __aic_disable_receive_intr()
+
+#define __ac97_write_tfifo(v) __aic_write_tfifo(v)
+#define __ac97_read_rfifo() __aic_read_rfifo()
+
+//
+// Define next ops for I2S compatible
+//
+
+#define I2S_ACSR AIC_I2SSR
+
+#define __i2s_enable() __aic_enable(); __aic_select_i2s()
+#define __i2s_disable() __aic_disable()
+#define __i2s_reset() __aic_reset()
+
+#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n)
+#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n)
+
+#define __i2s_enable_record() __aic_enable_record()
+#define __i2s_disable_record() __aic_disable_record()
+#define __i2s_enable_replay() __aic_enable_replay()
+#define __i2s_disable_replay() __aic_disable_replay()
+#define __i2s_enable_loopback() __aic_enable_loopback()
+#define __i2s_disable_loopback() __aic_disable_loopback()
+
+#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma()
+#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma()
+#define __i2s_enable_receive_dma() __aic_enable_receive_dma()
+#define __i2s_disable_receive_dma() __aic_disable_receive_dma()
+
+#define __i2s_transmit_request() __aic_transmit_request()
+#define __i2s_receive_request() __aic_receive_request()
+#define __i2s_transmit_underrun() __aic_transmit_underrun()
+#define __i2s_receive_overrun() __aic_receive_overrun()
+
+#define __i2s_clear_errors() __aic_clear_errors()
+
+#define __i2s_get_transmit_resident() __aic_get_transmit_resident()
+#define __i2s_get_receive_count() __aic_get_receive_count()
+
+#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr()
+#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr()
+#define __i2s_enable_receive_intr() __aic_enable_receive_intr()
+#define __i2s_disable_receive_intr() __aic_disable_receive_intr()
+
+#define __i2s_write_tfifo(v) __aic_write_tfifo(v)
+#define __i2s_read_rfifo() __aic_read_rfifo()
+
+#define __i2s_reset_codec() \
+ do { \
+ } while (0)
+
+
+/***************************************************************************
+ * ICDC
+ ***************************************************************************/
+#define __i2s_internal_codec() __aic_internal_codec()
+#define __i2s_external_codec() __aic_external_codec()
+
+/***************************************************************************
+ * INTC
+ ***************************************************************************/
+#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) )
+#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) )
+#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) )
+
+
+/***************************************************************************
+ * I2C
+ ***************************************************************************/
+
+#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE )
+#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE )
+
+#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA )
+#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO )
+#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC )
+#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC )
+
+#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF )
+#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF )
+#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF )
+
+#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) )
+#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY )
+#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND )
+
+#define __i2c_set_clk(dev_clk, i2c_clk) \
+ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 )
+
+#define __i2c_read() ( REG_I2C_DR )
+#define __i2c_write(val) ( REG_I2C_DR = (val) )
+
+
+/***************************************************************************
+ * MSC
+ ***************************************************************************/
+
+#define __msc_start_op() \
+ ( REG_MSC_STRPCL = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START )
+
+#define __msc_set_resto(to) ( REG_MSC_RESTO = to )
+#define __msc_set_rdto(to) ( REG_MSC_RDTO = to )
+#define __msc_set_cmd(cmd) ( REG_MSC_CMD = cmd )
+#define __msc_set_arg(arg) ( REG_MSC_ARG = arg )
+#define __msc_set_nob(nob) ( REG_MSC_NOB = nob )
+#define __msc_get_nob() ( REG_MSC_NOB )
+#define __msc_set_blklen(len) ( REG_MSC_BLKLEN = len )
+#define __msc_set_cmdat(cmdat) ( REG_MSC_CMDAT = cmdat )
+#define __msc_set_cmdat_ioabort() ( REG_MSC_CMDAT |= MSC_CMDAT_IO_ABORT )
+#define __msc_clear_cmdat_ioabort() ( REG_MSC_CMDAT &= ~MSC_CMDAT_IO_ABORT )
+
+#define __msc_set_cmdat_bus_width1() \
+do { \
+ REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \
+ REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_1BIT; \
+} while(0)
+
+#define __msc_set_cmdat_bus_width4() \
+do { \
+ REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \
+ REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_4BIT; \
+} while(0)
+
+#define __msc_set_cmdat_dma_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DMA_EN )
+#define __msc_set_cmdat_init() ( REG_MSC_CMDAT |= MSC_CMDAT_INIT )
+#define __msc_set_cmdat_busy() ( REG_MSC_CMDAT |= MSC_CMDAT_BUSY )
+#define __msc_set_cmdat_stream() ( REG_MSC_CMDAT |= MSC_CMDAT_STREAM_BLOCK )
+#define __msc_set_cmdat_block() ( REG_MSC_CMDAT &= ~MSC_CMDAT_STREAM_BLOCK )
+#define __msc_set_cmdat_read() ( REG_MSC_CMDAT &= ~MSC_CMDAT_WRITE_READ )
+#define __msc_set_cmdat_write() ( REG_MSC_CMDAT |= MSC_CMDAT_WRITE_READ )
+#define __msc_set_cmdat_data_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DATA_EN )
+
+/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */
+#define __msc_set_cmdat_res_format(r) \
+do { \
+ REG_MSC_CMDAT &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \
+ REG_MSC_CMDAT |= (r); \
+} while(0)
+
+#define __msc_clear_cmdat() \
+ REG_MSC_CMDAT &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \
+ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \
+ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK )
+
+#define __msc_get_imask() ( REG_MSC_IMASK )
+#define __msc_mask_all_intrs() ( REG_MSC_IMASK = 0xff )
+#define __msc_unmask_all_intrs() ( REG_MSC_IMASK = 0x00 )
+#define __msc_mask_rd() ( REG_MSC_IMASK |= MSC_IMASK_RXFIFO_RD_REQ )
+#define __msc_unmask_rd() ( REG_MSC_IMASK &= ~MSC_IMASK_RXFIFO_RD_REQ )
+#define __msc_mask_wr() ( REG_MSC_IMASK |= MSC_IMASK_TXFIFO_WR_REQ )
+#define __msc_unmask_wr() ( REG_MSC_IMASK &= ~MSC_IMASK_TXFIFO_WR_REQ )
+#define __msc_mask_endcmdres() ( REG_MSC_IMASK |= MSC_IMASK_END_CMD_RES )
+#define __msc_unmask_endcmdres() ( REG_MSC_IMASK &= ~MSC_IMASK_END_CMD_RES )
+#define __msc_mask_datatrandone() ( REG_MSC_IMASK |= MSC_IMASK_DATA_TRAN_DONE )
+#define __msc_unmask_datatrandone() ( REG_MSC_IMASK &= ~MSC_IMASK_DATA_TRAN_DONE )
+#define __msc_mask_prgdone() ( REG_MSC_IMASK |= MSC_IMASK_PRG_DONE )
+#define __msc_unmask_prgdone() ( REG_MSC_IMASK &= ~MSC_IMASK_PRG_DONE )
+
+/* n=0,1,2,3,4,5,6,7 */
+#define __msc_set_clkrt(n) \
+do { \
+ REG_MSC_CLKRT = n; \
+} while(0)
+
+#define __msc_get_ireg() ( REG_MSC_IREG )
+#define __msc_ireg_rd() ( REG_MSC_IREG & MSC_IREG_RXFIFO_RD_REQ )
+#define __msc_ireg_wr() ( REG_MSC_IREG & MSC_IREG_TXFIFO_WR_REQ )
+#define __msc_ireg_end_cmd_res() ( REG_MSC_IREG & MSC_IREG_END_CMD_RES )
+#define __msc_ireg_data_tran_done() ( REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE )
+#define __msc_ireg_prg_done() ( REG_MSC_IREG & MSC_IREG_PRG_DONE )
+#define __msc_ireg_clear_end_cmd_res() ( REG_MSC_IREG = MSC_IREG_END_CMD_RES )
+#define __msc_ireg_clear_data_tran_done() ( REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE )
+#define __msc_ireg_clear_prg_done() ( REG_MSC_IREG = MSC_IREG_PRG_DONE )
+
+#define __msc_get_stat() ( REG_MSC_STAT )
+#define __msc_stat_not_end_cmd_res() ( (REG_MSC_STAT & MSC_STAT_END_CMD_RES) == 0)
+#define __msc_stat_crc_err() \
+ ( REG_MSC_STAT & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) )
+#define __msc_stat_res_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_RES_ERR )
+#define __msc_stat_rd_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_READ_ERROR )
+#define __msc_stat_wr_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_WRITE_ERROR_YES )
+#define __msc_stat_resto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_RES )
+#define __msc_stat_rdto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_READ )
+
+#define __msc_rd_resfifo() ( REG_MSC_RES )
+#define __msc_rd_rxfifo() ( REG_MSC_RXFIFO )
+#define __msc_wr_txfifo(v) ( REG_MSC_TXFIFO = v )
+
+#define __msc_reset() \
+do { \
+ REG_MSC_STRPCL = MSC_STRPCL_RESET; \
+ while (REG_MSC_STAT & MSC_STAT_IS_RESETTING); \
+} while (0)
+
+#define __msc_start_clk() \
+do { \
+ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START; \
+} while (0)
+
+#define __msc_stop_clk() \
+do { \
+ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP; \
+} while (0)
+
+#define MMC_CLK 19169200
+#define SD_CLK 24576000
+
+/* msc_clk should little than pclk and little than clk retrieve from card */
+#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \
+do { \
+ unsigned int rate, pclk, i; \
+ pclk = dev_clk; \
+ rate = type?SD_CLK:MMC_CLK; \
+ if (msc_clk && msc_clk < pclk) \
+ pclk = msc_clk; \
+ i = 0; \
+ while (pclk < rate) \
+ { \
+ i ++; \
+ rate >>= 1; \
+ } \
+ lv = i; \
+} while(0)
+
+/* divide rate to little than or equal to 400kHz */
+#define __msc_calc_slow_clk_divisor(type, lv) \
+do { \
+ unsigned int rate, i; \
+ rate = (type?SD_CLK:MMC_CLK)/1000/400; \
+ i = 0; \
+ while (rate > 0) \
+ { \
+ rate >>= 1; \
+ i ++; \
+ } \
+ lv = i; \
+} while(0)
+
+
+/***************************************************************************
+ * SSI
+ ***************************************************************************/
+
+#define __ssi_enable() ( REG_SSI_CR0 |= SSI_CR0_SSIE )
+#define __ssi_disable() ( REG_SSI_CR0 &= ~SSI_CR0_SSIE )
+#define __ssi_select_ce() ( REG_SSI_CR0 &= ~SSI_CR0_FSEL )
+
+#define __ssi_normal_mode() ( REG_SSI_ITR &= ~SSI_ITR_IVLTM_MASK )
+
+#define __ssi_select_ce2() \
+do { \
+ REG_SSI_CR0 |= SSI_CR0_FSEL; \
+ REG_SSI_CR1 &= ~SSI_CR1_MULTS; \
+} while (0)
+
+#define __ssi_select_gpc() \
+do { \
+ REG_SSI_CR0 &= ~SSI_CR0_FSEL; \
+ REG_SSI_CR1 |= SSI_CR1_MULTS; \
+} while (0)
+
+#define __ssi_enable_tx_intr() \
+ ( REG_SSI_CR0 |= SSI_CR0_TIE | SSI_CR0_TEIE )
+
+#define __ssi_disable_tx_intr() \
+ ( REG_SSI_CR0 &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) )
+
+#define __ssi_enable_rx_intr() \
+ ( REG_SSI_CR0 |= SSI_CR0_RIE | SSI_CR0_REIE )
+
+#define __ssi_disable_rx_intr() \
+ ( REG_SSI_CR0 &= ~(SSI_CR0_RIE | SSI_CR0_REIE) )
+
+#define __ssi_enable_txfifo_half_empty_intr() \
+ ( REG_SSI_CR0 |= SSI_CR0_TIE )
+#define __ssi_disable_txfifo_half_empty_intr() \
+ ( REG_SSI_CR0 &= ~SSI_CR0_TIE )
+#define __ssi_enable_tx_error_intr() \
+ ( REG_SSI_CR0 |= SSI_CR0_TEIE )
+#define __ssi_disable_tx_error_intr() \
+ ( REG_SSI_CR0 &= ~SSI_CR0_TEIE )
+
+#define __ssi_enable_rxfifo_half_full_intr() \
+ ( REG_SSI_CR0 |= SSI_CR0_RIE )
+#define __ssi_disable_rxfifo_half_full_intr() \
+ ( REG_SSI_CR0 &= ~SSI_CR0_RIE )
+#define __ssi_enable_rx_error_intr() \
+ ( REG_SSI_CR0 |= SSI_CR0_REIE )
+#define __ssi_disable_rx_error_intr() \
+ ( REG_SSI_CR0 &= ~SSI_CR0_REIE )
+
+#define __ssi_enable_loopback() ( REG_SSI_CR0 |= SSI_CR0_LOOP )
+#define __ssi_disable_loopback() ( REG_SSI_CR0 &= ~SSI_CR0_LOOP )
+
+#define __ssi_enable_receive() ( REG_SSI_CR0 &= ~SSI_CR0_DISREV )
+#define __ssi_disable_receive() ( REG_SSI_CR0 |= SSI_CR0_DISREV )
+
+#define __ssi_finish_receive() \
+ ( REG_SSI_CR0 |= (SSI_CR0_RFINE | SSI_CR0_RFINC) )
+
+#define __ssi_disable_recvfinish() \
+ ( REG_SSI_CR0 &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) )
+
+#define __ssi_flush_txfifo() ( REG_SSI_CR0 |= SSI_CR0_TFLUSH )
+#define __ssi_flush_rxfifo() ( REG_SSI_CR0 |= SSI_CR0_RFLUSH )
+
+#define __ssi_flush_fifo() \
+ ( REG_SSI_CR0 |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH )
+
+#define __ssi_finish_transmit() ( REG_SSI_CR1 &= ~SSI_CR1_UNFIN )
+#define __ssi_wait_transmit() ( REG_SSI_CR1 |= SSI_CR1_UNFIN )
+
+#define __ssi_spi_format() \
+do { \
+ REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \
+ REG_SSI_CR1 |= SSI_CR1_FMAT_SPI; \
+ REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\
+ REG_SSI_CR1 |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \
+} while (0)
+
+/* TI's SSP format, must clear SSI_CR1.UNFIN */
+#define __ssi_ssp_format() \
+do { \
+ REG_SSI_CR1 &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \
+ REG_SSI_CR1 |= SSI_CR1_FMAT_SSP; \
+} while (0)
+
+/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */
+#define __ssi_microwire_format() \
+do { \
+ REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \
+ REG_SSI_CR1 |= SSI_CR1_FMAT_MW1; \
+ REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\
+ REG_SSI_CR1 |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \
+ REG_SSI_CR0 &= ~SSI_CR0_RFINE; \
+} while (0)
+
+/* CE# level (FRMHL), CE# in interval time (ITFRM),
+ clock phase and polarity (PHA POL),
+ interval time (SSIITR), interval characters/frame (SSIICR) */
+
+ /* frmhl,endian,mcom,flen,pha,pol MASK */
+#define SSICR1_MISC_MASK \
+ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \
+ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL ) \
+
+#define __ssi_spi_set_misc(frmhl,endian,flen,mcom,pha,pol) \
+do { \
+ REG_SSI_CR1 &= ~SSICR1_MISC_MASK; \
+ REG_SSI_CR1 |= ((frmhl) << 30) | ((endian) << 25) | \
+ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \
+ ((pha) << 1) | (pol); \
+} while(0)
+
+/* Transfer with MSB or LSB first */
+#define __ssi_set_msb() ( REG_SSI_CR1 &= ~SSI_CR1_LFST )
+#define __ssi_set_lsb() ( REG_SSI_CR1 |= SSI_CR1_LFST )
+
+#define __ssi_set_frame_length(n) \
+ REG_SSI_CR1 = (REG_SSI_CR1 & ~SSI_CR1_FLEN_MASK) | (((n) - 2) << 4)
+
+/* n = 1 - 16 */
+#define __ssi_set_microwire_command_length(n) \
+ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##n##BIT) )
+
+/* Set the clock phase for SPI */
+#define __ssi_set_spi_clock_phase(n) \
+ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_PHA) | ((n&0x1)<< 1)))
+
+/* Set the clock polarity for SPI */
+#define __ssi_set_spi_clock_polarity(n) \
+ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_POL) | (n&0x1)) )
+
+/* n = ix8 */
+#define __ssi_set_tx_trigger(n) \
+do { \
+ REG_SSI_CR1 &= ~SSI_CR1_TTRG_MASK; \
+ REG_SSI_CR1 |= (n/8)<<SSI_CR1_TTRG_BIT; \
+} while (0)
+
+/* n = ix8 */
+#define __ssi_set_rx_trigger(n) \
+do { \
+ REG_SSI_CR1 &= ~SSI_CR1_RTRG_MASK; \
+ REG_SSI_CR1 |= (n/8)<<SSI_CR1_RTRG_BIT; \
+} while (0)
+
+#define __ssi_get_txfifo_count() \
+ ( (REG_SSI_SR & SSI_SR_TFIFONUM_MASK) >> SSI_SR_TFIFONUM_BIT )
+
+#define __ssi_get_rxfifo_count() \
+ ( (REG_SSI_SR & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT )
+
+#define __ssi_transfer_end() ( REG_SSI_SR & SSI_SR_END )
+#define __ssi_is_busy() ( REG_SSI_SR & SSI_SR_BUSY )
+
+#define __ssi_txfifo_full() ( REG_SSI_SR & SSI_SR_TFF )
+#define __ssi_rxfifo_empty() ( REG_SSI_SR & SSI_SR_RFE )
+#define __ssi_rxfifo_half_full() ( REG_SSI_SR & SSI_SR_RFHF )
+#define __ssi_txfifo_half_empty() ( REG_SSI_SR & SSI_SR_TFHE )
+#define __ssi_underrun() ( REG_SSI_SR & SSI_SR_UNDR )
+#define __ssi_overrun() ( REG_SSI_SR & SSI_SR_OVER )
+#define __ssi_clear_underrun() ( REG_SSI_SR = ~SSI_SR_UNDR )
+#define __ssi_clear_overrun() ( REG_SSI_SR = ~SSI_SR_OVER )
+#define __ssi_clear_errors() \
+ ( REG_SSI_SR &= ~(SSI_SR_UNDR | SSI_SR_OVER) )
+
+
+#define __ssi_set_clk(dev_clk, ssi_clk) \
+ ( REG_SSI_GR = (dev_clk) / (2*(ssi_clk)) - 1 )
+
+#define __ssi_receive_data() REG_SSI_DR
+#define __ssi_transmit_data(v) ( REG_SSI_DR = (v) )
+
+
+/***************************************************************************
+ * CIM
+ ***************************************************************************/
+
+#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA )
+#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA )
+
+#define __cim_input_data_inverse() ( REG_CIM_CFG |= CIM_CFG_INV_DAT )
+#define __cim_input_data_normal() ( REG_CIM_CFG &= ~CIM_CFG_INV_DAT )
+
+#define __cim_vsync_active_low() ( REG_CIM_CFG |= CIM_CFG_VSP )
+#define __cim_vsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_VSP )
+
+#define __cim_hsync_active_low() ( REG_CIM_CFG |= CIM_CFG_HSP )
+#define __cim_hsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_HSP )
+
+#define __cim_sample_data_at_pclk_falling_edge() \
+ ( REG_CIM_CFG |= CIM_CFG_PCP )
+#define __cim_sample_data_at_pclk_rising_edge() \
+ ( REG_CIM_CFG &= ~CIM_CFG_PCP )
+
+#define __cim_enable_dummy_zero() ( REG_CIM_CFG |= CIM_CFG_DUMMY_ZERO )
+#define __cim_disable_dummy_zero() ( REG_CIM_CFG &= ~CIM_CFG_DUMMY_ZERO )
+
+#define __cim_select_external_vsync() ( REG_CIM_CFG |= CIM_CFG_EXT_VSYNC )
+#define __cim_select_internal_vsync() ( REG_CIM_CFG &= ~CIM_CFG_EXT_VSYNC )
+
+/* n=0-7 */
+#define __cim_set_data_packing_mode(n) \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_PACK_MASK; \
+ REG_CIM_CFG |= (CIM_CFG_PACK_##n); \
+} while (0)
+
+#define __cim_enable_ccir656_progressive_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_CPM; \
+} while (0)
+
+#define __cim_enable_ccir656_interlace_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_CIM; \
+} while (0)
+
+#define __cim_enable_gated_clock_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_GCM; \
+} while (0)
+
+#define __cim_enable_nongated_clock_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_NGCM; \
+} while (0)
+
+/* sclk:system bus clock
+ * mclk: CIM master clock
+ */
+#define __cim_set_master_clk(sclk, mclk) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_MCLKDIV_MASK; \
+ REG_CIM_CTRL |= (((sclk)/(mclk) - 1) << CIM_CTRL_MCLKDIV_BIT); \
+} while (0)
+
+#define __cim_enable_sof_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_SOFM )
+#define __cim_disable_sof_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_SOFM )
+
+#define __cim_enable_eof_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_EOFM )
+#define __cim_disable_eof_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EOFM )
+
+#define __cim_enable_stop_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_STOPM )
+#define __cim_disable_stop_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_STOPM )
+
+#define __cim_enable_trig_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_TRIGM )
+#define __cim_disable_trig_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIGM )
+
+#define __cim_enable_rxfifo_overflow_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_OFM )
+#define __cim_disable_rxfifo_overflow_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_OFM )
+
+/* n=1-16 */
+#define __cim_set_frame_rate(n) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_FRC_MASK; \
+ REG_CIM_CTRL |= CIM_CTRL_FRC_##n; \
+} while (0)
+
+#define __cim_enable_dma() ( REG_CIM_CTRL |= CIM_CTRL_DMA_EN )
+#define __cim_disable_dma() ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EN )
+
+#define __cim_reset_rxfifo() ( REG_CIM_CTRL |= CIM_CTRL_RXF_RST )
+#define __cim_unreset_rxfifo() ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_RST )
+
+/* n=4,8,12,16,20,24,28,32 */
+#define __cim_set_rxfifo_trigger(n) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \
+ REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \
+} while (0)
+
+#define __cim_clear_state() ( REG_CIM_STATE = 0 )
+
+#define __cim_disable_done() ( REG_CIM_STATE & CIM_STATE_VDD )
+#define __cim_rxfifo_empty() ( REG_CIM_STATE & CIM_STATE_RXF_EMPTY )
+#define __cim_rxfifo_reach_trigger() ( REG_CIM_STATE & CIM_STATE_RXF_TRIG )
+#define __cim_rxfifo_overflow() ( REG_CIM_STATE & CIM_STATE_RXF_OF )
+#define __cim_clear_rxfifo_overflow() ( REG_CIM_STATE &= ~CIM_STATE_RXF_OF )
+#define __cim_dma_stop() ( REG_CIM_STATE & CIM_STATE_DMA_STOP )
+#define __cim_dma_eof() ( REG_CIM_STATE & CIM_STATE_DMA_EOF )
+#define __cim_dma_sof() ( REG_CIM_STATE & CIM_STATE_DMA_SOF )
+
+#define __cim_get_iid() ( REG_CIM_IID )
+#define __cim_get_image_data() ( REG_CIM_RXFIFO )
+#define __cim_get_dam_cmd() ( REG_CIM_CMD )
+
+#define __cim_set_da(a) ( REG_CIM_DA = (a) )
+
+/***************************************************************************
+ * LCD
+ ***************************************************************************/
+#define __lcd_as_smart_lcd() ( REG_LCD_CFG |= (1<<LCD_CFG_LCDPIN_BIT) )
+#define __lcd_as_general_lcd() ( REG_LCD_CFG &= ~(1<<LCD_CFG_LCDPIN_BIT) )
+
+#define __lcd_set_dis() ( REG_LCD_CTRL |= LCD_CTRL_DIS )
+#define __lcd_clr_dis() ( REG_LCD_CTRL &= ~LCD_CTRL_DIS )
+
+#define __lcd_set_ena() ( REG_LCD_CTRL |= LCD_CTRL_ENA )
+#define __lcd_clr_ena() ( REG_LCD_CTRL &= ~LCD_CTRL_ENA )
+
+/* n=1,2,4,8,16 */
+#define __lcd_set_bpp(n) \
+ ( REG_LCD_CTRL = (REG_LCD_CTRL & ~LCD_CTRL_BPP_MASK) | LCD_CTRL_BPP_##n )
+
+/* n=4,8,16 */
+#define __lcd_set_burst_length(n) \
+do { \
+ REG_LCD_CTRL &= ~LCD_CTRL_BST_MASK; \
+ REG_LCD_CTRL |= LCD_CTRL_BST_n##; \
+} while (0)
+
+#define __lcd_select_rgb565() ( REG_LCD_CTRL &= ~LCD_CTRL_RGB555 )
+#define __lcd_select_rgb555() ( REG_LCD_CTRL |= LCD_CTRL_RGB555 )
+
+#define __lcd_set_ofup() ( REG_LCD_CTRL |= LCD_CTRL_OFUP )
+#define __lcd_clr_ofup() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUP )
+
+/* n=2,4,16 */
+#define __lcd_set_stn_frc(n) \
+do { \
+ REG_LCD_CTRL &= ~LCD_CTRL_FRC_MASK; \
+ REG_LCD_CTRL |= LCD_CTRL_FRC_n##; \
+} while (0)
+
+
+#define __lcd_pixel_endian_little() ( REG_LCD_CTRL |= LCD_CTRL_PEDN )
+#define __lcd_pixel_endian_big() ( REG_LCD_CTRL &= ~LCD_CTRL_PEDN )
+
+#define __lcd_reverse_byte_endian() ( REG_LCD_CTRL |= LCD_CTRL_BEDN )
+#define __lcd_normal_byte_endian() ( REG_LCD_CTRL &= ~LCD_CTRL_BEDN )
+
+#define __lcd_enable_eof_intr() ( REG_LCD_CTRL |= LCD_CTRL_EOFM )
+#define __lcd_disable_eof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_EOFM )
+
+#define __lcd_enable_sof_intr() ( REG_LCD_CTRL |= LCD_CTRL_SOFM )
+#define __lcd_disable_sof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_SOFM )
+
+#define __lcd_enable_ofu_intr() ( REG_LCD_CTRL |= LCD_CTRL_OFUM )
+#define __lcd_disable_ofu_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUM )
+
+#define __lcd_enable_ifu0_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM0 )
+#define __lcd_disable_ifu0_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM0 )
+
+#define __lcd_enable_ifu1_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM1 )
+#define __lcd_disable_ifu1_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM1 )
+
+#define __lcd_enable_ldd_intr() ( REG_LCD_CTRL |= LCD_CTRL_LDDM )
+#define __lcd_disable_ldd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_LDDM )
+
+#define __lcd_enable_qd_intr() ( REG_LCD_CTRL |= LCD_CTRL_QDM )
+#define __lcd_disable_qd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_QDM )
+
+
+/* LCD status register indication */
+
+#define __lcd_quick_disable_done() ( REG_LCD_STATE & LCD_STATE_QD )
+#define __lcd_disable_done() ( REG_LCD_STATE & LCD_STATE_LDD )
+#define __lcd_infifo0_underrun() ( REG_LCD_STATE & LCD_STATE_IFU0 )
+#define __lcd_infifo1_underrun() ( REG_LCD_STATE & LCD_STATE_IFU1 )
+#define __lcd_outfifo_underrun() ( REG_LCD_STATE & LCD_STATE_OFU )
+#define __lcd_start_of_frame() ( REG_LCD_STATE & LCD_STATE_SOF )
+#define __lcd_end_of_frame() ( REG_LCD_STATE & LCD_STATE_EOF )
+
+#define __lcd_clr_outfifounderrun() ( REG_LCD_STATE &= ~LCD_STATE_OFU )
+#define __lcd_clr_sof() ( REG_LCD_STATE &= ~LCD_STATE_SOF )
+#define __lcd_clr_eof() ( REG_LCD_STATE &= ~LCD_STATE_EOF )
+
+#define __lcd_panel_white() ( REG_LCD_CFG |= LCD_CFG_WHITE )
+#define __lcd_panel_black() ( REG_LCD_CFG &= ~LCD_CFG_WHITE )
+
+/* n=1,2,4,8 for single mono-STN
+ * n=4,8 for dual mono-STN
+ */
+#define __lcd_set_panel_datawidth(n) \
+do { \
+ REG_LCD_CFG &= ~LCD_CFG_PDW_MASK; \
+ REG_LCD_CFG |= LCD_CFG_PDW_n##; \
+} while (0)
+
+/* m=LCD_CFG_MODE_GENERUIC_TFT_xxx */
+#define __lcd_set_panel_mode(m) \
+do { \
+ REG_LCD_CFG &= ~LCD_CFG_MODE_MASK; \
+ REG_LCD_CFG |= (m); \
+} while(0)
+
+/* n = 0-255 */
+#define __lcd_disable_ac_bias() ( REG_LCD_IO = 0xff )
+#define __lcd_set_ac_bias(n) \
+do { \
+ REG_LCD_IO &= ~LCD_IO_ACB_MASK; \
+ REG_LCD_IO |= ((n) << LCD_IO_ACB_BIT); \
+} while(0)
+
+#define __lcd_io_set_dir() ( REG_LCD_IO |= LCD_IO_DIR )
+#define __lcd_io_clr_dir() ( REG_LCD_IO &= ~LCD_IO_DIR )
+
+#define __lcd_io_set_dep() ( REG_LCD_IO |= LCD_IO_DEP )
+#define __lcd_io_clr_dep() ( REG_LCD_IO &= ~LCD_IO_DEP )
+
+#define __lcd_io_set_vsp() ( REG_LCD_IO |= LCD_IO_VSP )
+#define __lcd_io_clr_vsp() ( REG_LCD_IO &= ~LCD_IO_VSP )
+
+#define __lcd_io_set_hsp() ( REG_LCD_IO |= LCD_IO_HSP )
+#define __lcd_io_clr_hsp() ( REG_LCD_IO &= ~LCD_IO_HSP )
+
+#define __lcd_io_set_pcp() ( REG_LCD_IO |= LCD_IO_PCP )
+#define __lcd_io_clr_pcp() ( REG_LCD_IO &= ~LCD_IO_PCP )
+
+#define __lcd_vsync_get_vps() \
+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPS_MASK) >> LCD_VSYNC_VPS_BIT )
+
+#define __lcd_vsync_get_vpe() \
+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT )
+#define __lcd_vsync_set_vpe(n) \
+do { \
+ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \
+ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \
+} while (0)
+
+#define __lcd_hsync_get_hps() \
+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT )
+#define __lcd_hsync_set_hps(n) \
+do { \
+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \
+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \
+} while (0)
+
+#define __lcd_hsync_get_hpe() \
+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT )
+#define __lcd_hsync_set_hpe(n) \
+do { \
+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \
+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \
+} while (0)
+
+#define __lcd_vat_get_ht() \
+ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT )
+#define __lcd_vat_set_ht(n) \
+do { \
+ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \
+ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \
+} while (0)
+
+#define __lcd_vat_get_vt() \
+ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT )
+#define __lcd_vat_set_vt(n) \
+do { \
+ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \
+ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \
+} while (0)
+
+#define __lcd_dah_get_hds() \
+ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT )
+#define __lcd_dah_set_hds(n) \
+do { \
+ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \
+ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \
+} while (0)
+
+#define __lcd_dah_get_hde() \
+ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT )
+#define __lcd_dah_set_hde(n) \
+do { \
+ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \
+ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \
+} while (0)
+
+#define __lcd_dav_get_vds() \
+ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT )
+#define __lcd_dav_set_vds(n) \
+do { \
+ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \
+ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \
+} while (0)
+
+#define __lcd_dav_get_vde() \
+ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT )
+#define __lcd_dav_set_vde(n) \
+do { \
+ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \
+ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \
+} while (0)
+
+#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT )
+#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT )
+#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT )
+#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT )
+
+#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT )
+#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT )
+#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT )
+#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT )
+
+#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL )
+#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL )
+
+#define __lcd_cmd0_get_len() \
+ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT )
+#define __lcd_cmd1_get_len() \
+ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT )
+
+/*******************************************************
+ * SMART LCD
+ *******************************************************/
+
+#define __slcd_dma_enable() (REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN)
+#define __slcd_dma_disable() \
+do {\
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); \
+ REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN; \
+} while(0)
+
+/*******************************************************
+ * SMART LCD
+ *******************************************************/
+
+#define __slcd_dma_enable() (REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN)
+#define __slcd_dma_disable() \
+do {\
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); \
+ REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN; \
+} while(0)
+
+/***************************************************************************
+ * RTC ops
+ ***************************************************************************/
+
+#define __rtc_write_ready() ( (REG_RTC_RCR & RTC_RCR_WRDY) >> RTC_RCR_WRDY_BIT )
+#define __rtc_enabled() ( REG_RTC_RCR |= RTC_RCR_RTCE )
+#define __rtc_disabled() ( REG_RTC_RCR &= ~RTC_RCR_RTCE )
+#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE )
+#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE )
+#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE )
+#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE )
+#define __rtc_enable_1Hz_irq() ( REG_RTC_RCR |= RTC_RCR_1HZIE )
+#define __rtc_disable_1Hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_1HZIE )
+
+#define __rtc_get_1Hz_flag() ( (REG_RTC_RCR >> RTC_RCR_1HZ_BIT) & 0x1 )
+#define __rtc_clear_1Hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_1HZ )
+#define __rtc_get_alarm_flag() ( (REG_RTC_RCR >> RTC_RCR_AF_BIT) & 0x1 )
+#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF )
+
+#define __rtc_get_second() ( REG_RTC_RSR )
+#define __rtc_set_second(v) ( REG_RTC_RSR = v )
+
+#define __rtc_get_alarm_second() ( REG_RTC_RSAR )
+#define __rtc_set_alarm_second(v) ( REG_RTC_RSAR = v )
+
+#define __rtc_RGR_is_locked() ( (REG_RTC_RGR >> RTC_RGR_LOCK) )
+#define __rtc_lock_RGR() ( REG_RTC_RGR |= RTC_RGR_LOCK )
+#define __rtc_unlock_RGR() ( REG_RTC_RGR &= ~RTC_RGR_LOCK )
+#define __rtc_get_adjc_val() ( (REG_RTC_RGR & RTC_RGR_ADJC_MASK) >> RTC_RGR_ADJC_BIT )
+#define __rtc_set_adjc_val(v) \
+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_ADJC_MASK) | (v << RTC_RGR_ADJC_BIT) ))
+#define __rtc_get_nc1Hz_val() ( (REG_RTC_RGR & RTC_RGR_NC1HZ_MASK) >> RTC_RGR_NC1HZ_BIT )
+#define __rtc_set_nc1Hz_val(v) \
+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_NC1HZ_MASK) | (v << RTC_RGR_NC1HZ_BIT) ))
+
+#define __rtc_power_down() ( REG_RTC_HCR |= RTC_HCR_PD )
+
+#define __rtc_get_hwfcr_val() ( REG_RTC_HWFCR & RTC_HWFCR_MASK )
+#define __rtc_set_hwfcr_val(v) ( REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK )
+#define __rtc_get_hrcr_val() ( REG_RTC_HRCR & RTC_HRCR_MASK )
+#define __rtc_set_hrcr_val(v) ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK )
+
+#define __rtc_enable_alarm_wakeup() ( REG_RTC_HWCR |= RTC_HWCR_EALM )
+#define __rtc_disable_alarm_wakeup() ( REG_RTC_HWCR &= ~RTC_HWCR_EALM )
+
+#define __rtc_status_hib_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_HR) & 0x1 )
+#define __rtc_status_ppr_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_PPR) & 0x1 )
+#define __rtc_status_wakeup_pin_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_PIN) & 0x1 )
+#define __rtc_status_alarm_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_ALM) & 0x1 )
+#define __rtc_clear_hib_stat_all() ( REG_RTC_HWRSR = 0 )
+
+#define __rtc_get_scratch_pattern() (REG_RTC_HSPR)
+#define __rtc_set_scratch_pattern(n) (REG_RTC_HSPR = n )
+
+
+
+#endif /* __JZ4740_OPS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/regs.h b/arch/mips/include/asm/mach-jz4740/regs.h
new file mode 100644
index 00000000000..510b72536f5
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/regs.h
@@ -0,0 +1,2396 @@
+/*
+ * linux/include/asm-mips/mach-jz4740/regs.h
+ *
+ * Ingenic's JZ4740 common include.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <yliu@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __JZ4740_REGS_H__
+#define __JZ4740_REGS_H__
+
+#if defined(__ASSEMBLY__) || defined(__LANGUAGE_ASSEMBLY)
+#define REG8(addr) (addr)
+#define REG16(addr) (addr)
+#define REG32(addr) (addr)
+#else
+#define REG8(addr) *((volatile unsigned char *)(addr))
+#define REG16(addr) *((volatile unsigned short *)(addr))
+#define REG32(addr) *((volatile unsigned int *)(addr))
+#endif
+
+/*
+ * Define the module base addresses
+ */
+#define CPM_BASE 0xB0000000
+#define INTC_BASE 0xB0001000
+#define TCU_BASE 0xB0002000
+#define WDT_BASE 0xB0002000
+#define RTC_BASE 0xB0003000
+#define GPIO_BASE 0xB0010000
+#define AIC_BASE 0xB0020000
+#define ICDC_BASE 0xB0020000
+#define MSC_BASE 0xB0021000
+#define UART0_BASE 0xB0030000
+#define UART1_BASE 0xB0031000
+#define I2C_BASE 0xB0042000
+#define SSI_BASE 0xB0043000
+#define SADC_BASE 0xB0070000
+#define EMC_BASE 0xB3010000
+#define DMAC_BASE 0xB3020000
+#define UHC_BASE 0xB3030000
+#define UDC_BASE 0xB3040000
+#define LCD_BASE 0xB3050000
+#define SLCD_BASE 0xB3050000
+#define CIM_BASE 0xB3060000
+#define IPU_BASE 0xB3080000
+#define ETH_BASE 0xB3100000
+
+
+/*************************************************************************
+ * INTC (Interrupt Controller)
+ *************************************************************************/
+#define INTC_ISR (INTC_BASE + 0x00)
+#define INTC_IMR (INTC_BASE + 0x04)
+#define INTC_IMSR (INTC_BASE + 0x08)
+#define INTC_IMCR (INTC_BASE + 0x0c)
+#define INTC_IPR (INTC_BASE + 0x10)
+
+#define REG_INTC_ISR REG32(INTC_ISR)
+#define REG_INTC_IMR REG32(INTC_IMR)
+#define REG_INTC_IMSR REG32(INTC_IMSR)
+#define REG_INTC_IMCR REG32(INTC_IMCR)
+#define REG_INTC_IPR REG32(INTC_IPR)
+
+// 1st-level interrupts
+#define IRQ_I2C 1
+#define IRQ_UHC 3
+#define IRQ_UART1 8
+#define IRQ_UART0 9
+#define IRQ_SADC 12
+#define IRQ_MSC 14
+#define IRQ_RTC 15
+#define IRQ_SSI 16
+#define IRQ_CIM 17
+#define IRQ_AIC 18
+#define IRQ_ETH 19
+#define IRQ_DMAC 20
+#define IRQ_TCU2 21
+#define IRQ_TCU1 22
+#define IRQ_TCU0 23
+#define IRQ_UDC 24
+#define IRQ_GPIO3 25
+#define IRQ_GPIO2 26
+#define IRQ_GPIO1 27
+#define IRQ_GPIO0 28
+#define IRQ_IPU 29
+#define IRQ_LCD 30
+
+// 2nd-level interrupts
+#define IRQ_DMA_0 32 /* 32 to 37 for DMAC channel 0 to 5 */
+#define IRQ_GPIO_0 48 /* 48 to 175 for GPIO pin 0 to 127 */
+
+#define NUM_DMA 6
+#define NUM_GPIO 128
+/*************************************************************************
+ * RTC
+ *************************************************************************/
+#define RTC_RCR (RTC_BASE + 0x00) /* RTC Control Register */
+#define RTC_RSR (RTC_BASE + 0x04) /* RTC Second Register */
+#define RTC_RSAR (RTC_BASE + 0x08) /* RTC Second Alarm Register */
+#define RTC_RGR (RTC_BASE + 0x0c) /* RTC Regulator Register */
+
+#define RTC_HCR (RTC_BASE + 0x20) /* Hibernate Control Register */
+#define RTC_HWFCR (RTC_BASE + 0x24) /* Hibernate Wakeup Filter Counter Reg */
+#define RTC_HRCR (RTC_BASE + 0x28) /* Hibernate Reset Counter Register */
+#define RTC_HWCR (RTC_BASE + 0x2c) /* Hibernate Wakeup Control Register */
+#define RTC_HWRSR (RTC_BASE + 0x30) /* Hibernate Wakeup Status Register */
+#define RTC_HSPR (RTC_BASE + 0x34) /* Hibernate Scratch Pattern Register */
+
+#define REG_RTC_RCR REG32(RTC_RCR)
+#define REG_RTC_RSR REG32(RTC_RSR)
+#define REG_RTC_RSAR REG32(RTC_RSAR)
+#define REG_RTC_RGR REG32(RTC_RGR)
+#define REG_RTC_HCR REG32(RTC_HCR)
+#define REG_RTC_HWFCR REG32(RTC_HWFCR)
+#define REG_RTC_HRCR REG32(RTC_HRCR)
+#define REG_RTC_HWCR REG32(RTC_HWCR)
+#define REG_RTC_HWRSR REG32(RTC_HWRSR)
+#define REG_RTC_HSPR REG32(RTC_HSPR)
+
+/* RTC Control Register */
+#define RTC_RCR_WRDY_BIT 7
+#define RTC_RCR_WRDY (1 << 7) /* Write Ready Flag */
+#define RTC_RCR_1HZ_BIT 6
+#define RTC_RCR_1HZ (1 << RTC_RCR_1HZ_BIT) /* 1Hz Flag */
+#define RTC_RCR_1HZIE (1 << 5) /* 1Hz Interrupt Enable */
+#define RTC_RCR_AF_BIT 4
+#define RTC_RCR_AF (1 << RTC_RCR_AF_BIT) /* Alarm Flag */
+#define RTC_RCR_AIE (1 << 3) /* Alarm Interrupt Enable */
+#define RTC_RCR_AE (1 << 2) /* Alarm Enable */
+#define RTC_RCR_RTCE (1 << 0) /* RTC Enable */
+
+/* RTC Regulator Register */
+#define RTC_RGR_LOCK (1 << 31) /* Lock Bit */
+#define RTC_RGR_ADJC_BIT 16
+#define RTC_RGR_ADJC_MASK (0x3ff << RTC_RGR_ADJC_BIT)
+#define RTC_RGR_NC1HZ_BIT 0
+#define RTC_RGR_NC1HZ_MASK (0xffff << RTC_RGR_NC1HZ_BIT)
+
+/* Hibernate Control Register */
+#define RTC_HCR_PD (1 << 0) /* Power Down */
+
+/* Hibernate Wakeup Filter Counter Register */
+#define RTC_HWFCR_BIT 5
+#define RTC_HWFCR_MASK (0x7ff << RTC_HWFCR_BIT)
+
+/* Hibernate Reset Counter Register */
+#define RTC_HRCR_BIT 5
+#define RTC_HRCR_MASK (0x7f << RTC_HRCR_BIT)
+
+/* Hibernate Wakeup Control Register */
+#define RTC_HWCR_EALM (1 << 0) /* RTC alarm wakeup enable */
+
+/* Hibernate Wakeup Status Register */
+#define RTC_HWRSR_HR (1 << 5) /* Hibernate reset */
+#define RTC_HWRSR_PPR (1 << 4) /* PPR reset */
+#define RTC_HWRSR_PIN (1 << 1) /* Wakeup pin status bit */
+#define RTC_HWRSR_ALM (1 << 0) /* RTC alarm status bit */
+
+
+/*************************************************************************
+ * CPM (Clock reset and Power control Management)
+ *************************************************************************/
+#define CPM_CPCCR (CPM_BASE+0x00)
+#define CPM_CPPCR (CPM_BASE+0x10)
+#define CPM_I2SCDR (CPM_BASE+0x60)
+#define CPM_LPCDR (CPM_BASE+0x64)
+#define CPM_MSCCDR (CPM_BASE+0x68)
+#define CPM_UHCCDR (CPM_BASE+0x6C)
+#define CPM_SSICDR (CPM_BASE+0x74)
+
+#define CPM_LCR (CPM_BASE+0x04)
+#define CPM_CLKGR (CPM_BASE+0x20)
+#define CPM_SCR (CPM_BASE+0x24)
+
+#define CPM_HCR (CPM_BASE+0x30)
+#define CPM_HWFCR (CPM_BASE+0x34)
+#define CPM_HRCR (CPM_BASE+0x38)
+#define CPM_HWCR (CPM_BASE+0x3c)
+#define CPM_HWSR (CPM_BASE+0x40)
+#define CPM_HSPR (CPM_BASE+0x44)
+
+#define CPM_RSR (CPM_BASE+0x08)
+
+
+#define REG_CPM_CPCCR REG32(CPM_CPCCR)
+#define REG_CPM_CPPCR REG32(CPM_CPPCR)
+#define REG_CPM_I2SCDR REG32(CPM_I2SCDR)
+#define REG_CPM_LPCDR REG32(CPM_LPCDR)
+#define REG_CPM_MSCCDR REG32(CPM_MSCCDR)
+#define REG_CPM_UHCCDR REG32(CPM_UHCCDR)
+#define REG_CPM_SSICDR REG32(CPM_SSICDR)
+
+#define REG_CPM_LCR REG32(CPM_LCR)
+#define REG_CPM_CLKGR REG32(CPM_CLKGR)
+#define REG_CPM_SCR REG32(CPM_SCR)
+#define REG_CPM_HCR REG32(CPM_HCR)
+#define REG_CPM_HWFCR REG32(CPM_HWFCR)
+#define REG_CPM_HRCR REG32(CPM_HRCR)
+#define REG_CPM_HWCR REG32(CPM_HWCR)
+#define REG_CPM_HWSR REG32(CPM_HWSR)
+#define REG_CPM_HSPR REG32(CPM_HSPR)
+
+#define REG_CPM_RSR REG32(CPM_RSR)
+
+
+/* Clock Control Register */
+#define CPM_CPCCR_I2CS (1 << 31)
+#define CPM_CPCCR_CLKOEN (1 << 30)
+#define CPM_CPCCR_UCS (1 << 29)
+#define CPM_CPCCR_UDIV_BIT 23
+#define CPM_CPCCR_UDIV_MASK (0x3f << CPM_CPCCR_UDIV_BIT)
+#define CPM_CPCCR_CE (1 << 22)
+#define CPM_CPCCR_PCS (1 << 21)
+#define CPM_CPCCR_LDIV_BIT 16
+#define CPM_CPCCR_LDIV_MASK (0x1f << CPM_CPCCR_LDIV_BIT)
+#define CPM_CPCCR_MDIV_BIT 12
+#define CPM_CPCCR_MDIV_MASK (0x0f << CPM_CPCCR_MDIV_BIT)
+#define CPM_CPCCR_PDIV_BIT 8
+#define CPM_CPCCR_PDIV_MASK (0x0f << CPM_CPCCR_PDIV_BIT)
+#define CPM_CPCCR_HDIV_BIT 4
+#define CPM_CPCCR_HDIV_MASK (0x0f << CPM_CPCCR_HDIV_BIT)
+#define CPM_CPCCR_CDIV_BIT 0
+#define CPM_CPCCR_CDIV_MASK (0x0f << CPM_CPCCR_CDIV_BIT)
+
+/* I2S Clock Divider Register */
+#define CPM_I2SCDR_I2SDIV_BIT 0
+#define CPM_I2SCDR_I2SDIV_MASK (0x1ff << CPM_I2SCDR_I2SDIV_BIT)
+
+/* LCD Pixel Clock Divider Register */
+#define CPM_LPCDR_PIXDIV_BIT 0
+#define CPM_LPCDR_PIXDIV_MASK (0x7ff << CPM_LPCDR_PIXDIV_BIT)
+
+/* MSC Clock Divider Register */
+#define CPM_MSCCDR_MSCDIV_BIT 0
+#define CPM_MSCCDR_MSCDIV_MASK (0x1f << CPM_MSCCDR_MSCDIV_BIT)
+
+/* UHC Clock Divider Register */
+#define CPM_UHCCDR_UHCDIV_BIT 0
+#define CPM_UHCCDR_UHCDIV_MASK (0xf << CPM_UHCCDR_UHCDIV_BIT)
+
+/* SSI Clock Divider Register */
+#define CPM_SSICDR_SCS (1<<31) /* SSI clock source selection, 0:EXCLK, 1: PLL */
+#define CPM_SSICDR_SSIDIV_BIT 0
+#define CPM_SSICDR_SSIDIV_MASK (0xf << CPM_SSICDR_SSIDIV_BIT)
+
+/* PLL Control Register */
+#define CPM_CPPCR_PLLM_BIT 23
+#define CPM_CPPCR_PLLM_MASK (0x1ff << CPM_CPPCR_PLLM_BIT)
+#define CPM_CPPCR_PLLN_BIT 18
+#define CPM_CPPCR_PLLN_MASK (0x1f << CPM_CPPCR_PLLN_BIT)
+#define CPM_CPPCR_PLLOD_BIT 16
+#define CPM_CPPCR_PLLOD_MASK (0x03 << CPM_CPPCR_PLLOD_BIT)
+#define CPM_CPPCR_PLLS (1 << 10)
+#define CPM_CPPCR_PLLBP (1 << 9)
+#define CPM_CPPCR_PLLEN (1 << 8)
+#define CPM_CPPCR_PLLST_BIT 0
+#define CPM_CPPCR_PLLST_MASK (0xff << CPM_CPPCR_PLLST_BIT)
+
+/* Low Power Control Register */
+#define CPM_LCR_DOZE_DUTY_BIT 3
+#define CPM_LCR_DOZE_DUTY_MASK (0x1f << CPM_LCR_DOZE_DUTY_BIT)
+#define CPM_LCR_DOZE_ON (1 << 2)
+#define CPM_LCR_LPM_BIT 0
+#define CPM_LCR_LPM_MASK (0x3 << CPM_LCR_LPM_BIT)
+ #define CPM_LCR_LPM_IDLE (0x0 << CPM_LCR_LPM_BIT)
+ #define CPM_LCR_LPM_SLEEP (0x1 << CPM_LCR_LPM_BIT)
+
+/* Clock Gate Register */
+#define CPM_CLKGR_UART1 (1 << 15)
+#define CPM_CLKGR_UHC (1 << 14)
+#define CPM_CLKGR_IPU (1 << 13)
+#define CPM_CLKGR_DMAC (1 << 12)
+#define CPM_CLKGR_UDC (1 << 11)
+#define CPM_CLKGR_LCD (1 << 10)
+#define CPM_CLKGR_CIM (1 << 9)
+#define CPM_CLKGR_SADC (1 << 8)
+#define CPM_CLKGR_MSC (1 << 7)
+#define CPM_CLKGR_AIC1 (1 << 6)
+#define CPM_CLKGR_AIC2 (1 << 5)
+#define CPM_CLKGR_SSI (1 << 4)
+#define CPM_CLKGR_I2C (1 << 3)
+#define CPM_CLKGR_RTC (1 << 2)
+#define CPM_CLKGR_TCU (1 << 1)
+#define CPM_CLKGR_UART0 (1 << 0)
+
+/* Sleep Control Register */
+#define CPM_SCR_O1ST_BIT 8
+#define CPM_SCR_O1ST_MASK (0xff << CPM_SCR_O1ST_BIT)
+#define CPM_SCR_USBPHY_ENABLE (1 << 6)
+#define CPM_SCR_OSC_ENABLE (1 << 4)
+
+/* Hibernate Control Register */
+#define CPM_HCR_PD (1 << 0)
+
+/* Wakeup Filter Counter Register in Hibernate Mode */
+#define CPM_HWFCR_TIME_BIT 0
+#define CPM_HWFCR_TIME_MASK (0x3ff << CPM_HWFCR_TIME_BIT)
+
+/* Reset Counter Register in Hibernate Mode */
+#define CPM_HRCR_TIME_BIT 0
+#define CPM_HRCR_TIME_MASK (0x7f << CPM_HRCR_TIME_BIT)
+
+/* Wakeup Control Register in Hibernate Mode */
+#define CPM_HWCR_WLE_LOW (0 << 2)
+#define CPM_HWCR_WLE_HIGH (1 << 2)
+#define CPM_HWCR_PIN_WAKEUP (1 << 1)
+#define CPM_HWCR_RTC_WAKEUP (1 << 0)
+
+/* Wakeup Status Register in Hibernate Mode */
+#define CPM_HWSR_WSR_PIN (1 << 1)
+#define CPM_HWSR_WSR_RTC (1 << 0)
+
+/* Reset Status Register */
+#define CPM_RSR_HR (1 << 2)
+#define CPM_RSR_WR (1 << 1)
+#define CPM_RSR_PR (1 << 0)
+
+
+/*************************************************************************
+ * TCU (Timer Counter Unit)
+ *************************************************************************/
+#define TCU_TSR (TCU_BASE + 0x1C) /* Timer Stop Register */
+#define TCU_TSSR (TCU_BASE + 0x2C) /* Timer Stop Set Register */
+#define TCU_TSCR (TCU_BASE + 0x3C) /* Timer Stop Clear Register */
+#define TCU_TER (TCU_BASE + 0x10) /* Timer Counter Enable Register */
+#define TCU_TESR (TCU_BASE + 0x14) /* Timer Counter Enable Set Register */
+#define TCU_TECR (TCU_BASE + 0x18) /* Timer Counter Enable Clear Register */
+#define TCU_TFR (TCU_BASE + 0x20) /* Timer Flag Register */
+#define TCU_TFSR (TCU_BASE + 0x24) /* Timer Flag Set Register */
+#define TCU_TFCR (TCU_BASE + 0x28) /* Timer Flag Clear Register */
+#define TCU_TMR (TCU_BASE + 0x30) /* Timer Mask Register */
+#define TCU_TMSR (TCU_BASE + 0x34) /* Timer Mask Set Register */
+#define TCU_TMCR (TCU_BASE + 0x38) /* Timer Mask Clear Register */
+#define TCU_TDFR0 (TCU_BASE + 0x40) /* Timer Data Full Register */
+#define TCU_TDHR0 (TCU_BASE + 0x44) /* Timer Data Half Register */
+#define TCU_TCNT0 (TCU_BASE + 0x48) /* Timer Counter Register */
+#define TCU_TCSR0 (TCU_BASE + 0x4C) /* Timer Control Register */
+#define TCU_TDFR1 (TCU_BASE + 0x50)
+#define TCU_TDHR1 (TCU_BASE + 0x54)
+#define TCU_TCNT1 (TCU_BASE + 0x58)
+#define TCU_TCSR1 (TCU_BASE + 0x5C)
+#define TCU_TDFR2 (TCU_BASE + 0x60)
+#define TCU_TDHR2 (TCU_BASE + 0x64)
+#define TCU_TCNT2 (TCU_BASE + 0x68)
+#define TCU_TCSR2 (TCU_BASE + 0x6C)
+#define TCU_TDFR3 (TCU_BASE + 0x70)
+#define TCU_TDHR3 (TCU_BASE + 0x74)
+#define TCU_TCNT3 (TCU_BASE + 0x78)
+#define TCU_TCSR3 (TCU_BASE + 0x7C)
+#define TCU_TDFR4 (TCU_BASE + 0x80)
+#define TCU_TDHR4 (TCU_BASE + 0x84)
+#define TCU_TCNT4 (TCU_BASE + 0x88)
+#define TCU_TCSR4 (TCU_BASE + 0x8C)
+#define TCU_TDFR5 (TCU_BASE + 0x90)
+#define TCU_TDHR5 (TCU_BASE + 0x94)
+#define TCU_TCNT5 (TCU_BASE + 0x98)
+#define TCU_TCSR5 (TCU_BASE + 0x9C)
+
+#define REG_TCU_TSR REG32(TCU_TSR)
+#define REG_TCU_TSSR REG32(TCU_TSSR)
+#define REG_TCU_TSCR REG32(TCU_TSCR)
+#define REG_TCU_TER REG8(TCU_TER)
+#define REG_TCU_TESR REG8(TCU_TESR)
+#define REG_TCU_TECR REG8(TCU_TECR)
+#define REG_TCU_TFR REG32(TCU_TFR)
+#define REG_TCU_TFSR REG32(TCU_TFSR)
+#define REG_TCU_TFCR REG32(TCU_TFCR)
+#define REG_TCU_TMR REG32(TCU_TMR)
+#define REG_TCU_TMSR REG32(TCU_TMSR)
+#define REG_TCU_TMCR REG32(TCU_TMCR)
+#define REG_TCU_TDFR0 REG16(TCU_TDFR0)
+#define REG_TCU_TDHR0 REG16(TCU_TDHR0)
+#define REG_TCU_TCNT0 REG16(TCU_TCNT0)
+#define REG_TCU_TCSR0 REG16(TCU_TCSR0)
+#define REG_TCU_TDFR1 REG16(TCU_TDFR1)
+#define REG_TCU_TDHR1 REG16(TCU_TDHR1)
+#define REG_TCU_TCNT1 REG16(TCU_TCNT1)
+#define REG_TCU_TCSR1 REG16(TCU_TCSR1)
+#define REG_TCU_TDFR2 REG16(TCU_TDFR2)
+#define REG_TCU_TDHR2 REG16(TCU_TDHR2)
+#define REG_TCU_TCNT2 REG16(TCU_TCNT2)
+#define REG_TCU_TCSR2 REG16(TCU_TCSR2)
+#define REG_TCU_TDFR3 REG16(TCU_TDFR3)
+#define REG_TCU_TDHR3 REG16(TCU_TDHR3)
+#define REG_TCU_TCNT3 REG16(TCU_TCNT3)
+#define REG_TCU_TCSR3 REG16(TCU_TCSR3)
+#define REG_TCU_TDFR4 REG16(TCU_TDFR4)
+#define REG_TCU_TDHR4 REG16(TCU_TDHR4)
+#define REG_TCU_TCNT4 REG16(TCU_TCNT4)
+#define REG_TCU_TCSR4 REG16(TCU_TCSR4)
+
+// n = 0,1,2,3,4,5
+#define TCU_TDFR(n) (TCU_BASE + (0x40 + (n)*0x10)) /* Timer Data Full Reg */
+#define TCU_TDHR(n) (TCU_BASE + (0x44 + (n)*0x10)) /* Timer Data Half Reg */
+#define TCU_TCNT(n) (TCU_BASE + (0x48 + (n)*0x10)) /* Timer Counter Reg */
+#define TCU_TCSR(n) (TCU_BASE + (0x4C + (n)*0x10)) /* Timer Control Reg */
+
+#define REG_TCU_TDFR(n) REG16(TCU_TDFR((n)))
+#define REG_TCU_TDHR(n) REG16(TCU_TDHR((n)))
+#define REG_TCU_TCNT(n) REG16(TCU_TCNT((n)))
+#define REG_TCU_TCSR(n) REG16(TCU_TCSR((n)))
+
+// Register definitions
+#define TCU_TCSR_PWM_SD (1 << 9)
+#define TCU_TCSR_PWM_INITL_HIGH (1 << 8)
+#define TCU_TCSR_PWM_EN (1 << 7)
+#define TCU_TCSR_PRESCALE_BIT 3
+#define TCU_TCSR_PRESCALE_MASK (0x7 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE1 (0x0 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE4 (0x1 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE16 (0x2 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE64 (0x3 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE256 (0x4 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE1024 (0x5 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_EXT_EN (1 << 2)
+#define TCU_TCSR_RTC_EN (1 << 1)
+#define TCU_TCSR_PCK_EN (1 << 0)
+
+#define TCU_TER_TCEN5 (1 << 5)
+#define TCU_TER_TCEN4 (1 << 4)
+#define TCU_TER_TCEN3 (1 << 3)
+#define TCU_TER_TCEN2 (1 << 2)
+#define TCU_TER_TCEN1 (1 << 1)
+#define TCU_TER_TCEN0 (1 << 0)
+
+#define TCU_TESR_TCST5 (1 << 5)
+#define TCU_TESR_TCST4 (1 << 4)
+#define TCU_TESR_TCST3 (1 << 3)
+#define TCU_TESR_TCST2 (1 << 2)
+#define TCU_TESR_TCST1 (1 << 1)
+#define TCU_TESR_TCST0 (1 << 0)
+
+#define TCU_TECR_TCCL5 (1 << 5)
+#define TCU_TECR_TCCL4 (1 << 4)
+#define TCU_TECR_TCCL3 (1 << 3)
+#define TCU_TECR_TCCL2 (1 << 2)
+#define TCU_TECR_TCCL1 (1 << 1)
+#define TCU_TECR_TCCL0 (1 << 0)
+
+#define TCU_TFR_HFLAG5 (1 << 21)
+#define TCU_TFR_HFLAG4 (1 << 20)
+#define TCU_TFR_HFLAG3 (1 << 19)
+#define TCU_TFR_HFLAG2 (1 << 18)
+#define TCU_TFR_HFLAG1 (1 << 17)
+#define TCU_TFR_HFLAG0 (1 << 16)
+#define TCU_TFR_FFLAG5 (1 << 5)
+#define TCU_TFR_FFLAG4 (1 << 4)
+#define TCU_TFR_FFLAG3 (1 << 3)
+#define TCU_TFR_FFLAG2 (1 << 2)
+#define TCU_TFR_FFLAG1 (1 << 1)
+#define TCU_TFR_FFLAG0 (1 << 0)
+
+#define TCU_TFSR_HFLAG5 (1 << 21)
+#define TCU_TFSR_HFLAG4 (1 << 20)
+#define TCU_TFSR_HFLAG3 (1 << 19)
+#define TCU_TFSR_HFLAG2 (1 << 18)
+#define TCU_TFSR_HFLAG1 (1 << 17)
+#define TCU_TFSR_HFLAG0 (1 << 16)
+#define TCU_TFSR_FFLAG5 (1 << 5)
+#define TCU_TFSR_FFLAG4 (1 << 4)
+#define TCU_TFSR_FFLAG3 (1 << 3)
+#define TCU_TFSR_FFLAG2 (1 << 2)
+#define TCU_TFSR_FFLAG1 (1 << 1)
+#define TCU_TFSR_FFLAG0 (1 << 0)
+
+#define TCU_TFCR_HFLAG5 (1 << 21)
+#define TCU_TFCR_HFLAG4 (1 << 20)
+#define TCU_TFCR_HFLAG3 (1 << 19)
+#define TCU_TFCR_HFLAG2 (1 << 18)
+#define TCU_TFCR_HFLAG1 (1 << 17)
+#define TCU_TFCR_HFLAG0 (1 << 16)
+#define TCU_TFCR_FFLAG5 (1 << 5)
+#define TCU_TFCR_FFLAG4 (1 << 4)
+#define TCU_TFCR_FFLAG3 (1 << 3)
+#define TCU_TFCR_FFLAG2 (1 << 2)
+#define TCU_TFCR_FFLAG1 (1 << 1)
+#define TCU_TFCR_FFLAG0 (1 << 0)
+
+#define TCU_TMR_HMASK5 (1 << 21)
+#define TCU_TMR_HMASK4 (1 << 20)
+#define TCU_TMR_HMASK3 (1 << 19)
+#define TCU_TMR_HMASK2 (1 << 18)
+#define TCU_TMR_HMASK1 (1 << 17)
+#define TCU_TMR_HMASK0 (1 << 16)
+#define TCU_TMR_FMASK5 (1 << 5)
+#define TCU_TMR_FMASK4 (1 << 4)
+#define TCU_TMR_FMASK3 (1 << 3)
+#define TCU_TMR_FMASK2 (1 << 2)
+#define TCU_TMR_FMASK1 (1 << 1)
+#define TCU_TMR_FMASK0 (1 << 0)
+
+#define TCU_TMSR_HMST5 (1 << 21)
+#define TCU_TMSR_HMST4 (1 << 20)
+#define TCU_TMSR_HMST3 (1 << 19)
+#define TCU_TMSR_HMST2 (1 << 18)
+#define TCU_TMSR_HMST1 (1 << 17)
+#define TCU_TMSR_HMST0 (1 << 16)
+#define TCU_TMSR_FMST5 (1 << 5)
+#define TCU_TMSR_FMST4 (1 << 4)
+#define TCU_TMSR_FMST3 (1 << 3)
+#define TCU_TMSR_FMST2 (1 << 2)
+#define TCU_TMSR_FMST1 (1 << 1)
+#define TCU_TMSR_FMST0 (1 << 0)
+
+#define TCU_TMCR_HMCL5 (1 << 21)
+#define TCU_TMCR_HMCL4 (1 << 20)
+#define TCU_TMCR_HMCL3 (1 << 19)
+#define TCU_TMCR_HMCL2 (1 << 18)
+#define TCU_TMCR_HMCL1 (1 << 17)
+#define TCU_TMCR_HMCL0 (1 << 16)
+#define TCU_TMCR_FMCL5 (1 << 5)
+#define TCU_TMCR_FMCL4 (1 << 4)
+#define TCU_TMCR_FMCL3 (1 << 3)
+#define TCU_TMCR_FMCL2 (1 << 2)
+#define TCU_TMCR_FMCL1 (1 << 1)
+#define TCU_TMCR_FMCL0 (1 << 0)
+
+#define TCU_TSR_WDTS (1 << 16)
+#define TCU_TSR_STOP5 (1 << 5)
+#define TCU_TSR_STOP4 (1 << 4)
+#define TCU_TSR_STOP3 (1 << 3)
+#define TCU_TSR_STOP2 (1 << 2)
+#define TCU_TSR_STOP1 (1 << 1)
+#define TCU_TSR_STOP0 (1 << 0)
+
+#define TCU_TSSR_WDTSS (1 << 16)
+#define TCU_TSSR_STPS5 (1 << 5)
+#define TCU_TSSR_STPS4 (1 << 4)
+#define TCU_TSSR_STPS3 (1 << 3)
+#define TCU_TSSR_STPS2 (1 << 2)
+#define TCU_TSSR_STPS1 (1 << 1)
+#define TCU_TSSR_STPS0 (1 << 0)
+
+#define TCU_TSSR_WDTSC (1 << 16)
+#define TCU_TSSR_STPC5 (1 << 5)
+#define TCU_TSSR_STPC4 (1 << 4)
+#define TCU_TSSR_STPC3 (1 << 3)
+#define TCU_TSSR_STPC2 (1 << 2)
+#define TCU_TSSR_STPC1 (1 << 1)
+#define TCU_TSSR_STPC0 (1 << 0)
+
+
+/*************************************************************************
+ * WDT (WatchDog Timer)
+ *************************************************************************/
+#define WDT_TDR (WDT_BASE + 0x00)
+#define WDT_TCER (WDT_BASE + 0x04)
+#define WDT_TCNT (WDT_BASE + 0x08)
+#define WDT_TCSR (WDT_BASE + 0x0C)
+
+#define REG_WDT_TDR REG16(WDT_TDR)
+#define REG_WDT_TCER REG8(WDT_TCER)
+#define REG_WDT_TCNT REG16(WDT_TCNT)
+#define REG_WDT_TCSR REG16(WDT_TCSR)
+
+// Register definition
+#define WDT_TCSR_PRESCALE_BIT 3
+#define WDT_TCSR_PRESCALE_MASK (0x7 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE1 (0x0 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE4 (0x1 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE16 (0x2 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE64 (0x3 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE256 (0x4 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE1024 (0x5 << WDT_TCSR_PRESCALE_BIT)
+#define WDT_TCSR_EXT_EN (1 << 2)
+#define WDT_TCSR_RTC_EN (1 << 1)
+#define WDT_TCSR_PCK_EN (1 << 0)
+
+#define WDT_TCER_TCEN (1 << 0)
+
+
+/*************************************************************************
+ * DMAC (DMA Controller)
+ *************************************************************************/
+
+#define MAX_DMA_NUM 6 /* max 6 channels */
+
+#define DMAC_DSAR(n) (DMAC_BASE + (0x00 + (n) * 0x20)) /* DMA source address */
+#define DMAC_DTAR(n) (DMAC_BASE + (0x04 + (n) * 0x20)) /* DMA target address */
+#define DMAC_DTCR(n) (DMAC_BASE + (0x08 + (n) * 0x20)) /* DMA transfer count */
+#define DMAC_DRSR(n) (DMAC_BASE + (0x0c + (n) * 0x20)) /* DMA request source */
+#define DMAC_DCCSR(n) (DMAC_BASE + (0x10 + (n) * 0x20)) /* DMA control/status */
+#define DMAC_DCMD(n) (DMAC_BASE + (0x14 + (n) * 0x20)) /* DMA command */
+#define DMAC_DDA(n) (DMAC_BASE + (0x18 + (n) * 0x20)) /* DMA descriptor address */
+#define DMAC_DMACR (DMAC_BASE + 0x0300) /* DMA control register */
+#define DMAC_DMAIPR (DMAC_BASE + 0x0304) /* DMA interrupt pending */
+#define DMAC_DMADBR (DMAC_BASE + 0x0308) /* DMA doorbell */
+#define DMAC_DMADBSR (DMAC_BASE + 0x030C) /* DMA doorbell set */
+
+// channel 0
+#define DMAC_DSAR0 DMAC_DSAR(0)
+#define DMAC_DTAR0 DMAC_DTAR(0)
+#define DMAC_DTCR0 DMAC_DTCR(0)
+#define DMAC_DRSR0 DMAC_DRSR(0)
+#define DMAC_DCCSR0 DMAC_DCCSR(0)
+#define DMAC_DCMD0 DMAC_DCMD(0)
+#define DMAC_DDA0 DMAC_DDA(0)
+
+// channel 1
+#define DMAC_DSAR1 DMAC_DSAR(1)
+#define DMAC_DTAR1 DMAC_DTAR(1)
+#define DMAC_DTCR1 DMAC_DTCR(1)
+#define DMAC_DRSR1 DMAC_DRSR(1)
+#define DMAC_DCCSR1 DMAC_DCCSR(1)
+#define DMAC_DCMD1 DMAC_DCMD(1)
+#define DMAC_DDA1 DMAC_DDA(1)
+
+// channel 2
+#define DMAC_DSAR2 DMAC_DSAR(2)
+#define DMAC_DTAR2 DMAC_DTAR(2)
+#define DMAC_DTCR2 DMAC_DTCR(2)
+#define DMAC_DRSR2 DMAC_DRSR(2)
+#define DMAC_DCCSR2 DMAC_DCCSR(2)
+#define DMAC_DCMD2 DMAC_DCMD(2)
+#define DMAC_DDA2 DMAC_DDA(2)
+
+// channel 3
+#define DMAC_DSAR3 DMAC_DSAR(3)
+#define DMAC_DTAR3 DMAC_DTAR(3)
+#define DMAC_DTCR3 DMAC_DTCR(3)
+#define DMAC_DRSR3 DMAC_DRSR(3)
+#define DMAC_DCCSR3 DMAC_DCCSR(3)
+#define DMAC_DCMD3 DMAC_DCMD(3)
+#define DMAC_DDA3 DMAC_DDA(3)
+
+// channel 4
+#define DMAC_DSAR4 DMAC_DSAR(4)
+#define DMAC_DTAR4 DMAC_DTAR(4)
+#define DMAC_DTCR4 DMAC_DTCR(4)
+#define DMAC_DRSR4 DMAC_DRSR(4)
+#define DMAC_DCCSR4 DMAC_DCCSR(4)
+#define DMAC_DCMD4 DMAC_DCMD(4)
+#define DMAC_DDA4 DMAC_DDA(4)
+
+// channel 5
+#define DMAC_DSAR5 DMAC_DSAR(5)
+#define DMAC_DTAR5 DMAC_DTAR(5)
+#define DMAC_DTCR5 DMAC_DTCR(5)
+#define DMAC_DRSR5 DMAC_DRSR(5)
+#define DMAC_DCCSR5 DMAC_DCCSR(5)
+#define DMAC_DCMD5 DMAC_DCMD(5)
+#define DMAC_DDA5 DMAC_DDA(5)
+
+#define REG_DMAC_DSAR(n) REG32(DMAC_DSAR((n)))
+#define REG_DMAC_DTAR(n) REG32(DMAC_DTAR((n)))
+#define REG_DMAC_DTCR(n) REG32(DMAC_DTCR((n)))
+#define REG_DMAC_DRSR(n) REG32(DMAC_DRSR((n)))
+#define REG_DMAC_DCCSR(n) REG32(DMAC_DCCSR((n)))
+#define REG_DMAC_DCMD(n) REG32(DMAC_DCMD((n)))
+#define REG_DMAC_DDA(n) REG32(DMAC_DDA((n)))
+#define REG_DMAC_DMACR REG32(DMAC_DMACR)
+#define REG_DMAC_DMAIPR REG32(DMAC_DMAIPR)
+#define REG_DMAC_DMADBR REG32(DMAC_DMADBR)
+#define REG_DMAC_DMADBSR REG32(DMAC_DMADBSR)
+
+// DMA request source register
+#define DMAC_DRSR_RS_BIT 0
+#define DMAC_DRSR_RS_MASK (0x1f << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSIOUT (22 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSIIN (23 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSCOUT (26 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSCIN (27 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_TCU (28 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SADC (29 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SLCD (30 << DMAC_DRSR_RS_BIT)
+
+// DMA channel control/status register
+#define DMAC_DCCSR_NDES (1 << 31) /* descriptor (0) or not (1) ? */
+#define DMAC_DCCSR_CDOA_BIT 16 /* copy of DMA offset address */
+#define DMAC_DCCSR_CDOA_MASK (0xff << DMAC_DCCSR_CDOA_BIT)
+#define DMAC_DCCSR_INV (1 << 6) /* descriptor invalid */
+#define DMAC_DCCSR_AR (1 << 4) /* address error */
+#define DMAC_DCCSR_TT (1 << 3) /* transfer terminated */
+#define DMAC_DCCSR_HLT (1 << 2) /* DMA halted */
+#define DMAC_DCCSR_CT (1 << 1) /* count terminated */
+#define DMAC_DCCSR_EN (1 << 0) /* channel enable bit */
+
+// DMA channel command register
+#define DMAC_DCMD_SAI (1 << 23) /* source address increment */
+#define DMAC_DCMD_DAI (1 << 22) /* dest address increment */
+#define DMAC_DCMD_RDIL_BIT 16 /* request detection interval length */
+#define DMAC_DCMD_RDIL_MASK (0x0f << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_IGN (0 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_2 (1 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_4 (2 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_8 (3 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_12 (4 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_16 (5 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_20 (6 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_24 (7 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_28 (8 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_32 (9 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_48 (10 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_60 (11 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_64 (12 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_124 (13 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_128 (14 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_200 (15 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_SWDH_BIT 14 /* source port width */
+#define DMAC_DCMD_SWDH_MASK (0x03 << DMAC_DCMD_SWDH_BIT)
+ #define DMAC_DCMD_SWDH_32 (0 << DMAC_DCMD_SWDH_BIT)
+ #define DMAC_DCMD_SWDH_8 (1 << DMAC_DCMD_SWDH_BIT)
+ #define DMAC_DCMD_SWDH_16 (2 << DMAC_DCMD_SWDH_BIT)
+#define DMAC_DCMD_DWDH_BIT 12 /* dest port width */
+#define DMAC_DCMD_DWDH_MASK (0x03 << DMAC_DCMD_DWDH_BIT)
+ #define DMAC_DCMD_DWDH_32 (0 << DMAC_DCMD_DWDH_BIT)
+ #define DMAC_DCMD_DWDH_8 (1 << DMAC_DCMD_DWDH_BIT)
+ #define DMAC_DCMD_DWDH_16 (2 << DMAC_DCMD_DWDH_BIT)
+#define DMAC_DCMD_DS_BIT 8 /* transfer data size of a data unit */
+#define DMAC_DCMD_DS_MASK (0x07 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_32BIT (0 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_8BIT (1 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_16BIT (2 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_16BYTE (3 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_32BYTE (4 << DMAC_DCMD_DS_BIT)
+#define DMAC_DCMD_TM (1 << 7) /* transfer mode: 0-single 1-block */
+#define DMAC_DCMD_DES_V (1 << 4) /* descriptor valid flag */
+#define DMAC_DCMD_DES_VM (1 << 3) /* descriptor valid mask: 1:support V-bit */
+#define DMAC_DCMD_DES_VIE (1 << 2) /* DMA valid error interrupt enable */
+#define DMAC_DCMD_TIE (1 << 1) /* DMA transfer interrupt enable */
+#define DMAC_DCMD_LINK (1 << 0) /* descriptor link enable */
+
+// DMA descriptor address register
+#define DMAC_DDA_BASE_BIT 12 /* descriptor base address */
+#define DMAC_DDA_BASE_MASK (0x0fffff << DMAC_DDA_BASE_BIT)
+#define DMAC_DDA_OFFSET_BIT 4 /* descriptor offset address */
+#define DMAC_DDA_OFFSET_MASK (0x0ff << DMAC_DDA_OFFSET_BIT)
+
+// DMA control register
+#define DMAC_DMACR_PR_BIT 8 /* channel priority mode */
+#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_012345 (0 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_023145 (1 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_201345 (2 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_RR (3 << DMAC_DMACR_PR_BIT) /* round robin */
+#define DMAC_DMACR_HLT (1 << 3) /* DMA halt flag */
+#define DMAC_DMACR_AR (1 << 2) /* address error flag */
+#define DMAC_DMACR_DMAE (1 << 0) /* DMA enable bit */
+
+// DMA doorbell register
+#define DMAC_DMADBR_DB5 (1 << 5) /* doorbell for channel 5 */
+#define DMAC_DMADBR_DB4 (1 << 5) /* doorbell for channel 4 */
+#define DMAC_DMADBR_DB3 (1 << 5) /* doorbell for channel 3 */
+#define DMAC_DMADBR_DB2 (1 << 5) /* doorbell for channel 2 */
+#define DMAC_DMADBR_DB1 (1 << 5) /* doorbell for channel 1 */
+#define DMAC_DMADBR_DB0 (1 << 5) /* doorbell for channel 0 */
+
+// DMA doorbell set register
+#define DMAC_DMADBSR_DBS5 (1 << 5) /* enable doorbell for channel 5 */
+#define DMAC_DMADBSR_DBS4 (1 << 5) /* enable doorbell for channel 4 */
+#define DMAC_DMADBSR_DBS3 (1 << 5) /* enable doorbell for channel 3 */
+#define DMAC_DMADBSR_DBS2 (1 << 5) /* enable doorbell for channel 2 */
+#define DMAC_DMADBSR_DBS1 (1 << 5) /* enable doorbell for channel 1 */
+#define DMAC_DMADBSR_DBS0 (1 << 5) /* enable doorbell for channel 0 */
+
+// DMA interrupt pending register
+#define DMAC_DMAIPR_CIRQ5 (1 << 5) /* irq pending status for channel 5 */
+#define DMAC_DMAIPR_CIRQ4 (1 << 4) /* irq pending status for channel 4 */
+#define DMAC_DMAIPR_CIRQ3 (1 << 3) /* irq pending status for channel 3 */
+#define DMAC_DMAIPR_CIRQ2 (1 << 2) /* irq pending status for channel 2 */
+#define DMAC_DMAIPR_CIRQ1 (1 << 1) /* irq pending status for channel 1 */
+#define DMAC_DMAIPR_CIRQ0 (1 << 0) /* irq pending status for channel 0 */
+
+
+/*************************************************************************
+ * GPIO (General-Purpose I/O Ports)
+ *************************************************************************/
+#define MAX_GPIO_NUM 128
+
+//n = 0,1,2,3
+#define GPIO_PXPIN(n) (GPIO_BASE + (0x00 + (n)*0x100)) /* PIN Level Register */
+#define GPIO_PXDAT(n) (GPIO_BASE + (0x10 + (n)*0x100)) /* Port Data Register */
+#define GPIO_PXDATS(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Data Set Register */
+#define GPIO_PXDATC(n) (GPIO_BASE + (0x18 + (n)*0x100)) /* Port Data Clear Register */
+#define GPIO_PXIM(n) (GPIO_BASE + (0x20 + (n)*0x100)) /* Interrupt Mask Register */
+#define GPIO_PXIMS(n) (GPIO_BASE + (0x24 + (n)*0x100)) /* Interrupt Mask Set Reg */
+#define GPIO_PXIMC(n) (GPIO_BASE + (0x28 + (n)*0x100)) /* Interrupt Mask Clear Reg */
+#define GPIO_PXPE(n) (GPIO_BASE + (0x30 + (n)*0x100)) /* Pull Enable Register */
+#define GPIO_PXPES(n) (GPIO_BASE + (0x34 + (n)*0x100)) /* Pull Enable Set Reg. */
+#define GPIO_PXPEC(n) (GPIO_BASE + (0x38 + (n)*0x100)) /* Pull Enable Clear Reg. */
+#define GPIO_PXFUN(n) (GPIO_BASE + (0x40 + (n)*0x100)) /* Function Register */
+#define GPIO_PXFUNS(n) (GPIO_BASE + (0x44 + (n)*0x100)) /* Function Set Register */
+#define GPIO_PXFUNC(n) (GPIO_BASE + (0x48 + (n)*0x100)) /* Function Clear Register */
+#define GPIO_PXSEL(n) (GPIO_BASE + (0x50 + (n)*0x100)) /* Select Register */
+#define GPIO_PXSELS(n) (GPIO_BASE + (0x54 + (n)*0x100)) /* Select Set Register */
+#define GPIO_PXSELC(n) (GPIO_BASE + (0x58 + (n)*0x100)) /* Select Clear Register */
+#define GPIO_PXDIR(n) (GPIO_BASE + (0x60 + (n)*0x100)) /* Direction Register */
+#define GPIO_PXDIRS(n) (GPIO_BASE + (0x64 + (n)*0x100)) /* Direction Set Register */
+#define GPIO_PXDIRC(n) (GPIO_BASE + (0x68 + (n)*0x100)) /* Direction Clear Register */
+#define GPIO_PXTRG(n) (GPIO_BASE + (0x70 + (n)*0x100)) /* Trigger Register */
+#define GPIO_PXTRGS(n) (GPIO_BASE + (0x74 + (n)*0x100)) /* Trigger Set Register */
+#define GPIO_PXTRGC(n) (GPIO_BASE + (0x78 + (n)*0x100)) /* Trigger Set Register */
+#define GPIO_PXFLG(n) (GPIO_BASE + (0x80 + (n)*0x100)) /* Port Flag Register */
+#define GPIO_PXFLGC(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Flag Clear Register */
+
+#define REG_GPIO_PXPIN(n) REG32(GPIO_PXPIN((n))) /* PIN level */
+#define REG_GPIO_PXDAT(n) REG32(GPIO_PXDAT((n))) /* 1: interrupt pending */
+#define REG_GPIO_PXDATS(n) REG32(GPIO_PXDATS((n)))
+#define REG_GPIO_PXDATC(n) REG32(GPIO_PXDATC((n)))
+#define REG_GPIO_PXIM(n) REG32(GPIO_PXIM((n))) /* 1: mask pin interrupt */
+#define REG_GPIO_PXIMS(n) REG32(GPIO_PXIMS((n)))
+#define REG_GPIO_PXIMC(n) REG32(GPIO_PXIMC((n)))
+#define REG_GPIO_PXPE(n) REG32(GPIO_PXPE((n))) /* 1: disable pull up/down */
+#define REG_GPIO_PXPES(n) REG32(GPIO_PXPES((n)))
+#define REG_GPIO_PXPEC(n) REG32(GPIO_PXPEC((n)))
+#define REG_GPIO_PXFUN(n) REG32(GPIO_PXFUN((n))) /* 0:GPIO or intr, 1:FUNC */
+#define REG_GPIO_PXFUNS(n) REG32(GPIO_PXFUNS((n)))
+#define REG_GPIO_PXFUNC(n) REG32(GPIO_PXFUNC((n)))
+#define REG_GPIO_PXSEL(n) REG32(GPIO_PXSEL((n))) /* 0:GPIO/Fun0,1:intr/fun1*/
+#define REG_GPIO_PXSELS(n) REG32(GPIO_PXSELS((n)))
+#define REG_GPIO_PXSELC(n) REG32(GPIO_PXSELC((n)))
+#define REG_GPIO_PXDIR(n) REG32(GPIO_PXDIR((n))) /* 0:input/low-level-trig/falling-edge-trig, 1:output/high-level-trig/rising-edge-trig */
+#define REG_GPIO_PXDIRS(n) REG32(GPIO_PXDIRS((n)))
+#define REG_GPIO_PXDIRC(n) REG32(GPIO_PXDIRC((n)))
+#define REG_GPIO_PXTRG(n) REG32(GPIO_PXTRG((n))) /* 0:level-trigger, 1:edge-trigger */
+#define REG_GPIO_PXTRGS(n) REG32(GPIO_PXTRGS((n)))
+#define REG_GPIO_PXTRGC(n) REG32(GPIO_PXTRGC((n)))
+#define REG_GPIO_PXFLG(n) REG32(GPIO_PXFLG((n))) /* interrupt flag */
+#define REG_GPIO_PXFLGC(n) REG32(GPIO_PXFLGC((n))) /* interrupt flag */
+
+
+/*************************************************************************
+ * UART
+ *************************************************************************/
+
+#define IRDA_BASE UART0_BASE
+#define UART_BASE UART0_BASE
+#define UART_OFF 0x1000
+
+/* Register Offset */
+#define OFF_RDR (0x00) /* R 8b H'xx */
+#define OFF_TDR (0x00) /* W 8b H'xx */
+#define OFF_DLLR (0x00) /* RW 8b H'00 */
+#define OFF_DLHR (0x04) /* RW 8b H'00 */
+#define OFF_IER (0x04) /* RW 8b H'00 */
+#define OFF_ISR (0x08) /* R 8b H'01 */
+#define OFF_FCR (0x08) /* W 8b H'00 */
+#define OFF_LCR (0x0C) /* RW 8b H'00 */
+#define OFF_MCR (0x10) /* RW 8b H'00 */
+#define OFF_LSR (0x14) /* R 8b H'00 */
+#define OFF_MSR (0x18) /* R 8b H'00 */
+#define OFF_SPR (0x1C) /* RW 8b H'00 */
+#define OFF_SIRCR (0x20) /* RW 8b H'00, UART0 */
+#define OFF_UMR (0x24) /* RW 8b H'00, UART M Register */
+#define OFF_UACR (0x28) /* RW 8b H'00, UART Add Cycle Register */
+
+/* Register Address */
+#define UART0_RDR (UART0_BASE + OFF_RDR)
+#define UART0_TDR (UART0_BASE + OFF_TDR)
+#define UART0_DLLR (UART0_BASE + OFF_DLLR)
+#define UART0_DLHR (UART0_BASE + OFF_DLHR)
+#define UART0_IER (UART0_BASE + OFF_IER)
+#define UART0_ISR (UART0_BASE + OFF_ISR)
+#define UART0_FCR (UART0_BASE + OFF_FCR)
+#define UART0_LCR (UART0_BASE + OFF_LCR)
+#define UART0_MCR (UART0_BASE + OFF_MCR)
+#define UART0_LSR (UART0_BASE + OFF_LSR)
+#define UART0_MSR (UART0_BASE + OFF_MSR)
+#define UART0_SPR (UART0_BASE + OFF_SPR)
+#define UART0_SIRCR (UART0_BASE + OFF_SIRCR)
+#define UART0_UMR (UART0_BASE + OFF_UMR)
+#define UART0_UACR (UART0_BASE + OFF_UACR)
+
+/*
+ * Define macros for UARTIER
+ * UART Interrupt Enable Register
+ */
+#define UARTIER_RIE (1 << 0) /* 0: receive fifo full interrupt disable */
+#define UARTIER_TIE (1 << 1) /* 0: transmit fifo empty interrupt disable */
+#define UARTIER_RLIE (1 << 2) /* 0: receive line status interrupt disable */
+#define UARTIER_MIE (1 << 3) /* 0: modem status interrupt disable */
+#define UARTIER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */
+
+/*
+ * Define macros for UARTISR
+ * UART Interrupt Status Register
+ */
+#define UARTISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */
+#define UARTISR_IID (7 << 1) /* Source of Interrupt */
+#define UARTISR_IID_MSI (0 << 1) /* Modem status interrupt */
+#define UARTISR_IID_THRI (1 << 1) /* Transmitter holding register empty */
+#define UARTISR_IID_RDI (2 << 1) /* Receiver data interrupt */
+#define UARTISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */
+#define UARTISR_IID_RTO (6 << 1) /* Receive timeout */
+#define UARTISR_FFMS (3 << 6) /* FIFO mode select, set when UARTFCR.FE is set to 1 */
+#define UARTISR_FFMS_NO_FIFO (0 << 6)
+#define UARTISR_FFMS_FIFO_MODE (3 << 6)
+
+/*
+ * Define macros for UARTFCR
+ * UART FIFO Control Register
+ */
+#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */
+#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */
+#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */
+#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */
+#define UARTFCR_UUE (1 << 4) /* 0: disable UART */
+#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */
+#define UARTFCR_RTRG_1 (0 << 6)
+#define UARTFCR_RTRG_4 (1 << 6)
+#define UARTFCR_RTRG_8 (2 << 6)
+#define UARTFCR_RTRG_15 (3 << 6)
+
+/*
+ * Define macros for UARTLCR
+ * UART Line Control Register
+ */
+#define UARTLCR_WLEN (3 << 0) /* word length */
+#define UARTLCR_WLEN_5 (0 << 0)
+#define UARTLCR_WLEN_6 (1 << 0)
+#define UARTLCR_WLEN_7 (2 << 0)
+#define UARTLCR_WLEN_8 (3 << 0)
+#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8
+ 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */
+#define UARTLCR_STOP1 (0 << 2)
+#define UARTLCR_STOP2 (1 << 2)
+#define UARTLCR_PE (1 << 3) /* 0: parity disable */
+#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */
+#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */
+#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */
+#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */
+
+/*
+ * Define macros for UARTLSR
+ * UART Line Status Register
+ */
+#define UARTLSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */
+#define UARTLSR_ORER (1 << 1) /* 0: no overrun error */
+#define UARTLSR_PER (1 << 2) /* 0: no parity error */
+#define UARTLSR_FER (1 << 3) /* 0; no framing error */
+#define UARTLSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */
+#define UARTLSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */
+#define UARTLSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */
+#define UARTLSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */
+
+/*
+ * Define macros for UARTMCR
+ * UART Modem Control Register
+ */
+#define UARTMCR_RTS (1 << 1) /* 0: RTS_ output high, 1: RTS_ output low */
+#define UARTMCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */
+#define UARTMCR_MCE (1 << 7) /* 0: modem function is disable */
+
+/*
+ * Define macros for UARTMSR
+ * UART Modem Status Register
+ */
+#define UARTMSR_CCTS (1 << 0) /* 1: a change on CTS_ pin */
+#define UARTMSR_CTS (1 << 4) /* 0: CTS_ pin is high */
+
+/*
+ * Define macros for SIRCR
+ * Slow IrDA Control Register
+ */
+#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: SIR mode */
+#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: SIR mode */
+#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length
+ 1: 0 pulse width is 1.6us for 115.2Kbps */
+#define SIRCR_TDPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */
+#define SIRCR_RDPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */
+
+
+/*************************************************************************
+ * AIC (AC97/I2S Controller)
+ *************************************************************************/
+#define AIC_FR (AIC_BASE + 0x000)
+#define AIC_CR (AIC_BASE + 0x004)
+#define AIC_ACCR1 (AIC_BASE + 0x008)
+#define AIC_ACCR2 (AIC_BASE + 0x00C)
+#define AIC_I2SCR (AIC_BASE + 0x010)
+#define AIC_SR (AIC_BASE + 0x014)
+#define AIC_ACSR (AIC_BASE + 0x018)
+#define AIC_I2SSR (AIC_BASE + 0x01C)
+#define AIC_ACCAR (AIC_BASE + 0x020)
+#define AIC_ACCDR (AIC_BASE + 0x024)
+#define AIC_ACSAR (AIC_BASE + 0x028)
+#define AIC_ACSDR (AIC_BASE + 0x02C)
+#define AIC_I2SDIV (AIC_BASE + 0x030)
+#define AIC_DR (AIC_BASE + 0x034)
+
+#define REG_AIC_FR REG32(AIC_FR)
+#define REG_AIC_CR REG32(AIC_CR)
+#define REG_AIC_ACCR1 REG32(AIC_ACCR1)
+#define REG_AIC_ACCR2 REG32(AIC_ACCR2)
+#define REG_AIC_I2SCR REG32(AIC_I2SCR)
+#define REG_AIC_SR REG32(AIC_SR)
+#define REG_AIC_ACSR REG32(AIC_ACSR)
+#define REG_AIC_I2SSR REG32(AIC_I2SSR)
+#define REG_AIC_ACCAR REG32(AIC_ACCAR)
+#define REG_AIC_ACCDR REG32(AIC_ACCDR)
+#define REG_AIC_ACSAR REG32(AIC_ACSAR)
+#define REG_AIC_ACSDR REG32(AIC_ACSDR)
+#define REG_AIC_I2SDIV REG32(AIC_I2SDIV)
+#define REG_AIC_DR REG32(AIC_DR)
+
+/* AIC Controller Configuration Register (AIC_FR) */
+
+#define AIC_FR_RFTH_BIT 12 /* Receive FIFO Threshold */
+#define AIC_FR_RFTH_MASK (0xf << AIC_FR_RFTH_BIT)
+#define AIC_FR_TFTH_BIT 8 /* Transmit FIFO Threshold */
+#define AIC_FR_TFTH_MASK (0xf << AIC_FR_TFTH_BIT)
+#define AIC_FR_LSMP (1 << 6) /* Play Zero sample or last sample */
+#define AIC_FR_ICDC (1 << 5) /* External(0) or Internal CODEC(1) */
+#define AIC_FR_AUSEL (1 << 4) /* AC97(0) or I2S/MSB-justified(1) */
+#define AIC_FR_RST (1 << 3) /* AIC registers reset */
+#define AIC_FR_BCKD (1 << 2) /* I2S BIT_CLK direction, 0:input,1:output */
+#define AIC_FR_SYNCD (1 << 1) /* I2S SYNC direction, 0:input,1:output */
+#define AIC_FR_ENB (1 << 0) /* AIC enable bit */
+
+/* AIC Controller Common Control Register (AIC_CR) */
+
+#define AIC_CR_OSS_BIT 19 /* Output Sample Size from memory (AIC V2 only) */
+#define AIC_CR_OSS_MASK (0x7 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_8BIT (0x0 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_16BIT (0x1 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_18BIT (0x2 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_20BIT (0x3 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_24BIT (0x4 << AIC_CR_OSS_BIT)
+#define AIC_CR_ISS_BIT 16 /* Input Sample Size from memory (AIC V2 only) */
+#define AIC_CR_ISS_MASK (0x7 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_8BIT (0x0 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_16BIT (0x1 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_18BIT (0x2 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_20BIT (0x3 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_24BIT (0x4 << AIC_CR_ISS_BIT)
+#define AIC_CR_RDMS (1 << 15) /* Receive DMA enable */
+#define AIC_CR_TDMS (1 << 14) /* Transmit DMA enable */
+#define AIC_CR_M2S (1 << 11) /* Mono to Stereo enable */
+#define AIC_CR_ENDSW (1 << 10) /* Endian switch enable */
+#define AIC_CR_AVSTSU (1 << 9) /* Signed <-> Unsigned toggle enable */
+#define AIC_CR_FLUSH (1 << 8) /* Flush FIFO */
+#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */
+#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */
+#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */
+#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */
+#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */
+#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */
+#define AIC_CR_EREC (1 << 0) /* Enable Record Function */
+
+/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */
+
+#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */
+#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT)
+ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */
+ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */
+ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */
+ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */
+ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */
+ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */
+ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */
+ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */
+ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */
+ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */
+#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */
+#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT)
+ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */
+ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */
+ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */
+ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */
+ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */
+ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */
+ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */
+ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */
+ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */
+ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */
+
+/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */
+
+#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */
+#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */
+#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */
+#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */
+#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT)
+ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */
+ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */
+ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */
+ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */
+#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */
+#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT)
+ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */
+ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */
+ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */
+ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */
+#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */
+#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */
+#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */
+#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */
+
+/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */
+
+#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */
+#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */
+#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT)
+ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */
+ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */
+ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */
+ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */
+ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */
+#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */
+
+/* AIC Controller FIFO Status Register (AIC_SR) */
+
+#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */
+#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT)
+#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */
+#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT)
+#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */
+#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */
+#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */
+#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */
+
+/* AIC Controller AC-link Status Register (AIC_ACSR) */
+
+#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */
+#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */
+#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */
+#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */
+#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */
+#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */
+
+/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */
+
+#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */
+
+/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */
+
+#define AIC_ACCAR_CAR_BIT 0
+#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT)
+
+/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */
+
+#define AIC_ACCDR_CDR_BIT 0
+#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT)
+
+/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */
+
+#define AIC_ACSAR_SAR_BIT 0
+#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT)
+
+/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */
+
+#define AIC_ACSDR_SDR_BIT 0
+#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT)
+
+/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */
+
+#define AIC_I2SDIV_DIV_BIT 0
+#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT)
+ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */
+ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */
+ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */
+ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */
+ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */
+ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */
+
+
+/*************************************************************************
+ * ICDC (Internal CODEC)
+ *************************************************************************/
+#define ICDC_CR (ICDC_BASE + 0x0400) /* ICDC Control Register */
+#define ICDC_APWAIT (ICDC_BASE + 0x0404) /* Anti-Pop WAIT Stage Timing Control Register */
+#define ICDC_APPRE (ICDC_BASE + 0x0408) /* Anti-Pop HPEN-PRE Stage Timing Control Register */
+#define ICDC_APHPEN (ICDC_BASE + 0x040C) /* Anti-Pop HPEN Stage Timing Control Register */
+#define ICDC_APSR (ICDC_BASE + 0x0410) /* Anti-Pop Status Register */
+#define ICDC_CDCCR1 (ICDC_BASE + 0x0080)
+#define ICDC_CDCCR2 (ICDC_BASE + 0x0084)
+
+#define REG_ICDC_CR REG32(ICDC_CR)
+#define REG_ICDC_APWAIT REG32(ICDC_APWAIT)
+#define REG_ICDC_APPRE REG32(ICDC_APPRE)
+#define REG_ICDC_APHPEN REG32(ICDC_APHPEN)
+#define REG_ICDC_APSR REG32(ICDC_APSR)
+#define REG_ICDC_CDCCR1 REG32(ICDC_CDCCR1)
+#define REG_ICDC_CDCCR2 REG32(ICDC_CDCCR2)
+
+/* ICDC Control Register */
+#define ICDC_CR_LINVOL_BIT 24 /* LINE Input Volume Gain: GAIN=LINVOL*1.5-34.5 */
+#define ICDC_CR_LINVOL_MASK (0x1f << ICDC_CR_LINVOL_BIT)
+#define ICDC_CR_ASRATE_BIT 20 /* Audio Sample Rate */
+#define ICDC_CR_ASRATE_MASK (0x0f << ICDC_CR_ASRATE_BIT)
+ #define ICDC_CR_ASRATE_8000 (0x0 << ICDC_CR_ASRATE_BIT)
+ #define ICDC_CR_ASRATE_11025 (0x1 << ICDC_CR_ASRATE_BIT)
+ #define ICDC_CR_ASRATE_12000 (0x2 << ICDC_CR_ASRATE_BIT)
+ #define ICDC_CR_ASRATE_16000 (0x3 << ICDC_CR_ASRATE_BIT)
+ #define ICDC_CR_ASRATE_22050 (0x4 << ICDC_CR_ASRATE_BIT)
+ #define ICDC_CR_ASRATE_24000 (0x5 << ICDC_CR_ASRATE_BIT)
+ #define ICDC_CR_ASRATE_32000 (0x6 << ICDC_CR_ASRATE_BIT)
+ #define ICDC_CR_ASRATE_44100 (0x7 << ICDC_CR_ASRATE_BIT)
+ #define ICDC_CR_ASRATE_48000 (0x8 << ICDC_CR_ASRATE_BIT)
+#define ICDC_CR_MICBG_BIT 18 /* MIC Boost Gain */
+#define ICDC_CR_MICBG_MASK (0x3 << ICDC_CR_MICBG_BIT)
+ #define ICDC_CR_MICBG_0DB (0x0 << ICDC_CR_MICBG_BIT)
+ #define ICDC_CR_MICBG_6DB (0x1 << ICDC_CR_MICBG_BIT)
+ #define ICDC_CR_MICBG_12DB (0x2 << ICDC_CR_MICBG_BIT)
+ #define ICDC_CR_MICBG_20DB (0x3 << ICDC_CR_MICBG_BIT)
+#define ICDC_CR_HPVOL_BIT 16 /* Headphone Volume Gain */
+#define ICDC_CR_HPVOL_MASK (0x3 << ICDC_CR_HPVOL_BIT)
+ #define ICDC_CR_HPVOL_0DB (0x0 << ICDC_CR_HPVOL_BIT)
+ #define ICDC_CR_HPVOL_2DB (0x1 << ICDC_CR_HPVOL_BIT)
+ #define ICDC_CR_HPVOL_4DB (0x2 << ICDC_CR_HPVOL_BIT)
+ #define ICDC_CR_HPVOL_6DB (0x3 << ICDC_CR_HPVOL_BIT)
+#define ICDC_CR_ELINEIN (1 << 13) /* Enable LINE Input */
+#define ICDC_CR_EMIC (1 << 12) /* Enable MIC Input */
+#define ICDC_CR_SW1ON (1 << 11) /* Switch 1 in CODEC is on */
+#define ICDC_CR_EADC (1 << 10) /* Enable ADC */
+#define ICDC_CR_SW2ON (1 << 9) /* Switch 2 in CODEC is on */
+#define ICDC_CR_EDAC (1 << 8) /* Enable DAC */
+#define ICDC_CR_HPMUTE (1 << 5) /* Headphone Mute */
+#define ICDC_CR_HPTON (1 << 4) /* Headphone Amplifier Trun On */
+#define ICDC_CR_HPTOFF (1 << 3) /* Headphone Amplifier Trun Off */
+#define ICDC_CR_TAAP (1 << 2) /* Turn Around of the Anti-Pop Procedure */
+#define ICDC_CR_EAP (1 << 1) /* Enable Anti-Pop Procedure */
+#define ICDC_CR_SUSPD (1 << 0) /* CODEC Suspend */
+
+/* Anti-Pop WAIT Stage Timing Control Register */
+#define ICDC_APWAIT_WAITSN_BIT 0
+#define ICDC_APWAIT_WAITSN_MASK (0x7ff << ICDC_APWAIT_WAITSN_BIT)
+
+/* Anti-Pop HPEN-PRE Stage Timing Control Register */
+#define ICDC_APPRE_PRESN_BIT 0
+#define ICDC_APPRE_PRESN_MASK (0x1ff << ICDC_APPRE_PRESN_BIT)
+
+/* Anti-Pop HPEN Stage Timing Control Register */
+#define ICDC_APHPEN_HPENSN_BIT 0
+#define ICDC_APHPEN_HPENSN_MASK (0x3fff << ICDC_APHPEN_HPENSN_BIT)
+
+/* Anti-Pop Status Register */
+#define ICDC_SR_HPST_BIT 14 /* Headphone Amplifier State */
+#define ICDC_SR_HPST_MASK (0x7 << ICDC_SR_HPST_BIT)
+#define ICDC_SR_HPST_HP_OFF (0x0 << ICDC_SR_HPST_BIT) /* HP amplifier is off */
+#define ICDC_SR_HPST_TON_WAIT (0x1 << ICDC_SR_HPST_BIT) /* wait state in turn-on */
+ #define ICDC_SR_HPST_TON_PRE (0x2 << ICDC_SR_HPST_BIT) /* pre-enable state in turn-on */
+#define ICDC_SR_HPST_TON_HPEN (0x3 << ICDC_SR_HPST_BIT) /* HP enable state in turn-on */
+ #define ICDC_SR_HPST_TOFF_HPEN (0x4 << ICDC_SR_HPST_BIT) /* HP enable state in turn-off */
+ #define ICDC_SR_HPST_TOFF_PRE (0x5 << ICDC_SR_HPST_BIT) /* pre-enable state in turn-off */
+ #define ICDC_SR_HPST_TOFF_WAIT (0x6 << ICDC_SR_HPST_BIT) /* wait state in turn-off */
+ #define ICDC_SR_HPST_HP_ON (0x7 << ICDC_SR_HPST_BIT) /* HP amplifier is on */
+#define ICDC_SR_SNCNT_BIT 0 /* Sample Number Counter */
+#define ICDC_SR_SNCNT_MASK (0x3fff << ICDC_SR_SNCNT_BIT)
+
+
+/*************************************************************************
+ * I2C
+ *************************************************************************/
+#define I2C_DR (I2C_BASE + 0x000)
+#define I2C_CR (I2C_BASE + 0x004)
+#define I2C_SR (I2C_BASE + 0x008)
+#define I2C_GR (I2C_BASE + 0x00C)
+
+#define REG_I2C_DR REG8(I2C_DR)
+#define REG_I2C_CR REG8(I2C_CR)
+#define REG_I2C_SR REG8(I2C_SR)
+#define REG_I2C_GR REG16(I2C_GR)
+
+/* I2C Control Register (I2C_CR) */
+
+#define I2C_CR_IEN (1 << 4)
+#define I2C_CR_STA (1 << 3)
+#define I2C_CR_STO (1 << 2)
+#define I2C_CR_AC (1 << 1)
+#define I2C_CR_I2CE (1 << 0)
+
+/* I2C Status Register (I2C_SR) */
+
+#define I2C_SR_STX (1 << 4)
+#define I2C_SR_BUSY (1 << 3)
+#define I2C_SR_TEND (1 << 2)
+#define I2C_SR_DRF (1 << 1)
+#define I2C_SR_ACKF (1 << 0)
+
+
+/*************************************************************************
+ * SSI
+ *************************************************************************/
+#define SSI_DR (SSI_BASE + 0x000)
+#define SSI_CR0 (SSI_BASE + 0x004)
+#define SSI_CR1 (SSI_BASE + 0x008)
+#define SSI_SR (SSI_BASE + 0x00C)
+#define SSI_ITR (SSI_BASE + 0x010)
+#define SSI_ICR (SSI_BASE + 0x014)
+#define SSI_GR (SSI_BASE + 0x018)
+
+#define REG_SSI_DR REG32(SSI_DR)
+#define REG_SSI_CR0 REG16(SSI_CR0)
+#define REG_SSI_CR1 REG32(SSI_CR1)
+#define REG_SSI_SR REG32(SSI_SR)
+#define REG_SSI_ITR REG16(SSI_ITR)
+#define REG_SSI_ICR REG8(SSI_ICR)
+#define REG_SSI_GR REG16(SSI_GR)
+
+/* SSI Data Register (SSI_DR) */
+
+#define SSI_DR_GPC_BIT 0
+#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT)
+
+/* SSI Control Register 0 (SSI_CR0) */
+
+#define SSI_CR0_SSIE (1 << 15)
+#define SSI_CR0_TIE (1 << 14)
+#define SSI_CR0_RIE (1 << 13)
+#define SSI_CR0_TEIE (1 << 12)
+#define SSI_CR0_REIE (1 << 11)
+#define SSI_CR0_LOOP (1 << 10)
+#define SSI_CR0_RFINE (1 << 9)
+#define SSI_CR0_RFINC (1 << 8)
+#define SSI_CR0_FSEL (1 << 6)
+#define SSI_CR0_TFLUSH (1 << 2)
+#define SSI_CR0_RFLUSH (1 << 1)
+#define SSI_CR0_DISREV (1 << 0)
+
+/* SSI Control Register 1 (SSI_CR1) */
+
+#define SSI_CR1_FRMHL_BIT 30
+#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT)
+ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */
+ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */
+ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */
+ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */
+#define SSI_CR1_TFVCK_BIT 28
+#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT)
+#define SSI_CR1_TCKFI_BIT 26
+#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT)
+#define SSI_CR1_LFST (1 << 25)
+#define SSI_CR1_ITFRM (1 << 24)
+#define SSI_CR1_UNFIN (1 << 23)
+#define SSI_CR1_MULTS (1 << 22)
+#define SSI_CR1_FMAT_BIT 20
+#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT)
+ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */
+ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */
+ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */
+ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */
+#define SSI_CR1_TTRG_BIT 16
+#define SSI_CR1_TTRG_MASK (0xf << SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_1 (0 << SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_8 (1 << SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_16 (2 << SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_24 (3 << SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_32 (4 << SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_40 (5 << SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_48 (6 << SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_56 (7 << SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_64 (8 << SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_72 (9 << SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_80 (10<< SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_88 (11<< SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_96 (12<< SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_104 (13<< SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_112 (14<< SSI_CR1_TTRG_BIT)
+ #define SSI_CR1_TTRG_120 (15<< SSI_CR1_TTRG_BIT)
+#define SSI_CR1_MCOM_BIT 12
+#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT)
+ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */
+ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */
+ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */
+ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */
+ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */
+ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */
+ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */
+ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */
+ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */
+ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */
+ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */
+ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */
+ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */
+ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */
+ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */
+ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */
+#define SSI_CR1_RTRG_BIT 8
+#define SSI_CR1_RTRG_MASK (0xf << SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_1 (0 << SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_8 (1 << SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_16 (2 << SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_24 (3 << SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_32 (4 << SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_40 (5 << SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_48 (6 << SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_56 (7 << SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_64 (8 << SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_72 (9 << SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_80 (10<< SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_88 (11<< SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_96 (12<< SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_104 (13<< SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_112 (14<< SSI_CR1_RTRG_BIT)
+ #define SSI_CR1_RTRG_120 (15<< SSI_CR1_RTRG_BIT)
+#define SSI_CR1_FLEN_BIT 4
+#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT)
+#define SSI_CR1_PHA (1 << 1)
+#define SSI_CR1_POL (1 << 0)
+
+/* SSI Status Register (SSI_SR) */
+
+#define SSI_SR_TFIFONUM_BIT 16
+#define SSI_SR_TFIFONUM_MASK (0xff << SSI_SR_TFIFONUM_BIT)
+#define SSI_SR_RFIFONUM_BIT 8
+#define SSI_SR_RFIFONUM_MASK (0xff << SSI_SR_RFIFONUM_BIT)
+#define SSI_SR_END (1 << 7)
+#define SSI_SR_BUSY (1 << 6)
+#define SSI_SR_TFF (1 << 5)
+#define SSI_SR_RFE (1 << 4)
+#define SSI_SR_TFHE (1 << 3)
+#define SSI_SR_RFHF (1 << 2)
+#define SSI_SR_UNDR (1 << 1)
+#define SSI_SR_OVER (1 << 0)
+
+/* SSI Interval Time Control Register (SSI_ITR) */
+
+#define SSI_ITR_CNTCLK (1 << 15)
+#define SSI_ITR_IVLTM_BIT 0
+#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT)
+
+
+/*************************************************************************
+ * MSC
+ *************************************************************************/
+#define MSC_STRPCL (MSC_BASE + 0x000)
+#define MSC_STAT (MSC_BASE + 0x004)
+#define MSC_CLKRT (MSC_BASE + 0x008)
+#define MSC_CMDAT (MSC_BASE + 0x00C)
+#define MSC_RESTO (MSC_BASE + 0x010)
+#define MSC_RDTO (MSC_BASE + 0x014)
+#define MSC_BLKLEN (MSC_BASE + 0x018)
+#define MSC_NOB (MSC_BASE + 0x01C)
+#define MSC_SNOB (MSC_BASE + 0x020)
+#define MSC_IMASK (MSC_BASE + 0x024)
+#define MSC_IREG (MSC_BASE + 0x028)
+#define MSC_CMD (MSC_BASE + 0x02C)
+#define MSC_ARG (MSC_BASE + 0x030)
+#define MSC_RES (MSC_BASE + 0x034)
+#define MSC_RXFIFO (MSC_BASE + 0x038)
+#define MSC_TXFIFO (MSC_BASE + 0x03C)
+
+#define REG_MSC_STRPCL REG16(MSC_STRPCL)
+#define REG_MSC_STAT REG32(MSC_STAT)
+#define REG_MSC_CLKRT REG16(MSC_CLKRT)
+#define REG_MSC_CMDAT REG32(MSC_CMDAT)
+#define REG_MSC_RESTO REG16(MSC_RESTO)
+#define REG_MSC_RDTO REG16(MSC_RDTO)
+#define REG_MSC_BLKLEN REG16(MSC_BLKLEN)
+#define REG_MSC_NOB REG16(MSC_NOB)
+#define REG_MSC_SNOB REG16(MSC_SNOB)
+#define REG_MSC_IMASK REG16(MSC_IMASK)
+#define REG_MSC_IREG REG16(MSC_IREG)
+#define REG_MSC_CMD REG8(MSC_CMD)
+#define REG_MSC_ARG REG32(MSC_ARG)
+#define REG_MSC_RES REG16(MSC_RES)
+#define REG_MSC_RXFIFO REG32(MSC_RXFIFO)
+#define REG_MSC_TXFIFO REG32(MSC_TXFIFO)
+
+/* MSC Clock and Control Register (MSC_STRPCL) */
+
+#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7)
+#define MSC_STRPCL_EXIT_TRANSFER (1 << 6)
+#define MSC_STRPCL_START_READWAIT (1 << 5)
+#define MSC_STRPCL_STOP_READWAIT (1 << 4)
+#define MSC_STRPCL_RESET (1 << 3)
+#define MSC_STRPCL_START_OP (1 << 2)
+#define MSC_STRPCL_CLOCK_CONTROL_BIT 0
+#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT)
+ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */
+ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */
+
+/* MSC Status Register (MSC_STAT) */
+
+#define MSC_STAT_IS_RESETTING (1 << 15)
+#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14)
+#define MSC_STAT_PRG_DONE (1 << 13)
+#define MSC_STAT_DATA_TRAN_DONE (1 << 12)
+#define MSC_STAT_END_CMD_RES (1 << 11)
+#define MSC_STAT_DATA_FIFO_AFULL (1 << 10)
+#define MSC_STAT_IS_READWAIT (1 << 9)
+#define MSC_STAT_CLK_EN (1 << 8)
+#define MSC_STAT_DATA_FIFO_FULL (1 << 7)
+#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6)
+#define MSC_STAT_CRC_RES_ERR (1 << 5)
+#define MSC_STAT_CRC_READ_ERROR (1 << 4)
+#define MSC_STAT_CRC_WRITE_ERROR_BIT 2
+#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT)
+ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */
+ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */
+ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */
+#define MSC_STAT_TIME_OUT_RES (1 << 1)
+#define MSC_STAT_TIME_OUT_READ (1 << 0)
+
+/* MSC Bus Clock Control Register (MSC_CLKRT) */
+
+#define MSC_CLKRT_CLK_RATE_BIT 0
+#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT)
+ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */
+
+/* MSC Command Sequence Control Register (MSC_CMDAT) */
+
+#define MSC_CMDAT_IO_ABORT (1 << 11)
+#define MSC_CMDAT_BUS_WIDTH_BIT 9
+#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT)
+ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */
+ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */
+ #define CMDAT_BUS_WIDTH1 (0x0 << MSC_CMDAT_BUS_WIDTH_BIT)
+ #define CMDAT_BUS_WIDTH4 (0x2 << MSC_CMDAT_BUS_WIDTH_BIT)
+#define MSC_CMDAT_DMA_EN (1 << 8)
+#define MSC_CMDAT_INIT (1 << 7)
+#define MSC_CMDAT_BUSY (1 << 6)
+#define MSC_CMDAT_STREAM_BLOCK (1 << 5)
+#define MSC_CMDAT_WRITE (1 << 4)
+#define MSC_CMDAT_READ (0 << 4)
+#define MSC_CMDAT_DATA_EN (1 << 3)
+#define MSC_CMDAT_RESPONSE_BIT 0
+#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT)
+ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */
+ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */
+ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */
+ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */
+ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */
+ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */
+ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */
+
+#define CMDAT_DMA_EN (1 << 8)
+#define CMDAT_INIT (1 << 7)
+#define CMDAT_BUSY (1 << 6)
+#define CMDAT_STREAM (1 << 5)
+#define CMDAT_WRITE (1 << 4)
+#define CMDAT_DATA_EN (1 << 3)
+
+/* MSC Interrupts Mask Register (MSC_IMASK) */
+
+#define MSC_IMASK_SDIO (1 << 7)
+#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6)
+#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5)
+#define MSC_IMASK_END_CMD_RES (1 << 2)
+#define MSC_IMASK_PRG_DONE (1 << 1)
+#define MSC_IMASK_DATA_TRAN_DONE (1 << 0)
+
+
+/* MSC Interrupts Status Register (MSC_IREG) */
+
+#define MSC_IREG_SDIO (1 << 7)
+#define MSC_IREG_TXFIFO_WR_REQ (1 << 6)
+#define MSC_IREG_RXFIFO_RD_REQ (1 << 5)
+#define MSC_IREG_END_CMD_RES (1 << 2)
+#define MSC_IREG_PRG_DONE (1 << 1)
+#define MSC_IREG_DATA_TRAN_DONE (1 << 0)
+
+
+/*************************************************************************
+ * EMC (External Memory Controller)
+ *************************************************************************/
+#define EMC_SMCR0 (EMC_BASE + 0x10) /* Static Memory Control Register 0 */
+#define EMC_SMCR1 (EMC_BASE + 0x14) /* Static Memory Control Register 1 */
+#define EMC_SMCR2 (EMC_BASE + 0x18) /* Static Memory Control Register 2 */
+#define EMC_SMCR3 (EMC_BASE + 0x1c) /* Static Memory Control Register 3 */
+#define EMC_SMCR4 (EMC_BASE + 0x20) /* Static Memory Control Register 4 */
+#define EMC_SACR0 (EMC_BASE + 0x30) /* Static Memory Bank 0 Addr Config Reg */
+#define EMC_SACR1 (EMC_BASE + 0x34) /* Static Memory Bank 1 Addr Config Reg */
+#define EMC_SACR2 (EMC_BASE + 0x38) /* Static Memory Bank 2 Addr Config Reg */
+#define EMC_SACR3 (EMC_BASE + 0x3c) /* Static Memory Bank 3 Addr Config Reg */
+#define EMC_SACR4 (EMC_BASE + 0x40) /* Static Memory Bank 4 Addr Config Reg */
+
+#define EMC_NFCSR (EMC_BASE + 0x050) /* NAND Flash Control/Status Register */
+#define EMC_NFECR (EMC_BASE + 0x100) /* NAND Flash ECC Control Register */
+#define EMC_NFECC (EMC_BASE + 0x104) /* NAND Flash ECC Data Register */
+#define EMC_NFPAR0 (EMC_BASE + 0x108) /* NAND Flash RS Parity 0 Register */
+#define EMC_NFPAR1 (EMC_BASE + 0x10c) /* NAND Flash RS Parity 1 Register */
+#define EMC_NFPAR2 (EMC_BASE + 0x110) /* NAND Flash RS Parity 2 Register */
+#define EMC_NFINTS (EMC_BASE + 0x114) /* NAND Flash Interrupt Status Register */
+#define EMC_NFINTE (EMC_BASE + 0x118) /* NAND Flash Interrupt Enable Register */
+#define EMC_NFERR0 (EMC_BASE + 0x11c) /* NAND Flash RS Error Report 0 Register */
+#define EMC_NFERR1 (EMC_BASE + 0x120) /* NAND Flash RS Error Report 1 Register */
+#define EMC_NFERR2 (EMC_BASE + 0x124) /* NAND Flash RS Error Report 2 Register */
+#define EMC_NFERR3 (EMC_BASE + 0x128) /* NAND Flash RS Error Report 3 Register */
+
+#define EMC_DMCR (EMC_BASE + 0x80) /* DRAM Control Register */
+#define EMC_RTCSR (EMC_BASE + 0x84) /* Refresh Time Control/Status Register */
+#define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */
+#define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */
+#define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */
+#define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */
+
+
+#define REG_EMC_SMCR0 REG32(EMC_SMCR0)
+#define REG_EMC_SMCR1 REG32(EMC_SMCR1)
+#define REG_EMC_SMCR2 REG32(EMC_SMCR2)
+#define REG_EMC_SMCR3 REG32(EMC_SMCR3)
+#define REG_EMC_SMCR4 REG32(EMC_SMCR4)
+#define REG_EMC_SACR0 REG32(EMC_SACR0)
+#define REG_EMC_SACR1 REG32(EMC_SACR1)
+#define REG_EMC_SACR2 REG32(EMC_SACR2)
+#define REG_EMC_SACR3 REG32(EMC_SACR3)
+#define REG_EMC_SACR4 REG32(EMC_SACR4)
+
+#define REG_EMC_NFCSR REG32(EMC_NFCSR)
+#define REG_EMC_NFECR REG32(EMC_NFECR)
+#define REG_EMC_NFECC REG32(EMC_NFECC)
+#define REG_EMC_NFPAR0 REG32(EMC_NFPAR0)
+#define REG_EMC_NFPAR1 REG32(EMC_NFPAR1)
+#define REG_EMC_NFPAR2 REG32(EMC_NFPAR2)
+#define REG_EMC_NFINTS REG32(EMC_NFINTS)
+#define REG_EMC_NFINTE REG32(EMC_NFINTE)
+#define REG_EMC_NFERR0 REG32(EMC_NFERR0)
+#define REG_EMC_NFERR1 REG32(EMC_NFERR1)
+#define REG_EMC_NFERR2 REG32(EMC_NFERR2)
+#define REG_EMC_NFERR3 REG32(EMC_NFERR3)
+
+#define REG_EMC_DMCR REG32(EMC_DMCR)
+#define REG_EMC_RTCSR REG16(EMC_RTCSR)
+#define REG_EMC_RTCNT REG16(EMC_RTCNT)
+#define REG_EMC_RTCOR REG16(EMC_RTCOR)
+#define REG_EMC_DMAR0 REG32(EMC_DMAR0)
+
+/* Static Memory Control Register */
+#define EMC_SMCR_STRV_BIT 24
+#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT)
+#define EMC_SMCR_TAW_BIT 20
+#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT)
+#define EMC_SMCR_TBP_BIT 16
+#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT)
+#define EMC_SMCR_TAH_BIT 12
+#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT)
+#define EMC_SMCR_TAS_BIT 8
+#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT)
+#define EMC_SMCR_BW_BIT 6
+#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT)
+#define EMC_SMCR_BCM (1 << 3)
+#define EMC_SMCR_BL_BIT 1
+#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT)
+#define EMC_SMCR_SMT (1 << 0)
+
+/* Static Memory Bank Addr Config Reg */
+#define EMC_SACR_BASE_BIT 8
+#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT)
+#define EMC_SACR_MASK_BIT 0
+#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT)
+
+/* NAND Flash Control/Status Register */
+#define EMC_NFCSR_NFCE4 (1 << 7) /* NAND Flash Enable */
+#define EMC_NFCSR_NFE4 (1 << 6) /* NAND Flash FCE# Assertion Enable */
+#define EMC_NFCSR_NFCE3 (1 << 5)
+#define EMC_NFCSR_NFE3 (1 << 4)
+#define EMC_NFCSR_NFCE2 (1 << 3)
+#define EMC_NFCSR_NFE2 (1 << 2)
+#define EMC_NFCSR_NFCE1 (1 << 1)
+#define EMC_NFCSR_NFE1 (1 << 0)
+
+/* NAND Flash ECC Control Register */
+#define EMC_NFECR_PRDY (1 << 4) /* Parity Ready */
+#define EMC_NFECR_RS_DECODING (0 << 3) /* RS is in decoding phase */
+#define EMC_NFECR_RS_ENCODING (1 << 3) /* RS is in encoding phase */
+#define EMC_NFECR_HAMMING (0 << 2) /* Select HAMMING Correction Algorithm */
+#define EMC_NFECR_RS (1 << 2) /* Select RS Correction Algorithm */
+#define EMC_NFECR_ERST (1 << 1) /* ECC Reset */
+#define EMC_NFECR_ECCE (1 << 0) /* ECC Enable */
+
+/* NAND Flash ECC Data Register */
+#define EMC_NFECC_ECC2_BIT 16
+#define EMC_NFECC_ECC2_MASK (0xff << EMC_NFECC_ECC2_BIT)
+#define EMC_NFECC_ECC1_BIT 8
+#define EMC_NFECC_ECC1_MASK (0xff << EMC_NFECC_ECC1_BIT)
+#define EMC_NFECC_ECC0_BIT 0
+#define EMC_NFECC_ECC0_MASK (0xff << EMC_NFECC_ECC0_BIT)
+
+/* NAND Flash Interrupt Status Register */
+#define EMC_NFINTS_ERRCNT_BIT 29 /* Error Count */
+#define EMC_NFINTS_ERRCNT_MASK (0x7 << EMC_NFINTS_ERRCNT_BIT)
+#define EMC_NFINTS_PADF (1 << 4) /* Padding Finished */
+#define EMC_NFINTS_DECF (1 << 3) /* Decoding Finished */
+#define EMC_NFINTS_ENCF (1 << 2) /* Encoding Finished */
+#define EMC_NFINTS_UNCOR (1 << 1) /* Uncorrectable Error Occurred */
+#define EMC_NFINTS_ERR (1 << 0) /* Error Occurred */
+
+/* NAND Flash Interrupt Enable Register */
+#define EMC_NFINTE_PADFE (1 << 4) /* Padding Finished Interrupt Enable */
+#define EMC_NFINTE_DECFE (1 << 3) /* Decoding Finished Interrupt Enable */
+#define EMC_NFINTE_ENCFE (1 << 2) /* Encoding Finished Interrupt Enable */
+#define EMC_NFINTE_UNCORE (1 << 1) /* Uncorrectable Error Occurred Intr Enable */
+#define EMC_NFINTE_ERRE (1 << 0) /* Error Occurred Interrupt */
+
+/* NAND Flash RS Error Report Register */
+#define EMC_NFERR_INDEX_BIT 16 /* Error Symbol Index */
+#define EMC_NFERR_INDEX_MASK (0x1ff << EMC_NFERR_INDEX_BIT)
+#define EMC_NFERR_MASK_BIT 0 /* Error Symbol Value */
+#define EMC_NFERR_MASK_MASK (0x1ff << EMC_NFERR_MASK_BIT)
+
+
+/* DRAM Control Register */
+#define EMC_DMCR_BW_BIT 31
+#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT)
+#define EMC_DMCR_CA_BIT 26
+#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT)
+#define EMC_DMCR_RMODE (1 << 25)
+#define EMC_DMCR_RFSH (1 << 24)
+#define EMC_DMCR_MRSET (1 << 23)
+#define EMC_DMCR_RA_BIT 20
+#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT)
+#define EMC_DMCR_BA_BIT 19
+#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT)
+#define EMC_DMCR_PDM (1 << 18)
+#define EMC_DMCR_EPIN (1 << 17)
+#define EMC_DMCR_TRAS_BIT 13
+#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT)
+#define EMC_DMCR_RCD_BIT 11
+#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT)
+#define EMC_DMCR_TPC_BIT 8
+#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT)
+#define EMC_DMCR_TRWL_BIT 5
+#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT)
+#define EMC_DMCR_TRC_BIT 2
+#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT)
+#define EMC_DMCR_TCL_BIT 0
+#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT)
+
+/* Refresh Time Control/Status Register */
+#define EMC_RTCSR_CMF (1 << 7)
+#define EMC_RTCSR_CKS_BIT 0
+#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT)
+
+/* SDRAM Bank Address Configuration Register */
+#define EMC_DMAR_BASE_BIT 8
+#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT)
+#define EMC_DMAR_MASK_BIT 0
+#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT)
+
+/* Mode Register of SDRAM bank 0 */
+#define EMC_SDMR_BM (1 << 9) /* Write Burst Mode */
+#define EMC_SDMR_OM_BIT 7 /* Operating Mode */
+#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT)
+ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT)
+#define EMC_SDMR_CAS_BIT 4 /* CAS Latency */
+#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT)
+#define EMC_SDMR_BT_BIT 3 /* Burst Type */
+#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT)
+ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) /* Sequential */
+ #define EMC_SDMR_BT_INT (1 << EMC_SDMR_BT_BIT) /* Interleave */
+#define EMC_SDMR_BL_BIT 0 /* Burst Length */
+#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT)
+
+#define EMC_SDMR_CAS2_16BIT \
+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2)
+#define EMC_SDMR_CAS2_32BIT \
+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4)
+#define EMC_SDMR_CAS3_16BIT \
+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2)
+#define EMC_SDMR_CAS3_32BIT \
+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4)
+
+
+/*************************************************************************
+ * CIM
+ *************************************************************************/
+#define CIM_CFG (CIM_BASE + 0x0000)
+#define CIM_CTRL (CIM_BASE + 0x0004)
+#define CIM_STATE (CIM_BASE + 0x0008)
+#define CIM_IID (CIM_BASE + 0x000C)
+#define CIM_RXFIFO (CIM_BASE + 0x0010)
+#define CIM_DA (CIM_BASE + 0x0020)
+#define CIM_FA (CIM_BASE + 0x0024)
+#define CIM_FID (CIM_BASE + 0x0028)
+#define CIM_CMD (CIM_BASE + 0x002C)
+
+#define REG_CIM_CFG REG32(CIM_CFG)
+#define REG_CIM_CTRL REG32(CIM_CTRL)
+#define REG_CIM_STATE REG32(CIM_STATE)
+#define REG_CIM_IID REG32(CIM_IID)
+#define REG_CIM_RXFIFO REG32(CIM_RXFIFO)
+#define REG_CIM_DA REG32(CIM_DA)
+#define REG_CIM_FA REG32(CIM_FA)
+#define REG_CIM_FID REG32(CIM_FID)
+#define REG_CIM_CMD REG32(CIM_CMD)
+
+/* CIM Configuration Register (CIM_CFG) */
+
+#define CIM_CFG_INV_DAT (1 << 15)
+#define CIM_CFG_VSP (1 << 14)
+#define CIM_CFG_HSP (1 << 13)
+#define CIM_CFG_PCP (1 << 12)
+#define CIM_CFG_DUMMY_ZERO (1 << 9)
+#define CIM_CFG_EXT_VSYNC (1 << 8)
+#define CIM_CFG_PACK_BIT 4
+#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT)
+#define CIM_CFG_DSM_BIT 0
+#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT)
+ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */
+ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */
+ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */
+ #define CIM_CFG_DSM_NGCM (3 << CIM_CFG_DSM_BIT) /* Non-Gated Clock Mode */
+
+/* CIM Control Register (CIM_CTRL) */
+
+#define CIM_CTRL_MCLKDIV_BIT 24
+#define CIM_CTRL_MCLKDIV_MASK (0xff << CIM_CTRL_MCLKDIV_BIT)
+#define CIM_CTRL_FRC_BIT 16
+#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT)
+ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */
+ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */
+ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */
+ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */
+ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */
+ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */
+ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */
+ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */
+ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */
+ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */
+ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */
+ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */
+ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */
+ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */
+ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */
+ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */
+#define CIM_CTRL_VDDM (1 << 13)
+#define CIM_CTRL_DMA_SOFM (1 << 12)
+#define CIM_CTRL_DMA_EOFM (1 << 11)
+#define CIM_CTRL_DMA_STOPM (1 << 10)
+#define CIM_CTRL_RXF_TRIGM (1 << 9)
+#define CIM_CTRL_RXF_OFM (1 << 8)
+#define CIM_CTRL_RXF_TRIG_BIT 4
+#define CIM_CTRL_RXF_TRIG_MASK (0x7 << CIM_CTRL_RXF_TRIG_BIT)
+ #define CIM_CTRL_RXF_TRIG_4 (0 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 4 */
+ #define CIM_CTRL_RXF_TRIG_8 (1 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 8 */
+ #define CIM_CTRL_RXF_TRIG_12 (2 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 12 */
+ #define CIM_CTRL_RXF_TRIG_16 (3 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 16 */
+ #define CIM_CTRL_RXF_TRIG_20 (4 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 20 */
+ #define CIM_CTRL_RXF_TRIG_24 (5 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 24 */
+ #define CIM_CTRL_RXF_TRIG_28 (6 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 28 */
+ #define CIM_CTRL_RXF_TRIG_32 (7 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 32 */
+#define CIM_CTRL_DMA_EN (1 << 2)
+#define CIM_CTRL_RXF_RST (1 << 1)
+#define CIM_CTRL_ENA (1 << 0)
+
+/* CIM State Register (CIM_STATE) */
+
+#define CIM_STATE_DMA_SOF (1 << 6)
+#define CIM_STATE_DMA_EOF (1 << 5)
+#define CIM_STATE_DMA_STOP (1 << 4)
+#define CIM_STATE_RXF_OF (1 << 3)
+#define CIM_STATE_RXF_TRIG (1 << 2)
+#define CIM_STATE_RXF_EMPTY (1 << 1)
+#define CIM_STATE_VDD (1 << 0)
+
+/* CIM DMA Command Register (CIM_CMD) */
+
+#define CIM_CMD_SOFINT (1 << 31)
+#define CIM_CMD_EOFINT (1 << 30)
+#define CIM_CMD_STOP (1 << 28)
+#define CIM_CMD_LEN_BIT 0
+#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT)
+
+
+/*************************************************************************
+ * SADC (Smart A/D Controller)
+ *************************************************************************/
+
+#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */
+#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */
+#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */
+#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/
+#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */
+#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */
+#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */
+#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC PBAT Data Register */
+#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC SADCIN Data Register */
+
+#define REG_SADC_ENA REG8(SADC_ENA)
+#define REG_SADC_CFG REG32(SADC_CFG)
+#define REG_SADC_CTRL REG8(SADC_CTRL)
+#define REG_SADC_STATE REG8(SADC_STATE)
+#define REG_SADC_SAMETIME REG16(SADC_SAMETIME)
+#define REG_SADC_WAITTIME REG16(SADC_WAITTIME)
+#define REG_SADC_TSDAT REG32(SADC_TSDAT)
+#define REG_SADC_BATDAT REG16(SADC_BATDAT)
+#define REG_SADC_SADDAT REG16(SADC_SADDAT)
+
+/* ADC Enable Register */
+#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */
+#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */
+#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */
+#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */
+
+/* ADC Configure Register */
+#define SADC_CFG_SPZZ (1 << 31)
+#define SADC_CFG_EXIN (1 << 30)
+#define SADC_CFG_CLKOUT_NUM_BIT 16
+#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT)
+#define SADC_CFG_DNUM(x) (((x) - 1) << SADC_CFG_CLKOUT_NUM_BIT)
+#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */
+#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */
+#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT)
+ #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT)
+ #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT)
+ #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT)
+#define SADC_CFG_SNUM_BIT 10 /* Sample Number */
+#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT)
+#define SADC_CFG_SNUM(x) (((x) - 1) << SADC_CFG_SNUM_BIT)
+
+#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */
+#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT)
+#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */
+#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */
+#define SADC_CFG_CMD_BIT 0 /* ADC Command */
+#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT)
+ #define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */
+ #define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */
+ #define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */
+ #define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */
+ #define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */
+ #define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */
+ #define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */
+ #define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */
+ #define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */
+ #define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */
+ #define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */
+ #define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */
+ #define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */
+
+/* ADC Control Register */
+#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */
+#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */
+#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */
+#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */
+#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */
+
+/* ADC Status Register */
+#define SADC_STATE_TSBUSY (1 << 7) /* TS A/D is working */
+#define SADC_STATE_PBATBUSY (1 << 6) /* PBAT A/D is working */
+#define SADC_STATE_SBUSY (1 << 5) /* SADCIN A/D is working */
+#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */
+#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */
+#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */
+#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */
+#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */
+
+/* ADC Touch Screen Data Register */
+#define SADC_TSDAT_DATA0_BIT 0
+#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT)
+#define SADC_TSDAT_TYPE0 (1 << 15)
+#define SADC_TSDAT_DATA1_BIT 16
+#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT)
+#define SADC_TSDAT_TYPE1 (1 << 31)
+
+
+/*************************************************************************
+ * SLCD (Smart LCD Controller)
+ *************************************************************************/
+
+#define SLCD_CFG (SLCD_BASE + 0xA0) /* SLCD Configure Register */
+#define SLCD_CTRL (SLCD_BASE + 0xA4) /* SLCD Control Register */
+#define SLCD_STATE (SLCD_BASE + 0xA8) /* SLCD Status Register */
+#define SLCD_DATA (SLCD_BASE + 0xAC) /* SLCD Data Register */
+#define SLCD_FIFO (SLCD_BASE + 0xB0) /* SLCD FIFO Register */
+
+#define REG_SLCD_CFG REG32(SLCD_CFG)
+#define REG_SLCD_CTRL REG8(SLCD_CTRL)
+#define REG_SLCD_STATE REG8(SLCD_STATE)
+#define REG_SLCD_DATA REG32(SLCD_DATA)
+#define REG_SLCD_FIFO REG32(SLCD_FIFO)
+
+/* SLCD Configure Register */
+#define SLCD_CFG_BURST_BIT 14
+#define SLCD_CFG_BURST_MASK (0x3 << SLCD_CFG_BURST_BIT)
+ #define SLCD_CFG_BURST_4_WORD (0 << SLCD_CFG_BURST_BIT)
+ #define SLCD_CFG_BURST_8_WORD (1 << SLCD_CFG_BURST_BIT)
+#define SLCD_CFG_DWIDTH_BIT 10
+#define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_18 (0 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_16 (1 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_8_x3 (2 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_8_x2 (3 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_8_x1 (4 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_9_x2 (7 << SLCD_CFG_DWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_16BIT (0 << 8)
+#define SLCD_CFG_CWIDTH_8BIT (1 << 8)
+#define SLCD_CFG_CWIDTH_18BIT (2 << 8)
+#define SLCD_CFG_CS_ACTIVE_LOW (0 << 4)
+#define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4)
+#define SLCD_CFG_RS_CMD_LOW (0 << 3)
+#define SLCD_CFG_RS_CMD_HIGH (1 << 3)
+#define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1)
+#define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1)
+#define SLCD_CFG_TYPE_PARALLEL (0 << 0)
+#define SLCD_CFG_TYPE_SERIAL (1 << 0)
+
+/* SLCD Control Register */
+#define SLCD_CTRL_DMA_EN (1 << 0)
+
+/* SLCD Status Register */
+#define SLCD_STATE_BUSY (1 << 0)
+
+/* SLCD Data Register */
+#define SLCD_DATA_RS_DATA (0 << 31)
+#define SLCD_DATA_RS_COMMAND (1 << 31)
+
+/* SLCD FIFO Register */
+#define SLCD_FIFO_RS_DATA (0 << 31)
+#define SLCD_FIFO_RS_COMMAND (1 << 31)
+
+
+/*************************************************************************
+ * LCD (LCD Controller)
+ *************************************************************************/
+#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */
+#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */
+#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */
+#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */
+#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */
+#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */
+#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */
+#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */
+#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */
+#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */
+#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */
+#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */
+#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */
+#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */
+#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */
+#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */
+#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */
+#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */
+#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */
+#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */
+#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */
+
+#define REG_LCD_CFG REG32(LCD_CFG)
+#define REG_LCD_VSYNC REG32(LCD_VSYNC)
+#define REG_LCD_HSYNC REG32(LCD_HSYNC)
+#define REG_LCD_VAT REG32(LCD_VAT)
+#define REG_LCD_DAH REG32(LCD_DAH)
+#define REG_LCD_DAV REG32(LCD_DAV)
+#define REG_LCD_PS REG32(LCD_PS)
+#define REG_LCD_CLS REG32(LCD_CLS)
+#define REG_LCD_SPL REG32(LCD_SPL)
+#define REG_LCD_REV REG32(LCD_REV)
+#define REG_LCD_CTRL REG32(LCD_CTRL)
+#define REG_LCD_STATE REG32(LCD_STATE)
+#define REG_LCD_IID REG32(LCD_IID)
+#define REG_LCD_DA0 REG32(LCD_DA0)
+#define REG_LCD_SA0 REG32(LCD_SA0)
+#define REG_LCD_FID0 REG32(LCD_FID0)
+#define REG_LCD_CMD0 REG32(LCD_CMD0)
+#define REG_LCD_DA1 REG32(LCD_DA1)
+#define REG_LCD_SA1 REG32(LCD_SA1)
+#define REG_LCD_FID1 REG32(LCD_FID1)
+#define REG_LCD_CMD1 REG32(LCD_CMD1)
+
+/* LCD Configure Register */
+#define LCD_CFG_LCDPIN_BIT 31 /* LCD pins selection */
+#define LCD_CFG_LCDPIN_MASK (0x1 << LCD_CFG_LCDPIN_BIT)
+ #define LCD_CFG_LCDPIN_LCD (0x0 << LCD_CFG_LCDPIN_BIT)
+ #define LCD_CFG_LCDPIN_SLCD (0x1 << LCD_CFG_LCDPIN_BIT)
+#define LCD_CFG_PSM (1 << 23) /* PS signal mode */
+#define LCD_CFG_CLSM (1 << 22) /* CLS signal mode */
+#define LCD_CFG_SPLM (1 << 21) /* SPL signal mode */
+#define LCD_CFG_REVM (1 << 20) /* REV signal mode */
+#define LCD_CFG_HSYNM (1 << 19) /* HSYNC signal mode */
+#define LCD_CFG_PCLKM (1 << 18) /* PCLK signal mode */
+#define LCD_CFG_INVDAT (1 << 17) /* Inverse output data */
+#define LCD_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */
+#define LCD_CFG_PSP (1 << 15) /* PS pin reset state */
+#define LCD_CFG_CLSP (1 << 14) /* CLS pin reset state */
+#define LCD_CFG_SPLP (1 << 13) /* SPL pin reset state */
+#define LCD_CFG_REVP (1 << 12) /* REV pin reset state */
+#define LCD_CFG_HSP (1 << 11) /* HSYNC pority:0-active high,1-active low */
+#define LCD_CFG_PCP (1 << 10) /* PCLK pority:0-rising,1-falling */
+#define LCD_CFG_DEP (1 << 9) /* DE pority:0-active high,1-active low */
+#define LCD_CFG_VSP (1 << 8) /* VSYNC pority:0-rising,1-falling */
+#define LCD_CFG_PDW_BIT 4 /* STN pins utilization */
+#define LCD_CFG_PDW_MASK (0x3 << LCD_DEV_PDW_BIT)
+#define LCD_CFG_PDW_1 (0 << LCD_CFG_PDW_BIT) /* LCD_D[0] */
+ #define LCD_CFG_PDW_2 (1 << LCD_CFG_PDW_BIT) /* LCD_D[0:1] */
+ #define LCD_CFG_PDW_4 (2 << LCD_CFG_PDW_BIT) /* LCD_D[0:3]/LCD_D[8:11] */
+ #define LCD_CFG_PDW_8 (3 << LCD_CFG_PDW_BIT) /* LCD_D[0:7]/LCD_D[8:15] */
+#define LCD_CFG_MODE_BIT 0 /* Display Device Mode Select */
+#define LCD_CFG_MODE_MASK (0x0f << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_CFG_MODE_BIT) /* 16,18 bit TFT */
+ #define LCD_CFG_MODE_SPECIAL_TFT_1 (1 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SPECIAL_TFT_2 (2 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SPECIAL_TFT_3 (3 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SERIAL_TFT (12 << LCD_CFG_MODE_BIT)
+ /* JZ47XX defines */
+ #define LCD_CFG_MODE_SHARP_HR (1 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_CASIO_TFT (2 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SAMSUNG_ALPHA (3 << LCD_CFG_MODE_BIT)
+
+
+
+/* Vertical Synchronize Register */
+#define LCD_VSYNC_VPS_BIT 16 /* VSYNC pulse start in line clock, fixed to 0 */
+#define LCD_VSYNC_VPS_MASK (0xffff << LCD_VSYNC_VPS_BIT)
+#define LCD_VSYNC_VPE_BIT 0 /* VSYNC pulse end in line clock */
+#define LCD_VSYNC_VPE_MASK (0xffff << LCD_VSYNC_VPS_BIT)
+
+/* Horizontal Synchronize Register */
+#define LCD_HSYNC_HPS_BIT 16 /* HSYNC pulse start position in dot clock */
+#define LCD_HSYNC_HPS_MASK (0xffff << LCD_HSYNC_HPS_BIT)
+#define LCD_HSYNC_HPE_BIT 0 /* HSYNC pulse end position in dot clock */
+#define LCD_HSYNC_HPE_MASK (0xffff << LCD_HSYNC_HPE_BIT)
+
+/* Virtual Area Setting Register */
+#define LCD_VAT_HT_BIT 16 /* Horizontal Total size in dot clock */
+#define LCD_VAT_HT_MASK (0xffff << LCD_VAT_HT_BIT)
+#define LCD_VAT_VT_BIT 0 /* Vertical Total size in dot clock */
+#define LCD_VAT_VT_MASK (0xffff << LCD_VAT_VT_BIT)
+
+/* Display Area Horizontal Start/End Point Register */
+#define LCD_DAH_HDS_BIT 16 /* Horizontal display area start in dot clock */
+#define LCD_DAH_HDS_MASK (0xffff << LCD_DAH_HDS_BIT)
+#define LCD_DAH_HDE_BIT 0 /* Horizontal display area end in dot clock */
+#define LCD_DAH_HDE_MASK (0xffff << LCD_DAH_HDE_BIT)
+
+/* Display Area Vertical Start/End Point Register */
+#define LCD_DAV_VDS_BIT 16 /* Vertical display area start in line clock */
+#define LCD_DAV_VDS_MASK (0xffff << LCD_DAV_VDS_BIT)
+#define LCD_DAV_VDE_BIT 0 /* Vertical display area end in line clock */
+#define LCD_DAV_VDE_MASK (0xffff << LCD_DAV_VDE_BIT)
+
+/* PS Signal Setting */
+#define LCD_PS_PSS_BIT 16 /* PS signal start position in dot clock */
+#define LCD_PS_PSS_MASK (0xffff << LCD_PS_PSS_BIT)
+#define LCD_PS_PSE_BIT 0 /* PS signal end position in dot clock */
+#define LCD_PS_PSE_MASK (0xffff << LCD_PS_PSE_BIT)
+
+/* CLS Signal Setting */
+#define LCD_CLS_CLSS_BIT 16 /* CLS signal start position in dot clock */
+#define LCD_CLS_CLSS_MASK (0xffff << LCD_CLS_CLSS_BIT)
+#define LCD_CLS_CLSE_BIT 0 /* CLS signal end position in dot clock */
+#define LCD_CLS_CLSE_MASK (0xffff << LCD_CLS_CLSE_BIT)
+
+/* SPL Signal Setting */
+#define LCD_SPL_SPLS_BIT 16 /* SPL signal start position in dot clock */
+#define LCD_SPL_SPLS_MASK (0xffff << LCD_SPL_SPLS_BIT)
+#define LCD_SPL_SPLE_BIT 0 /* SPL signal end position in dot clock */
+#define LCD_SPL_SPLE_MASK (0xffff << LCD_SPL_SPLE_BIT)
+
+/* REV Signal Setting */
+#define LCD_REV_REVS_BIT 16 /* REV signal start position in dot clock */
+#define LCD_REV_REVS_MASK (0xffff << LCD_REV_REVS_BIT)
+
+/* LCD Control Register */
+#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */
+#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT)
+ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */
+ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */
+ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */
+#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode */
+#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode */
+#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */
+#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */
+#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT)
+ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */
+ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */
+ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */
+#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */
+#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT)
+#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */
+#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */
+#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */
+#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */
+#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */
+#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */
+#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */
+#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */
+#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */
+#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */
+#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */
+#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */
+#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT)
+ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */
+ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */
+ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */
+ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */
+ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */
+ #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */
+
+/* LCD Status Register */
+#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */
+#define LCD_STATE_EOF (1 << 5) /* EOF Flag */
+#define LCD_STATE_SOF (1 << 4) /* SOF Flag */
+#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */
+#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */
+#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */
+#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */
+
+/* DMA Command Register */
+#define LCD_CMD_SOFINT (1 << 31)
+#define LCD_CMD_EOFINT (1 << 30)
+#define LCD_CMD_PAL (1 << 28)
+#define LCD_CMD_LEN_BIT 0
+#define LCD_CMD_LEN_MASK (0xffffff << LCD_CMD_LEN_BIT)
+
+
+/*************************************************************************
+ * USB Device
+ *************************************************************************/
+#define USB_BASE UDC_BASE
+
+#define USB_REG_FADDR (USB_BASE + 0x00) /* Function Address 8-bit */
+#define USB_REG_POWER (USB_BASE + 0x01) /* Power Managemetn 8-bit */
+#define USB_REG_INTRIN (USB_BASE + 0x02) /* Interrupt IN 16-bit */
+#define USB_REG_INTROUT (USB_BASE + 0x04) /* Interrupt OUT 16-bit */
+#define USB_REG_INTRINE (USB_BASE + 0x06) /* Intr IN enable 16-bit */
+#define USB_REG_INTROUTE (USB_BASE + 0x08) /* Intr OUT enable 16-bit */
+#define USB_REG_INTRUSB (USB_BASE + 0x0a) /* Interrupt USB 8-bit */
+#define USB_REG_INTRUSBE (USB_BASE + 0x0b) /* Interrupt USB Enable 8-bit */
+#define USB_REG_FRAME (USB_BASE + 0x0c) /* Frame number 16-bit */
+#define USB_REG_INDEX (USB_BASE + 0x0e) /* Index register 8-bit */
+#define USB_REG_TESTMODE (USB_BASE + 0x0f) /* USB test mode 8-bit */
+
+#define USB_REG_CSR0 (USB_BASE + 0x12) /* EP0 CSR 8-bit */
+#define USB_REG_INMAXP (USB_BASE + 0x10) /* EP1-2 IN Max Pkt Size 16-bit */
+#define USB_REG_INCSR (USB_BASE + 0x12) /* EP1-2 IN CSR LSB 8/16bit */
+#define USB_REG_INCSRH (USB_BASE + 0x13) /* EP1-2 IN CSR MSB 8-bit */
+#define USB_REG_OUTMAXP (USB_BASE + 0x14) /* EP1 OUT Max Pkt Size 16-bit */
+#define USB_REG_OUTCSR (USB_BASE + 0x16) /* EP1 OUT CSR LSB 8/16bit */
+#define USB_REG_OUTCSRH (USB_BASE + 0x17) /* EP1 OUT CSR MSB 8-bit */
+#define USB_REG_OUTCOUNT (USB_BASE + 0x18) /* bytes in EP0/1 OUT FIFO 16-bit */
+
+#define USB_FIFO_EP0 (USB_BASE + 0x20)
+#define USB_FIFO_EP1 (USB_BASE + 0x24)
+#define USB_FIFO_EP2 (USB_BASE + 0x28)
+
+#define USB_REG_EPINFO (USB_BASE + 0x78) /* Endpoint information */
+#define USB_REG_RAMINFO (USB_BASE + 0x79) /* RAM information */
+
+#define USB_REG_INTR (USB_BASE + 0x200) /* DMA pending interrupts */
+#define USB_REG_CNTL1 (USB_BASE + 0x204) /* DMA channel 1 control */
+#define USB_REG_ADDR1 (USB_BASE + 0x208) /* DMA channel 1 AHB memory addr */
+#define USB_REG_COUNT1 (USB_BASE + 0x20c) /* DMA channel 1 byte count */
+#define USB_REG_CNTL2 (USB_BASE + 0x214) /* DMA channel 2 control */
+#define USB_REG_ADDR2 (USB_BASE + 0x218) /* DMA channel 2 AHB memory addr */
+#define USB_REG_COUNT2 (USB_BASE + 0x21c) /* DMA channel 2 byte count */
+
+
+/* Power register bit masks */
+#define USB_POWER_SUSPENDM 0x01
+#define USB_POWER_RESUME 0x04
+#define USB_POWER_HSMODE 0x10
+#define USB_POWER_HSENAB 0x20
+#define USB_POWER_SOFTCONN 0x40
+
+/* Interrupt register bit masks */
+#define USB_INTR_SUSPEND 0x01
+#define USB_INTR_RESUME 0x02
+#define USB_INTR_RESET 0x04
+
+#define USB_INTR_EP0 0x0001
+#define USB_INTR_INEP1 0x0002
+#define USB_INTR_INEP2 0x0004
+#define USB_INTR_OUTEP1 0x0002
+
+/* CSR0 bit masks */
+#define USB_CSR0_OUTPKTRDY 0x01
+#define USB_CSR0_INPKTRDY 0x02
+#define USB_CSR0_SENTSTALL 0x04
+#define USB_CSR0_DATAEND 0x08
+#define USB_CSR0_SETUPEND 0x10
+#define USB_CSR0_SENDSTALL 0x20
+#define USB_CSR0_SVDOUTPKTRDY 0x40
+#define USB_CSR0_SVDSETUPEND 0x80
+
+/* Endpoint CSR register bits */
+#define USB_INCSRH_AUTOSET 0x80
+#define USB_INCSRH_ISO 0x40
+#define USB_INCSRH_MODE 0x20
+#define USB_INCSRH_DMAREQENAB 0x10
+#define USB_INCSRH_DMAREQMODE 0x04
+#define USB_INCSR_CDT 0x40
+#define USB_INCSR_SENTSTALL 0x20
+#define USB_INCSR_SENDSTALL 0x10
+#define USB_INCSR_FF 0x08
+#define USB_INCSR_UNDERRUN 0x04
+#define USB_INCSR_FFNOTEMPT 0x02
+#define USB_INCSR_INPKTRDY 0x01
+#define USB_OUTCSRH_AUTOCLR 0x80
+#define USB_OUTCSRH_ISO 0x40
+#define USB_OUTCSRH_DMAREQENAB 0x20
+#define USB_OUTCSRH_DNYT 0x10
+#define USB_OUTCSRH_DMAREQMODE 0x08
+#define USB_OUTCSR_CDT 0x80
+#define USB_OUTCSR_SENTSTALL 0x40
+#define USB_OUTCSR_SENDSTALL 0x20
+#define USB_OUTCSR_FF 0x10
+#define USB_OUTCSR_DATAERR 0x08
+#define USB_OUTCSR_OVERRUN 0x04
+#define USB_OUTCSR_FFFULL 0x02
+#define USB_OUTCSR_OUTPKTRDY 0x01
+
+/* Testmode register bits */
+#define USB_TEST_SE0NAK 0x01
+#define USB_TEST_J 0x02
+#define USB_TEST_K 0x04
+#define USB_TEST_PACKET 0x08
+
+/* DMA control bits */
+#define USB_CNTL_ENA 0x01
+#define USB_CNTL_DIR_IN 0x02
+#define USB_CNTL_MODE_1 0x04
+#define USB_CNTL_INTR_EN 0x08
+#define USB_CNTL_EP(n) ((n) << 4)
+#define USB_CNTL_BURST_0 (0 << 9)
+#define USB_CNTL_BURST_4 (1 << 9)
+#define USB_CNTL_BURST_8 (2 << 9)
+#define USB_CNTL_BURST_16 (3 << 9)
+
+#endif /* __JZ4740_REGS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/serial.h b/arch/mips/include/asm/mach-jz4740/serial.h
new file mode 100644
index 00000000000..c4819b98255
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/serial.h
@@ -0,0 +1,30 @@
+/*
+ * linux/include/asm-mips/mach-jz4740/serial.h
+ *
+ * Ingenic's JZ4740 common include.
+ *
+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Author: <yliu@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_BOARD_SERIAL_H__
+#define __ASM_BOARD_SERIAL_H__
+
+#ifndef CONFIG_SERIAL_MANY_PORTS
+#undef RS_TABLE_SIZE
+#define RS_TABLE_SIZE 1
+#endif
+
+#define JZ_BASE_BAUD (12000000/16)
+
+#define JZ_SERIAL_PORT_DEFNS \
+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \
+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \
+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM },
+
+#endif /* __ASM_BORAD_SERIAL_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/war.h b/arch/mips/include/asm/mach-jz4740/war.h
new file mode 100644
index 00000000000..3a5bc17e28f
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4740/war.h
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H
+#define __ASM_MIPS_MACH_JZ4740_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR 0
+#define R4600_V1_HIT_CACHEOP_WAR 0
+#define R4600_V2_HIT_CACHEOP_WAR 0
+#define R5432_CP0_INTERRUPT_WAR 0
+#define BCM1250_M3_WAR 0
+#define SIBYTE_1956_WAR 0
+#define MIPS4K_ICACHE_REFILL_WAR 0
+#define MIPS_CACHE_SYNC_WAR 0
+#define TX49XX_ICACHE_INDEX_INV_WAR 0
+#define RM9000_CDEX_SMP_WAR 0
+#define ICACHE_REFILLS_WORKAROUND_WAR 0
+#define R10000_LLSC_WAR 0
+#define MIPS34K_MISSED_ITLB_WAR 0
+
+#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */
diff --git a/arch/mips/include/asm/mach-jz4750/board-apus.h b/arch/mips/include/asm/mach-jz4750/board-apus.h
new file mode 100644
index 00000000000..12e45e1ded3
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750/board-apus.h
@@ -0,0 +1,209 @@
+/*
+ * linux/include/asm-mips/mach-jz4750/board-apus.h
+ *
+ * JZ4750-based APUS board ver 1.x definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750_APUS_H__
+#define __ASM_JZ4750_APUS_H__
+
+/*======================================================================
+ * Frequencies of on-board oscillators
+ */
+#define JZ_EXTAL 24000000 /* Main extal freq: 24 MHz */
+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
+
+/*======================================================================
+ * GPIO
+ */
+#define GPIO_DISP_OFF_N (32*4+25) /* GPE25 */
+#define GPIO_SD0_VCC_EN_N (32*2+10) /* GPC10 */
+#define GPIO_SD0_CD_N (32*2+11) /* GPC11 */
+#define GPIO_SD0_WP (32*2+12) /* GPC12 */
+#define GPIO_SD1_VCC_EN_N (32*2+13) /* GPC13 */
+#define GPIO_SD1_CD_N (32*2+14) /* GPC14 */
+#define GPIO_USB_DETE (32*2+15) /* GPC15 */
+#define GPIO_DC_DETE_N (32*2+8) /* GPC8 */
+#define GPIO_CHARG_STAT_N (32*2+9) /* GPC9 */
+#define GPIO_LCD_VCC_EN_N (32*3+30) /* GPC10 */
+#define GPIO_LCD_PWM (32*4+24) /* GPE24 */
+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
+
+
+/*======================================================================
+ * LCD backlight
+ */
+#define LCD_PWM_CHN 4 /* pwm channel */
+
+#define LCD_MAX_BACKLIGHT 100
+#define LCD_MIN_BACKLIGHT 1
+#define LCD_DEFAULT_BACKLIGHT 80
+
+/* LCD Backlight PWM Control - River. */
+#define HAVE_LCD_PWM_CONTROL 1
+
+#ifdef HAVE_LCD_PWM_CONTROL
+static inline void __lcd_pwm_set_backlight_level(int n)
+{
+ __tcu_stop_counter(LCD_PWM_CHN);
+
+ __tcu_set_pwm_output_shutdown_abrupt(LCD_PWM_CHN);
+ __tcu_disable_pwm_output(LCD_PWM_CHN);
+
+ __tcu_set_count(LCD_PWM_CHN, 0);
+ __tcu_set_full_data(LCD_PWM_CHN, LCD_MAX_BACKLIGHT + 1);
+ __tcu_set_half_data(LCD_PWM_CHN, n);
+
+ __tcu_enable_pwm_output(LCD_PWM_CHN);
+ __tcu_start_counter(LCD_PWM_CHN);
+
+ return;
+}
+
+static inline void __lcd_pwm_start(void)
+{
+ __gpio_as_pwm(4);
+
+ __tcu_stop_counter(LCD_PWM_CHN);
+
+ __tcu_select_extalclk(LCD_PWM_CHN);
+ __tcu_select_clk_div4(LCD_PWM_CHN);
+ __tcu_init_pwm_output_high(LCD_PWM_CHN);
+
+ __lcd_pwm_set_backlight_level(LCD_DEFAULT_BACKLIGHT);
+
+ return;
+}
+
+static inline void __lcd_pwm_stop(void)
+{
+ __tcu_stop_counter(LCD_PWM_CHN);
+
+ __tcu_set_pwm_output_shutdown_abrupt(LCD_PWM_CHN);
+ __tcu_disable_pwm_output(LCD_PWM_CHN);
+
+ return;
+}
+
+#define __lcd_set_backlight_level(n) __lcd_pwm_set_backlight_level(n)
+
+#else /* Old GPIO Control */
+/* 100 level: 0,1,...,100 */
+#define __lcd_set_backlight_level(n) \
+do { \
+ __gpio_as_output(GPIO_LCD_PWM); \
+ __gpio_set_pin(GPIO_LCD_PWM); \
+} while (0)
+#endif
+
+#define __lcd_close_backlight() \
+do { \
+ __gpio_as_output(GPIO_LCD_PWM); \
+ __gpio_clear_pin(GPIO_LCD_PWM); \
+} while (0)
+
+//20091116
+#define CFG_PBAT_DIV 4
+/*====================================================================
+ * GPIO KEYS and ADKEYS
+ */
+#define GPIO_HOME (32*5+22) // SW3-GPF22
+#define GPIO_MENU (32*5+20) // SW5-GPF20
+#define GPIO_CALL (32*5+23) // SW2-GPF23
+#define GPIO_ENDCALL (32*2+31) // SW6-boot_sel1-GPC31
+#define GPIO_BACK (32*5+21) // SW4-GPF21
+#define GPIO_SW7 (32*2+30) // SW7-boot_sel0-GPC30
+#define GPIO_ADKEY_INT (32+30) // GPB30
+/*====================================================================
+ * ADKEYS LEVEL
+ */
+
+#define DPAD_LEFT_LEVEL 225 //0.18105V, 225=0.18105/3.3*4096
+#define DPAD_DOWN_LEVEL 535 //0.4314V
+#define DPAD_UP_LEVEL 887 //0.7143V
+#define DPAD_CENTER_LEVEL 1422 //1.1456V
+#define DPAD_RIGHT_LEVEL 2333 //1.88V
+/*
+ * The key interrupt pin is low voltage or fall edge acitve
+ */
+#define ACTIVE_LOW_HOME 1
+#define ACTIVE_LOW_MENU 1
+#define ACTIVE_LOW_BACK 1
+#define ACTIVE_LOW_CALL 1
+#define ACTIVE_LOW_ENDCALL 0
+#define ACTIVE_LOW_SW10 1
+#define ACTIVE_LOW_ADKEY 0
+#define ACTIVE_LOW_MSC0_CD 1 /* work when GPIO_SD1_CD_N is low */
+#define ACTIVE_LOW_MSC1_CD 0 /* work when GPIO_SD1_CD_N is high */
+#define ACTIVE_WAKE_UP 1
+
+
+/*======================================================================
+ * MMC/SD
+ */
+
+#define MSC0_WP_PIN GPIO_SD0_WP
+#define MSC0_HOTPLUG_PIN GPIO_SD0_CD_N
+#define MSC0_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD0_CD_N)
+
+#define MSC1_WP_PIN GPIO_SD1_WP
+#define MSC1_HOTPLUG_PIN GPIO_SD1_CD_N
+#define MSC1_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD1_CD_N)
+
+#define __msc0_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD0_VCC_EN_N); \
+ __gpio_as_input(GPIO_SD0_CD_N); \
+} while (0)
+
+#define __msc0_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD0_VCC_EN_N); \
+} while (0)
+
+#define __msc0_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD0_VCC_EN_N); \
+} while (0)
+
+#define __msc0_card_detected(s) \
+({ \
+ int detected = 1; \
+ if (__gpio_get_pin(GPIO_SD0_CD_N)) \
+ detected = 0; \
+ detected; \
+})
+
+#define __msc1_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD1_VCC_EN_N); \
+ __gpio_as_input(GPIO_SD1_CD_N); \
+} while (0)
+
+#define __msc1_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD1_VCC_EN_N); \
+} while (0)
+
+#define __msc1_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD1_VCC_EN_N); \
+} while (0)
+
+#define __msc1_card_detected(s) \
+({ \
+ int detected = 0; \
+ if (__gpio_get_pin(GPIO_SD1_CD_N)) \
+ detected = 1; \
+ detected; \
+})
+
+#endif /* __ASM_JZ4750_APUS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750/board-fuwa.h b/arch/mips/include/asm/mach-jz4750/board-fuwa.h
new file mode 100644
index 00000000000..8b6a1992c9e
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750/board-fuwa.h
@@ -0,0 +1,93 @@
+/*
+ * linux/include/asm-mips/mach-jz4750/board-fuwa.h
+ *
+ * JZ4750-based FUWA board ver 1.x definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750_FUWA_H__
+#define __ASM_JZ4750_FUWA_H__
+
+#define CONFIG_FPGA /* fuwa is an FPGA board */
+
+/*======================================================================
+ * Frequencies of on-board oscillators
+ */
+#define JZ_EXTAL 48000000 /* Main extal freq: 12 MHz */
+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
+
+
+/*======================================================================
+ * GPIO
+ */
+#define GPIO_SD_VCC_EN_N 113 /* GPD17 */
+#define GPIO_SD_CD_N 110 /* GPD14 */
+#define GPIO_SD_WP 112 /* GPD16 */
+#define GPIO_USB_DETE 102 /* GPD6 */
+#define GPIO_DC_DETE_N 103 /* GPD7 */
+#define GPIO_CHARG_STAT_N 111 /* GPD15 */
+#define GPIO_DISP_OFF_N 121 /* GPD25, LCD_REV */
+#define GPIO_LED_EN 124 /* GPD28 */
+
+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
+
+/*======================================================================
+ * LCD backlight
+ */
+#define GPIO_LCD_PWM (32*4+20) /* GPE20 */
+
+#define LCD_PWM_CHN 0 /* pwm channel */
+#define LCD_PWM_FULL 101
+/* 100 level: 0,1,...,100 */
+#define __lcd_set_backlight_level(n) \
+do { \
+ __gpio_as_output(GPIO_LCD_PWM); \
+ __gpio_set_pin(GPIO_LCD_PWM); \
+} while (0)
+
+#define __lcd_close_backlight() \
+do { \
+ __gpio_as_output(GPIO_LCD_PWM); \
+ __gpio_clear_pin(GPIO_LCD_PWM); \
+} while (0)
+
+/*======================================================================
+ * MMC/SD
+ */
+
+#define MSC_WP_PIN GPIO_SD_WP
+#define MSC_HOTPLUG_PIN GPIO_SD_CD_N
+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N)
+
+#define __msc_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD_VCC_EN_N); \
+ __gpio_as_input(GPIO_SD_CD_N); \
+} while (0)
+
+#define __msc_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \
+} while (0)
+
+#define __msc_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD_VCC_EN_N); \
+} while (0)
+
+#define __msc_card_detected(s) \
+({ \
+ int detected = 1; \
+ if (__gpio_get_pin(GPIO_SD_CD_N)) \
+ detected = 0; \
+ detected; \
+})
+
+#endif /* __ASM_JZ4750_FUWA_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750/clock.h b/arch/mips/include/asm/mach-jz4750/clock.h
new file mode 100644
index 00000000000..d3444f9e93f
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750/clock.h
@@ -0,0 +1,204 @@
+/*
+ * linux/include/asm-mips/mach-jz4750/clock.h
+ *
+ * JZ4750 clocks definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750_CLOCK_H__
+#define __ASM_JZ4750_CLOCK_H__
+
+#ifndef JZ_EXTAL
+#define JZ_EXTAL 12000000 /* 12 MHz */
+#endif
+#ifndef JZ_EXTAL2
+#define JZ_EXTAL2 32768 /* 32.768 KHz */
+#endif
+
+/*
+ * JZ4750 clocks structure
+ */
+typedef struct {
+ unsigned int cclk; /* CPU clock */
+ unsigned int hclk; /* System bus clock */
+ unsigned int pclk; /* Peripheral bus clock */
+ unsigned int mclk; /* Flash/SRAM/SDRAM clock */
+ unsigned int lcdclk; /* LCDC module clock */
+ unsigned int pixclk; /* LCD pixel clock */
+ unsigned int i2sclk; /* AIC module clock */
+ unsigned int usbclk; /* USB module clock */
+ unsigned int mscclk; /* MSC module clock */
+ unsigned int extalclk; /* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */
+ unsigned int rtcclk; /* RTC clock for CPM,INTC,RTC,TCU,WDT */
+} jz_clocks_t;
+
+extern jz_clocks_t jz_clocks;
+
+
+/* PLL output frequency */
+static __inline__ unsigned int __cpm_get_pllout(void)
+{
+ unsigned long m, n, no, pllout;
+ unsigned long cppcr = REG_CPM_CPPCR;
+ unsigned long od[4] = {1, 2, 2, 4};
+ if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) {
+ m = __cpm_get_pllm() + 2;
+ n = __cpm_get_plln() + 2;
+ no = od[__cpm_get_pllod()];
+ pllout = ((JZ_EXTAL) / (n * no)) * m;
+ } else
+ pllout = JZ_EXTAL;
+ return pllout;
+}
+
+/* PLL output frequency for MSC/I2S/LCD/USB */
+static __inline__ unsigned int __cpm_get_pllout2(void)
+{
+ if (REG_CPM_CPCCR & CPM_CPCCR_PCS)
+ return __cpm_get_pllout();
+ else
+ return __cpm_get_pllout()/2;
+}
+
+/* CPU core clock */
+static __inline__ unsigned int __cpm_get_cclk(void)
+{
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_cdiv()];
+}
+
+/* AHB system bus clock */
+static __inline__ unsigned int __cpm_get_hclk(void)
+{
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_hdiv()];
+}
+
+/* Memory bus clock */
+static __inline__ unsigned int __cpm_get_mclk(void)
+{
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_mdiv()];
+}
+
+/* APB peripheral bus clock */
+static __inline__ unsigned int __cpm_get_pclk(void)
+{
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_pdiv()];
+}
+
+/* LCDC module clock */
+static __inline__ unsigned int __cpm_get_lcdclk(void)
+{
+ return __cpm_get_pllout2() / (__cpm_get_ldiv() + 1);
+}
+
+/* LCD pixel clock */
+static __inline__ unsigned int __cpm_get_pixclk(void)
+{
+ return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1);
+}
+
+/* I2S clock */
+static __inline__ unsigned int __cpm_get_i2sclk(void)
+{
+ if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) {
+ return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1);
+ }
+ else {
+ return JZ_EXTAL;
+ }
+}
+
+/* USB clock */
+static __inline__ unsigned int __cpm_get_usbclk(void)
+{
+ if (REG_CPM_CPCCR & CPM_CPCCR_UCS) {
+ return __cpm_get_pllout2() / (__cpm_get_udiv() + 1);
+ }
+ else {
+ return JZ_EXTAL;
+ }
+}
+
+/*
+ * MSC clock
+ * @n: the index of MMC/SD controller
+ */
+static __inline__ unsigned int __cpm_get_mscclk(int n)
+{
+ return __cpm_get_pllout2() / (__cpm_get_mscdiv(n) + 1);
+}
+
+/* EXTAL clock */
+static __inline__ unsigned int __cpm_get_extalclk0(void)
+{
+ return JZ_EXTAL;
+}
+
+/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */
+static __inline__ unsigned int __cpm_get_extalclk(void)
+{
+#if defined(CONFIG_FPGA)
+ return JZ_EXTAL;
+#else
+ if (REG_CPM_CPCCR & CPM_CPCCR_ECS)
+ return __cpm_get_extalclk0()/2;
+ else
+ return __cpm_get_extalclk0();
+#endif
+}
+
+/* RTC clock for CPM,INTC,RTC,TCU,WDT */
+static __inline__ unsigned int __cpm_get_rtcclk(void)
+{
+ return JZ_EXTAL2;
+}
+
+/*
+ * Output 24MHz for SD and 16MHz for MMC.
+ * @n: the index of MMC/SD controller
+ */
+static inline void __cpm_select_msc_clk(int n, int sd)
+{
+ unsigned int pllout2 = __cpm_get_pllout2();
+ unsigned int div = 0;
+
+ if (sd) {
+ div = pllout2 / 24000000;
+ }
+ else {
+ div = pllout2 / 16000000;
+ }
+
+ REG_CPM_MSCCDR(n) = div - 1;
+ REG_CPM_CPCCR |= CPM_CPCCR_CE;
+}
+
+/*
+ * Output 48MHz for high speed card.
+ */
+static inline void __cpm_select_msc_clk_high(int n, int sd)
+{
+ unsigned int pllout2 = __cpm_get_pllout2();
+ unsigned int div = 0;
+
+ div = pllout2 / 48000000;
+
+ REG_CPM_MSCCDR(n) = div - 1;
+ REG_CPM_CPCCR |= CPM_CPCCR_CE;
+}
+
+#endif /* __ASM_JZ4750_CLOCK_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750/dma.h b/arch/mips/include/asm/mach-jz4750/dma.h
new file mode 100644
index 00000000000..fc1f2c8e92d
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750/dma.h
@@ -0,0 +1,307 @@
+/*
+ * linux/include/asm-mips/mach-jz4750/dma.h
+ *
+ * JZ4750 DMA definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750_DMA_H__
+#define __ASM_JZ4750_DMA_H__
+
+#include <linux/interrupt.h>
+#include <asm/io.h> /* need byte IO */
+#include <linux/spinlock.h> /* And spinlocks */
+#include <linux/delay.h>
+#include <asm/system.h>
+
+/*
+ * Descriptor structure for JZ4750 DMA engine
+ * Note: this structure must always be aligned to a 16-bytes boundary.
+ */
+
+/* old descriptor 4-word */
+typedef struct {
+ volatile u32 dcmd; /* DCMD value for the current transfer */
+ volatile u32 dsadr; /* DSAR value for the current transfer */
+ volatile u32 dtadr; /* DTAR value for the current transfer */
+ volatile u32 ddadr; /* Points to the next descriptor + transfer count */
+} jz_dma_desc;
+
+/* new descriptor 8-word */
+typedef struct {
+ volatile u32 dcmd; /* DCMD value for the current transfer */
+ volatile u32 dsadr; /* DSAR value for the current transfer */
+ volatile u32 dtadr; /* DTAR value for the current transfer */
+ volatile u32 ddadr; /* Points to the next descriptor + transfer count */
+ volatile u32 dstrd; /* DMA source and target stride address */
+ volatile u32 dreqt; /* DMA request type for current transfer */
+ volatile u32 reserved0; /* Reserved */
+ volatile u32 reserved1; /* Reserved */
+} jz_dma_desc_8word;
+
+/* DMA Device ID's follow */
+enum {
+ DMA_ID_EXT = 0, /* External request with DREQn */
+ DMA_ID_NAND, /* NAND DMA request */
+ DMA_ID_BCH_ENC, /* BCH Encoding DMA request */
+ DMA_ID_BCH_DEC, /* BCH Decoding DMA request */
+ DMA_ID_AUTO, /* Auto-request */
+// DMA_ID_TSSI_RX, /* TSSI receive fifo full request */
+ DMA_ID_UART3_TX, /* UART3 transmit-fifo-empty request */
+ DMA_ID_UART3_RX, /* UART3 receve-fifo-full request */
+ DMA_ID_UART2_TX, /* UART2 transmit-fifo-empty request */
+ DMA_ID_UART2_RX, /* UART2 receve-fifo-full request */
+ DMA_ID_UART1_TX, /* UART1 transmit-fifo-empty request */
+ DMA_ID_UART1_RX, /* UART1 receve-fifo-full request */
+ DMA_ID_UART0_TX, /* UART0 transmit-fifo-empty request */
+ DMA_ID_UART0_RX, /* UART0 receve-fifo-full request */
+ DMA_ID_SSI0_TX, /* SSI0 transmit-fifo-full request */
+ DMA_ID_SSI0_RX, /* SSI0 receive-fifo-empty request */
+ DMA_ID_AIC_TX, /* AIC transmit-fifo-full request */
+ DMA_ID_AIC_RX, /* AIC receive-fifo-empty request */
+ DMA_ID_MSC0_TX, /* MSC0 transmit-fifo-full request */
+ DMA_ID_MSC0_RX, /* MSC0 receive-fifo-empty request */
+ DMA_ID_TCU_OVERFLOW, /* TCU channel n overflow interrupt */
+ DMA_ID_SADC, /* SADC transfer request */
+ DMA_ID_MSC1_TX, /* MSC1 transmit-fifo-full request */
+ DMA_ID_MSC1_RX, /* MSC1 receive-fifo-empty request */
+ DMA_ID_SSI1_TX, /* SSI1 transmit-fifo-full request */
+ DMA_ID_SSI1_RX, /* SSI1 receive-fifo-empty request */
+ DMA_ID_PCM_TX, /* PM transmit-fifo-full request */
+ DMA_ID_PCM_RX, /* PM receive-fifo-empty request */
+ DMA_ID_RAW_SET,
+ DMA_ID_MAX
+};
+
+/* DMA modes, simulated by sw */
+#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */
+#define DMA_AUTOINIT 0x2
+#define DMA_MODE_MASK 0x3
+
+struct jz_dma_chan {
+ int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */
+ unsigned int io; /* DMA channel number */
+ const char *dev_str; /* string describes the DMA channel */
+ int irq; /* DMA irq number */
+ void *irq_dev; /* DMA private device structure */
+ unsigned int fifo_addr; /* physical fifo address of the requested device */
+ unsigned int cntl; /* DMA controll */
+ unsigned int mode; /* DMA configuration */
+ unsigned int source; /* DMA request source */
+};
+
+extern struct jz_dma_chan jz_dma_table[];
+
+
+#define DMA_8BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_8BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_32_32BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
+#define DMA_AIC_32_16BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_32_16BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BYTE_TX_CMD_UC \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+extern int jz_request_dma(int dev_id,
+ const char *dev_str,
+ irqreturn_t (*irqhandler)(int, void *),
+ unsigned long irqflags,
+ void *irq_dev_id);
+extern void jz_free_dma(unsigned int dmanr);
+
+extern int jz_dma_read_proc(char *buf, char **start, off_t fpos,
+ int length, int *eof, void *data);
+extern void dump_jz_dma_channel(unsigned int dmanr);
+
+extern void enable_dma(unsigned int dmanr);
+extern void disable_dma(unsigned int dmanr);
+extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr);
+extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt);
+extern void set_dma_mode(unsigned int dmanr, unsigned int mode);
+extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
+extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
+extern void jz_set_dma_src_width(int dmanr, int nbit);
+extern void jz_set_dma_dest_width(int dmanr, int nbit);
+extern void jz_set_dma_block_size(int dmanr, int nbyte);
+extern unsigned int get_dma_residue(unsigned int dmanr);
+
+extern spinlock_t dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dma_spin_lock, flags);
+ return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+ spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ */
+#define clear_dma_ff(channel)
+
+static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr)
+{
+ if (dmanr > MAX_DMA_NUM
+ || jz_dma_table[dmanr].dev_id < 0)
+ return NULL;
+ return &jz_dma_table[dmanr];
+}
+
+static __inline__ int dma_halted(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 1;
+ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0;
+}
+
+static __inline__ unsigned int get_dma_mode(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+ return chan->mode;
+}
+
+static __inline__ void clear_dma_done(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+}
+
+static __inline__ void clear_dma_halt(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT);
+ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT);
+}
+
+static __inline__ void clear_dma_flag(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR);
+}
+
+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
+{
+}
+
+static __inline__ unsigned int get_dma_done_status(unsigned int dmanr)
+{
+ unsigned long dccsr;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+ dccsr = REG_DMAC_DCCSR(chan->io);
+ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+}
+
+static __inline__ int get_dma_done_irq(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return -1;
+ return chan->irq;
+}
+
+#endif /* __ASM_JZ4750_DMA_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750/i2c.h b/arch/mips/include/asm/mach-jz4750/i2c.h
new file mode 100644
index 00000000000..c80297eb290
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750/i2c.h
@@ -0,0 +1,70 @@
+/*
+ * linux/arch/mips/jz4750/i2c.c
+ *
+ * JZ4750 I2C Simple Driver.
+ *
+ * Copyright (c) 2005-2010 Ingenic Semiconductor Inc.
+ * Author: River <zwang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __I_I2C_H__
+#define __I_I2C_H__
+
+enum {
+ I_I2C_IO_DIR_READ = 0,
+ I_I2C_IO_DIR_WRITE,
+};
+
+enum {
+ I_I2C_CAP_SEQ_READ = (1 << 0),
+ I_I2C_CAP_SEQ_WRITE = (1 << 1),
+ I_I2C_CAP_16BIT_OFFSET_MSB = (1 << 2),
+ I_I2C_CAP_16BIT_OFFSET_LSB = (1 << 3),
+};
+
+enum {
+ I_I2C_FLAG_STOP_BEFORE_RESTART = (1 << 0),
+};
+
+struct i_i2c_timing {
+ int id;
+
+ unsigned long clk;
+ unsigned long timeout;
+
+ unsigned long t_wr;
+};
+
+struct i_i2c_dev {
+ int id;
+
+ char *name;
+
+ unsigned int address;
+
+ spinlock_t lock;
+
+ unsigned long cap;
+ unsigned long flags;
+
+ unsigned long size;
+
+ unsigned int read_size;
+ unsigned int write_size;
+
+ int timing_id;
+ struct i_i2c_timing *timing;
+};
+
+int i_i2c_read_dev(struct i_i2c_dev *dev, off_t off, void *buf, size_t count);
+
+int i_i2c_write_dev(struct i_i2c_dev *dev, off_t off, void *buf, size_t count);
+
+int i_i2c_init_dev(struct i_i2c_dev *dev);
+
+#endif
diff --git a/arch/mips/include/asm/mach-jz4750/jz4750.h b/arch/mips/include/asm/mach-jz4750/jz4750.h
new file mode 100644
index 00000000000..4cd6698e6d3
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750/jz4750.h
@@ -0,0 +1,47 @@
+/*
+ * linux/include/asm-mips/mach-jz4750/jz4750.h
+ *
+ * JZ4750 common definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750_H__
+#define __ASM_JZ4750_H__
+
+#include <asm/mach-jz4750/regs.h>
+#include <asm/mach-jz4750/ops.h>
+#include <asm/mach-jz4750/dma.h>
+#include <asm/mach-jz4750/misc.h>
+
+/*------------------------------------------------------------------
+ * Platform definitions
+ */
+#define JZ_SOC_NAME "JZ4750"
+
+#ifdef CONFIG_JZ4750_FUWA
+#include <asm/mach-jz4750/board-fuwa.h>
+#endif
+
+#ifdef CONFIG_JZ4750_APUS
+#include <asm/mach-jz4750/board-apus.h>
+#endif
+
+/* Add other platform definition here ... */
+
+
+/*------------------------------------------------------------------
+ * Follows are related to platform definitions
+ */
+
+#include <asm/mach-jz4750/clock.h>
+#include <asm/mach-jz4750/serial.h>
+#include <asm/mach-jz4750/i2c.h>
+
+#endif /* __ASM_JZ4750_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750/misc.h b/arch/mips/include/asm/mach-jz4750/misc.h
new file mode 100644
index 00000000000..f6c75c9cf6c
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750/misc.h
@@ -0,0 +1,44 @@
+/*
+ * linux/include/asm-mips/mach-jz4750/misc.h
+ *
+ * Ingenic's JZ4750 common include.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750_MISC_H__
+#define __ASM_JZ4750_MISC_H__
+
+/*==========================================================
+ * I2C
+ *===========================================================*/
+
+#define I2C_EEPROM_DEV 0xA /* b'1010 */
+#define I2C_RTC_DEV 0xD /* b'1101 */
+#define DIMM0_SPD_ADDR 0
+#define DIMM1_SPD_ADDR 1
+#define DIMM2_SPD_ADDR 2
+#define DIMM3_SPD_ADDR 3
+#define JZ_HCI_ADDR 7
+
+#define DIMM_SPD_LEN 128
+#define JZ_HCI_LEN 512 /* 4K bits E2PROM */
+#define I2C_RTC_LEN 16
+#define HCI_MAC_OFFSET 64
+
+extern void i2c_open(void);
+extern void i2c_close(void);
+extern void i2c_setclk(unsigned int i2cclk);
+
+extern int i2c_read(unsigned char device, unsigned char *buf,
+ unsigned char address, int count);
+extern int i2c_write(unsigned char device, unsigned char *buf,
+ unsigned char address, int count);
+
+#endif /* __ASM_JZ4750_MISC_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750/ops.h b/arch/mips/include/asm/mach-jz4750/ops.h
new file mode 100644
index 00000000000..a7ebb97cd5a
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750/ops.h
@@ -0,0 +1,3570 @@
+/*
+ * linux/include/asm-mips/mach-jz4750/ops.h
+ *
+ * JZ4750 register definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#ifndef __JZ4750_OPS_H__
+#define __JZ4750_OPS_H__
+
+/*
+ * Definition of Module Operations
+ */
+
+/***************************************************************************
+ * EMC
+ ***************************************************************************/
+#define is_share_mode() ((REG_EMC_BCR & EMC_BCR_BSR_MASK) == EMC_BCR_BSR_SHARE)
+#define is_normal_order() (!(REG_EMC_BCR & EMC_BCR_PK_SEL))
+
+/***************************************************************************
+ * GPIO
+ ***************************************************************************/
+
+//------------------------------------------------------
+// GPIO Pins Description
+//
+// PORT 0:
+//
+// PIN/BIT N FUNC0 FUNC1 NOTE
+// 0 D0 -
+// 1 D1 -
+// 2 D2 -
+// 3 D3 -
+// 4 D4 -
+// 5 D5 -
+// 6 D6 -
+// 7 D7 -
+// 8 D8 -
+// 9 D9 -
+// 10 D10 -
+// 11 D11 -
+// 12 D12 -
+// 13 D13 -
+// 14 D14 -
+// 15 D15 -
+// 16 D16 -
+// 17 D17 -
+// 18 D18 -
+// 19 D19 -
+// 20 D20 -
+// 21 D21 -
+// 22 D22 -
+// 23 D23 -
+// 24 D24 -
+// 25 D25 -
+// 26 D26 -
+// 27 D27 -
+// 28 D28 -
+// 29 D29 -
+// 30 D30 -
+// 31 D31 -
+//
+//------------------------------------------------------
+// PORT 1:
+//
+// PIN/BIT N FUNC0 FUNC1 NOTE
+// 0 A0 -
+// 1 A1 -
+// 2 A2 -
+// 3 A3 -
+// 4 A4 -
+// 5 A5 -
+// 6 A6 -
+// 7 A7 -
+// 8 A8 -
+// 9 A9 -
+// 10 A10 -
+// 11 A11 -
+// 12 A12 -
+// 13 A13 -
+// 14 A14 -
+// 15 A15/CLE SA3
+// 16 DCS0# -
+// 17 RAS# -
+// 18 CAS# -
+// 19 RDWE#/BUFD# -
+// 20 WE0# -
+// 21 WE1# -
+// 22 WE2# -
+// 23 WE3# -
+// 24 CKO - Note1
+// 25 CKE -
+// 26 SSI0_CLK -
+// 27 SSI0_DT -
+// 28 SSI0_DR -
+// 29 SSI0_CE0# -
+// 30 SSI0_CE1#_GPC -
+// 31 SSI0_CE2# -
+//
+// Note1: BIT24: it is CKO when chip is reset
+//
+//------------------------------------------------------
+// PORT 2:
+//
+// PIN/BIT N FUNC0 FUNC1 NOTE
+// 0 SD0 A20
+// 1 SD1 A21
+// 2 SD2 A22
+// 3 SD3 A23
+// 4 SD4 A24
+// 5 SD5 A25
+// 6 SD6 -
+// 7 SD7 -
+// 8 SD8 TSDI0
+// 9 SD9 TSDI1
+// 10 SD10 TSDI2
+// 11 SD11 TSDI3
+// 12 SD12 TSDI4
+// 13 SD13 TSDI5
+// 14 SD14 TSDI6
+// 15 SD15 TSDI7
+// 16 A16/ALE SA4
+// 17 SA0 A17
+// 18 SA1 A18
+// 19 SA2 A19
+// 20 WAIT# - Note2
+// 21 CS1# -
+// 22 CS2# -
+// 23 CS3# -
+// 24 CS4# -
+// 25 RD# -
+// 26 WR# -
+// 27 FRB# - Note3
+// 28 FRE# -
+// 29 FWE# -
+// 30 BOOT_SEL0 - Note4
+// 31 BOOT_SEL1 - Note5
+//
+// Note2: BIT20: it is WAIT# pin when chip is reset
+//
+// Note3: BIT27: when NAND is used, it should connect to NANF FRB#.
+//
+// Note4: BIT30: it is BOOT_SEL0 when chip is reset, it can used as output GPIO.
+//
+// Note5: BIT31: it is BOOT_SEL1 when chip is reset, it can used as general GPIO.
+//
+//------------------------------------------------------
+// PORT 3:
+//
+// PIN/BIT N FUNC0 FUNC1 NOTE
+// 0 LCD_D0 -
+// 1 LCD_D1 -
+// 2 LCD_D2 -
+// 3 LCD_D3 -
+// 4 LCD_D4 -
+// 5 LCD_D5 -
+// 6 LCD_D6 -
+// 7 LCD_D7 -
+// 8 LCD_D8 -
+// 9 LCD_D9 -
+// 10 LCD_D10 -
+// 11 LCD_D11 -
+// 12 LCD_D12 -
+// 13 LCD_D13 -
+// 14 LCD_D14 -
+// 15 LCD_D15 -
+// 16 LCD_D16 -
+// 17 LCD_D17 -
+// 18 LCD_PCLK -
+// 19 LCD_HSYNC -
+// 20 LCD_VSYNC -
+// 21 LCD_DE -
+// 22 LCD_CLS -
+// 23 LCD_SPL -
+// 24 LCD_PS -
+// 25 LCD_REV -
+// 26 SSI1_CLK -
+// 27 SSI1_DT -
+// 28 SSI1_DR -
+// 29 SSI1_CE0# -
+// 30 SSI1_CE1# -
+// 31 - -
+//
+//------------------------------------------------------
+// PORT 4:
+//
+// PIN/BIT N FUNC0 FUNC1 NOTE
+// 0 CIM_D0 -
+// 1 CIM_D1 -
+// 2 CIM_D2 -
+// 3 CIM_D3 -
+// 4 CIM_D4 -
+// 5 CIM_D5 -
+// 6 CIM_D6 -
+// 7 CIM_D7 -
+// 8 CIM_MCLK -
+// 9 CIM_PCLK -
+// 10 CIM_VSYNC -
+// 11 CIM_HSYNC -
+// 12 I2C_SDA -
+// 13 I2C_SCK -
+// 14 - -
+// 15 - -
+// 16 UART1_RxD -
+// 17 UART1_TxD -
+// 18 UART1_CTS PCM_DIN
+// 19 UART1_RTS PCM_DOUT
+// 20 PWM0 PCM_CLK
+// 21 PWM1 PCM_SYN
+// 22 PWM2 SCLK_RSTN
+// 23 PWM3 BCLK
+// 24 PWM4 SYNC
+// 25 PWM5 OWI
+// 26 SDATO UART2_TxD
+// 27 SDATI UART2_RxD
+// 28 DCS1# -
+// 29 - -
+// 30 WKUP - Note6
+// 31 - - Note7
+//
+// Note6: BIT30: it is only used as input and interrupt, and with no pull-up and pull-down
+//
+// Note7: BIT31: it is used to select the function of UART or JTAG set by PESEL[31]
+// PESEL[31] = 0, select JTAG function
+// PESEL[31] = 1, select UART function
+//
+//------------------------------------------------------
+// PORT 5:
+//
+// PIN/BIT N FUNC0 FUNC1 NOTE
+// 0 MSC0_D0 -
+// 1 MSC0_D1 -
+// 2 MSC0_D2 DREQ
+// 3 MSC0_D3 DACK
+// 4 MSC0_D4 UART0_RxD
+// 5 MSC0_D5 UART0_TxD
+// 6 MSC0_D6 UART0_CTS
+// 7 MSC0_D7 UART0_RTS
+// 8 MSC0_CLK -
+// 9 MSC0_CMD -
+// 10 MSC1_D0 -
+// 11 MSC1_D1 -
+// 12 MSC1_D2 -
+// 13 MSC1_D3 -
+// 14 MSC1_CLK -
+// 15 MSC1_CMD -
+// 16 UART3_RxD -
+// 17 UART3_TxD -
+// 18 UART3_CTS -
+// 19 UART3_RTS -
+// 20 TSCLK -
+// 21 TSSTR -
+// 22 TSFRM -
+// 23 TSFAIL -
+// 24 - -
+// 25 - -
+// 26 - -
+// 27 - -
+// 28 - -
+// 29 - -
+// 30 - -
+// 31 - -
+//
+//////////////////////////////////////////////////////////
+
+/*
+ * p is the port number (0,1,2,3,4,5)
+ * o is the pin offset (0-31) inside the port
+ * n is the absolute number of a pin (0-191), regardless of the port
+ */
+
+//-------------------------------------------
+// Function Pins Mode
+
+#define __gpio_as_func0(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFUNS(p) = (1 << o); \
+ REG_GPIO_PXSELC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_func1(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFUNS(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+} while (0)
+
+/*
+ * D0 ~ D31, A0 ~ A14, DCS0#, RAS#, CAS#,
+ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE#
+ */
+#define __gpio_as_sdram_32bit() \
+do { \
+ REG_GPIO_PXFUNS(0) = 0xffffffff; \
+ REG_GPIO_PXSELC(0) = 0xffffffff; \
+ REG_GPIO_PXPES(0) = 0xffffffff; \
+ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \
+ REG_GPIO_PXSELC(1) = 0x03ff7fff; \
+ REG_GPIO_PXPES(1) = 0x03ff7fff; \
+} while (0)
+
+/*
+ * D0 ~ D15, A0 ~ A14, DCS0#, RAS#, CAS#,
+ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE#
+ */
+#define __gpio_as_sdram_16bit() \
+do { \
+ if (is_normal_order()) { \
+ /* 32/16-bit data normal order */ \
+ REG_GPIO_PXFUNS(0) = 0x0000ffff; \
+ REG_GPIO_PXSELC(0) = 0x0000ffff; \
+ REG_GPIO_PXPES(0) = 0x0000ffff; \
+ } else { \
+ /* 16-bit data special order */ \
+ REG_GPIO_PXFUNS(0) = 0x00ffff00; \
+ REG_GPIO_PXSELC(0) = 0x00ffff00; \
+ REG_GPIO_PXPES(0) = 0x00ffff00; \
+ } \
+ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \
+ REG_GPIO_PXSELC(1) = 0x03ff7fff; \
+ REG_GPIO_PXPES(1) = 0x03ff7fff; \
+} while (0)
+
+/*
+ * D0 ~ D7, CS1#, CLE, ALE, FRE#, FWE#, FRB#, RDWE#/BUFD#
+ * @n: chip select number(1 ~ 4)
+ */
+#define __gpio_as_nand_8bit(n) \
+do { \
+ if (!is_share_mode()) { \
+ /* unshare mode */ \
+ REG_GPIO_PXFUNS(2) = 0x000000ff; /* SD0~SD7 */ \
+ REG_GPIO_PXSELC(2) = 0x000000ff; \
+ REG_GPIO_PXPES(2) = 0x000000ff; \
+ REG_GPIO_PXFUNS(1) = 0x00008000; /* CLE(SA3) */ \
+ REG_GPIO_PXSELS(1) = 0x00008000; \
+ REG_GPIO_PXPES(1) = 0x00008000; \
+ REG_GPIO_PXFUNS(2) = 0x00010000; /* ALE(SA4) */ \
+ REG_GPIO_PXSELS(2) = 0x00010000; \
+ REG_GPIO_PXPES(2) = 0x00010000; \
+ } else { \
+ /* share mode */ \
+ if (is_normal_order()) { \
+ /* 32/16-bit data normal order */ \
+ REG_GPIO_PXFUNS(0) = 0x000000ff; /* D0~D7 */ \
+ REG_GPIO_PXSELC(0) = 0x000000ff; \
+ REG_GPIO_PXPES(0) = 0x000000ff; \
+ } else { \
+ /* 16-bit data special order */ \
+ REG_GPIO_PXFUNS(0) = 0x0000ff00; /* D0~D7 */ \
+ REG_GPIO_PXSELC(0) = 0x0000ff00; \
+ REG_GPIO_PXPES(0) = 0x0000ff00; \
+ } \
+ REG_GPIO_PXFUNS(1) = 0x00008000; /* CLE(A15) */ \
+ REG_GPIO_PXSELC(1) = 0x00008000; \
+ REG_GPIO_PXPES(1) = 0x00008000; \
+ REG_GPIO_PXFUNS(2) = 0x00010000; /* ALE(A16) */ \
+ REG_GPIO_PXSELC(2) = 0x00010000; \
+ REG_GPIO_PXPES(2) = 0x00010000; \
+ } \
+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \
+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \
+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \
+ \
+ REG_GPIO_PXFUNS(1) = 0x00080000; /* RDWE#/BUFD# */ \
+ REG_GPIO_PXSELC(1) = 0x00080000; \
+ REG_GPIO_PXPES(1) = 0x00080000; \
+ REG_GPIO_PXFUNS(2) = 0x30000000; /* FRE#, FWE# */ \
+ REG_GPIO_PXSELC(2) = 0x30000000; \
+ REG_GPIO_PXPES(2) = 0x30000000; \
+ REG_GPIO_PXFUNC(2) = 0x08000000; /* FRB#(input) */ \
+ REG_GPIO_PXSELC(2) = 0x08000000; \
+ REG_GPIO_PXDIRC(2) = 0x08000000; \
+ REG_GPIO_PXPES(2) = 0x08000000; \
+} while (0)
+
+
+/*
+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D7
+ * @n: chip select number(1 ~ 4)
+ */
+#define __gpio_as_nor_8bit(n) \
+do { \
+ if (is_normal_order()) { \
+ /* 32/16-bit data normal order */ \
+ REG_GPIO_PXFUNS(0) = 0x000000ff; \
+ REG_GPIO_PXSELC(0) = 0x000000ff; \
+ REG_GPIO_PXPES(0) = 0x000000ff; \
+ } else { \
+ /* 16-bit data special order */ \
+ REG_GPIO_PXFUNS(0) = 0x0000ff00; \
+ REG_GPIO_PXSELC(0) = 0x0000ff00; \
+ REG_GPIO_PXPES(0) = 0x0000ff00; \
+ } \
+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \
+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \
+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \
+ \
+ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \
+ REG_GPIO_PXSELC(1) = 0x0000ffff; \
+ REG_GPIO_PXPES(1) = 0x0000ffff; \
+ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \
+ REG_GPIO_PXSELC(2) = 0x06110007; \
+ REG_GPIO_PXPES(2) = 0x06110007; \
+ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \
+ REG_GPIO_PXSELS(2) = 0x000e0000; \
+ REG_GPIO_PXPES(2) = 0x000e0000; \
+} while (0)
+
+/*
+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D15
+ * @n: chip select number(1 ~ 4)
+ */
+#define __gpio_as_nor_16bit(n) \
+do { \
+ if (is_normal_order()) { \
+ /* 32/16-bit data normal order */ \
+ REG_GPIO_PXFUNS(0) = 0x0000ffff; \
+ REG_GPIO_PXSELC(0) = 0x0000ffff; \
+ REG_GPIO_PXPES(0) = 0x0000ffff; \
+ } else { \
+ /* 16-bit data special order */ \
+ REG_GPIO_PXFUNS(0) = 0x00ffff00; \
+ REG_GPIO_PXSELC(0) = 0x00ffff00; \
+ REG_GPIO_PXPES(0) = 0x00ffff00; \
+ } \
+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \
+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \
+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \
+ \
+ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \
+ REG_GPIO_PXSELC(1) = 0x0000ffff; \
+ REG_GPIO_PXPES(1) = 0x0000ffff; \
+ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \
+ REG_GPIO_PXSELC(2) = 0x06110007; \
+ REG_GPIO_PXPES(2) = 0x06110007; \
+ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \
+ REG_GPIO_PXSELS(2) = 0x000e0000; \
+ REG_GPIO_PXPES(2) = 0x000e0000; \
+} while (0)
+
+/*
+ * UART0_TxD, UART0_RxD
+ */
+#define __gpio_as_uart0() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x00000030; \
+ REG_GPIO_PXSELS(5) = 0x00000030; \
+ REG_GPIO_PXPES(5) = 0x00000030; \
+} while (0)
+
+/*
+ * UART0_TxD, UART0_RxD, UART0_CTS, UART0_RTS
+ */
+#define __gpio_as_uart0_ctsrts() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x000000f0; \
+ REG_GPIO_PXSELS(5) = 0x000000f0; \
+ REG_GPIO_PXPES(5) = 0x000000f0; \
+} while (0)
+
+/*
+ * UART1_TxD, UART1_RxD
+ */
+#define __gpio_as_uart1() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00030000; \
+ REG_GPIO_PXSELC(4) = 0x00030000; \
+ REG_GPIO_PXPES(4) = 0x00030000; \
+} while (0)
+
+/*
+ * UART1_TxD, UART1_RxD, UART1_CTS, UART1_RTS
+ */
+#define __gpio_as_uart1_ctsrts() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x000f0000; \
+ REG_GPIO_PXSELC(4) = 0x000f0000; \
+ REG_GPIO_PXPES(4) = 0x000f0000; \
+} while (0)
+
+/*
+ * UART2_TxD, UART2_RxD
+ */
+#define __gpio_as_uart2() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x0c000000; \
+ REG_GPIO_PXSELS(4) = 0x0c000000; \
+ REG_GPIO_PXPES(4) = 0x0c000000; \
+} while (0)
+
+/*
+ * UART3_TxD, UART3_RxD
+ */
+#define __gpio_as_uart3() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x00030000; \
+ REG_GPIO_PXSELC(5) = 0x00030000; \
+ REG_GPIO_PXPES(5) = 0x00030000; \
+} while (0)
+
+/*
+ * UART3_TxD, UART3_RxD, UART3_CTS, UART3_RTS
+ */
+#define __gpio_as_uart3_ctsrts() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x000f0000; \
+ REG_GPIO_PXSELC(5) = 0x000f0000; \
+ REG_GPIO_PXPES(5) = 0x000f0000; \
+} while (0)
+
+/*
+ * TSCLK, TSSTR, TSFRM, TSFAIL, TSDI0~7
+ */
+#define __gpio_as_tssi() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x0000ff00; \
+ REG_GPIO_PXSELS(2) = 0x0000ff00; \
+ REG_GPIO_PXPES(2) = 0x0000ff00; \
+ REG_GPIO_PXFUNS(5) = 0x00f00000; \
+ REG_GPIO_PXSELC(5) = 0x00f00000; \
+ REG_GPIO_PXPES(5) = 0x00f00000; \
+} while (0)
+
+/*
+ * LCD_D0~LCD_D7, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_8bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x003c00ff; \
+ REG_GPIO_PXSELC(3) = 0x003c00ff; \
+ REG_GPIO_PXPES(3) = 0x003c00ff; \
+} while (0)
+
+/*
+ * LCD_D0~LCD_D15, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_16bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x003cffff; \
+ REG_GPIO_PXSELC(3) = 0x003cffff; \
+ REG_GPIO_PXPES(3) = 0x003cffff; \
+} while (0)
+
+/*
+ * LCD_D0~LCD_D17, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_18bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x003fffff; \
+ REG_GPIO_PXSELC(3) = 0x003fffff; \
+ REG_GPIO_PXPES(3) = 0x003fffff; \
+} while (0)
+
+/*
+ * LCD_D0~LCD_D17, LCD_D_R1, LCD_D_G0, LCD_D_G1, LCD_D_B1,
+ * LCD_D_R0, LCD_D_B0, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_24bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x003fffff; \
+ REG_GPIO_PXSELC(3) = 0x003fffff; \
+ REG_GPIO_PXPES(3) = 0x003fffff; \
+ REG_GPIO_PXFUNS(3) = 0x03c00000; \
+ REG_GPIO_PXSELS(3) = 0x03c00000; \
+ REG_GPIO_PXPES(3) = 0x03c00000; \
+ REG_GPIO_PXFUNS(5) = 0x000c0000; \
+ REG_GPIO_PXSELS(5) = 0x000c0000; \
+ REG_GPIO_PXPES(5) = 0x000c0000; \
+} while (0)
+
+/*
+ * SLCD_DAT0~7, SLCD_CLK, SLCD_RS, SLCD_CS
+ */
+#define __gpio_as_lcd_smart_pal_8bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x001c00ff; \
+ REG_GPIO_PXSELC(3) = 0x001c00ff; \
+ REG_GPIO_PXPES(3) = 0x001c00ff; \
+} while (0)
+
+/*
+ * SLCD_DAT0~15, SLCD_CLK, SLCD_RS, SLCD_CS
+ */
+#define __gpio_as_lcd_smart_pal_15bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x001cffff; \
+ REG_GPIO_PXSELC(3) = 0x001cffff; \
+ REG_GPIO_PXPES(3) = 0x001cffff; \
+} while (0)
+
+/*
+ * SLCD_DAT0~17, SLCD_CLK, SLCD_RS, SLCD_CS
+ */
+#define __gpio_as_lcd_smart_pal_17bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x001fffff; \
+ REG_GPIO_PXSELC(3) = 0x001fffff; \
+ REG_GPIO_PXPES(3) = 0x001fffff; \
+} while (0)
+
+/*
+ * SLCD_DAT15, SLCD_CLK, SLCD_RS, SLCD_CS
+ */
+#define __gpio_as_lcd_smart_serial() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x001c8000; \
+ REG_GPIO_PXSELC(3) = 0x001c8000; \
+ REG_GPIO_PXPES(3) = 0x001c8000; \
+} while (0)
+
+/*
+ * LCD_CLS, LCD_SPL, LCD_PS, LCD_REV
+ */
+#define __gpio_as_lcd_special() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x03C00000; \
+ REG_GPIO_PXSELC(3) = 0x03C00000; \
+ REG_GPIO_PXPES(3) = 0x03C00000; \
+} while (0)
+
+/*
+ * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC
+ */
+#define __gpio_as_cim() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00000fff; \
+ REG_GPIO_PXSELC(4) = 0x00000fff; \
+ REG_GPIO_PXPES(4) = 0x00000fff; \
+} while (0)
+
+/*
+ * SDATO, SDATI, BCLK, SYNC, SCLK_RSTN(gpio sepc) or
+ * SDATA_OUT, SDATA_IN, BIT_CLK, SYNC, SCLK_RESET(aic spec)
+ */
+#define __gpio_as_aic() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x0c000000; \
+ REG_GPIO_PXSELS(4) = 0x0c000000; \
+ REG_GPIO_PXPES(4) = 0x0c000000; \
+ REG_GPIO_PXFUNS(4) = 0x00e00000; \
+ REG_GPIO_PXSELC(4) = 0x00e00000; \
+ REG_GPIO_PXPES(4) = 0x00e00000; \
+} while (0)
+
+/*
+ * PCM_DIN, PCM_DOUT, PCM_CLK, PCM_SYN
+*/
+#define __gpio_as_pcm() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x003c0000; \
+ REG_GPIO_PXSELS(4) = 0x003c0000; \
+ REG_GPIO_PXPES(4) = 0x003c0000; \
+} while (0)
+
+/*
+ * OWI
+*/
+#define __gpio_as_owi() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x02000000; \
+ REG_GPIO_PXSELS(4) = 0x02000000; \
+ REG_GPIO_PXPES(4) = 0x02000000; \
+} while (0)
+
+/*
+ * MSC0_CMD, MSC0_CLK, MSC0_D0 ~ MSC0_D3
+ */
+#define __gpio_as_msc0_4bit() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x0000030f; \
+ REG_GPIO_PXSELC(5) = 0x0000030f; \
+ REG_GPIO_PXPES(5) = 0x0000030f; \
+} while (0)
+
+/*
+ * MSC0_CMD, MSC0_CLK, MSC0_D0 ~ MSC0_D7
+ */
+#define __gpio_as_msc0_8bit() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x000003ff; \
+ REG_GPIO_PXSELC(5) = 0x000003ff; \
+ REG_GPIO_PXPES(5) = 0x000003ff; \
+} while (0)
+
+/*
+ * MSC1_CMD, MSC1_CLK, MSC1_D0 ~ MSC1_D3
+ */
+#define __gpio_as_msc1_4bit() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x0000fc00; \
+ REG_GPIO_PXSELC(5) = 0x0000fc00; \
+ REG_GPIO_PXPES(5) = 0x0000fc00; \
+} while (0)
+
+#define __gpio_as_msc __gpio_as_msc0_8bit /* default as msc0 8bit */
+#define __gpio_as_msc0 __gpio_as_msc0_8bit /* msc0 default as 8bit */
+#define __gpio_as_msc1 __gpio_as_msc1_4bit /* msc1 only support 4bit */
+
+/*
+ * SSI0_CE0, SSI0_CE1#_GPC, SSI0_CE2, SSI0_CLK, SSI0_DT, SSI0_DR
+ */
+#define __gpio_as_ssi0() \
+do { \
+ REG_GPIO_PXFUNS(1) = 0xfc000000; \
+ REG_GPIO_PXSELC(1) = 0xfc000000; \
+ REG_GPIO_PXPES(1) = 0xfc000000; \
+} while (0)
+
+/*
+ * SSI1_CE0, SSI1_CE1, SSI1_CLK, SSI1_DT, SSI1_DR
+ */
+#define __gpio_as_ssi1() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x7c000000; \
+ REG_GPIO_PXSELC(3) = 0x7c000000; \
+ REG_GPIO_PXPES(3) = 0x7c000000; \
+} while (0)
+
+/* n = 0(SSI0), 1(SSI1) */
+#define __gpio_as_ssi(n) __gpio_as_ssi##n()
+
+/*
+ * I2C_SCK, I2C_SDA
+ */
+#define __gpio_as_i2c() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00003000; \
+ REG_GPIO_PXSELC(4) = 0x00003000; \
+ REG_GPIO_PXPES(4) = 0x00003000; \
+} while (0)
+
+/*
+ * PWM0
+ */
+#define __gpio_as_pwm0() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00100000; \
+ REG_GPIO_PXSELC(4) = 0x00100000; \
+ REG_GPIO_PXPES(4) = 0x00100000; \
+} while (0)
+
+/*
+ * PWM1
+ */
+#define __gpio_as_pwm1() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00200000; \
+ REG_GPIO_PXSELC(4) = 0x00200000; \
+ REG_GPIO_PXPES(4) = 0x00200000; \
+} while (0)
+
+/*
+ * PWM2
+ */
+#define __gpio_as_pwm2() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00400000; \
+ REG_GPIO_PXSELC(4) = 0x00400000; \
+ REG_GPIO_PXPES(4) = 0x00400000; \
+} while (0)
+
+/*
+ * PWM3
+ */
+#define __gpio_as_pwm3() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00800000; \
+ REG_GPIO_PXSELC(4) = 0x00800000; \
+ REG_GPIO_PXPES(4) = 0x00800000; \
+} while (0)
+
+/*
+ * PWM4
+ */
+#define __gpio_as_pwm4() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x01000000; \
+ REG_GPIO_PXSELC(4) = 0x01000000; \
+ REG_GPIO_PXPES(4) = 0x01000000; \
+} while (0)
+
+/*
+ * PWM5
+ */
+#define __gpio_as_pwm5() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x02000000; \
+ REG_GPIO_PXSELC(4) = 0x02000000; \
+ REG_GPIO_PXPES(4) = 0x02000000; \
+} while (0)
+
+/*
+ * n = 0 ~ 5
+ */
+#define __gpio_as_pwm(n) __gpio_as_pwm##n()
+
+/*
+ * DREQ
+ */
+#define __gpio_as_dreq() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x00000004; \
+ REG_GPIO_PXSELS(5) = 0x00000004; \
+ REG_GPIO_PXPES(5) = 0x00000004; \
+} while (0)
+
+/*
+ * DACK
+ */
+#define __gpio_as_dack() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x00000008; \
+ REG_GPIO_PXSELS(5) = 0x00000008; \
+ REG_GPIO_PXPES(5) = 0x00000008; \
+} while (0)
+
+/*
+ * GPIO or Interrupt Mode
+ */
+#define __gpio_get_port(p) (REG_GPIO_PXPIN(p))
+
+#define __gpio_port_as_output(p, o) \
+do { \
+ REG_GPIO_PXFUNC(p) = (1 << (o)); \
+ REG_GPIO_PXSELC(p) = (1 << (o)); \
+ REG_GPIO_PXDIRS(p) = (1 << (o)); \
+} while (0)
+
+#define __gpio_port_as_input(p, o) \
+do { \
+ REG_GPIO_PXFUNC(p) = (1 << (o)); \
+ REG_GPIO_PXSELC(p) = (1 << (o)); \
+ REG_GPIO_PXDIRC(p) = (1 << (o)); \
+} while (0)
+
+#define __gpio_as_output(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_as_output(p, o); \
+} while (0)
+
+#define __gpio_as_input(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_as_input(p, o); \
+} while (0)
+
+#define __gpio_set_pin(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXDATS(p) = (1 << o); \
+} while (0)
+
+#define __gpio_clear_pin(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXDATC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_get_pin(n) \
+({ \
+ unsigned int p, o, v; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ if (__gpio_get_port(p) & (1 << o)) \
+ v = 1; \
+ else \
+ v = 0; \
+ v; \
+})
+
+#define __gpio_as_irq_high_level(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGC(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRS(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_irq_low_level(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGC(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRC(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_irq_rise_edge(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGS(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRS(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_irq_fall_edge(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGS(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRC(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_mask_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+} while (0)
+
+#define __gpio_unmask_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_ack_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_get_irq() \
+({ \
+ unsigned int p, i, tmp, v = 0; \
+ for (p = 3; p >= 0; p--) { \
+ tmp = REG_GPIO_PXFLG(p); \
+ for (i = 0; i < 32; i++) \
+ if (tmp & (1 << i)) \
+ v = (32*p + i); \
+ } \
+ v; \
+})
+
+#define __gpio_group_irq(n) \
+({ \
+ register int tmp, i; \
+ tmp = REG_GPIO_PXFLG((n)); \
+ for (i=31;i>=0;i--) \
+ if (tmp & (1 << i)) \
+ break; \
+ i; \
+})
+
+#define __gpio_enable_pull(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXPEC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_disable_pull(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXPES(p) = (1 << o); \
+} while (0)
+
+
+/***************************************************************************
+ * CPM
+ ***************************************************************************/
+#define __cpm_get_pllm() \
+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLM_MASK) >> CPM_CPPCR_PLLM_BIT)
+#define __cpm_get_plln() \
+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLN_MASK) >> CPM_CPPCR_PLLN_BIT)
+#define __cpm_get_pllod() \
+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLOD_MASK) >> CPM_CPPCR_PLLOD_BIT)
+
+#define __cpm_get_cdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_CDIV_MASK) >> CPM_CPCCR_CDIV_BIT)
+#define __cpm_get_hdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_HDIV_MASK) >> CPM_CPCCR_HDIV_BIT)
+#define __cpm_get_pdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_PDIV_MASK) >> CPM_CPCCR_PDIV_BIT)
+#define __cpm_get_mdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT)
+#define __cpm_get_ldiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_LDIV_MASK) >> CPM_CPCCR_LDIV_BIT)
+#define __cpm_get_udiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_UDIV_MASK) >> CPM_CPCCR_UDIV_BIT)
+#define __cpm_get_i2sdiv() \
+ ((REG_CPM_I2SCDR & CPM_I2SCDR_I2SDIV_MASK) >> CPM_I2SCDR_I2SDIV_BIT)
+#define __cpm_get_pixdiv() \
+ ((REG_CPM_LPCDR & CPM_LPCDR_PIXDIV_MASK) >> CPM_LPCDR_PIXDIV_BIT)
+#define __cpm_get_mscdiv(n) \
+ ((REG_CPM_MSCCDR(n) & CPM_MSCCDR_MSCDIV_MASK) >> CPM_MSCCDR_MSCDIV_BIT)
+#define __cpm_get_uhcdiv() \
+ ((REG_CPM_UHCCDR & CPM_UHCCDR_UHCDIV_MASK) >> CPM_UHCCDR_UHCDIV_BIT)
+#define __cpm_get_ssidiv() \
+ ((REG_CPM_SSICCDR & CPM_SSICDR_SSICDIV_MASK) >> CPM_SSICDR_SSIDIV_BIT)
+#define __cpm_get_pcmdiv(v) \
+ ((REG_CPM_PCMCDR & CPM_PCMCDR_PCMCD_MASK) >> CPM_PCMCDR_PCMCD_BIT)
+
+#define __cpm_set_cdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_CDIV_MASK) | ((v) << (CPM_CPCCR_CDIV_BIT)))
+#define __cpm_set_hdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_HDIV_MASK) | ((v) << (CPM_CPCCR_HDIV_BIT)))
+#define __cpm_set_pdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_PDIV_MASK) | ((v) << (CPM_CPCCR_PDIV_BIT)))
+#define __cpm_set_mdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_MDIV_MASK) | ((v) << (CPM_CPCCR_MDIV_BIT)))
+#define __cpm_set_ldiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_LDIV_MASK) | ((v) << (CPM_CPCCR_LDIV_BIT)))
+#define __cpm_set_udiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_UDIV_MASK) | ((v) << (CPM_CPCCR_UDIV_BIT)))
+#define __cpm_set_i2sdiv(v) \
+ (REG_CPM_I2SCDR = (REG_CPM_I2SCDR & ~CPM_I2SCDR_I2SDIV_MASK) | ((v) << (CPM_I2SCDR_I2SDIV_BIT)))
+#define __cpm_set_pixdiv(v) \
+ (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT)))
+#define __cpm_set_mscdiv(n, v) \
+ (REG_CPM_MSCCDR(n) = (REG_CPM_MSCCDR(n) & ~CPM_MSCCDR_MSCDIV_MASK) | ((v) << (CPM_MSCCDR_MSCDIV_BIT)))
+#define __cpm_set_uhcdiv(v) \
+ (REG_CPM_UHCCDR = (REG_CPM_UHCCDR & ~CPM_UHCCDR_UHCDIV_MASK) | ((v) << (CPM_UHCCDR_UHCDIV_BIT)))
+#define __cpm_set_ssidiv(v) \
+ (REG_CPM_SSICDR = (REG_CPM_SSICDR & ~CPM_SSICDR_SSIDIV_MASK) | ((v) << (CPM_SSICDR_SSIDIV_BIT)))
+#define __cpm_set_pcmdiv(v) \
+ (REG_CPM_PCMCDR = (REG_CPM_PCMCDR & ~CPM_PCMCDR_PCMCD_MASK) | ((v) << (CPM_PCMCDR_PCMCD_BIT)))
+
+#define __cpm_select_pcmclk_pll() (REG_CPM_PCMCDR |= CPM_PCMCDR_PCMS)
+#define __cpm_select_pcmclk_exclk() (REG_CPM_PCMCDR &= ~CPM_PCMCDR_PCMS)
+#define __cpm_select_pixclk_ext() (REG_CPM_LPCDR |= CPM_LPCDR_LPCS)
+#define __cpm_select_pixclk_pll() (REG_CPM_LPCDR &= ~CPM_LPCDR_LPCS)
+#define __cpm_select_tveclk_exclk() (REG_CPM_LPCDR |= CPM_CPCCR_LSCS)
+#define __cpm_select_tveclk_pll() (REG_CPM_LPCDR &= ~CPM_LPCDR_LSCS)
+#define __cpm_select_pixclk_lcd() (REG_CPM_LPCDR &= ~CPM_LPCDR_LTCS)
+#define __cpm_select_pixclk_tve() (REG_CPM_LPCDR |= CPM_LPCDR_LTCS)
+#define __cpm_select_i2sclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_I2CS)
+#define __cpm_select_i2sclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_I2CS)
+#define __cpm_select_usbclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_UCS)
+#define __cpm_select_usbclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_UCS)
+
+#define __cpm_enable_cko()
+#define __cpm_exclk_direct() (REG_CPM_CPCCR &= ~CPM_CPCCR_ECS)
+#define __cpm_exclk_div2() (REG_CPM_CPCCR |= CPM_CPCCR_ECS)
+#define __cpm_enable_pll_change() (REG_CPM_CPCCR |= CPM_CPCCR_CE)
+#define __cpm_pllout_direct() (REG_CPM_CPCCR |= CPM_CPCCR_PCS)
+#define __cpm_pllout_div2() (REG_CPM_CPCCR &= ~CPM_CPCCR_PCS)
+#define __cpm_pll_enable() (REG_CPM_CPPCR |= CPM_CPPCR_PLLEN)
+
+#define __cpm_pll_is_off() (REG_CPM_CPPSR & CPM_CPPSR_PLLOFF)
+#define __cpm_pll_is_on() (REG_CPM_CPPSR & CPM_CPPSR_PLLON)
+#define __cpm_pll_bypass() (REG_CPM_CPPSR |= CPM_CPPSR_PLLBP)
+
+#define __cpm_get_cclk_doze_duty() \
+ ((REG_CPM_LCR & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT)
+#define __cpm_set_cclk_doze_duty(v) \
+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_DOZE_DUTY_MASK) | ((v) << (CPM_LCR_DOZE_DUTY_BIT)))
+
+#define __cpm_doze_mode() (REG_CPM_LCR |= CPM_LCR_DOZE_ON)
+#define __cpm_idle_mode() \
+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_IDLE)
+#define __cpm_sleep_mode() \
+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_SLEEP)
+
+#define __cpm_stop_all() (REG_CPM_CLKGR = 0x1fffffff)
+#define __cpm_stop_cimram() (REG_CPM_CLKGR |= CPM_CLKGR_CIMRAM)
+#define __cpm_stop_idct() (REG_CPM_CLKGR |= CPM_CLKGR_IDCT)
+#define __cpm_stop_db() (REG_CPM_CLKGR |= CPM_CLKGR_DB)
+#define __cpm_stop_me() (REG_CPM_CLKGR |= CPM_CLKGR_ME)
+#define __cpm_stop_mc() (REG_CPM_CLKGR |= CPM_CLKGR_MC)
+#define __cpm_stop_tve() (REG_CPM_CLKGR |= CPM_CLKGR_TVE)
+#define __cpm_stop_tssi() (REG_CPM_CLKGR |= CPM_CLKGR_TSSI)
+#define __cpm_stop_owi() (REG_CPM_CLKGR |= CPM_CLKGR_OWI)
+#define __cpm_stop_pcm() (REG_CPM_CLKGR |= CPM_CLKGR_PCM)
+#define __cpm_stop_uart3() (REG_CPM_CLKGR |= CPM_CLKGR_UART3)
+#define __cpm_stop_uart2() (REG_CPM_CLKGR |= CPM_CLKGR_UART2)
+#define __cpm_stop_uart1() (REG_CPM_CLKGR |= CPM_CLKGR_UART1)
+#define __cpm_stop_uhc() (REG_CPM_CLKGR |= CPM_CLKGR_UHC)
+#define __cpm_stop_ipu() (REG_CPM_CLKGR |= CPM_CLKGR_IPU)
+#define __cpm_stop_dmac() (REG_CPM_CLKGR |= CPM_CLKGR_DMAC)
+#define __cpm_stop_udc() (REG_CPM_CLKGR |= CPM_CLKGR_UDC)
+#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD)
+#define __cpm_stop_cim() (REG_CPM_CLKGR |= CPM_CLKGR_CIM)
+#define __cpm_stop_sadc() (REG_CPM_CLKGR |= CPM_CLKGR_SADC)
+#define __cpm_stop_msc(n) (REG_CPM_CLKGR |= CPM_CLKGR_MSC##n)
+#define __cpm_stop_aic1() (REG_CPM_CLKGR |= CPM_CLKGR_AIC1)
+#define __cpm_stop_aic2() (REG_CPM_CLKGR |= CPM_CLKGR_AIC2)
+#define __cpm_stop_ssi(n) (REG_CPM_CLKGR |= CPM_CLKGR_SSI##n)
+#define __cpm_stop_i2c() (REG_CPM_CLKGR |= CPM_CLKGR_I2C)
+#define __cpm_stop_rtc() (REG_CPM_CLKGR |= CPM_CLKGR_RTC)
+#define __cpm_stop_tcu() (REG_CPM_CLKGR |= CPM_CLKGR_TCU)
+#define __cpm_stop_uart0() (REG_CPM_CLKGR |= CPM_CLKGR_UART0)
+
+#define __cpm_start_all() (REG_CPM_CLKGR = 0x0)
+#define __cpm_start_cimram() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIMRAM)
+#define __cpm_start_idct() (REG_CPM_CLKGR &= ~CPM_CLKGR_IDCT)
+#define __cpm_start_db() (REG_CPM_CLKGR &= ~CPM_CLKGR_DB)
+#define __cpm_start_me() (REG_CPM_CLKGR &= ~CPM_CLKGR_ME)
+#define __cpm_start_mc() (REG_CPM_CLKGR &= ~CPM_CLKGR_MC)
+#define __cpm_start_tve() (REG_CPM_CLKGR &= ~CPM_CLKGR_TVE)
+#define __cpm_start_tssi() (REG_CPM_CLKGR &= ~CPM_CLKGR_TSSI)
+#define __cpm_start_owi() (REG_CPM_CLKGR &= ~CPM_CLKGR_OWI)
+#define __cpm_start_pcm() (REG_CPM_CLKGR &= ~CPM_CLKGR_PCM)
+#define __cpm_start_uart3() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART3)
+#define __cpm_start_uart2() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART2)
+#define __cpm_start_uart1() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART1)
+#define __cpm_start_uhc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UHC)
+#define __cpm_start_ipu() (REG_CPM_CLKGR &= ~CPM_CLKGR_IPU)
+#define __cpm_start_dmac() (REG_CPM_CLKGR &= ~CPM_CLKGR_DMAC)
+#define __cpm_start_udc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UDC)
+#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD)
+#define __cpm_start_cim() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIM)
+#define __cpm_start_sadc() (REG_CPM_CLKGR &= ~CPM_CLKGR_SADC)
+#define __cpm_start_msc(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_MSC##n)
+#define __cpm_start_aic1() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC1)
+#define __cpm_start_aic2() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC2)
+#define __cpm_start_ssi(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_SSI##n)
+#define __cpm_start_i2c() (REG_CPM_CLKGR &= ~CPM_CLKGR_I2C)
+#define __cpm_start_rtc() (REG_CPM_CLKGR &= ~CPM_CLKGR_RTC)
+#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU)
+#define __cpm_start_uart0() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART0)
+
+#define __cpm_get_o1st() \
+ ((REG_CPM_OPCR & CPM_OPCR_O1ST_MASK) >> CPM_OPCR_O1ST_BIT)
+#define __cpm_set_o1st(v) \
+ (REG_CPM_OPCR = (REG_CPM_OPCR & ~CPM_OPCR_O1ST_MASK) | ((v) << (CPM_OPCR_O1ST_BIT)))
+#define __cpm_enable_uhcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UHCPHY_DISABLE)
+#define __cpm_suspend_uhcphy() (REG_CPM_OPCR |= CPM_OPCR_UHCPHY_DISABLE)
+#define __cpm_enable_udcphy() (REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE)
+#define __cpm_suspend_udcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE)
+#define __cpm_enable_osc_in_sleep() (REG_CPM_OPCR |= CPM_OPCR_OSC_ENABLE)
+#define __cpm_disable_osc_in_sleep() (REG_CPM_OPCR &= ~CPM_OPCR_OSC_ENABLE)
+#define __cpm_select_rtcclk_rtc() (REG_CPM_OPCR |= CPM_OPCR_ERCS)
+#define __cpm_select_rtcclk_exclk() (REG_CPM_OPCR &= ~CPM_OPCR_ERCS)
+
+
+/***************************************************************************
+ * TCU
+ ***************************************************************************/
+// where 'n' is the TCU channel
+#define __tcu_select_extalclk(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_EXT_EN)
+#define __tcu_select_rtcclk(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_RTC_EN)
+#define __tcu_select_pclk(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_PCK_EN)
+#define __tcu_disable_pclk(n) \
+ REG_TCU_TCSR(n) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PCK_EN);
+#define __tcu_select_clk_div1(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1)
+#define __tcu_select_clk_div4(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE4)
+#define __tcu_select_clk_div16(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE16)
+#define __tcu_select_clk_div64(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE64)
+#define __tcu_select_clk_div256(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE256)
+#define __tcu_select_clk_div1024(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1024)
+
+#define __tcu_enable_pwm_output(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_EN)
+#define __tcu_disable_pwm_output(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_EN)
+
+#define __tcu_init_pwm_output_high(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_INITL_HIGH)
+#define __tcu_init_pwm_output_low(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_INITL_HIGH)
+
+#define __tcu_set_pwm_output_shutdown_graceful(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_SD)
+#define __tcu_set_pwm_output_shutdown_abrupt(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_SD)
+
+#define __tcu_clear_counter_to_zero(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_CNT_CLRZ)
+
+#define __tcu_ost_enabled() (REG_TCU_TER & TCU_TER_OSTEN)
+#define __tcu_enable_ost() (REG_TCU_TESR = TCU_TESR_OSTST)
+#define __tcu_disable_ost() (REG_TCU_TECR = TCU_TECR_OSTCL)
+
+#define __tcu_counter_enabled(n) (REG_TCU_TER & (1 << (n)))
+#define __tcu_start_counter(n) (REG_TCU_TESR |= (1 << (n)))
+#define __tcu_stop_counter(n) (REG_TCU_TECR |= (1 << (n)))
+
+#define __tcu_half_match_flag(n) (REG_TCU_TFR & (1 << ((n) + 16)))
+#define __tcu_full_match_flag(n) (REG_TCU_TFR & (1 << (n)))
+#define __tcu_set_half_match_flag(n) (REG_TCU_TFSR = (1 << ((n) + 16)))
+#define __tcu_set_full_match_flag(n) (REG_TCU_TFSR = (1 << (n)))
+#define __tcu_clear_half_match_flag(n) (REG_TCU_TFCR = (1 << ((n) + 16)))
+#define __tcu_clear_full_match_flag(n) (REG_TCU_TFCR = (1 << (n)))
+#define __tcu_mask_half_match_irq(n) (REG_TCU_TMSR = (1 << ((n) + 16)))
+#define __tcu_mask_full_match_irq(n) (REG_TCU_TMSR = (1 << (n)))
+#define __tcu_unmask_half_match_irq(n) (REG_TCU_TMCR = (1 << ((n) + 16)))
+#define __tcu_unmask_full_match_irq(n) (REG_TCU_TMCR = (1 << (n)))
+
+#define __tcu_ost_match_flag() (REG_TCU_TFR & TCU_TFR_OSTFLAG)
+#define __tcu_set_ost_match_flag() (REG_TCU_TFSR = TCU_TFSR_OSTFST)
+#define __tcu_clear_ost_match_flag() (REG_TCU_TFCR = TCU_TFCR_OSTFCL)
+#define __tcu_ost_match_irq_masked() (REG_TCU_TMR & TCU_TMR_OSTMASK)
+#define __tcu_mask_ost_match_irq() (REG_TCU_TMSR = TCU_TMSR_OSTMST)
+#define __tcu_unmask_ost_match_irq() (REG_TCU_TMCR = TCU_TMCR_OSTMCL)
+
+#define __tcu_wdt_clock_stopped() (REG_TCU_TSR & TCU_TSSR_WDTSC)
+#define __tcu_ost_clock_stopped() (REG_TCU_TSR & TCU_TSR_OST)
+#define __tcu_timer_clock_stopped(n) (REG_TCU_TSR & (1 << (n)))
+
+#define __tcu_start_wdt_clock() (REG_TCU_TSCR = TCU_TSSR_WDTSC)
+#define __tcu_start_ost_clock() (REG_TCU_TSCR = TCU_TSCR_OSTSC)
+#define __tcu_start_timer_clock(n) (REG_TCU_TSCR = (1 << (n)))
+
+#define __tcu_stop_wdt_clock() (REG_TCU_TSSR = TCU_TSSR_WDTSC)
+#define __tcu_stop_ost_clock() (REG_TCU_TSSR = TCU_TSSR_OSTSS)
+#define __tcu_stop_timer_clock(n) (REG_TCU_TSSR = (1 << (n)))
+
+#define __tcu_get_count(n) (REG_TCU_TCNT((n)))
+#define __tcu_set_count(n,v) (REG_TCU_TCNT((n)) = (v))
+#define __tcu_set_full_data(n,v) (REG_TCU_TDFR((n)) = (v))
+#define __tcu_set_half_data(n,v) (REG_TCU_TDHR((n)) = (v))
+
+/* TCU2, counter 1, 2*/
+#define __tcu_read_real_value(n) (REG_TCU_TSTR & (1 << ((n) + 16)))
+#define __tcu_read_false_value(n) (REG_TCU_TSTR & (1 << ((n) + 16)))
+#define __tcu_counter_busy(n) (REG_TCU_TSTR & (1 << (n)))
+#define __tcu_counter_ready(n) (REG_TCU_TSTR & (1 << (n)))
+
+#define __tcu_set_read_real_value(n) (REG_TCU_TSTSR = (1 << ((n) + 16)))
+#define __tcu_set_read_false_value(n) (REG_TCU_TSTCR = (1 << ((n) + 16)))
+#define __tcu_set_counter_busy(n) (REG_TCU_TSTSR = (1 << (n)))
+#define __tcu_set_counter_ready(n) (REG_TCU_TSTCR = (1 << (n)))
+
+/* ost counter */
+#define __ostcu_set_pwm_output_shutdown_graceful() (REG_TCU_OSTCSR &= ~TCU_TCSR_PWM_SD)
+#define __ostcu_set_ost_output_shutdown_abrupt() (REG_TCU_OSTCSR |= TCU_TCSR_PWM_SD)
+#define __ostcu_select_clk_div1() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1)
+#define __ostcu_select_clk_div4() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE4)
+#define __ostcu_select_clk_div16() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE16)
+#define __ostcu_select_clk_div64() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE64)
+#define __ostcu_select_clk_div256() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE256)
+#define __ostcu_select_clk_div1024() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1024)
+#define __ostcu_select_rtcclk() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_RTC_EN)
+#define __ostcu_select_extalclk() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_EXT_EN)
+#define __ostcu_select_pclk() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_PCK_EN)
+
+
+/***************************************************************************
+ * WDT
+ ***************************************************************************/
+#define __wdt_start() ( REG_WDT_TCER |= WDT_TCER_TCEN )
+#define __wdt_stop() ( REG_WDT_TCER &= ~WDT_TCER_TCEN )
+#define __wdt_set_count(v) ( REG_WDT_TCNT = (v) )
+#define __wdt_set_data(v) ( REG_WDT_TDR = (v) )
+
+#define __wdt_select_extalclk() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_EXT_EN)
+#define __wdt_select_rtcclk() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_RTC_EN)
+#define __wdt_select_pclk() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_PCK_EN)
+
+#define __wdt_select_clk_div1() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1)
+#define __wdt_select_clk_div4() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE4)
+#define __wdt_select_clk_div16() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE16)
+#define __wdt_select_clk_div64() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE64)
+#define __wdt_select_clk_div256() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE256)
+#define __wdt_select_clk_div1024() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1024)
+
+
+/***************************************************************************
+ * UART
+ ***************************************************************************/
+
+#define __uart_enable(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE )
+#define __uart_disable(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE )
+
+#define __uart_enable_transmit_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE )
+#define __uart_disable_transmit_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE )
+
+#define __uart_enable_receive_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE )
+#define __uart_disable_receive_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) )
+
+#define __uart_enable_loopback(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP )
+#define __uart_disable_loopback(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP )
+
+#define __uart_set_8n1(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 )
+
+#define __uart_set_baud(n, devclk, baud) \
+ do { \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \
+ } while (0)
+
+#define __uart_parity_error(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 )
+
+#define __uart_clear_errors(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) )
+
+#define __uart_transmit_fifo_empty(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 )
+
+#define __uart_transmit_end(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 )
+
+#define __uart_transmit_char(n, ch) \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch)
+
+#define __uart_receive_fifo_full(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 )
+
+#define __uart_receive_ready(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 )
+
+#define __uart_receive_char(n) \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR)
+
+#define __uart_disable_irda() \
+ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) )
+#define __uart_enable_irda() \
+ /* Tx high pulse as 0, Rx low pulse as 0 */ \
+ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS )
+
+
+/***************************************************************************
+ * DMAC
+ ***************************************************************************/
+
+/* m is the DMA controller index (0, 1), n is the DMA channel index (0 - 11) */
+
+#define __dmac_enable_module(m) \
+ ( REG_DMAC_DMACR(m) |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_012345 )
+#define __dmac_disable_module(m) \
+ ( REG_DMAC_DMACR(m) &= ~DMAC_DMACR_DMAE )
+
+/* p=0,1,2,3 */
+#define __dmac_set_priority(m,p) \
+do { \
+ REG_DMAC_DMACR(m) &= ~DMAC_DMACR_PR_MASK; \
+ REG_DMAC_DMACR(m) |= ((p) << DMAC_DMACR_PR_BIT); \
+} while (0)
+
+#define __dmac_test_halt_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_HLT )
+#define __dmac_test_addr_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_AR )
+
+#define __dmac_channel_enable_clk(n) \
+ REG_DMAC_DMACKE((n)/HALF_DMA_NUM) |= 1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM);
+
+#define __dmac_enable_descriptor(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES )
+#define __dmac_disable_descriptor(n) \
+ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES )
+
+#define __dmac_enable_channel(n) \
+do { \
+ REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN; \
+} while (0)
+#define __dmac_disable_channel(n) \
+do { \
+ REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN; \
+} while (0)
+#define __dmac_channel_enabled(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN )
+
+#define __dmac_channel_enable_irq(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE )
+#define __dmac_channel_disable_irq(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE )
+
+#define __dmac_channel_transmit_halt_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT )
+#define __dmac_channel_transmit_end_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT )
+#define __dmac_channel_address_error_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR )
+#define __dmac_channel_count_terminated_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT )
+#define __dmac_channel_descriptor_invalid_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV )
+
+#define __dmac_channel_clear_transmit_halt(n) \
+ do { \
+ /* clear both channel halt error and globle halt error */ \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT; \
+ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_HLT; \
+ } while (0)
+#define __dmac_channel_clear_transmit_end(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT )
+#define __dmac_channel_clear_address_error(n) \
+ do { \
+ REG_DMAC_DDA(n) = 0; /* clear descriptor address register */ \
+ REG_DMAC_DSAR(n) = 0; /* clear source address register */ \
+ REG_DMAC_DTAR(n) = 0; /* clear target address register */ \
+ /* clear both channel addr error and globle address error */ \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR; \
+ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_AR; \
+ } while (0)
+#define __dmac_channel_clear_count_terminated(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT )
+#define __dmac_channel_clear_descriptor_invalid(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV )
+
+#define __dmac_channel_set_transfer_unit_32bit(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_16bit(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_8bit(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_16byte(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_32byte(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \
+} while (0)
+
+/* w=8,16,32 */
+#define __dmac_channel_set_dest_port_width(n,w) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \
+} while (0)
+
+/* w=8,16,32 */
+#define __dmac_channel_set_src_port_width(n,w) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \
+} while (0)
+
+/* v=0-15 */
+#define __dmac_channel_set_rdil(n,v) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \
+ REG_DMAC_DCMD((n) |= ((v) << DMAC_DCMD_RDIL_BIT); \
+} while (0)
+
+#define __dmac_channel_dest_addr_fixed(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI )
+#define __dmac_channel_dest_addr_increment(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI )
+
+#define __dmac_channel_src_addr_fixed(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI )
+#define __dmac_channel_src_addr_increment(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI )
+
+#define __dmac_channel_set_doorbell(n) \
+ ( REG_DMAC_DMADBSR((n)/HALF_DMA_NUM) = (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) )
+
+#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) & (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) )
+#define __dmac_channel_ack_irq(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) &= ~(1 <<((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) )
+
+static __inline__ int __dmac_get_irq(void)
+{
+ int i;
+ for (i = 0; i < MAX_DMA_NUM; i++)
+ if (__dmac_channel_irq_detected(i))
+ return i;
+ return -1;
+}
+
+
+/***************************************************************************
+ * AIC (AC'97 & I2S Controller)
+ ***************************************************************************/
+
+#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB )
+#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB )
+
+#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL )
+#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL )
+
+#define __aic_play_zero() ( REG_AIC_FR &= ~AIC_FR_LSMP )
+#define __aic_play_lastsample() ( REG_AIC_FR |= AIC_FR_LSMP )
+
+#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD )
+#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) )
+#define __aic_reset_status() ( REG_AIC_FR & AIC_FR_RST )
+
+#define __aic_reset() \
+do { \
+ REG_AIC_FR |= AIC_FR_RST; \
+} while(0)
+
+
+#define __aic_set_transmit_trigger(n) \
+do { \
+ REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \
+ REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \
+} while(0)
+
+#define __aic_set_receive_trigger(n) \
+do { \
+ REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \
+ REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \
+} while(0)
+
+#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC )
+#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC )
+#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL )
+#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL )
+#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF )
+#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF )
+
+#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH )
+#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH )
+
+#define __aic_enable_transmit_intr() \
+ ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) )
+#define __aic_disable_transmit_intr() \
+ ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) )
+#define __aic_enable_receive_intr() \
+ ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) )
+#define __aic_disable_receive_intr() \
+ ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) )
+
+#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS )
+#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS )
+#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS )
+#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS )
+
+#define __aic_enable_mono2stereo() ( REG_AIC_CR |= AIC_CR_M2S )
+#define __aic_disable_mono2stereo() ( REG_AIC_CR &= ~AIC_CR_M2S )
+#define __aic_enable_byteswap() ( REG_AIC_CR |= AIC_CR_ENDSW )
+#define __aic_disable_byteswap() ( REG_AIC_CR &= ~AIC_CR_ENDSW )
+#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU )
+#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU )
+
+#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3
+#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4
+#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6
+#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7
+#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8
+#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9
+
+#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3
+#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4
+#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6
+#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7
+#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8
+#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9
+
+#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK )
+#define __ac97_set_xs_mono() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \
+} while(0)
+#define __ac97_set_xs_stereo() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \
+} while(0)
+
+/* In fact, only stereo is support now. */
+#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK )
+#define __ac97_set_rs_mono() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \
+} while(0)
+#define __ac97_set_rs_stereo() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \
+} while(0)
+
+#define __ac97_warm_reset_codec() \
+ do { \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SA; \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SS; \
+ udelay(2); \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \
+ } while (0)
+
+#define __ac97_cold_reset_codec() \
+ do { \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SR; \
+ udelay(2); \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \
+ } while (0)
+
+/* n=8,16,18,20 */
+#define __ac97_set_iass(n) \
+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT )
+#define __ac97_set_oass(n) \
+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT )
+
+#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL )
+#define __i2s_select_msbjustified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL )
+
+/* n=8,16,18,20,24 */
+/*#define __i2s_set_sample_size(n) \
+ ( REG_AIC_I2SCR |= (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )*/
+
+#define __i2s_set_oss_sample_size(n) \
+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT )
+#define __i2s_set_iss_sample_size(n) \
+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT )
+
+#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK )
+#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK )
+
+#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS )
+#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS )
+#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR )
+#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR )
+
+#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) )
+
+#define __aic_get_transmit_resident() \
+ ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT )
+#define __aic_get_receive_count() \
+ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT )
+
+#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT )
+#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR )
+#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO )
+#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM )
+#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY )
+#define __ac97_slot_error_detected() ( REG_AIC_ACSR & AIC_ACSR_SLTERR )
+#define __ac97_clear_slot_error() ( REG_AIC_ACSR &= ~AIC_ACSR_SLTERR )
+
+#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY )
+
+#define CODEC_READ_CMD (1 << 19)
+#define CODEC_WRITE_CMD (0 << 19)
+#define CODEC_REG_INDEX_BIT 12
+#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */
+#define CODEC_REG_DATA_BIT 4
+#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */
+
+#define __ac97_out_rcmd_addr(reg) \
+do { \
+ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \
+} while (0)
+
+#define __ac97_out_wcmd_addr(reg) \
+do { \
+ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \
+} while (0)
+
+#define __ac97_out_data(value) \
+do { \
+ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \
+} while (0)
+
+#define __ac97_in_data() \
+ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT )
+
+#define __ac97_in_status_addr() \
+ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT )
+
+#define __i2s_set_sample_rate(i2sclk, sync) \
+ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) )
+
+#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) )
+#define __aic_read_rfifo() ( REG_AIC_DR )
+
+#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC )
+#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC )
+
+//
+// Define next ops for AC97 compatible
+//
+
+#define AC97_ACSR AIC_ACSR
+
+#define __ac97_enable() __aic_enable(); __aic_select_ac97()
+#define __ac97_disable() __aic_disable()
+#define __ac97_reset() __aic_reset()
+
+#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n)
+#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n)
+
+#define __ac97_enable_record() __aic_enable_record()
+#define __ac97_disable_record() __aic_disable_record()
+#define __ac97_enable_replay() __aic_enable_replay()
+#define __ac97_disable_replay() __aic_disable_replay()
+#define __ac97_enable_loopback() __aic_enable_loopback()
+#define __ac97_disable_loopback() __aic_disable_loopback()
+
+#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma()
+#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma()
+#define __ac97_enable_receive_dma() __aic_enable_receive_dma()
+#define __ac97_disable_receive_dma() __aic_disable_receive_dma()
+
+#define __ac97_transmit_request() __aic_transmit_request()
+#define __ac97_receive_request() __aic_receive_request()
+#define __ac97_transmit_underrun() __aic_transmit_underrun()
+#define __ac97_receive_overrun() __aic_receive_overrun()
+
+#define __ac97_clear_errors() __aic_clear_errors()
+
+#define __ac97_get_transmit_resident() __aic_get_transmit_resident()
+#define __ac97_get_receive_count() __aic_get_receive_count()
+
+#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr()
+#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr()
+#define __ac97_enable_receive_intr() __aic_enable_receive_intr()
+#define __ac97_disable_receive_intr() __aic_disable_receive_intr()
+
+#define __ac97_write_tfifo(v) __aic_write_tfifo(v)
+#define __ac97_read_rfifo() __aic_read_rfifo()
+
+//
+// Define next ops for I2S compatible
+//
+
+#define I2S_ACSR AIC_I2SSR
+
+#define __i2s_enable() __aic_enable(); __aic_select_i2s()
+#define __i2s_disable() __aic_disable()
+#define __i2s_reset() __aic_reset()
+
+#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n)
+#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n)
+
+#define __i2s_enable_record() __aic_enable_record()
+#define __i2s_disable_record() __aic_disable_record()
+#define __i2s_enable_replay() __aic_enable_replay()
+#define __i2s_disable_replay() __aic_disable_replay()
+#define __i2s_enable_loopback() __aic_enable_loopback()
+#define __i2s_disable_loopback() __aic_disable_loopback()
+
+#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma()
+#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma()
+#define __i2s_enable_receive_dma() __aic_enable_receive_dma()
+#define __i2s_disable_receive_dma() __aic_disable_receive_dma()
+
+#define __i2s_transmit_request() __aic_transmit_request()
+#define __i2s_receive_request() __aic_receive_request()
+#define __i2s_transmit_underrun() __aic_transmit_underrun()
+#define __i2s_receive_overrun() __aic_receive_overrun()
+
+#define __i2s_clear_errors() __aic_clear_errors()
+
+#define __i2s_get_transmit_resident() __aic_get_transmit_resident()
+#define __i2s_get_receive_count() __aic_get_receive_count()
+
+#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr()
+#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr()
+#define __i2s_enable_receive_intr() __aic_enable_receive_intr()
+#define __i2s_disable_receive_intr() __aic_disable_receive_intr()
+
+#define __i2s_write_tfifo(v) __aic_write_tfifo(v)
+#define __i2s_read_rfifo() __aic_read_rfifo()
+
+#define __i2s_reset_codec() \
+ do { \
+ } while (0)
+
+/*************************************************************************
+ * PCM Controller operation
+ *************************************************************************/
+
+#define __pcm_enable() ( REG_PCM_CTL |= PCM_CTL_PCMEN )
+#define __pcm_disable() ( REG_PCM_CTL &= ~PCM_CTL_PCMEN )
+
+#define __pcm_clk_enable() ( REG_PCM_CTL |= PCM_CTL_CLKEN )
+#define __pcm_clk_disable() ( REG_PCM_CTL &= ~PCM_CTL_CLKEN )
+
+#define __pcm_reset() ( REG_PCM_CTL |= PCM_CTL_RST )
+#define __pcm_flush_fifo() ( REG_PCM_CTL |= PCM_CTL_FLUSH )
+
+#define __pcm_enable_record() ( REG_PCM_CTL |= PCM_CTL_EREC )
+#define __pcm_disable_record() ( REG_PCM_CTL &= ~PCM_CTL_EREC )
+#define __pcm_enable_playback() ( REG_PCM_CTL |= PCM_CTL_ERPL )
+#define __pcm_disable_playback() ( REG_PCM_CTL &= ~PCM_CTL_ERPL )
+
+#define __pcm_enable_rxfifo() __pcm_enable_record()
+#define __pcm_disable_rxfifo() __pcm_disable_record()
+#define __pcm_enable_txfifo() __pcm_enable_playback()
+#define __pcm_disable_txfifo() __pcm_disable_playback()
+
+#define __pcm_last_sample() ( REG_PCM_CTL |= PCM_CTL_LSMP )
+#define __pcm_zero_sample() ( REG_PCM_CTL &= ~PCM_CTL_LSMP )
+
+#define __pcm_enable_transmit_dma() ( REG_PCM_CTL |= PCM_CTL_ETDMA )
+#define __pcm_disable_transmit_dma() ( REG_PCM_CTL &= ~PCM_CTL_ETDMA )
+#define __pcm_enable_receive_dma() ( REG_PCM_CTL |= PCM_CTL_ERDMA )
+#define __pcm_disable_receive_dma() ( REG_PCM_CTL &= ~PCM_CTL_ERDMA )
+
+#define __pcm_as_master() ( REG_PCM_CFG &= PCM_CFG_MODE )
+#define __pcm_as_slave() ( REG_PCM_CFG |= ~PCM_CFG_MODE )
+
+#define __pcm_set_transmit_trigger(n) \
+do { \
+ REG_PCM_CFG &= ~PCM_CFG_TFTH_MASK; \
+ REG_PCM_CFG |= ((n) << PCM_CFG_TFTH_BIT); \
+} while(0)
+
+#define __pcm_set_receive_trigger(n) \
+do { \
+ REG_PCM_CFG &= ~PCM_CFG_RFTH_MASK; \
+ REG_PCM_CFG |= ((n) << PCM_CFG_RFTH_BIT); \
+} while(0)
+
+#define __pcm_omsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_OMSBPOS )
+#define __pcm_omsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_OMSBPOS )
+
+#define __pcm_imsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_IMSBPOS )
+#define __pcm_imsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_IMSBPOS )
+
+/* set input sample size 8 or 16*/
+#define __pcm_set_iss(n) \
+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_ISS_MASK) | PCM_CFG_ISS_##n )
+/* set output sample size 8 or 16*/
+#define __pcm_set_oss(n) \
+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_OSS_MASK) | PCM_CFG_OSS_##n )
+
+#define __pcm_set_valid_slot(n) \
+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_SLOT_MASK) | PCM_CFG_SLOT_##n )
+
+#define __pcm_write_data(v) ( REG_PCM_DP = (v) )
+#define __pcm_read_data() ( REG_PCM_DP )
+
+#define __pcm_enable_tfs_intr() ( REG_PCM_INTC |= PCM_INTC_ETFS )
+#define __pcm_disable_tfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETFS )
+
+#define __pcm_enable_tur_intr() ( REG_PCM_INTC |= PCM_INTC_ETUR )
+#define __pcm_disable_tur_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETUR )
+
+#define __pcm_enable_rfs_intr() ( REG_PCM_INTC |= PCM_INTC_ERFS )
+#define __pcm_disable_rfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ERFS )
+
+#define __pcm_enable_ror_intr() ( REG_PCM_INTC |= PCM_INTC_EROR )
+#define __pcm_disable_ror_intr() ( REG_PCM_INTC &= ~PCM_INTC_EROR )
+
+#define __pcm_ints_valid_tx() \
+( ((REG_PCM_INTS & PCM_INTS_TFL_MASK) >> PCM_INTS_TFL_BIT) )
+#define __pcm_ints_valid_rx() \
+( ((REG_PCM_INTS & PCM_INTS_RFL_MASK) >> PCM_INTS_RFL_BIT) )
+
+#define __pcm_set_clk_div(n) \
+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_CLKDIV_MASK) | ((n) << PCM_DIV_CLKDIV_BIT) )
+
+/* sysclk(cpm_pcm_sysclk) Hz is created by cpm logic, and pcmclk Hz is the pcm in/out clock wanted */
+#define __pcm_set_clk_rate(sysclk, pcmclk) \
+__pcm_set_clk_div(((sysclk) / (pcmclk) - 1))
+
+#define __pcm_set_sync_div(n) \
+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNDIV_MASK) | ((n) << PCM_DIV_SYNDIV_BIT) )
+
+/* pcmclk is source clock Hz, and sync is the frame sync clock Hz wanted */
+#define __pcm_set_sync_rate(pcmclk, sync) \
+__pcm_set_sync_div(((pcmclk) / (8 * (sync)) - 1))
+
+ /* set sync length in pcmclk n = 0 ... 63 */
+#define __pcm_set_sync_len(n) \
+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNL_MASK) | (n << PCM_DIV_SYNL_BIT) )
+
+
+/***************************************************************************
+ * ICDC
+ ***************************************************************************/
+#define __i2s_internal_codec() __aic_internal_codec()
+#define __i2s_external_codec() __aic_external_codec()
+
+#define __icdc_clk_ready() ( REG_ICDC_CKCFG & ICDC_CKCFG_CKRDY )
+#define __icdc_sel_adc() ( REG_ICDC_CKCFG |= ICDC_CKCFG_SELAD )
+#define __icdc_sel_dac() ( REG_ICDC_CKCFG &= ~ICDC_CKCFG_SELAD )
+
+#define __icdc_set_rgwr() ( REG_ICDC_RGADW |= ICDC_RGADW_RGWR )
+#define __icdc_clear_rgwr() ( REG_ICDC_RGADW &= ~ICDC_RGADW_RGWR )
+#define __icdc_rgwr_ready() ( REG_ICDC_RGADW & ICDC_RGADW_RGWR )
+
+#define __icdc_set_addr(n) \
+do { \
+ REG_ICDC_RGADW &= ~ICDC_RGADW_RGADDR_MASK; \
+ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGADDR_BIT; \
+} while(0)
+
+#define __icdc_set_cmd(n) \
+do { \
+ REG_ICDC_RGADW &= ~ICDC_RGADW_RGDIN_MASK; \
+ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGDIN_BIT; \
+} while(0)
+
+#define __icdc_irq_pending() ( REG_ICDC_RGDATA & ICDC_RGDATA_IRQ )
+#define __icdc_get_value() ( REG_ICDC_RGDATA & ICDC_RGDATA_RGDOUT_MASK )
+
+/***************************************************************************
+ * INTC
+ ***************************************************************************/
+#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) )
+#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) )
+#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) /* A dummy ack, as the Pending Register is Read Only. Should we remove __intc_ack_irq() */
+
+
+/***************************************************************************
+ * I2C
+ ***************************************************************************/
+
+#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE )
+#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE )
+
+#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA )
+#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO )
+#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC )
+#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC )
+
+#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF )
+#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF )
+#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF )
+
+#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) )
+#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY )
+#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND )
+
+#define __i2c_set_clk(dev_clk, i2c_clk) \
+ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 )
+
+#define __i2c_read() ( REG_I2C_DR )
+#define __i2c_write(val) ( REG_I2C_DR = (val) )
+
+
+/***************************************************************************
+ * MSC
+ ***************************************************************************/
+/* n = 0, 1 (MSC0, MSC1) */
+
+#define __msc_start_op(n) \
+ ( REG_MSC_STRPCL(n) = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START )
+
+#define __msc_set_resto(n, to) ( REG_MSC_RESTO(n) = to )
+#define __msc_set_rdto(n, to) ( REG_MSC_RDTO(n) = to )
+#define __msc_set_cmd(n, cmd) ( REG_MSC_CMD(n) = cmd )
+#define __msc_set_arg(n, arg) ( REG_MSC_ARG(n) = arg )
+#define __msc_set_nob(n, nob) ( REG_MSC_NOB(n) = nob )
+#define __msc_get_nob(n) ( REG_MSC_NOB(n) )
+#define __msc_set_blklen(n, len) ( REG_MSC_BLKLEN(n) = len )
+#define __msc_set_cmdat(n, cmdat) ( REG_MSC_CMDAT(n) = cmdat )
+#define __msc_set_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_IO_ABORT )
+#define __msc_clear_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_IO_ABORT )
+
+#define __msc_set_cmdat_bus_width1(n) \
+do { \
+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \
+ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_1BIT; \
+} while(0)
+
+#define __msc_set_cmdat_bus_width4(n) \
+do { \
+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \
+ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_4BIT; \
+} while(0)
+
+#define __msc_set_cmdat_dma_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DMA_EN )
+#define __msc_set_cmdat_init(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_INIT )
+#define __msc_set_cmdat_busy(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_BUSY )
+#define __msc_set_cmdat_stream(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_STREAM_BLOCK )
+#define __msc_set_cmdat_block(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_STREAM_BLOCK )
+#define __msc_set_cmdat_read(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_WRITE_READ )
+#define __msc_set_cmdat_write(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_WRITE_READ )
+#define __msc_set_cmdat_data_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DATA_EN )
+
+/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */
+#define __msc_set_cmdat_res_format(n, r) \
+do { \
+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \
+ REG_MSC_CMDAT(n) |= (r); \
+} while(0)
+
+#define __msc_clear_cmdat(n) \
+ REG_MSC_CMDAT(n) &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \
+ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \
+ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK )
+
+#define __msc_get_imask(n) ( REG_MSC_IMASK(n) )
+#define __msc_mask_all_intrs(n) ( REG_MSC_IMASK(n) = 0xff )
+#define __msc_unmask_all_intrs(n) ( REG_MSC_IMASK(n) = 0x00 )
+#define __msc_mask_rd(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_RXFIFO_RD_REQ )
+#define __msc_unmask_rd(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_RXFIFO_RD_REQ )
+#define __msc_mask_wr(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_TXFIFO_WR_REQ )
+#define __msc_unmask_wr(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_TXFIFO_WR_REQ )
+#define __msc_mask_endcmdres(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_END_CMD_RES )
+#define __msc_unmask_endcmdres(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_END_CMD_RES )
+#define __msc_mask_datatrandone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_DATA_TRAN_DONE )
+#define __msc_unmask_datatrandone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_DATA_TRAN_DONE )
+#define __msc_mask_prgdone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_PRG_DONE )
+#define __msc_unmask_prgdone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_PRG_DONE )
+
+/* m=0,1,2,3,4,5,6,7 */
+#define __msc_set_clkrt(n, m) \
+do { \
+ REG_MSC_CLKRT(n) = m; \
+} while(0)
+
+#define __msc_get_ireg(n) ( REG_MSC_IREG(n) )
+#define __msc_ireg_rd(n) ( REG_MSC_IREG(n) & MSC_IREG_RXFIFO_RD_REQ )
+#define __msc_ireg_wr(n) ( REG_MSC_IREG(n) & MSC_IREG_TXFIFO_WR_REQ )
+#define __msc_ireg_end_cmd_res(n) ( REG_MSC_IREG(n) & MSC_IREG_END_CMD_RES )
+#define __msc_ireg_data_tran_done(n) ( REG_MSC_IREG(n) & MSC_IREG_DATA_TRAN_DONE )
+#define __msc_ireg_prg_done(n) ( REG_MSC_IREG(n) & MSC_IREG_PRG_DONE )
+#define __msc_ireg_clear_end_cmd_res(n) ( REG_MSC_IREG(n) = MSC_IREG_END_CMD_RES )
+#define __msc_ireg_clear_data_tran_done(n) ( REG_MSC_IREG(n) = MSC_IREG_DATA_TRAN_DONE )
+#define __msc_ireg_clear_prg_done(n) ( REG_MSC_IREG(n) = MSC_IREG_PRG_DONE )
+
+#define __msc_get_stat(n) ( REG_MSC_STAT(n) )
+#define __msc_stat_not_end_cmd_res(n) ( (REG_MSC_STAT(n) & MSC_STAT_END_CMD_RES) == 0)
+#define __msc_stat_crc_err(n) \
+ ( REG_MSC_STAT(n) & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) )
+#define __msc_stat_res_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_RES_ERR )
+#define __msc_stat_rd_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_READ_ERROR )
+#define __msc_stat_wr_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_WRITE_ERROR_YES )
+#define __msc_stat_resto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_RES )
+#define __msc_stat_rdto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_READ )
+
+#define __msc_rd_resfifo(n) ( REG_MSC_RES(n) )
+#define __msc_rd_rxfifo(n) ( REG_MSC_RXFIFO(n) )
+#define __msc_wr_txfifo(n, v) ( REG_MSC_TXFIFO(n) = v )
+
+#define __msc_reset(n) \
+do { \
+ REG_MSC_STRPCL(n) = MSC_STRPCL_RESET; \
+ while (REG_MSC_STAT(n) & MSC_STAT_IS_RESETTING); \
+} while (0)
+
+#define __msc_start_clk(n) \
+do { \
+ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_START; \
+} while (0)
+
+#define __msc_stop_clk(n) \
+do { \
+ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_STOP; \
+} while (0)
+
+#define MMC_CLK 19169200
+#define SD_CLK 24576000
+
+/* msc_clk should little than pclk and little than clk retrieve from card */
+#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \
+do { \
+ unsigned int rate, pclk, i; \
+ pclk = dev_clk; \
+ rate = type?SD_CLK:MMC_CLK; \
+ if (msc_clk && msc_clk < pclk) \
+ pclk = msc_clk; \
+ i = 0; \
+ while (pclk < rate) \
+ { \
+ i ++; \
+ rate >>= 1; \
+ } \
+ lv = i; \
+} while(0)
+
+/* divide rate to little than or equal to 400kHz */
+#define __msc_calc_slow_clk_divisor(type, lv) \
+do { \
+ unsigned int rate, i; \
+ rate = (type?SD_CLK:MMC_CLK)/1000/400; \
+ i = 0; \
+ while (rate > 0) \
+ { \
+ rate >>= 1; \
+ i ++; \
+ } \
+ lv = i; \
+} while(0)
+
+
+/***************************************************************************
+ * SSI (Synchronous Serial Interface)
+ ***************************************************************************/
+/* n = 0, 1 (SSI0, SSI1) */
+#define __ssi_enable(n) ( REG_SSI_CR0(n) |= SSI_CR0_SSIE )
+#define __ssi_disable(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_SSIE )
+#define __ssi_select_ce(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_FSEL )
+
+#define __ssi_normal_mode(n) ( REG_SSI_ITR(n) &= ~SSI_ITR_IVLTM_MASK )
+
+#define __ssi_select_ce2(n) \
+do { \
+ REG_SSI_CR0(n) |= SSI_CR0_FSEL; \
+ REG_SSI_CR1(n) &= ~SSI_CR1_MULTS; \
+} while (0)
+
+#define __ssi_select_gpc(n) \
+do { \
+ REG_SSI_CR0(n) &= ~SSI_CR0_FSEL; \
+ REG_SSI_CR1(n) |= SSI_CR1_MULTS; \
+} while (0)
+
+#define __ssi_underrun_auto_clear(n) \
+do { \
+ REG_SSI_CR0(n) |= SSI_CR0_EACLRUN; \
+} while (0)
+
+#define __ssi_underrun_clear_manually(n) \
+do { \
+ REG_SSI_CR0(n) &= ~SSI_CR0_EACLRUN; \
+} while (0)
+
+#define __ssi_enable_tx_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_TIE | SSI_CR0_TEIE )
+
+#define __ssi_disable_tx_intr(n) \
+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) )
+
+#define __ssi_enable_rx_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_RIE | SSI_CR0_REIE )
+
+#define __ssi_disable_rx_intr(n) \
+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RIE | SSI_CR0_REIE) )
+
+#define __ssi_enable_txfifo_half_empty_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_TIE )
+#define __ssi_disable_txfifo_half_empty_intr(n) \
+ ( REG_SSI_CR0(n) &= ~SSI_CR0_TIE )
+#define __ssi_enable_tx_error_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_TEIE )
+#define __ssi_disable_tx_error_intr(n) \
+ ( REG_SSI_CR0(n) &= ~SSI_CR0_TEIE )
+#define __ssi_enable_rxfifo_half_full_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_RIE )
+#define __ssi_disable_rxfifo_half_full_intr(n) \
+ ( REG_SSI_CR0(n) &= ~SSI_CR0_RIE )
+#define __ssi_enable_rx_error_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_REIE )
+#define __ssi_disable_rx_error_intr(n) \
+ ( REG_SSI_CR0(n) &= ~SSI_CR0_REIE )
+
+#define __ssi_enable_loopback(n) ( REG_SSI_CR0(n) |= SSI_CR0_LOOP )
+#define __ssi_disable_loopback(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_LOOP )
+
+#define __ssi_enable_receive(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_DISREV )
+#define __ssi_disable_receive(n) ( REG_SSI_CR0(n) |= SSI_CR0_DISREV )
+
+#define __ssi_finish_receive(n) \
+ ( REG_SSI_CR0(n) |= (SSI_CR0_RFINE | SSI_CR0_RFINC) )
+
+#define __ssi_disable_recvfinish(n) \
+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) )
+
+#define __ssi_flush_txfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH )
+#define __ssi_flush_rxfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_RFLUSH )
+
+#define __ssi_flush_fifo(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH )
+
+#define __ssi_finish_transmit(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_UNFIN )
+#define __ssi_wait_transmit(n) ( REG_SSI_CR1(n) |= SSI_CR1_UNFIN )
+#define __ssi_use_busy_wait_mode(n) __ssi_wait_transmit(n)
+#define __ssi_unset_busy_wait_mode(n) __ssi_finish_transmit(n)
+
+#define __ssi_spi_format(n) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \
+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SPI; \
+ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \
+ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \
+ } while (0)
+
+/* TI's SSP format, must clear SSI_CR1.UNFIN */
+#define __ssi_ssp_format(n) \
+ do { \
+ REG_SSI_CR1(n) &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \
+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SSP; \
+ } while (0)
+
+/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */
+#define __ssi_microwire_format(n) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \
+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_MW1; \
+ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \
+ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \
+ REG_SSI_CR0(n) &= ~SSI_CR0_RFINE; \
+ } while (0)
+
+/* CE# level (FRMHL), CE# in interval time (ITFRM),
+ clock phase and polarity (PHA POL),
+ interval time (SSIITR), interval characters/frame (SSIICR) */
+
+/* frmhl,endian,mcom,flen,pha,pol MASK */
+#define SSICR1_MISC_MASK \
+ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \
+ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL )
+
+#define __ssi_spi_set_misc(n,frmhl,endian,flen,mcom,pha,pol) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSICR1_MISC_MASK; \
+ REG_SSI_CR1(n) |= ((frmhl) << 30) | ((endian) << 25) | \
+ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \
+ ((pha) << 1) | (pol); \
+ } while(0)
+
+/* Transfer with MSB or LSB first */
+#define __ssi_set_msb(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_LFST )
+#define __ssi_set_lsb(n) ( REG_SSI_CR1(n) |= SSI_CR1_LFST )
+
+#define __ssi_set_frame_length(n, m) \
+ REG_SSI_CR1(n) = (REG_SSI_CR1(n) & ~SSI_CR1_FLEN_MASK) | (((m) - 2) << 4)
+
+/* m = 1 - 16 */
+#define __ssi_set_microwire_command_length(n,m) \
+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##m##BIT) )
+
+/* Set the clock phase for SPI */
+#define __ssi_set_spi_clock_phase(n, m) \
+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_PHA) | (((m)&0x1)<< 1)))
+
+/* Set the clock polarity for SPI */
+#define __ssi_set_spi_clock_polarity(n, p) \
+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_POL) | ((p)&0x1)) )
+
+/* SSI tx trigger, m = i x 8 */
+#define __ssi_set_tx_trigger(n, m) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSI_CR1_TTRG_MASK; \
+ REG_SSI_CR1(n) |= ((m)/8)<<SSI_CR1_TTRG_BIT; \
+ } while (0)
+
+/* SSI rx trigger, m = i x 8 */
+#define __ssi_set_rx_trigger(n, m) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSI_CR1_RTRG_MASK; \
+ REG_SSI_CR1(n) |= ((m)/8)<<SSI_CR1_RTRG_BIT; \
+ } while (0)
+
+#define __ssi_get_txfifo_count(n) \
+ ( (REG_SSI_SR(n) & SSI_SR_TFIFONUM_MASK) >> SSI_SR_TFIFONUM_BIT )
+
+#define __ssi_get_rxfifo_count(n) \
+ ( (REG_SSI_SR(n) & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT )
+
+#define __ssi_transfer_end(n) ( REG_SSI_SR(n) & SSI_SR_END )
+#define __ssi_is_busy(n) ( REG_SSI_SR(n) & SSI_SR_BUSY )
+
+#define __ssi_txfifo_full(n) ( REG_SSI_SR(n) & SSI_SR_TFF )
+#define __ssi_rxfifo_empty(n) ( REG_SSI_SR(n) & SSI_SR_RFE )
+#define __ssi_rxfifo_half_full(n) ( REG_SSI_SR(n) & SSI_SR_RFHF )
+#define __ssi_txfifo_half_empty(n) ( REG_SSI_SR(n) & SSI_SR_TFHE )
+#define __ssi_underrun(n) ( REG_SSI_SR(n) & SSI_SR_UNDR )
+#define __ssi_overrun(n) ( REG_SSI_SR(n) & SSI_SR_OVER )
+#define __ssi_clear_underrun(n) ( REG_SSI_SR(n) = ~SSI_SR_UNDR )
+#define __ssi_clear_overrun(n) ( REG_SSI_SR(n) = ~SSI_SR_OVER )
+#define __ssi_clear_errors(n) ( REG_SSI_SR(n) &= ~(SSI_SR_UNDR | SSI_SR_OVER) )
+
+#define __ssi_set_clk(n, dev_clk, ssi_clk) \
+ ( REG_SSI_GR(n) = (dev_clk) / (2*(ssi_clk)) - 1 )
+
+#define __ssi_receive_data(n) REG_SSI_DR(n)
+#define __ssi_transmit_data(n, v) (REG_SSI_DR(n) = (v))
+
+
+/***************************************************************************
+ * CIM
+ ***************************************************************************/
+
+#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA )
+#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA )
+
+/* n = 0, 1, 2, 3 */
+#define __cim_set_input_data_stream_order(n) \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_ORDER_MASK; \
+ REG_CIM_CFG |= ((n)<<CIM_CFG_ORDER_BIT)&CIM_CFG_ORDER_MASK; \
+ } while (0)
+
+#define __cim_input_data_format_select_RGB() \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_DF_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DF_RGB; \
+ } while (0)
+
+#define __cim_input_data_format_select_YUV444() \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_DF_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DF_YUV444; \
+ } while (0)
+
+#define __cim_input_data_format_select_YUV422() \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_DF_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DF_YUV422; \
+ } while (0)
+
+#define __cim_input_data_format_select_ITU656() \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_DF_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DF_ITU656; \
+ } while (0)
+
+#define __cim_input_data_inverse() ( REG_CIM_CFG |= CIM_CFG_INV_DAT )
+#define __cim_input_data_normal() ( REG_CIM_CFG &= ~CIM_CFG_INV_DAT )
+
+#define __cim_vsync_active_low() ( REG_CIM_CFG |= CIM_CFG_VSP )
+#define __cim_vsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_VSP )
+
+#define __cim_hsync_active_low() ( REG_CIM_CFG |= CIM_CFG_HSP )
+#define __cim_hsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_HSP )
+
+#define __cim_sample_data_at_pclk_falling_edge() \
+ ( REG_CIM_CFG |= CIM_CFG_PCP )
+#define __cim_sample_data_at_pclk_rising_edge() \
+ ( REG_CIM_CFG &= ~CIM_CFG_PCP )
+
+#define __cim_enable_dummy_zero() ( REG_CIM_CFG |= CIM_CFG_DUMMY_ZERO )
+#define __cim_disable_dummy_zero() ( REG_CIM_CFG &= ~CIM_CFG_DUMMY_ZERO )
+
+#define __cim_select_external_vsync() ( REG_CIM_CFG |= CIM_CFG_EXT_VSYNC )
+#define __cim_select_internal_vsync() ( REG_CIM_CFG &= ~CIM_CFG_EXT_VSYNC )
+
+/* n=0-7 */
+#define __cim_set_data_packing_mode(n) \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_PACK_MASK; \
+ REG_CIM_CFG |= (CIM_CFG_PACK_##n); \
+} while (0)
+
+#define __cim_enable_bypass_func() (REG_CIM_CFG |= CIM_CFG_BYPASS)
+#define __cim_disable_bypass_func() (REG_CIM_CFG &= ~CIM_CFG_BYPASS_MASK)
+
+#define __cim_enable_ccir656_progressive_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_CPM; \
+} while (0)
+
+#define __cim_enable_ccir656_interlace_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_CIM; \
+} while (0)
+
+#define __cim_enable_gated_clock_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_GCM; \
+} while (0)
+
+#define __cim_enable_nongated_clock_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_NGCM; \
+} while (0)
+
+/* sclk:system bus clock
+ * mclk: CIM master clock
+ */
+#define __cim_set_master_clk(sclk, mclk) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_MCLKDIV_MASK; \
+ REG_CIM_CTRL |= (((sclk)/(mclk) - 1) << CIM_CTRL_MCLKDIV_BIT); \
+} while (0)
+/* n=1-16 */
+#define __cim_set_frame_rate(n) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_FRC_MASK; \
+ REG_CIM_CTRL |= CIM_CTRL_FRC_##n; \
+} while (0)
+
+#define __cim_enable_size_func() \
+ ( REG_CIM_CTRL |= CIM_CTRL_SIZEEN )
+#define __cim_disable_size_func() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_SIZEEN_MASK )
+
+#define __cim_enable_vdd_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_VDDM )
+#define __cim_disable_vdd_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_VDDM )
+
+#define __cim_enable_sof_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_SOFM )
+#define __cim_disable_sof_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_SOFM )
+
+#define __cim_enable_eof_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_EOFM )
+#define __cim_disable_eof_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EOFM )
+
+#define __cim_enable_stop_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_STOPM )
+#define __cim_disable_stop_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_STOPM )
+
+#define __cim_enable_trig_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_TRIGM )
+#define __cim_disable_trig_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIGM )
+
+#define __cim_enable_rxfifo_overflow_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_OFM )
+#define __cim_disable_rxfifo_overflow_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_OFM )
+
+/* n=4,8,12,16,20,24,28,32 */
+#define __cim_set_rxfifo_trigger(n) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \
+ REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \
+} while (0)
+#define __cim_enable_fast_mode() ( REG_CIM_CTRL |= CIM_CTRL_FAST_MODE )
+#define __cim_disable_fast_mode() ( REG_CIM_CTRL &= ~CIM_CTRL_FAST_MODE )
+#define __cim_use_normal_mode() __cim_disable_fast_mode()
+#define __cim_enable_dma() ( REG_CIM_CTRL |= CIM_CTRL_DMA_EN )
+#define __cim_disable_dma() ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EN )
+#define __cim_reset_rxfifo() ( REG_CIM_CTRL |= CIM_CTRL_RXF_RST )
+#define __cim_unreset_rxfifo() ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_RST )
+
+#define __cim_clear_state() ( REG_CIM_STATE = 0 )
+
+#define __cim_disable_done() ( REG_CIM_STATE & CIM_STATE_VDD )
+#define __cim_rxfifo_empty() ( REG_CIM_STATE & CIM_STATE_RXF_EMPTY )
+#define __cim_rxfifo_reach_trigger() ( REG_CIM_STATE & CIM_STATE_RXF_TRIG )
+#define __cim_rxfifo_overflow() ( REG_CIM_STATE & CIM_STATE_RXF_OF )
+#define __cim_clear_rxfifo_overflow() ( REG_CIM_STATE &= ~CIM_STATE_RXF_OF )
+#define __cim_dma_stop() ( REG_CIM_STATE & CIM_STATE_DMA_STOP )
+#define __cim_dma_eof() ( REG_CIM_STATE & CIM_STATE_DMA_EOF )
+#define __cim_dma_sof() ( REG_CIM_STATE & CIM_STATE_DMA_SOF )
+
+#define __cim_get_iid() ( REG_CIM_IID )
+#define __cim_get_fid() ( REG_CIM_FID )
+#define __cim_get_image_data() ( REG_CIM_RXFIFO )
+#define __cim_get_dma_cmd() ( REG_CIM_CMD )
+
+#define __cim_set_da(a) ( REG_CIM_DA = (a) )
+
+#define __cim_set_line(a) ( REG_CIM_SIZE = (REG_CIM_SIZE&(~CIM_SIZE_LPF_MASK))|((a)<<CIM_SIZE_LPF_BIT) )
+#define __cim_set_pixel(a) ( REG_CIM_SIZE = (REG_CIM_SIZE&(~CIM_SIZE_PPL_MASK))|((a)<<CIM_SIZE_PPL_BIT) )
+#define __cim_get_line() ((REG_CIM_SIZE&CIM_SIZE_LPF_MASK)>>CIM_SIZE_LPF_BIT)
+#define __cim_get_pixel() ((REG_CIM_SIZE&CIM_SIZE_PPL_MASK)>>CIM_SIZE_PPL_BIT)
+
+#define __cim_set_v_offset(a) ( REG_CIM_OFFSET = (REG_CIM_OFFSET&(~CIM_OFFSET_V_MASK)) | ((a)<<CIM_OFFSET_V_BIT) )
+#define __cim_set_h_offset(a) ( REG_CIM_OFFSET = (REG_CIM_OFFSET&(~CIM_OFFSET_H_MASK)) | ((a)<<CIM_OFFSET_H_BIT) )
+#define __cim_get_v_offset() ((REG_CIM_OFFSET&CIM_OFFSET_V_MASK)>>CIM_OFFSET_V_BIT)
+#define __cim_get_h_offset() ((REG_CIM_OFFSET&CIM_OFFSET_H_MASK)>>CIM_OFFSET_H_BIT)
+
+/*************************************************************************
+ * SLCD (Smart LCD Controller)
+ *************************************************************************/
+#define __slcd_set_data_18bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_18BIT )
+#define __slcd_set_data_16bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_16BIT )
+#define __slcd_set_data_8bit_x3() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x3 )
+#define __slcd_set_data_8bit_x2() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x2 )
+#define __slcd_set_data_8bit_x1() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x1 )
+#define __slcd_set_data_24bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_24BIT )
+#define __slcd_set_data_9bit_x2() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_9BIT_x2 )
+
+#define __slcd_set_cmd_16bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_16BIT )
+#define __slcd_set_cmd_8bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_8BIT )
+#define __slcd_set_cmd_18bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_18BIT )
+#define __slcd_set_cmd_24bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_24BIT )
+
+#define __slcd_set_cs_high() ( REG_SLCD_CFG |= SLCD_CFG_CS_ACTIVE_HIGH )
+#define __slcd_set_cs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_CS_ACTIVE_HIGH )
+
+#define __slcd_set_rs_high() ( REG_SLCD_CFG |= SLCD_CFG_RS_CMD_HIGH )
+#define __slcd_set_rs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_RS_CMD_HIGH )
+
+#define __slcd_set_clk_falling() ( REG_SLCD_CFG &= ~SLCD_CFG_CLK_ACTIVE_RISING )
+#define __slcd_set_clk_rising() ( REG_SLCD_CFG |= SLCD_CFG_CLK_ACTIVE_RISING )
+
+#define __slcd_set_parallel_type() ( REG_SLCD_CFG &= ~SLCD_CFG_TYPE_SERIAL )
+#define __slcd_set_serial_type() ( REG_SLCD_CFG |= SLCD_CFG_TYPE_SERIAL )
+
+/* SLCD Control Register */
+#define __slcd_enable_dma() ( REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN )
+#define __slcd_disable_dma() ( REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN )
+
+/* SLCD Status Register */
+#define __slcd_is_busy() ( REG_SLCD_STATE & SLCD_STATE_BUSY )
+
+/* SLCD Data Register */
+#define __slcd_set_cmd_rs() ( REG_SLCD_DATA |= SLCD_DATA_RS_COMMAND)
+#define __slcd_set_data_rs() ( REG_SLCD_DATA &= ~SLCD_DATA_RS_COMMAND)
+
+
+/***************************************************************************
+ * LCD
+ ***************************************************************************/
+
+/***************************************************************************
+ * LCD
+ ***************************************************************************/
+#define __lcd_as_smart_lcd() ( REG_LCD_CFG |= ( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD))
+#define __lcd_as_general_lcd() ( REG_LCD_CFG &= ~( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD))
+
+#define __lcd_enable_tvepeh() ( REG_LCD_CFG |= LCD_CFG_TVEPEH )
+#define __lcd_disable_tvepeh() ( REG_LCD_CFG &= ~LCD_CFG_TVEPEH )
+
+#define __lcd_enable_fuhold() ( REG_LCD_CFG |= LCD_CFG_FUHOLD )
+#define __lcd_disable_fuhold() ( REG_LCD_CFG &= ~LCD_CFG_FUHOLD )
+
+#define __lcd_des_8word() ( REG_LCD_CFG |= LCD_CFG_NEWDES )
+#define __lcd_des_4word() ( REG_LCD_CFG &= ~LCD_CFG_NEWDES )
+
+#define __lcd_enable_bypass_pal() ( REG_LCD_CFG |= LCD_CFG_PALBP )
+#define __lcd_disable_bypass_pal() ( REG_LCD_CFG &= ~LCD_CFG_PALBP )
+
+#define __lcd_set_lcdpnl_term() ( REG_LCD_CTRL |= LCD_CFG_TVEN )
+#define __lcd_set_tv_term() ( REG_LCD_CTRL &= ~LCD_CFG_TVEN )
+
+#define __lcd_enable_auto_recover() ( REG_LCD_CFG |= LCD_CFG_RECOVER )
+#define __lcd_disable_auto_recover() ( REG_LCD_CFG &= ~LCD_CFG_RECOVER )
+
+#define __lcd_enable_dither() ( REG_LCD_CFG |= LCD_CFG_DITHER )
+#define __lcd_disable_dither() ( REG_LCD_CFG &= ~LCD_CFG_DITHER )
+
+#define __lcd_disable_ps_mode() ( REG_LCD_CFG |= LCD_CFG_PSM )
+#define __lcd_enable_ps_mode() ( REG_LCD_CFG &= ~LCD_CFG_PSM )
+
+#define __lcd_disable_cls_mode() ( REG_LCD_CFG |= LCD_CFG_CLSM )
+#define __lcd_enable_cls_mode() ( REG_LCD_CFG &= ~LCD_CFG_CLSM )
+
+#define __lcd_disable_spl_mode() ( REG_LCD_CFG |= LCD_CFG_SPLM )
+#define __lcd_enable_spl_mode() ( REG_LCD_CFG &= ~LCD_CFG_SPLM )
+
+#define __lcd_disable_rev_mode() ( REG_LCD_CFG |= LCD_CFG_REVM )
+#define __lcd_enable_rev_mode() ( REG_LCD_CFG &= ~LCD_CFG_REVM )
+
+#define __lcd_disable_hsync_mode() ( REG_LCD_CFG |= LCD_CFG_HSYNM )
+#define __lcd_enable_hsync_mode() ( REG_LCD_CFG &= ~LCD_CFG_HSYNM )
+
+#define __lcd_disable_pclk_mode() ( REG_LCD_CFG |= LCD_CFG_PCLKM )
+#define __lcd_enable_pclk_mode() ( REG_LCD_CFG &= ~LCD_CFG_PCLKM )
+
+#define __lcd_normal_outdata() ( REG_LCD_CFG &= ~LCD_CFG_INVDAT )
+#define __lcd_inverse_outdata() ( REG_LCD_CFG |= LCD_CFG_INVDAT )
+
+#define __lcd_sync_input() ( REG_LCD_CFG |= LCD_CFG_SYNDIR_IN )
+#define __lcd_sync_output() ( REG_LCD_CFG &= ~LCD_CFG_SYNDIR_IN )
+
+#define __lcd_hsync_active_high() ( REG_LCD_CFG &= ~LCD_CFG_HSP )
+#define __lcd_hsync_active_low() ( REG_LCD_CFG |= LCD_CFG_HSP )
+
+#define __lcd_pclk_rising() ( REG_LCD_CFG &= ~LCD_CFG_PCP )
+#define __lcd_pclk_falling() ( REG_LCD_CFG |= LCD_CFG_PCP )
+
+#define __lcd_de_active_high() ( REG_LCD_CFG &= ~LCD_CFG_DEP )
+#define __lcd_de_active_low() ( REG_LCD_CFG |= LCD_CFG_DEP )
+
+#define __lcd_vsync_rising() ( REG_LCD_CFG &= ~LCD_CFG_VSP )
+#define __lcd_vsync_falling() ( REG_LCD_CFG |= LCD_CFG_VSP )
+
+#define __lcd_set_16_tftpnl() \
+ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_16BIT )
+
+#define __lcd_set_18_tftpnl() \
+ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_18BIT )
+
+#define __lcd_set_24_tftpnl() ( REG_LCD_CFG |= LCD_CFG_MODE_TFT_24BIT )
+
+/*
+ * n=1,2,4,8 for single mono-STN
+ * n=4,8 for dual mono-STN
+ */
+#define __lcd_set_panel_datawidth(n) \
+do { \
+ REG_LCD_CFG &= ~LCD_CFG_PDW_MASK; \
+ REG_LCD_CFG |= LCD_CFG_PDW_n##; \
+} while (0)
+
+/* m = LCD_CFG_MODE_GENERUIC_TFT_xxx */
+#define __lcd_set_panel_mode(m) \
+do { \
+ REG_LCD_CFG &= ~LCD_CFG_MODE_MASK; \
+ REG_LCD_CFG |= (m); \
+} while(0)
+
+/* n=4,8,16 */
+#define __lcd_set_burst_length(n) \
+do { \
+ REG_LCD_CTRL &= ~LCD_CTRL_BST_MASK; \
+ REG_LCD_CTRL |= LCD_CTRL_BST_n##; \
+} while (0)
+
+#define __lcd_select_rgb565() ( REG_LCD_CTRL &= ~LCD_CTRL_RGB555 )
+#define __lcd_select_rgb555() ( REG_LCD_CTRL |= LCD_CTRL_RGB555 )
+
+#define __lcd_set_ofup() ( REG_LCD_CTRL |= LCD_CTRL_OFUP )
+#define __lcd_clr_ofup() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUP )
+
+/* n=2,4,16 */
+#define __lcd_set_stn_frc(n) \
+do { \
+ REG_LCD_CTRL &= ~LCD_CTRL_FRC_MASK; \
+ REG_LCD_CTRL |= LCD_CTRL_FRC_n##; \
+} while (0)
+
+#define __lcd_enable_eof_intr() ( REG_LCD_CTRL |= LCD_CTRL_EOFM )
+#define __lcd_disable_eof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_EOFM )
+
+#define __lcd_enable_sof_intr() ( REG_LCD_CTRL |= LCD_CTRL_SOFM )
+#define __lcd_disable_sof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_SOFM )
+
+#define __lcd_enable_ofu_intr() ( REG_LCD_CTRL |= LCD_CTRL_OFUM )
+#define __lcd_disable_ofu_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUM )
+
+#define __lcd_enable_ifu0_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM0 )
+#define __lcd_disable_ifu0_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM0 )
+
+#define __lcd_enable_ifu1_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM1 )
+#define __lcd_disable_ifu1_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM1 )
+
+#define __lcd_enable_ldd_intr() ( REG_LCD_CTRL |= LCD_CTRL_LDDM )
+#define __lcd_disable_ldd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_LDDM )
+
+#define __lcd_enable_qd_intr() ( REG_LCD_CTRL |= LCD_CTRL_QDM )
+#define __lcd_disable_qd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_QDM )
+
+#define __lcd_reverse_byte_endian() ( REG_LCD_CTRL |= LCD_CTRL_BEDN )
+#define __lcd_normal_byte_endian() ( REG_LCD_CTRL &= ~LCD_CTRL_BEDN )
+
+#define __lcd_pixel_endian_little() ( REG_LCD_CTRL |= LCD_CTRL_PEDN )
+#define __lcd_pixel_endian_big() ( REG_LCD_CTRL &= ~LCD_CTRL_PEDN )
+
+#define __lcd_set_dis() ( REG_LCD_CTRL |= LCD_CTRL_DIS )
+#define __lcd_clr_dis() ( REG_LCD_CTRL &= ~LCD_CTRL_DIS )
+
+#define __lcd_set_ena() ( REG_LCD_CTRL |= LCD_CTRL_ENA )
+#define __lcd_clr_ena() ( REG_LCD_CTRL &= ~LCD_CTRL_ENA )
+
+/* n=1,2,4,8,16 */
+#define __lcd_set_bpp(n) \
+ ( REG_LCD_CTRL = (REG_LCD_CTRL & ~LCD_CTRL_BPP_MASK) | LCD_CTRL_BPP_##n )
+
+/* LCD status register indication */
+
+#define __lcd_quick_disable_done() ( REG_LCD_STATE & LCD_STATE_QD )
+#define __lcd_disable_done() ( REG_LCD_STATE & LCD_STATE_LDD )
+#define __lcd_infifo0_underrun() ( REG_LCD_STATE & LCD_STATE_IFU0 )
+#define __lcd_infifo1_underrun() ( REG_LCD_STATE & LCD_STATE_IFU1 )
+#define __lcd_outfifo_underrun() ( REG_LCD_STATE & LCD_STATE_OFU )
+#define __lcd_start_of_frame() ( REG_LCD_STATE & LCD_STATE_SOF )
+#define __lcd_end_of_frame() ( REG_LCD_STATE & LCD_STATE_EOF )
+
+#define __lcd_clr_outfifounderrun() ( REG_LCD_STATE &= ~LCD_STATE_OFU )
+#define __lcd_clr_sof() ( REG_LCD_STATE &= ~LCD_STATE_SOF )
+#define __lcd_clr_eof() ( REG_LCD_STATE &= ~LCD_STATE_EOF )
+
+/* OSD functions */
+#define __lcd_enable_osd() (REG_LCD_OSDC |= LCD_OSDC_OSDEN)
+#define __lcd_enable_f0() (REG_LCD_OSDC |= LCD_OSDC_F0EN)
+#define __lcd_enable_f1() (REG_LCD_OSDC |= LCD_OSDC_F1EN)
+#define __lcd_enable_alpha() (REG_LCD_OSDC |= LCD_OSDC_ALPHAEN)
+#define __lcd_enable_alphamd() (REG_LCD_OSDC |= LCD_OSDC_ALPHAMD)
+
+#define __lcd_disable_osd() (REG_LCD_OSDC &= ~LCD_OSDC_OSDEN)
+#define __lcd_disable_f0() (REG_LCD_OSDC &= ~LCD_OSDC_F0EN)
+#define __lcd_disable_f1() (REG_LCD_OSDC &= ~LCD_OSDC_F1EN)
+#define __lcd_disable_alpha() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAEN)
+#define __lcd_disable_alphamd() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAMD)
+
+/* OSD Controll Register */
+#define __lcd_fg1_use_ipu() (REG_LCD_OSDCTRL |= LCD_OSDCTRL_IPU)
+#define __lcd_fg1_use_dma_chan1() (REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_IPU)
+#define __lcd_fg1_unuse_ipu() __lcd_fg1_use_dma_chan1()
+#define __lcd_osd_rgb555_mode() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_RGB555 )
+#define __lcd_osd_rgb565_mode() ( REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_RGB555 )
+#define __lcd_osd_change_size() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES )
+#define __lcd_osd_bpp_15_16() \
+ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_15_16 )
+#define __lcd_osd_bpp_18_24() \
+ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_18_24 )
+
+/* OSD State Register */
+#define __lcd_start_of_fg1() ( REG_LCD_STATE & LCD_OSDS_SOF1 )
+#define __lcd_end_of_fg1() ( REG_LCD_STATE & LCD_OSDS_EOF1 )
+#define __lcd_start_of_fg0() ( REG_LCD_STATE & LCD_OSDS_SOF0 )
+#define __lcd_end_of_fg0() ( REG_LCD_STATE & LCD_OSDS_EOF0 )
+#define __lcd_change_is_rdy() ( REG_LCD_STATE & LCD_OSDS_READY )
+
+/* Foreground Color Key Register 0,1(foreground 0, foreground 1) */
+#define __lcd_enable_colorkey0() (REG_LCD_KEY0 |= LCD_KEY_KEYEN)
+#define __lcd_enable_colorkey1() (REG_LCD_KEY1 |= LCD_KEY_KEYEN)
+#define __lcd_enable_colorkey0_md() (REG_LCD_KEY0 |= LCD_KEY_KEYMD)
+#define __lcd_enable_colorkey1_md() (REG_LCD_KEY1 |= LCD_KEY_KEYMD)
+#define __lcd_set_colorkey0(key) (REG_LCD_KEY0 = (REG_LCD_KEY0&~0xFFFFFF)|(key))
+#define __lcd_set_colorkey1(key) (REG_LCD_KEY1 = (REG_LCD_KEY1&~0xFFFFFF)|(key))
+
+#define __lcd_disable_colorkey0() (REG_LCD_KEY0 &= ~LCD_KEY_KEYEN)
+#define __lcd_disable_colorkey1() (REG_LCD_KEY1 &= ~LCD_KEY_KEYEN)
+#define __lcd_disable_colorkey0_md() (REG_LCD_KEY0 &= ~LCD_KEY_KEYMD)
+#define __lcd_disable_colorkey1_md() (REG_LCD_KEY1 &= ~LCD_KEY_KEYMD)
+
+/* IPU Restart Register */
+#define __lcd_enable_ipu_restart() (REG_LCD_IPUR |= LCD_IPUR_IPUREN)
+#define __lcd_disable_ipu_restart() (REG_LCD_IPUR &= ~LCD_IPUR_IPUREN)
+#define __lcd_set_ipu_restart_triger(n) (REG_LCD_IPUR = (REG_LCD_IPUR&(~0xFFFFFF))|(n))
+
+/* RGB Control Register */
+#define __lcd_enable_rgb_dummy() (REG_LCD_RGBC |= LCD_RGBC_RGBDM)
+#define __lcd_disable_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_RGBDM)
+
+#define __lcd_dummy_rgb() (REG_LCD_RGBC |= LCD_RGBC_DMM)
+#define __lcd_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_DMM)
+
+#define __lcd_rgb2ycc() (REG_LCD_RGBC |= LCD_RGBC_YCC)
+#define __lcd_notrgb2ycc() (REG_LCD_RGBC &= ~LCD_RGBC_YCC)
+
+#define __lcd_odd_mode_rgb() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RGB )
+#define __lcd_odd_mode_rbg() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RBG )
+#define __lcd_odd_mode_grb() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GRB)
+
+#define __lcd_odd_mode_gbr() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GBR)
+#define __lcd_odd_mode_brg() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BRG)
+#define __lcd_odd_mode_bgr() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BGR)
+
+#define __lcd_even_mode_rgb() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RGB )
+#define __lcd_even_mode_rbg() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RBG )
+#define __lcd_even_mode_grb() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GRB)
+
+#define __lcd_even_mode_gbr() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GBR)
+#define __lcd_even_mode_brg() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BRG)
+#define __lcd_even_mode_bgr() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BGR)
+
+/* Vertical Synchronize Register */
+#define __lcd_vsync_get_vps() \
+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPS_MASK) >> LCD_VSYNC_VPS_BIT )
+
+#define __lcd_vsync_get_vpe() \
+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT )
+#define __lcd_vsync_set_vpe(n) \
+do { \
+ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \
+ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \
+} while (0)
+
+#define __lcd_hsync_get_hps() \
+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT )
+#define __lcd_hsync_set_hps(n) \
+do { \
+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \
+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \
+} while (0)
+
+#define __lcd_hsync_get_hpe() \
+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT )
+#define __lcd_hsync_set_hpe(n) \
+do { \
+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \
+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \
+} while (0)
+
+#define __lcd_vat_get_ht() \
+ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT )
+#define __lcd_vat_set_ht(n) \
+do { \
+ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \
+ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \
+} while (0)
+
+#define __lcd_vat_get_vt() \
+ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT )
+#define __lcd_vat_set_vt(n) \
+do { \
+ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \
+ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \
+} while (0)
+
+#define __lcd_dah_get_hds() \
+ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT )
+#define __lcd_dah_set_hds(n) \
+do { \
+ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \
+ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \
+} while (0)
+
+#define __lcd_dah_get_hde() \
+ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT )
+#define __lcd_dah_set_hde(n) \
+do { \
+ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \
+ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \
+} while (0)
+
+#define __lcd_dav_get_vds() \
+ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT )
+#define __lcd_dav_set_vds(n) \
+do { \
+ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \
+ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \
+} while (0)
+
+#define __lcd_dav_get_vde() \
+ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT )
+#define __lcd_dav_set_vde(n) \
+do { \
+ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \
+ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \
+} while (0)
+
+/* DMA Command Register */
+#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT )
+#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT )
+#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT )
+#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT )
+
+#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT )
+#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT )
+#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT )
+#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT )
+
+#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL )
+#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL )
+
+#define __lcd_cmd0_get_len() \
+ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT )
+#define __lcd_cmd1_get_len() \
+ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT )
+
+/*************************************************************************
+ * TVE (TV Encoder Controller) ops
+ *************************************************************************/
+/* TV Encoder Control register ops */
+#define __tve_soft_reset() (REG_TVE_CTRL |= TVE_CTRL_SWRST)
+
+#define __tve_output_colorbar() (REG_TVE_CTRL |= TVE_CTRL_CLBAR)
+#define __tve_output_video() (REG_TVE_CTRL &= ~TVE_CTRL_CLBAR)
+
+#define __tve_input_cr_first() (REG_TVE_CTRL |= TVE_CTRL_CR1ST)
+#define __tve_input_cb_first() (REG_TVE_CTRL &= ~TVE_CTRL_CR1ST)
+
+#define __tve_set_0_as_black() (REG_TVE_CTRL |= TVE_CTRL_ZBLACK)
+#define __tve_set_16_as_black() (REG_TVE_CTRL &= ~TVE_CTRL_ZBLACK)
+
+#define __tve_ena_invert_top_bottom() (REG_TVE_CTRL |= TVE_CTRL_FINV)
+#define __tve_dis_invert_top_bottom() (REG_TVE_CTRL &= ~TVE_CTRL_FINV)
+
+#define __tve_set_pal_mode() (REG_TVE_CTRL |= TVE_CTRL_PAL)
+#define __tve_set_ntsc_mode() (REG_TVE_CTRL &= ~TVE_CTRL_PAL)
+
+#define __tve_set_pal_dura() (REG_TVE_CTRL |= TVE_CTRL_SYNCT)
+#define __tve_set_ntsc_dura() (REG_TVE_CTRL &= ~TVE_CTRL_SYNCT)
+
+/* n = 0 ~ 3 */
+#define __tve_set_c_bandwidth(n) \
+do {\
+ REG_TVE_CTRL &= ~TVE_CTRL_CBW_MASK;\
+ REG_TVE_CTRL |= (n) << TVE_CTRL_CBW_BIT; \
+}while(0)
+
+/* n = 0 ~ 3 */
+#define __tve_set_c_gain(n) \
+do {\
+ REG_TVE_CTRL &= ~TVE_CTRL_CGAIN_MASK;\
+ (REG_TVE_CTRL |= (n) << TVE_CTRL_CGAIN_BIT; \
+}while(0)
+
+/* n = 0 ~ 7 */
+#define __tve_set_yc_delay(n) \
+do { \
+ REG_TVE_CTRL &= ~TVE_CTRL_YCDLY_MASK \
+ REG_TVE_CTRL |= ((n) << TVE_CTRL_YCDLY_BIT); \
+} while(0)
+
+#define __tve_disable_all_dacs() (REG_TVE_CTRL |= TVE_CTRL_DAPD)
+#define __tve_disable_dac1() (REG_TVE_CTRL |= TVE_CTRL_DAPD1)
+#define __tve_enable_dac1() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD1)
+#define __tve_disable_dac2() (REG_TVE_CTRL |= TVE_CTRL_DAPD2)
+#define __tve_enable_dac2() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD2)
+#define __tve_disable_dac3() (REG_TVE_CTRL |= TVE_CTRL_DAPD3)
+#define __tve_enable_dac3() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD3)
+
+#define __tve_enable_svideo_fmt() (REG_TVE_CTRL |= TVE_CTRL_ECVBS)
+#define __tve_enable_cvbs_fmt() (REG_TVE_CTRL &= ~TVE_CTRL_ECVBS)
+
+/* TV Encoder Frame Configure register ops */
+/* n = 0 ~ 255 */
+#define __tve_set_first_video_line(n) \
+do {\
+ REG_TVE_FRCFG &= ~TVE_FRCFG_L1ST_MASK;\
+ REG_TVE_FRCFG |= (n) << TVE_FRCFG_L1ST_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_line_num_per_frm(n) \
+do {\
+ REG_TVE_FRCFG &= ~TVE_FRCFG_NLINE_MASK;\
+ REG_TVE_CFG |= (n) << TVE_FRCFG_NLINE_BIT;\
+} while(0)
+#define __tve_get_video_line_num()\
+ (((REG_TVE_FRCFG & TVE_FRCFG_NLINE_MASK) >> TVE_FRCFG_NLINE_BIT) - 1 - 2 * ((REG_TVE_FRCFG & TVE_FRCFG_L1ST_MASK) >> TVE_FRCFG_L1ST_BIT))
+
+/* TV Encoder Signal Level Configure register ops */
+/* n = 0 ~ 1023 */
+#define __tve_set_white_level(n) \
+do {\
+ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_WHITEL_MASK;\
+ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_WHITEL_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_black_level(n) \
+do {\
+ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_BLACKL_MASK;\
+ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_BLACKL_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_blank_level(n) \
+do {\
+ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_BLANKL_MASK;\
+ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_BLANKL_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_vbi_blank_level(n) \
+do {\
+ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_VBLANKL_MASK;\
+ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_VBLANKL_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_sync_level(n) \
+do {\
+ REG_TVE_SLCFG3 &= ~TVE_SLCFG3_SYNCL_MASK;\
+ REG_TVE_SLCFG3 |= (n) << TVE_SLCFG3_SYNCL_BIT;\
+} while(0)
+
+/* TV Encoder Signal Level Configure register ops */
+/* n = 0 ~ 31 */
+#define __tve_set_front_porch(n) \
+do {\
+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_FRONTP_MASK;\
+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_FRONTP_BIT; \
+} while(0)
+/* n = 0 ~ 127 */
+#define __tve_set_hsync_width(n) \
+do {\
+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_HSYNCW_MASK;\
+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_HSYNCW_BIT; \
+} while(0)
+/* n = 0 ~ 127 */
+#define __tve_set_back_porch(n) \
+do {\
+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_BACKP_MASK;\
+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_BACKP_BIT; \
+} while(0)
+/* n = 0 ~ 2047 */
+#define __tve_set_active_linec(n) \
+do {\
+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_ACTLIN_MASK;\
+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_ACTLIN_BIT; \
+} while(0)
+/* n = 0 ~ 31 */
+#define __tve_set_breezy_way(n) \
+do {\
+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_PREBW_MASK;\
+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_PREBW_BIT; \
+} while(0)
+
+/* n = 0 ~ 127 */
+#define __tve_set_burst_width(n) \
+do {\
+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_BURSTW_MASK;\
+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_BURSTW_BIT; \
+} while(0)
+
+/* TV Encoder Chrominance filter and Modulation register ops */
+/* n = 0 ~ (2^32-1) */
+#define __tve_set_c_sub_carrier_freq(n) REG_TVE_CFREQ = (n)
+/* n = 0 ~ 255 */
+#define __tve_set_c_sub_carrier_init_phase(n) \
+do { \
+ REG_TVE_CPHASE &= ~TVE_CPHASE_INITPH_MASK; \
+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_INITPH_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_c_sub_carrier_act_phase(n) \
+do { \
+ REG_TVE_CPHASE &= ~TVE_CPHASE_ACTPH_MASK; \
+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_ACTPH_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_c_phase_rst_period(n) \
+do { \
+ REG_TVE_CPHASE &= ~TVE_CPHASE_CCRSTP_MASK; \
+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_CCRSTP_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_cb_burst_amp(n) \
+do { \
+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBBA_MASK; \
+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBBA_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_cr_burst_amp(n) \
+do { \
+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRBA_MASK; \
+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRBA_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_cb_gain_amp(n) \
+do { \
+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBGAIN_MASK; \
+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBGAIN_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_cr_gain_amp(n) \
+do { \
+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRGAIN_MASK; \
+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRGAIN_BIT; \
+} while(0)
+
+/* TV Encoder Wide Screen Signal Control register ops */
+/* n = 0 ~ 7 */
+#define __tve_set_notch_freq(n) \
+do { \
+ REG_TVE_WSSCR &= ~TVE_WSSCR_NCHFREQ_MASK; \
+ REG_TVE_WSSCR |= (n) << TVE_WSSCR_NCHFREQ_BIT; \
+} while(0)
+/* n = 0 ~ 7 */
+#define __tve_set_notch_width() (REG_TVE_WSSCR |= TVE_WSSCR_NCHW_BIT)
+#define __tve_clear_notch_width() (REG_TVE_WSSCR &= ~TVE_WSSCR_NCHW_BIT)
+#define __tve_enable_notch() (REG_TVE_WSSCR |= TVE_WSSCR_ENCH_BIT)
+#define __tve_disable_notch() (REG_TVE_WSSCR &= ~TVE_WSSCR_ENCH_BIT)
+/* n = 0 ~ 7 */
+#define __tve_set_wss_edge(n) \
+do { \
+ REG_TVE_WSSCR &= ~TVE_WSSCR_WSSEDGE_MASK; \
+ REG_TVE_WSSCR |= (n) << TVE_WSSCR_WSSEDGE_BIT; \
+} while(0)
+#define __tve_set_wss_clkbyp() (REG_TVE_WSSCR |= TVE_WSSCR_WSSCKBP_BIT)
+#define __tve_set_wss_type() (REG_TVE_WSSCR |= TVE_WSSCR_WSSTP_BIT)
+#define __tve_enable_wssf1() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS1_BIT)
+#define __tve_enable_wssf0() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS0_BIT)
+
+/* TV Encoder Wide Screen Signal Configure register 1, 2 and 3 ops */
+/* n = 0 ~ 1023 */
+#define __tve_set_wss_level(n) \
+do { \
+ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSL_MASK; \
+ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSL_BIT; \
+} while(0)
+/* n = 0 ~ 4095 */
+#define __tve_set_wss_freq(n) \
+do { \
+ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSFREQ_MASK; \
+ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSFREQ_BIT; \
+} while(0)
+/* n = 0, 1; l = 0 ~ 255 */
+#define __tve_set_wss_line(n,v) \
+do { \
+ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \
+ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \
+} while(0)
+/* n = 0, 1; d = 0 ~ (2^20-1) */
+#define __tve_set_wss_data(n, v) \
+do { \
+ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \
+ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \
+} while(0)
+
+/***************************************************************************
+ * RTC ops
+ ***************************************************************************/
+
+#define __rtc_write_ready() ( (REG_RTC_RCR & RTC_RCR_WRDY) >> RTC_RCR_WRDY_BIT )
+#define __rtc_enabled() ( REG_RTC_RCR |= RTC_RCR_RTCE )
+#define __rtc_disabled() ( REG_RTC_RCR &= ~RTC_RCR_RTCE )
+#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE )
+#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE )
+#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE )
+#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE )
+#define __rtc_enable_1Hz_irq() ( REG_RTC_RCR |= RTC_RCR_1HZIE )
+#define __rtc_disable_1Hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_1HZIE )
+
+#define __rtc_get_1Hz_flag() ( (REG_RTC_RCR >> RTC_RCR_1HZ_BIT) & 0x1 )
+#define __rtc_clear_1Hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_1HZ )
+#define __rtc_get_alarm_flag() ( (REG_RTC_RCR >> RTC_RCR_AF_BIT) & 0x1 )
+#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF )
+
+#define __rtc_get_second() ( REG_RTC_RSR )
+#define __rtc_set_second(v) ( REG_RTC_RSR = v )
+
+#define __rtc_get_alarm_second() ( REG_RTC_RSAR )
+#define __rtc_set_alarm_second(v) ( REG_RTC_RSAR = v )
+
+#define __rtc_RGR_is_locked() ( (REG_RTC_RGR >> RTC_RGR_LOCK) )
+#define __rtc_lock_RGR() ( REG_RTC_RGR |= RTC_RGR_LOCK )
+#define __rtc_unlock_RGR() ( REG_RTC_RGR &= ~RTC_RGR_LOCK )
+#define __rtc_get_adjc_val() ( (REG_RTC_RGR & RTC_RGR_ADJC_MASK) >> RTC_RGR_ADJC_BIT )
+#define __rtc_set_adjc_val(v) \
+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_ADJC_MASK) | (v << RTC_RGR_ADJC_BIT) ))
+#define __rtc_get_nc1Hz_val() ( (REG_RTC_RGR & RTC_RGR_NC1HZ_MASK) >> RTC_RGR_NC1HZ_BIT )
+#define __rtc_set_nc1Hz_val(v) \
+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_NC1HZ_MASK) | (v << RTC_RGR_NC1HZ_BIT) ))
+
+#define __rtc_power_down() ( REG_RTC_HCR |= RTC_HCR_PD )
+
+#define __rtc_get_hwfcr_val() ( REG_RTC_HWFCR & RTC_HWFCR_MASK )
+#define __rtc_set_hwfcr_val(v) ( REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK )
+#define __rtc_get_hrcr_val() ( REG_RTC_HRCR & RTC_HRCR_MASK )
+#define __rtc_set_hrcr_val(v) ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK )
+
+#define __rtc_enable_alarm_wakeup() ( REG_RTC_HWCR |= RTC_HWCR_EALM )
+#define __rtc_disable_alarm_wakeup() ( REG_RTC_HWCR &= ~RTC_HWCR_EALM )
+
+#define __rtc_status_hib_reset_occur() ( REG_RTC_HWRSR & RTC_HWRSR_HR )
+#define __rtc_status_ppr_reset_occur() ( REG_RTC_HWRSR & RTC_HWRSR_PPR )
+#define __rtc_status_wakeup_pin_waken_up() ( REG_RTC_HWRSR & RTC_HWRSR_PIN )
+#define __rtc_status_alarm_waken_up() ( REG_RTC_HWRSR & RTC_HWRSR_ALM )
+#define __rtc_clear_hib_stat_all() ( REG_RTC_HWRSR = 0 )
+
+#define __rtc_get_scratch_pattern() (REG_RTC_HSPR)
+#define __rtc_set_scratch_pattern(n) (REG_RTC_HSPR = n )
+
+/*************************************************************************
+ * BCH
+ *************************************************************************/
+#define __ecc_encoding_4bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \
+ REG_BCH_CRC = BCH_CR_BSEL8; \
+} while(0)
+#define __ecc_decoding_4bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BCHE; \
+ REG_BCH_CRC = BCH_CR_ENCE | BCH_CR_BSEL8; \
+} while(0)
+#define __ecc_encoding_8bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \
+} while(0)
+#define __ecc_decoding_8bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \
+ REG_BCH_CRC = BCH_CR_ENCE; \
+} while(0)
+#define __ecc_dma_enable() ( REG_BCH_CRS = BCH_CR_DMAE )
+#define __ecc_dma_disable() ( REG_BCH_CRC = BCH_CR_DMAE )
+#define __ecc_disable() ( REG_BCH_CRC = BCH_CR_BCHE )
+#define __ecc_encode_sync() while (!(REG_BCH_INTS & BCH_INTS_ENCF))
+#define __ecc_decode_sync() while (!(REG_BCH_INTS & BCH_INTS_DECF))
+#define __ecc_cnt_dec(n) \
+do { \
+ REG_BCH_CNT &= ~(BCH_CNT_DEC_MASK << BCH_CNT_DEC_BIT); \
+ REG_BCH_CNT = (n) << BCH_CNT_DEC_BIT; \
+} while(0)
+#define __ecc_cnt_enc(n) \
+do { \
+ REG_BCH_CNT &= ~(BCH_CNT_ENC_MASK << BCH_CNT_ENC_BIT); \
+ REG_BCH_CNT = (n) << BCH_CNT_ENC_BIT; \
+} while(0)
+
+/***************************************************************************
+ * OWI (one-wire bus) ops
+ ***************************************************************************/
+
+/* OW control register ops */
+#define __owi_enable_all_interrupts() ( REG_OWI_CTL = (OWI_CTL_EBYTE | OWI_CTL_EBIT | OWI_CTL_ERST) )
+#define __owi_disable_all_interrupts() ( REG_OWI_CTL = 0 )
+
+#define __owi_enable_byte_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBYTE )
+#define __owi_disable_byte_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBYTE )
+#define __owi_enable_bit_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBIT )
+#define __owi_disable_bit_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBIT )
+#define __owi_enable_rst_interrupt() ( REG_OWI_CTL |= OWI_CTL_ERST )
+#define __owi_disable_rst_interrupt() ( REG_OWI_CTL &=~OWI_CTL_ERST )
+
+/* OW configure register ops */
+#define __owi_select_regular_mode() ( REG_OWI_CFG &= ~OWI_CFG_MODE )
+#define __owi_select_overdrive_mode() ( REG_OWI_CFG |= OWI_CFG_MODE )
+
+#define __owi_set_rddata() ( REG_OWI_CFG |= OWI_CFG_RDDATA )
+#define __owi_clr_rddata() ( REG_OWI_CFG &= ~OWI_CFG_RDDATA )
+#define __owi_get_rddata() ( REG_OWI_CFG & OWI_CFG_RDDATA )
+
+#define __owi_set_wrdata() ( REG_OWI_CFG |= OWI_CFG_WRDATA )
+#define __owi_clr_wrdata() ( REG_OWI_CFG &= ~OWI_CFG_WRDATA )
+#define __owi_get_wrdata() ( REG_OWI_CFG & OWI_CFG_WRDATA )
+
+#define __owi_get_rdst() ( REG_OWI_CFG & OWI_CFG_RDST )
+
+#define __owi_set_wr1rd() ( REG_OWI_CFG |= OWI_CFG_WR1RD )
+#define __owi_clr_wr1rd() ( REG_OWI_CFG &= ~OWI_CFG_WR1RD )
+#define __owi_get_wr1rd() ( REG_OWI_CFG & OWI_CFG_WR1RD )
+
+#define __owi_set_wr0() ( REG_OWI_CFG |= OWI_CFG_WR0 )
+#define __owi_clr_wr0() ( REG_OWI_CFG &= ~OWI_CFG_WR0 )
+#define __owi_get_wr0() ( REG_OWI_CFG & OWI_CFG_WR0 )
+
+#define __owi_set_rst() ( REG_OWI_CFG |= OWI_CFG_RST )
+#define __owi_clr_rst() ( REG_OWI_CFG &= ~OWI_CFG_RST )
+#define __owi_get_rst() ( REG_OWI_CFG & OWI_CFG_RST )
+
+#define __owi_enable_ow_ops() ( REG_OWI_CFG |= OWI_CFG_ENA )
+#define __owi_disable_ow_ops() ( REG_OWI_CFG &= ~OWI_CFG_ENA )
+#define __owi_get_enable() ( REG_OWI_CFG & OWI_CFG_ENA )
+
+#define __owi_wait_ops_rdy() \
+ do { \
+ while(__owi_get_enable()); \
+ udelay(1); \
+ } while(0);
+
+/* OW status register ops */
+#define __owi_clr_sts() ( REG_OWI_STS = 0 )
+#define __owi_get_sts_pst() ( REG_OWI_STS & OWI_STS_PST )
+#define __owi_get_sts_byte_rdy() ( REG_OWI_STS & OWI_STS_BYTE_RDY )
+#define __owi_get_sts_bit_rdy() ( REG_OWI_STS & OWI_STS_BIT_RDY )
+#define __owi_get_sts_pst_rdy() ( REG_OWI_STS & OWI_STS_PST_RDY )
+
+/*************************************************************************
+ * TSSI MPEG 2-TS slave interface operation
+ *************************************************************************/
+#define __tssi_enable() ( REG_TSSI_ENA |= TSSI_ENA_ENA )
+#define __tssi_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_ENA )
+#define __tssi_soft_reset() ( REG_TSSI_ENA |= TSSI_ENA_SFT_RST )
+#define __tssi_dma_enable() ( REG_TSSI_ENA |= TSSI_ENA_DMA_EN )
+#define __tssi_dma_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_DMA_EN )
+#define __tssi_filter_enable() ( REG_TSSI_ENA |= TSSI_ENA_PID_EN )
+#define __tssi_filter_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_PID_EN )
+
+/* n = 4, 8, 16 */
+#define __tssi_set_tigger_num(n) \
+ do { \
+ REG_TSSI_CFG &= ~TSSI_CFG_TRIG_MASK; \
+ REG_TSSI_CFG |= TSSI_CFG_TRIG_##n; \
+ } while (0)
+
+#define __tssi_set_wd_1() ( REG_TSSI_CFG |= TSSI_CFG_END_WD )
+#define __tssi_set_wd_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_WD )
+
+#define __tssi_set_bt_1() ( REG_TSSI_CFG |= TSSI_CFG_END_BD )
+#define __tssi_set_bt_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_BD )
+
+#define __tssi_set_data_pola_high() ( REG_TSSI_CFG |= TSSI_CFG_TSDI_H )
+#define __tssi_set_data_pola_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSDI_H )
+
+#define __tssi_set_data_use_data0() ( REG_TSSI_CFG |= TSSI_CFG_USE_0 )
+#define __tssi_set_data_use_data7() ( REG_TSSI_CFG &= ~TSSI_CFG_USE_0 )
+
+#define __tssi_select_clk_fast() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_CH )
+#define __tssi_select_clk_slow() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_CH )
+
+#define __tssi_select_serail_mode() ( REG_TSSI_CFG &= ~TSSI_CFG_PARAL )
+#define __tssi_select_paral_mode() ( REG_TSSI_CFG |= TSSI_CFG_PARAL )
+
+#define __tssi_select_clk_nega_edge() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_P )
+#define __tssi_select_clk_posi_edge() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_P )
+
+#define __tssi_select_frm_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFRM_H )
+#define __tssi_select_frm_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFRM_H )
+
+#define __tssi_select_str_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSSTR_H )
+#define __tssi_select_str_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSSTR_H )
+
+#define __tssi_select_fail_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFAIL_H )
+#define __tssi_select_fail_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFAIL_H )
+
+#define __tssi_enable_ovrn_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_OVRNM )
+#define __tssi_disable_ovrn_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_OVRNM )
+
+#define __tssi_enable_trig_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_TRIGM )
+#define __tssi_disable_trig_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_TRIGM )
+
+#define __tssi_state_is_overrun() ( REG_TSSI_STAT & TSSI_STAT_OVRN )
+#define __tssi_state_trigger_meet() ( REG_TSSI_STAT & TSSI_STAT_TRIG )
+#define __tssi_clear_state() ( REG_TSSI_STAT = 0 ) /* write 0??? */
+#define __tssi_state_clear_overrun() ( REG_TSSI_STAT = TSSI_STAT_OVRN )
+
+#define __tssi_enable_filte_pid0() ( REG_TSSI_PEN |= TSSI_PEN_PID0 )
+#define __tssi_disable_filte_pid0() ( REG_TSSI_PEN &= ~TSSI_PEN_PID0 )
+
+/* m = 0, ..., 15 */
+#define __tssi_enable_pid_filter(m) \
+ do { \
+ int n = (m); \
+ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \
+ if ( n >= TSSI_PID_MAX ) n += 8; \
+ REG_TSSI_PEN |= ( 1 << n ); \
+ } \
+ } while (0)
+
+/* m = 0, ..., 15 */
+#define __tssi_disable_pid_filter(m) \
+ do { \
+ int n = (m); \
+ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \
+ if ( n >= TSSI_PID_MAX ) n += 8; \
+ REG_TSSI_PEN &= ~( 1 << n ); \
+ } \
+ } while (0)
+
+/* n = 0, ..., 7 */
+#define __tssi_set_pid0(n, pid0) \
+ do { \
+ REG_TSSI_PID(n) &= ~TSSI_PID_PID0_MASK; \
+ REG_TSSI_PID(n) |= ((pid0)<<TSSI_PID_PID0_BIT)&TSSI_PID_PID0_MASK; \
+ }while (0)
+/* n = 0, ..., 7 */
+#define __tssi_set_pid1(n, pid1) \
+ do { \
+ REG_TSSI_PID(n) &= ~TSSI_PID_PID1_MASK; \
+ REG_TSSI_PID(n) |= ((pid1)<<TSSI_PID_PID1_BIT)&TSSI_PID_PID1_MASK; \
+ }while (0)
+
+/* n = 0, ..., 15 */
+#define __tssi_set_pid(n, pid) \
+ do { \
+ if ( n>=0 && n < TSSI_PID_MAX*2) { \
+ if ( n < TSSI_PID_MAX ) \
+ __tssi_set_pid0(n, pid); \
+ else \
+ __tssi_set_pid1(n-TSSI_PID_MAX, pid); \
+ } \
+ }while (0)
+
+
+#if 0
+/*************************************************************************
+ * IPU (Image Processing Unit)
+ *************************************************************************/
+#define u32 volatile unsigned long
+
+#define write_reg(reg, val) \
+do { \
+ *(u32 *)(reg) = (val); \
+} while(0)
+
+#define read_reg(reg, off) (*(u32 *)((reg)+(off)))
+
+
+#define set_ipu_fmt(rgb_888_out_fmt, rgb_out_oft, out_fmt, yuv_pkg_out, in_oft, in_fmt ) \
+({ write_reg( (IPU_V_BASE + REG_D_FMT), ((in_fmt) & IN_FMT_MSK)<<IN_FMT_SFT \
+| ((in_oft) & IN_OFT_MSK)<< IN_OFT_SFT \
+| ((out_fmt) & OUT_FMT_MSK)<<OUT_FMT_SFT \
+| ((yuv_pkg_out) & YUV_PKG_OUT_MSK ) << YUV_PKG_OUT_SFT \
+| ((rgb_888_out_fmt) & RGB888_FMT_MSK ) << RGB888_FMT_SFT \
+| ((rgb_out_oft) & RGB_OUT_OFT_MSK ) << RGB_OUT_OFT_SFT); \
+})
+#define set_y_addr(y_addr) \
+({ write_reg( (IPU_V_BASE + REG_Y_ADDR), y_addr); \
+})
+#define set_u_addr(u_addr) \
+({ write_reg( (IPU_V_BASE + REG_U_ADDR), u_addr); \
+})
+
+#define set_v_addr(v_addr) \
+({ write_reg( (IPU_V_BASE + REG_V_ADDR), v_addr); \
+})
+
+#define set_y_phy_t_addr(y_phy_t_addr) \
+({ write_reg( (IPU_V_BASE + REG_Y_PHY_T_ADDR), y_phy_t_addr); \
+})
+
+#define set_u_phy_t_addr(u_phy_t_addr) \
+({ write_reg( (IPU_V_BASE + REG_U_PHY_T_ADDR), u_phy_t_addr); \
+})
+
+#define set_v_phy_t_addr(v_phy_t_addr) \
+({ write_reg( (IPU_V_BASE + REG_V_PHY_T_ADDR), v_phy_t_addr); \
+})
+
+#define set_out_phy_t_addr(out_phy_t_addr) \
+({ write_reg( (IPU_V_BASE + REG_OUT_PHY_T_ADDR), out_phy_t_addr); \
+})
+
+#define set_inframe_gsize(width, height, y_stride, u_stride, v_stride) \
+({ write_reg( (IPU_V_BASE + REG_IN_FM_GS), ((width) & IN_FM_W_MSK)<<IN_FM_W_SFT \
+| ((height) & IN_FM_H_MSK)<<IN_FM_H_SFT); \
+ write_reg( (IPU_V_BASE + REG_Y_STRIDE), ((y_stride) & Y_S_MSK)<<Y_S_SFT); \
+ write_reg( (IPU_V_BASE + REG_UV_STRIDE), ((u_stride) & U_S_MSK)<<U_S_SFT \
+| ((v_stride) & V_S_MSK)<<V_S_SFT); \
+})
+#define set_out_addr(out_addr) \
+({ write_reg( (IPU_V_BASE + REG_OUT_ADDR), out_addr); \
+})
+#define set_outframe_gsize(width, height, o_stride) \
+({ write_reg( (IPU_V_BASE + REG_OUT_GS), ((width) & OUT_FM_W_MSK)<<OUT_FM_W_SFT \
+| ((height) & OUT_FM_H_MSK)<<OUT_FM_H_SFT); \
+ write_reg( (IPU_V_BASE + REG_OUT_STRIDE), ((o_stride) & OUT_S_MSK)<<OUT_S_SFT); \
+})
+#define set_rsz_lut_end(h_end, v_end) \
+({ write_reg( (IPU_V_BASE + REG_RSZ_COEF_INDEX), ((h_end) & HE_IDX_MSK)<<HE_IDX_SFT \
+| ((v_end) & VE_IDX_MSK)<<VE_IDX_SFT); \
+})
+#define set_csc_c0(c0_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_CO_COEF), ((c0_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_csc_c1(c1_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_C1_COEF), ((c1_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_csc_c2(c2_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_C2_COEF), ((c2_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_csc_c3(c3_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_C3_COEF), ((c3_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_csc_c4(c4_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_C4_COEF), ((c4_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_hrsz_lut_coef(coef, in_n, out_n) \
+({ write_reg( (IPU_V_BASE + HRSZ_LUT_BASE ), ((coef) & W_COEF_MSK)<<W_COEF_SFT \
+| ((in_n) & IN_N_MSK)<<IN_N_SFT | ((out_n) & OUT_N_MSK)<<OUT_N_SFT); \
+})
+#define set_vrsz_lut_coef(coef, in_n, out_n) \
+({ write_reg( (IPU_V_BASE + VRSZ_LUT_BASE), ((coef) & W_COEF_MSK)<<W_COEF_SFT \
+| ((in_n) & IN_N_MSK)<<IN_N_SFT | ((out_n) & OUT_N_MSK)<<OUT_N_SFT); \
+})
+
+#define set_primary_ctrl(vrsz_en, hrsz_en,csc_en, irq_en) \
+({ write_reg( (IPU_V_BASE + REG_CTRL), ((irq_en) & FM_IRQ_EN_MSK)<<FM_IRQ_EN_SFT \
+| ((vrsz_en) & VRSZ_EN_MSK)<<VRSZ_EN_SFT \
+| ((hrsz_en) & HRSZ_EN_MSK)<<HRSZ_EN_SFT \
+| ((csc_en) & CSC_EN_MSK)<<CSC_EN_SFT \
+| (read_reg(IPU_V_BASE, REG_CTRL)) \
+& ~(CSC_EN_MSK<<CSC_EN_SFT | FM_IRQ_EN_MSK<<FM_IRQ_EN_SFT | VRSZ_EN_MSK<<VRSZ_EN_SFT | HRSZ_EN_MSK<<HRSZ_EN_SFT ) ); \
+})
+
+#define set_source_ctrl(pkg_sel, spage_sel) \
+({ write_reg( (IPU_V_BASE + REG_CTRL), ((pkg_sel) & PKG_SEL_MSK )<< PKG_SEL_SFT \
+| ((spage_sel) & SPAGE_MAP_MSK )<< SPAGE_MAP_SFT \
+| (read_reg(IPU_V_BASE, REG_CTRL)) \
+& ~(SPAGE_MAP_MSK << SPAGE_MAP_SFT | PKG_SEL_MSK << PKG_SEL_SFT ) ) ; \
+})
+
+#define set_out_ctrl(lcdc_sel, dpage_sel, disp_sel) \
+({ write_reg( (IPU_V_BASE + REG_CTRL), ((lcdc_sel) & LCDC_SEL_MSK )<< LCDC_SEL_SFT \
+| ((dpage_sel) & DPAGE_SEL_MSK )<< DPAGE_SEL_SFT \
+| ((disp_sel) & DISP_SEL_MSK )<< DISP_SEL_SFT \
+| (read_reg(IPU_V_BASE, REG_CTRL)) \
+& ~(LCDC_SEL_MSK<< LCDC_SEL_SFT | DPAGE_SEL_MSK << DPAGE_SEL_SFT | DISP_SEL_MSK << DISP_SEL_SFT ) ); \
+})
+
+#define set_scale_ctrl(v_scal, h_scal) \
+({ write_reg( (IPU_V_BASE + REG_CTRL), ((v_scal) & V_SCALE_MSK)<<V_SCALE_SFT \
+| ((h_scal) & H_SCALE_MSK)<<H_SCALE_SFT \
+| (read_reg(IPU_V_BASE, REG_CTRL)) & ~(V_SCALE_MSK<<V_SCALE_SFT | H_SCALE_MSK<<H_SCALE_SFT ) ); \
+})
+
+
+#define set_csc_ofset_para(chrom_oft, luma_oft) \
+({ write_reg( (IPU_V_BASE + REG_CSC_OFSET_PARA ), ((chrom_oft) & CHROM_OF_MSK ) << CHROM_OF_SFT \
+| ((luma_oft) & LUMA_OF_MSK ) << LUMA_OF_SFT ) ; \
+})
+
+#define sw_reset_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) \
+| IPU_RST_MSK<<IPU_RST_SFT); \
+})
+#define enable_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) | 0x1); \
+})
+#define disable_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) & ~0x1); \
+})
+#define run_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) | 0x2); \
+})
+#define stop_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) & ~0x2); \
+})
+
+#define polling_end_flag() \
+({ (read_reg(IPU_V_BASE, REG_STATUS)) & 0x01; \
+})
+
+#define start_vlut_coef_write() \
+({ write_reg( (IPU_V_BASE + VRSZ_LUT_BASE), ( 0x1<<12 ) ); \
+})
+
+#define start_hlut_coef_write() \
+({ write_reg( (IPU_V_BASE + HRSZ_LUT_BASE), ( 0x01<<12 ) ); \
+})
+
+#define clear_end_flag() \
+({ write_reg( (IPU_V_BASE + REG_STATUS), 0); \
+})
+#endif /* #if 0 */
+
+
+#endif /* __JZ4750_OPS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750/regs.h b/arch/mips/include/asm/mach-jz4750/regs.h
new file mode 100644
index 00000000000..29db7fbe8c7
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750/regs.h
@@ -0,0 +1,3415 @@
+/*
+ * linux/include/asm-mips/mach-jz4750/regs.h
+ *
+ * JZ4750 register definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __JZ4750_REGS_H__
+#define __JZ4750_REGS_H__
+
+#if defined(__ASSEMBLY__) || defined(__LANGUAGE_ASSEMBLY)
+#define REG8(addr) (addr)
+#define REG16(addr) (addr)
+#define REG32(addr) (addr)
+#else
+#define REG8(addr) *((volatile unsigned char *)(addr))
+#define REG16(addr) *((volatile unsigned short *)(addr))
+#define REG32(addr) *((volatile unsigned int *)(addr))
+#endif
+
+/*
+ * Define the module base addresses
+ */
+#define CPM_BASE 0xB0000000
+#define INTC_BASE 0xB0001000
+#define TCU_BASE 0xB0002000
+#define WDT_BASE 0xB0002000
+#define RTC_BASE 0xB0003000
+#define GPIO_BASE 0xB0010000
+#define AIC_BASE 0xB0020000
+#define ICDC_BASE 0xB0020000
+#define MSC_BASE 0xB0021000
+#define UART0_BASE 0xB0030000
+#define UART1_BASE 0xB0031000
+#define UART2_BASE 0xB0032000
+#define UART3_BASE 0xB0033000
+#define I2C_BASE 0xB0042000
+#define SSI_BASE 0xB0043000
+#define SADC_BASE 0xB0070000
+#define PCM_BASE 0xB0071000
+#define EMC_BASE 0xB3010000
+#define DMAC_BASE 0xB3020000
+#define UHC_BASE 0xB3030000
+#define UDC_BASE 0xB3040000
+#define LCD_BASE 0xB3050000
+#define SLCD_BASE 0xB3050000
+#define TVE_BASE 0xB3050100
+#define CIM_BASE 0xB3060000
+#define IPU_BASE 0xB3080000
+#define ME_BASE 0xB3090000
+#define MC_BASE 0xB30A0000
+#define BCH_BASE 0xB30D0000
+#define ETH_BASE 0xB3100000
+#define TCSM_BASE 0xF4000000
+#define OWI_BASE 0XB0072000
+#define OTP_BASE 0xB3012000
+#define TSSI_BASE 0xB0073000
+
+/*************************************************************************
+ * INTC (Interrupt Controller)
+ *************************************************************************/
+#define INTC_ISR (INTC_BASE + 0x00)
+#define INTC_IMR (INTC_BASE + 0x04)
+#define INTC_IMSR (INTC_BASE + 0x08)
+#define INTC_IMCR (INTC_BASE + 0x0c)
+#define INTC_IPR (INTC_BASE + 0x10)
+
+#define REG_INTC_ISR REG32(INTC_ISR)
+#define REG_INTC_IMR REG32(INTC_IMR)
+#define REG_INTC_IMSR REG32(INTC_IMSR)
+#define REG_INTC_IMCR REG32(INTC_IMCR)
+#define REG_INTC_IPR REG32(INTC_IPR)
+
+// 1st-level interrupts
+#define IRQ_OWI 0
+#define IRQ_I2C 1
+#define IRQ_TSSI 2
+#define IRQ_UART3 3
+#define IRQ_UART2 4
+#define IRQ_UART1 5
+#define IRQ_UART0 6
+#define IRQ_PCM 7
+#define IRQ_AIC 8
+#define IRQ_RTC 9
+#define IRQ_ETH 9
+#define IRQ_SADC 10
+#define IRQ_SSI1 11
+#define IRQ_SSI0 12
+#define IRQ_MSC1 13
+#define IRQ_MSC0 14
+#define IRQ_DMAC1 15
+#define IRQ_BCH 16
+#define IRQ_UHC 17
+#define IRQ_CIM 18
+#define IRQ_UDC 19
+#define IRQ_DMAC0 20
+#define IRQ_TCU2 21
+#define IRQ_TCU1 22
+#define IRQ_TCU0 23
+#define IRQ_GPIO5 24
+#define IRQ_GPIO4 25
+#define IRQ_GPIO3 26
+#define IRQ_GPIO2 27
+#define IRQ_GPIO1 28
+#define IRQ_GPIO0 29
+#define IRQ_IPU 30
+#define IRQ_LCD 31
+
+// 2nd-level interrupts
+#define IRQ_DMA_0 32 /* 32 to 43 for DMAC0's 0-5 and DMAC1's 0-5 */
+#define IRQ_GPIO_0 48 /* 48 to 240 for GPIO pin 0 to 192 */
+
+#define NUM_DMA MAX_DMA_NUM /* 12 */
+#define NUM_GPIO MAX_GPIO_NUM /* GPIO NUM: 192, Jz4750 real num GPIO 178 */
+
+
+/*************************************************************************
+ * RTC
+ *************************************************************************/
+#define RTC_RCR (RTC_BASE + 0x00) /* RTC Control Register */
+#define RTC_RSR (RTC_BASE + 0x04) /* RTC Second Register */
+#define RTC_RSAR (RTC_BASE + 0x08) /* RTC Second Alarm Register */
+#define RTC_RGR (RTC_BASE + 0x0c) /* RTC Regulator Register */
+
+#define RTC_HCR (RTC_BASE + 0x20) /* Hibernate Control Register */
+#define RTC_HWFCR (RTC_BASE + 0x24) /* Hibernate Wakeup Filter Counter Reg */
+#define RTC_HRCR (RTC_BASE + 0x28) /* Hibernate Reset Counter Register */
+#define RTC_HWCR (RTC_BASE + 0x2c) /* Hibernate Wakeup Control Register */
+#define RTC_HWRSR (RTC_BASE + 0x30) /* Hibernate Wakeup Status Register */
+#define RTC_HSPR (RTC_BASE + 0x34) /* Hibernate Scratch Pattern Register */
+
+#define REG_RTC_RCR REG32(RTC_RCR)
+#define REG_RTC_RSR REG32(RTC_RSR)
+#define REG_RTC_RSAR REG32(RTC_RSAR)
+#define REG_RTC_RGR REG32(RTC_RGR)
+#define REG_RTC_HCR REG32(RTC_HCR)
+#define REG_RTC_HWFCR REG32(RTC_HWFCR)
+#define REG_RTC_HRCR REG32(RTC_HRCR)
+#define REG_RTC_HWCR REG32(RTC_HWCR)
+#define REG_RTC_HWRSR REG32(RTC_HWRSR)
+#define REG_RTC_HSPR REG32(RTC_HSPR)
+
+/* RTC Control Register */
+#define RTC_RCR_WRDY_BIT 7
+#define RTC_RCR_WRDY (1 << 7) /* Write Ready Flag */
+#define RTC_RCR_1HZ_BIT 6
+#define RTC_RCR_1HZ (1 << RTC_RCR_1HZ_BIT) /* 1Hz Flag */
+#define RTC_RCR_1HZIE (1 << 5) /* 1Hz Interrupt Enable */
+#define RTC_RCR_AF_BIT 4
+#define RTC_RCR_AF (1 << RTC_RCR_AF_BIT) /* Alarm Flag */
+#define RTC_RCR_AIE (1 << 3) /* Alarm Interrupt Enable */
+#define RTC_RCR_AE (1 << 2) /* Alarm Enable */
+#define RTC_RCR_RTCE (1 << 0) /* RTC Enable */
+
+/* RTC Regulator Register */
+#define RTC_RGR_LOCK (1 << 31) /* Lock Bit */
+#define RTC_RGR_ADJC_BIT 16
+#define RTC_RGR_ADJC_MASK (0x3ff << RTC_RGR_ADJC_BIT)
+#define RTC_RGR_NC1HZ_BIT 0
+#define RTC_RGR_NC1HZ_MASK (0xffff << RTC_RGR_NC1HZ_BIT)
+
+/* Hibernate Control Register */
+#define RTC_HCR_PD (1 << 0) /* Power Down */
+
+/* Hibernate Wakeup Filter Counter Register */
+#define RTC_HWFCR_BIT 5
+#define RTC_HWFCR_MASK (0x7ff << RTC_HWFCR_BIT)
+
+/* Hibernate Reset Counter Register */
+#define RTC_HRCR_BIT 5
+#define RTC_HRCR_MASK (0x7f << RTC_HRCR_BIT)
+
+/* Hibernate Wakeup Control Register */
+#define RTC_HWCR_EALM (1 << 0) /* RTC alarm wakeup enable */
+
+/* Hibernate Wakeup Status Register */
+#define RTC_HWRSR_HR (1 << 5) /* Hibernate reset */
+#define RTC_HWRSR_PPR (1 << 4) /* PPR reset */
+#define RTC_HWRSR_PIN (1 << 1) /* Wakeup pin status bit */
+#define RTC_HWRSR_ALM (1 << 0) /* RTC alarm status bit */
+
+
+/*************************************************************************
+ * CPM (Clock reset and Power control Management)
+ *************************************************************************/
+#define CPM_CPCCR (CPM_BASE+0x00)
+#define CPM_CPPCR (CPM_BASE+0x10)
+#define CPM_CPPSR (CPM_BASE+0x14) /* PLL Switch and Status Register */
+#define CPM_I2SCDR (CPM_BASE+0x60)
+#define CPM_LPCDR (CPM_BASE+0x64)
+#define CPM_MSCCDR(n) (CPM_BASE+0x10*(n)+0x68) /* MSC0(n=0) or MSC1(n=1) device clock divider Register */
+#define CPM_UHCCDR (CPM_BASE+0x6C)
+#define CPM_SSICDR (CPM_BASE+0x74)
+#define CPM_PCMCDR (CPM_BASE+0x7C) /* PCM device clock divider Register */
+
+#define CPM_LCR (CPM_BASE+0x04)
+#define CPM_CLKGR (CPM_BASE+0x20)
+#define CPM_OPCR (CPM_BASE+0x24) /* Oscillator and Power Control Register */
+
+#define CPM_RSR (CPM_BASE+0x08)
+
+#define REG_CPM_CPCCR REG32(CPM_CPCCR)
+#define REG_CPM_CPPCR REG32(CPM_CPPCR)
+#define REG_CPM_CPPSR REG32(CPM_CPPSR)
+#define REG_CPM_I2SCDR REG32(CPM_I2SCDR)
+#define REG_CPM_LPCDR REG32(CPM_LPCDR)
+#define REG_CPM_MSCCDR(n) REG32(CPM_MSCCDR(n))
+#define REG_CPM_UHCCDR REG32(CPM_UHCCDR)
+#define REG_CPM_SSICDR REG32(CPM_SSICDR)
+#define REG_CPM_PCMCDR REG32(CPM_PCMCDR)
+
+#define REG_CPM_LCR REG32(CPM_LCR)
+#define REG_CPM_CLKGR REG32(CPM_CLKGR)
+#define REG_CPM_OPCR REG32(CPM_OPCR)
+
+#define REG_CPM_RSR REG32(CPM_RSR)
+
+/* Clock Control Register */
+#define CPM_CPCCR_I2CS (1 << 31)
+#define CPM_CPCCR_ECS (1 << 30) /* Select the between EXCLK and EXCLK/2 output */
+#define CPM_CPCCR_UCS (1 << 29)
+#define CPM_CPCCR_UDIV_BIT 23
+#define CPM_CPCCR_UDIV_MASK (0x3f << CPM_CPCCR_UDIV_BIT)
+#define CPM_CPCCR_CE (1 << 22)
+#define CPM_CPCCR_PCS (1 << 21)
+#define CPM_CPCCR_LDIV_BIT 16
+#define CPM_CPCCR_LDIV_MASK (0x1f << CPM_CPCCR_LDIV_BIT)
+#define CPM_CPCCR_MDIV_BIT 12
+#define CPM_CPCCR_MDIV_MASK (0x0f << CPM_CPCCR_MDIV_BIT)
+#define CPM_CPCCR_PDIV_BIT 8
+#define CPM_CPCCR_PDIV_MASK (0x0f << CPM_CPCCR_PDIV_BIT)
+#define CPM_CPCCR_HDIV_BIT 4
+#define CPM_CPCCR_HDIV_MASK (0x0f << CPM_CPCCR_HDIV_BIT)
+#define CPM_CPCCR_CDIV_BIT 0
+#define CPM_CPCCR_CDIV_MASK (0x0f << CPM_CPCCR_CDIV_BIT)
+
+/* PLL Switch and Status Register */
+#define CPM_CPPSR_PLLOFF (1<<31)
+#define CPM_CPPSR_PLLBP (1<<30)
+#define CPM_CPPSR_PLLON (1<<29)
+#define CPM_CPPSR_PS (1<<28) /* Indicate whether the PLL parameters' change has finished */
+#define CPM_CPPSR_FS (1<<27) /* Indicate whether the main clock's change has finished */
+#define CPM_CPPSR_CS (1<<26) /* Indicate whether the clock switch has finished */
+#define CPM_CPPSR_PM (1<<1) /* Clock switch mode */
+#define CPM_CPPSR_FM (1<<0) /* Clock frequency change mode */
+
+/* I2S Clock Divider Register */
+#define CPM_I2SCDR_I2SDIV_BIT 0
+#define CPM_I2SCDR_I2SDIV_MASK (0x1ff << CPM_I2SCDR_I2SDIV_BIT)
+
+/* LCD Pixel Clock Divider Register */
+#define CPM_LPCDR_LSCS (1<<31) /* TV encoder Source Pixel Clock Selection */
+#define CPM_LPCDR_LPCS (1<<30) /* LCD Panel pix clock Selection */
+#define CPM_LPCDR_LTCS (1<<29) /* LCD TV Encoder or Panel pix clock Selection */
+#define CPM_LPCDR_PIXDIV_BIT 0
+#define CPM_LPCDR_PIXDIV_MASK (0x7ff << CPM_LPCDR_PIXDIV_BIT)
+
+/* MSC Clock Divider Register */
+#define CPM_MSCCDR_MSCDIV_BIT 0
+#define CPM_MSCCDR_MSCDIV_MASK (0x1f << CPM_MSCCDR_MSCDIV_BIT)
+
+/* UHC Clock Divider Register */
+#define CPM_UHCCDR_UHCDIV_BIT 0
+#define CPM_UHCCDR_UHCDIV_MASK (0xf << CPM_UHCCDR_UHCDIV_BIT)
+
+/* SSI Clock Divider Register */
+#define CPM_SSICDR_SSIDIV_BIT 0
+#define CPM_SSICDR_SSIDIV_MASK (0xf << CPM_SSICDR_SSIDIV_BIT)
+
+/* PCM device clock divider Register */
+#define CPM_PCMCDR_PCMS 31 /* PCM source clock Selection */
+#define CPM_PCMCDR_PCMCD_BIT 0
+#define CPM_PCMCDR_PCMCD_MASK (0x1ff << CPM_PCMCDR_PCMCD_BIT)
+
+/* PLL Control Register */
+#define CPM_CPPCR_PLLM_BIT 23
+#define CPM_CPPCR_PLLM_MASK (0x1ff << CPM_CPPCR_PLLM_BIT)
+#define CPM_CPPCR_PLLN_BIT 18
+#define CPM_CPPCR_PLLN_MASK (0x1f << CPM_CPPCR_PLLN_BIT)
+#define CPM_CPPCR_PLLOD_BIT 16
+#define CPM_CPPCR_PLLOD_MASK (0x03 << CPM_CPPCR_PLLOD_BIT)
+#define CPM_CPPCR_PLLS (1 << 10) /* obsolete, replaced by CPM_CPPSR_PLLON */
+#define CPM_CPPCR_PLLBP (1 << 9)
+#define CPM_CPPCR_PLLEN (1 << 8)
+#define CPM_CPPCR_PLLST_BIT 0
+#define CPM_CPPCR_PLLST_MASK (0xff << CPM_CPPCR_PLLST_BIT)
+
+/* Low Power Control Register */
+#define CPM_LCR_DOZE_DUTY_BIT 3
+#define CPM_LCR_DOZE_DUTY_MASK (0x1f << CPM_LCR_DOZE_DUTY_BIT)
+#define CPM_LCR_DOZE_ON (1 << 2)
+#define CPM_LCR_LPM_BIT 0
+#define CPM_LCR_LPM_MASK (0x3 << CPM_LCR_LPM_BIT)
+ #define CPM_LCR_LPM_IDLE (0x0 << CPM_LCR_LPM_BIT)
+ #define CPM_LCR_LPM_SLEEP (0x1 << CPM_LCR_LPM_BIT)
+
+/* Clock Gate Register */
+#define CPM_CLKGR_CIMRAM (1 << 28)
+#define CPM_CLKGR_IDCT (1 << 27)
+#define CPM_CLKGR_DB (1 << 26)
+#define CPM_CLKGR_ME (1 << 25)
+#define CPM_CLKGR_MC (1 << 24)
+#define CPM_CLKGR_TVE (1 << 23)
+#define CPM_CLKGR_TSSI (1 << 22)
+#define CPM_CLKGR_OWI (1 << 21)
+#define CPM_CLKGR_PCM (1 << 20)
+#define CPM_CLKGR_MSC1 (1 << 19)
+#define CPM_CLKGR_SSI0 (1 << 18)
+#define CPM_CLKGR_UART3 (1 << 17)
+#define CPM_CLKGR_UART2 (1 << 16)
+#define CPM_CLKGR_UART1 (1 << 15)
+#define CPM_CLKGR_UHC (1 << 14)
+#define CPM_CLKGR_IPU (1 << 13)
+#define CPM_CLKGR_DMAC (1 << 12)
+#define CPM_CLKGR_UDC (1 << 11)
+#define CPM_CLKGR_LCD (1 << 10)
+#define CPM_CLKGR_CIM (1 << 9)
+#define CPM_CLKGR_SADC (1 << 8)
+#define CPM_CLKGR_MSC0 (1 << 7)
+#define CPM_CLKGR_AIC1 (1 << 6)
+#define CPM_CLKGR_AIC2 (1 << 5)
+#define CPM_CLKGR_SSI1 (1 << 4)
+#define CPM_CLKGR_I2C (1 << 3)
+#define CPM_CLKGR_RTC (1 << 2)
+#define CPM_CLKGR_TCU (1 << 1)
+#define CPM_CLKGR_UART0 (1 << 0)
+
+/* Oscillator and Power Control Register */
+#define CPM_OPCR_O1ST_BIT 8
+#define CPM_OPCR_O1ST_MASK (0xff << CPM_SCR_O1ST_BIT)
+#define CPM_OPCR_UHCPHY_DISABLE (1 << 7)
+#define CPM_OPCR_UDCPHY_ENABLE (1 << 6)
+#define CPM_OPCR_OSC_ENABLE (1 << 4)
+#define CPM_OPCR_ERCS (1 << 2) /* EXCLK/512 clock and RTCLK clock selection */
+#define CPM_OPCR_MOSE (1 << 1) /* Main Oscillator Enable */
+#define CPM_OPCR_MCS (1 << 0) /* Main clock source select register */
+
+/* Reset Status Register */
+#define CPM_RSR_HR (1 << 2)
+#define CPM_RSR_WR (1 << 1)
+#define CPM_RSR_PR (1 << 0)
+
+
+/*************************************************************************
+ * TCU (Timer Counter Unit)
+ *************************************************************************/
+#define TCU_TSTR (TCU_BASE + 0xF0) /* Timer Status Register,Only Used In Tcu2 Mode */
+#define TCU_TSTSR (TCU_BASE + 0xF4) /* Timer Status Set Register */
+#define TCU_TSTCR (TCU_BASE + 0xF8) /* Timer Status Clear Register */
+#define TCU_TSR (TCU_BASE + 0x1C) /* Timer Stop Register */
+#define TCU_TSSR (TCU_BASE + 0x2C) /* Timer Stop Set Register */
+#define TCU_TSCR (TCU_BASE + 0x3C) /* Timer Stop Clear Register */
+#define TCU_TER (TCU_BASE + 0x10) /* Timer Counter Enable Register */
+#define TCU_TESR (TCU_BASE + 0x14) /* Timer Counter Enable Set Register */
+#define TCU_TECR (TCU_BASE + 0x18) /* Timer Counter Enable Clear Register */
+#define TCU_TFR (TCU_BASE + 0x20) /* Timer Flag Register */
+#define TCU_TFSR (TCU_BASE + 0x24) /* Timer Flag Set Register */
+#define TCU_TFCR (TCU_BASE + 0x28) /* Timer Flag Clear Register */
+#define TCU_TMR (TCU_BASE + 0x30) /* Timer Mask Register */
+#define TCU_TMSR (TCU_BASE + 0x34) /* Timer Mask Set Register */
+#define TCU_TMCR (TCU_BASE + 0x38) /* Timer Mask Clear Register */
+
+#define TCU_TDFR0 (TCU_BASE + 0x40) /* Timer Data Full Register */
+#define TCU_TDHR0 (TCU_BASE + 0x44) /* Timer Data Half Register */
+#define TCU_TCNT0 (TCU_BASE + 0x48) /* Timer Counter Register */
+#define TCU_TCSR0 (TCU_BASE + 0x4C) /* Timer Control Register */
+#define TCU_TDFR1 (TCU_BASE + 0x50)
+#define TCU_TDHR1 (TCU_BASE + 0x54)
+#define TCU_TCNT1 (TCU_BASE + 0x58)
+#define TCU_TCSR1 (TCU_BASE + 0x5C)
+#define TCU_TDFR2 (TCU_BASE + 0x60)
+#define TCU_TDHR2 (TCU_BASE + 0x64)
+#define TCU_TCNT2 (TCU_BASE + 0x68)
+#define TCU_TCSR2 (TCU_BASE + 0x6C)
+#define TCU_TDFR3 (TCU_BASE + 0x70)
+#define TCU_TDHR3 (TCU_BASE + 0x74)
+#define TCU_TCNT3 (TCU_BASE + 0x78)
+#define TCU_TCSR3 (TCU_BASE + 0x7C)
+#define TCU_TDFR4 (TCU_BASE + 0x80)
+#define TCU_TDHR4 (TCU_BASE + 0x84)
+#define TCU_TCNT4 (TCU_BASE + 0x88)
+#define TCU_TCSR4 (TCU_BASE + 0x8C)
+#define TCU_TDFR5 (TCU_BASE + 0x90)
+#define TCU_TDHR5 (TCU_BASE + 0x94)
+#define TCU_TCNT5 (TCU_BASE + 0x98)
+#define TCU_TCSR5 (TCU_BASE + 0x9C)
+
+#define REG_TCU_TSTR REG32(TCU_TSTR)
+#define REG_TCU_TSTSR REG32(TCU_TSTSR)
+#define REG_TCU_TSTCR REG32(TCU_TSTCR)
+#define REG_TCU_TSR REG32(TCU_TSR)
+#define REG_TCU_TSSR REG32(TCU_TSSR)
+#define REG_TCU_TSCR REG32(TCU_TSCR)
+#define REG_TCU_TER REG16(TCU_TER)
+#define REG_TCU_TESR REG32(TCU_TESR)
+#define REG_TCU_TECR REG32(TCU_TECR)
+#define REG_TCU_TFR REG32(TCU_TFR)
+#define REG_TCU_TFSR REG32(TCU_TFSR)
+#define REG_TCU_TFCR REG32(TCU_TFCR)
+#define REG_TCU_TMR REG32(TCU_TMR)
+#define REG_TCU_TMSR REG32(TCU_TMSR)
+#define REG_TCU_TMCR REG32(TCU_TMCR)
+#define REG_TCU_TDFR0 REG16(TCU_TDFR0)
+#define REG_TCU_TDHR0 REG16(TCU_TDHR0)
+#define REG_TCU_TCNT0 REG16(TCU_TCNT0)
+#define REG_TCU_TCSR0 REG16(TCU_TCSR0)
+#define REG_TCU_TDFR1 REG16(TCU_TDFR1)
+#define REG_TCU_TDHR1 REG16(TCU_TDHR1)
+#define REG_TCU_TCNT1 REG16(TCU_TCNT1)
+#define REG_TCU_TCSR1 REG16(TCU_TCSR1)
+#define REG_TCU_TDFR2 REG16(TCU_TDFR2)
+#define REG_TCU_TDHR2 REG16(TCU_TDHR2)
+#define REG_TCU_TCNT2 REG16(TCU_TCNT2)
+#define REG_TCU_TCSR2 REG16(TCU_TCSR2)
+#define REG_TCU_TDFR3 REG16(TCU_TDFR3)
+#define REG_TCU_TDHR3 REG16(TCU_TDHR3)
+#define REG_TCU_TCNT3 REG16(TCU_TCNT3)
+#define REG_TCU_TCSR3 REG16(TCU_TCSR3)
+#define REG_TCU_TDFR4 REG16(TCU_TDFR4)
+#define REG_TCU_TDHR4 REG16(TCU_TDHR4)
+#define REG_TCU_TCNT4 REG16(TCU_TCNT4)
+#define REG_TCU_TCSR4 REG16(TCU_TCSR4)
+
+// n = 0,1,2,3,4,5
+#define TCU_TDFR(n) (TCU_BASE + (0x40 + (n)*0x10)) /* Timer Data Full Reg */
+#define TCU_TDHR(n) (TCU_BASE + (0x44 + (n)*0x10)) /* Timer Data Half Reg */
+#define TCU_TCNT(n) (TCU_BASE + (0x48 + (n)*0x10)) /* Timer Counter Reg */
+#define TCU_TCSR(n) (TCU_BASE + (0x4C + (n)*0x10)) /* Timer Control Reg */
+#define TCU_OSTDR (TCU_BASE + 0xe0) /* Operating System Timer Data Reg */
+#define TCU_OSTCNT (TCU_BASE + 0xe8) /* Operating System Timer Counter Reg */
+#define TCU_OSTCSR (TCU_BASE + 0xeC) /* Operating System Timer Control Reg */
+
+#define REG_TCU_TDFR(n) REG16(TCU_TDFR((n)))
+#define REG_TCU_TDHR(n) REG16(TCU_TDHR((n)))
+#define REG_TCU_TCNT(n) REG16(TCU_TCNT((n)))
+#define REG_TCU_TCSR(n) REG16(TCU_TCSR((n)))
+#define REG_TCU_OSTDR REG32(TCU_OSTDR)
+#define REG_TCU_OSTCNT REG32(TCU_OSTCNT)
+#define REG_TCU_OSTCSR REG32(TCU_OSTCSR)
+
+// Register definitions
+#define TCU_TSTR_REAL2 (1 << 18) /* only used in TCU2 mode */
+#define TCU_TSTR_REAL1 (1 << 17) /* only used in TCU2 mode */
+#define TCU_TSTR_BUSY2 (1 << 2) /* only used in TCU2 mode */
+#define TCU_TSTR_BUSY1 (1 << 1) /* only used in TCU2 mode */
+
+#define TCU_TSTSR_REAL2 (1 << 18)
+#define TCU_TSTSR_REAL1 (1 << 17)
+#define TCU_TSTSR_BUSY2 (1 << 2)
+#define TCU_TSTSR_BUSY1 (1 << 1)
+
+#define TCU_TSTCR_REAL2 (1 << 18)
+#define TCU_TSTCR_REAL1 (1 << 17)
+#define TCU_TSTCR_BUSY2 (1 << 2)
+#define TCU_TSTCR_BUSY1 (1 << 1)
+
+#define TCU_TSR_WDTS (1 << 16) /*the clock supplies to wdt is stopped */
+#define TCU_TSR_OSTS (1 << 15) /*the clock supplies to osts is stopped */
+#define TCU_TSR_STOP5 (1 << 5) /*the clock supplies to timer5 is stopped */
+#define TCU_TSR_STOP4 (1 << 4) /*the clock supplies to timer4 is stopped */
+#define TCU_TSR_STOP3 (1 << 3) /*the clock supplies to timer3 is stopped */
+#define TCU_TSR_STOP2 (1 << 2) /*the clock supplies to timer2 is stopped */
+#define TCU_TSR_STOP1 (1 << 1) /*the clock supplies to timer1 is stopped */
+#define TCU_TSR_STOP0 (1 << 0) /*the clock supplies to timer0 is stopped */
+
+#define TCU_TSSR_WDTSS (1 << 16)
+#define TCU_TSSR_OSTSS (1 << 15)
+#define TCU_TSSR_STPS5 (1 << 5)
+#define TCU_TSSR_STPS4 (1 << 4)
+#define TCU_TSSR_STPS3 (1 << 3)
+#define TCU_TSSR_STPS2 (1 << 2)
+#define TCU_TSSR_STPS1 (1 << 1)
+#define TCU_TSSR_STPS0 (1 << 0)
+
+#define TCU_TSCR_WDTSC (1 << 16)
+#define TCU_TSCR_OSTSC (1 << 15)
+#define TCU_TSCR_STPC5 (1 << 5)
+#define TCU_TSCR_STPC4 (1 << 4)
+#define TCU_TSCR_STPC3 (1 << 3)
+#define TCU_TSCR_STPC2 (1 << 2)
+#define TCU_TSCR_STPC1 (1 << 1)
+#define TCU_TSCR_STPC0 (1 << 0)
+
+#define TCU_TER_OSTEN (1 << 15) /* enable the counter in ost */
+#define TCU_TER_TCEN5 (1 << 5) /* enable the counter in timer5 */
+#define TCU_TER_TCEN4 (1 << 4)
+#define TCU_TER_TCEN3 (1 << 3)
+#define TCU_TER_TCEN2 (1 << 2)
+#define TCU_TER_TCEN1 (1 << 1)
+#define TCU_TER_TCEN0 (1 << 0)
+
+#define TCU_TESR_OSTST (1 << 15)
+#define TCU_TESR_TCST5 (1 << 5)
+#define TCU_TESR_TCST4 (1 << 4)
+#define TCU_TESR_TCST3 (1 << 3)
+#define TCU_TESR_TCST2 (1 << 2)
+#define TCU_TESR_TCST1 (1 << 1)
+#define TCU_TESR_TCST0 (1 << 0)
+
+#define TCU_TECR_OSTCL (1 << 15)
+#define TCU_TECR_TCCL5 (1 << 5)
+#define TCU_TECR_TCCL4 (1 << 4)
+#define TCU_TECR_TCCL3 (1 << 3)
+#define TCU_TECR_TCCL2 (1 << 2)
+#define TCU_TECR_TCCL1 (1 << 1)
+#define TCU_TECR_TCCL0 (1 << 0)
+
+#define TCU_TFR_HFLAG5 (1 << 21) /* half comparison match flag */
+#define TCU_TFR_HFLAG4 (1 << 20)
+#define TCU_TFR_HFLAG3 (1 << 19)
+#define TCU_TFR_HFLAG2 (1 << 18)
+#define TCU_TFR_HFLAG1 (1 << 17)
+#define TCU_TFR_HFLAG0 (1 << 16)
+#define TCU_TFR_OSTFLAG (1 << 15) /* ost comparison match flag */
+#define TCU_TFR_FFLAG5 (1 << 5) /* full comparison match flag */
+#define TCU_TFR_FFLAG4 (1 << 4)
+#define TCU_TFR_FFLAG3 (1 << 3)
+#define TCU_TFR_FFLAG2 (1 << 2)
+#define TCU_TFR_FFLAG1 (1 << 1)
+#define TCU_TFR_FFLAG0 (1 << 0)
+
+#define TCU_TFSR_HFST5 (1 << 21)
+#define TCU_TFSR_HFST4 (1 << 20)
+#define TCU_TFSR_HFST3 (1 << 19)
+#define TCU_TFSR_HFST2 (1 << 18)
+#define TCU_TFSR_HFST1 (1 << 17)
+#define TCU_TFSR_HFST0 (1 << 16)
+#define TCU_TFSR_OSTFST (1 << 15)
+#define TCU_TFSR_FFST5 (1 << 5)
+#define TCU_TFSR_FFST4 (1 << 4)
+#define TCU_TFSR_FFST3 (1 << 3)
+#define TCU_TFSR_FFST2 (1 << 2)
+#define TCU_TFSR_FFST1 (1 << 1)
+#define TCU_TFSR_FFST0 (1 << 0)
+
+#define TCU_TFCR_HFCL5 (1 << 21)
+#define TCU_TFCR_HFCL4 (1 << 20)
+#define TCU_TFCR_HFCL3 (1 << 19)
+#define TCU_TFCR_HFCL2 (1 << 18)
+#define TCU_TFCR_HFCL1 (1 << 17)
+#define TCU_TFCR_HFCL0 (1 << 16)
+#define TCU_TFCR_OSTFCL (1 << 15)
+#define TCU_TFCR_FFCL5 (1 << 5)
+#define TCU_TFCR_FFCL4 (1 << 4)
+#define TCU_TFCR_FFCL3 (1 << 3)
+#define TCU_TFCR_FFCL2 (1 << 2)
+#define TCU_TFCR_FFCL1 (1 << 1)
+#define TCU_TFCR_FFCL0 (1 << 0)
+
+#define TCU_TMR_HMASK5 (1 << 21) /* half comparison match interrupt mask */
+#define TCU_TMR_HMASK4 (1 << 20)
+#define TCU_TMR_HMASK3 (1 << 19)
+#define TCU_TMR_HMASK2 (1 << 18)
+#define TCU_TMR_HMASK1 (1 << 17)
+#define TCU_TMR_HMASK0 (1 << 16)
+#define TCU_TMR_OSTMASK (1 << 15) /* ost comparison match interrupt mask */
+#define TCU_TMR_FMASK5 (1 << 5) /* full comparison match interrupt mask */
+#define TCU_TMR_FMASK4 (1 << 4)
+#define TCU_TMR_FMASK3 (1 << 3)
+#define TCU_TMR_FMASK2 (1 << 2)
+#define TCU_TMR_FMASK1 (1 << 1)
+#define TCU_TMR_FMASK0 (1 << 0)
+
+#define TCU_TMSR_HMST5 (1 << 21)
+#define TCU_TMSR_HMST4 (1 << 20)
+#define TCU_TMSR_HMST3 (1 << 19)
+#define TCU_TMSR_HMST2 (1 << 18)
+#define TCU_TMSR_HMST1 (1 << 17)
+#define TCU_TMSR_HMST0 (1 << 16)
+#define TCU_TMSR_OSTMST (1 << 15)
+#define TCU_TMSR_FMST5 (1 << 5)
+#define TCU_TMSR_FMST4 (1 << 4)
+#define TCU_TMSR_FMST3 (1 << 3)
+#define TCU_TMSR_FMST2 (1 << 2)
+#define TCU_TMSR_FMST1 (1 << 1)
+#define TCU_TMSR_FMST0 (1 << 0)
+
+#define TCU_TMCR_HMCL5 (1 << 21)
+#define TCU_TMCR_HMCL4 (1 << 20)
+#define TCU_TMCR_HMCL3 (1 << 19)
+#define TCU_TMCR_HMCL2 (1 << 18)
+#define TCU_TMCR_HMCL1 (1 << 17)
+#define TCU_TMCR_HMCL0 (1 << 16)
+#define TCU_TMCR_OSTMCL (1 << 15)
+#define TCU_TMCR_FMCL5 (1 << 5)
+#define TCU_TMCR_FMCL4 (1 << 4)
+#define TCU_TMCR_FMCL3 (1 << 3)
+#define TCU_TMCR_FMCL2 (1 << 2)
+#define TCU_TMCR_FMCL1 (1 << 1)
+#define TCU_TMCR_FMCL0 (1 << 0)
+
+#define TCU_TCSR_CNT_CLRZ (1 << 10) /* clear counter to 0, only used in TCU2 mode */
+#define TCU_TCSR_PWM_SD (1 << 9) /* shut down the pwm output only used in TCU1 mode */
+#define TCU_TCSR_PWM_INITL_HIGH (1 << 8) /* selects an initial output level for pwm output */
+#define TCU_TCSR_PWM_EN (1 << 7) /* pwm pin output enable */
+#define TCU_TCSR_PRESCALE_BIT 3 /* select the tcnt count clock frequency*/
+#define TCU_TCSR_PRESCALE_MASK (0x7 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE1 (0x0 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE4 (0x1 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE16 (0x2 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE64 (0x3 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE256 (0x4 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE1024 (0x5 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_EXT_EN (1 << 2) /* select extal as the timer clock input */
+#define TCU_TCSR_RTC_EN (1 << 1) /* select rtcclk as the timer clock input */
+#define TCU_TCSR_PCK_EN (1 << 0) /* select pclk as the timer clock input */
+
+#define TCU_TSTR_REAL2 (1 << 18) /* the value read from counter 2 is a real value */
+#define TCU_TSTR_REAL1 (1 << 17)
+#define TCU_TSTR_BUSY2 (1 << 2) /* the counter 2 is busy now */
+#define TCU_TSTR_BUSY1 (1 << 1)
+
+#define TCU_TSTSR_REALS2 (1 << 18)
+#define TCU_TSTSR_REALS1 (1 << 17)
+#define TCU_TSTSR_BUSYS2 (1 << 2)
+#define TCU_TSTSR_BUSYS1 (1 << 1)
+
+#define TCU_TSTCR_REALC2 (1 << 18)
+#define TCU_TSTCR_REALC1 (1 << 17)
+#define TCU_TSTCR_BUSYC2 (1 << 2)
+#define TCU_TSTCR_BUSYC1 (1 << 1)
+
+#define TCU_OSTCR_CNT_MD (1 << 15) /* when the value counter is equal to compare value,the counter is go on increasing till overflow,and then icrease from 0 */
+#define TCU_OSTCR_PWM_SD (1 << 9) /* shut down the pwm output, only used in TCU1 mode */
+#define TCU_OSTCSR_PRESCALE_BIT 3
+#define TCU_OSTCSR_PRESCALE_MASK (0x7 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE1 (0x0 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE4 (0x1 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE16 (0x2 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE64 (0x3 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE256 (0x4 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE1024 (0x5 << TCU_OSTCSR_PRESCALE_BIT)
+#define TCU_OSTCSR_EXT_EN (1 << 2) /* select extal as the timer clock input */
+#define TCU_OSTCSR_RTC_EN (1 << 1) /* select rtcclk as the timer clock input */
+#define TCU_OSTCSR_PCK_EN (1 << 0) /* select pclk as the timer clock input */
+
+/*************************************************************************
+ * WDT (WatchDog Timer)
+ *************************************************************************/
+#define WDT_TDR (WDT_BASE + 0x00)
+#define WDT_TCER (WDT_BASE + 0x04)
+#define WDT_TCNT (WDT_BASE + 0x08)
+#define WDT_TCSR (WDT_BASE + 0x0C)
+
+#define REG_WDT_TDR REG16(WDT_TDR)
+#define REG_WDT_TCER REG8(WDT_TCER)
+#define REG_WDT_TCNT REG16(WDT_TCNT)
+#define REG_WDT_TCSR REG16(WDT_TCSR)
+
+// Register definition
+#define WDT_TCSR_PRESCALE_BIT 3
+#define WDT_TCSR_PRESCALE_MASK (0x7 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE1 (0x0 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE4 (0x1 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE16 (0x2 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE64 (0x3 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE256 (0x4 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE1024 (0x5 << WDT_TCSR_PRESCALE_BIT)
+#define WDT_TCSR_EXT_EN (1 << 2)
+#define WDT_TCSR_RTC_EN (1 << 1)
+#define WDT_TCSR_PCK_EN (1 << 0)
+
+#define WDT_TCER_TCEN (1 << 0)
+
+
+/*************************************************************************
+ * DMAC (DMA Controller)
+ *************************************************************************/
+
+#define MAX_DMA_NUM 12 /* max 12 channels */
+#define HALF_DMA_NUM 6 /* the number of one dma controller's channels */
+
+/* m is the DMA controller index (0, 1), n is the DMA channel index (0 - 11) */
+
+#define DMAC_DSAR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x00 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA source address */
+#define DMAC_DTAR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x04 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA target address */
+#define DMAC_DTCR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x08 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA transfer count */
+#define DMAC_DRSR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x0c + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA request source */
+#define DMAC_DCCSR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x10 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA control/status */
+#define DMAC_DCMD(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x14 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA command */
+#define DMAC_DDA(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x18 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA descriptor address */
+#define DMAC_DSD(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0xc0 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x04)) /* DMA Stride Address */
+
+#define DMAC_DMACR(m) (DMAC_BASE + 0x0300 + 0x100 * (m)) /* DMA control register */
+#define DMAC_DMAIPR(m) (DMAC_BASE + 0x0304 + 0x100 * (m)) /* DMA interrupt pending */
+#define DMAC_DMADBR(m) (DMAC_BASE + 0x0308 + 0x100 * (m)) /* DMA doorbell */
+#define DMAC_DMADBSR(m) (DMAC_BASE + 0x030C + 0x100 * (m)) /* DMA doorbell set */
+#define DMAC_DMACKE(m) (DMAC_BASE + 0x0310 + 0x100 * (m))
+
+#define REG_DMAC_DSAR(n) REG32(DMAC_DSAR((n)))
+#define REG_DMAC_DTAR(n) REG32(DMAC_DTAR((n)))
+#define REG_DMAC_DTCR(n) REG32(DMAC_DTCR((n)))
+#define REG_DMAC_DRSR(n) REG32(DMAC_DRSR((n)))
+#define REG_DMAC_DCCSR(n) REG32(DMAC_DCCSR((n)))
+#define REG_DMAC_DCMD(n) REG32(DMAC_DCMD((n)))
+#define REG_DMAC_DDA(n) REG32(DMAC_DDA((n)))
+#define REG_DMAC_DSD(n) REG32(DMAC_DSD(n))
+#define REG_DMAC_DMACR(m) REG32(DMAC_DMACR(m))
+#define REG_DMAC_DMAIPR(m) REG32(DMAC_DMAIPR(m))
+#define REG_DMAC_DMADBR(m) REG32(DMAC_DMADBR(m))
+#define REG_DMAC_DMADBSR(m) REG32(DMAC_DMADBSR(m))
+#define REG_DMAC_DMACKE(m) REG32(DMAC_DMACKE(m))
+
+// DMA request source register
+#define DMAC_DRSR_RS_BIT 0
+#define DMAC_DRSR_RS_MASK (0x3f << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_EXT (0 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_NAND (1 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_BCH_ENC (2 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_BCH_DEC (3 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_TSSIIN (9 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART3OUT (14 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART3IN (15 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART2OUT (16 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART2IN (17 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART1OUT (18 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART1IN (19 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSI0OUT (22 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSI0IN (23 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSC0OUT (26 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSC0IN (27 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_TCU (28 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SADC (29 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSC1OUT (30 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSC1IN (31 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSI1OUT (32 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSI1IN (33 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_PMOUT (34 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_PMIN (35 << DMAC_DRSR_RS_BIT)
+
+// DMA channel control/status register
+#define DMAC_DCCSR_NDES (1 << 31) /* descriptor (0) or not (1) ? */
+#define DMAC_DCCSR_DES8 (1 << 30) /* Descriptor 8 Word */
+#define DMAC_DCCSR_DES4 (0 << 30) /* Descriptor 4 Word */
+#define DMAC_DCCSR_CDOA_BIT 16 /* copy of DMA offset address */
+#define DMAC_DCCSR_CDOA_MASK (0xff << DMAC_DCCSR_CDOA_BIT)
+#define DMAC_DCCSR_BERR (1 << 7) /* BCH error within this transfer, Only for channel 0 */
+#define DMAC_DCCSR_INV (1 << 6) /* descriptor invalid */
+#define DMAC_DCCSR_AR (1 << 4) /* address error */
+#define DMAC_DCCSR_TT (1 << 3) /* transfer terminated */
+#define DMAC_DCCSR_HLT (1 << 2) /* DMA halted */
+#define DMAC_DCCSR_CT (1 << 1) /* count terminated */
+#define DMAC_DCCSR_EN (1 << 0) /* channel enable bit */
+
+// DMA channel command register
+#define DMAC_DCMD_EACKS_LOW (1 << 31) /* External DACK Output Level Select, active low */
+#define DMAC_DCMD_EACKS_HIGH (0 << 31) /* External DACK Output Level Select, active high */
+#define DMAC_DCMD_EACKM_WRITE (1 << 30) /* External DACK Output Mode Select, output in write cycle */
+#define DMAC_DCMD_EACKM_READ (0 << 30) /* External DACK Output Mode Select, output in read cycle */
+#define DMAC_DCMD_ERDM_BIT 28 /* External DREQ Detection Mode Select */
+#define DMAC_DCMD_ERDM_MASK (0x03 << DMAC_DCMD_ERDM_BIT)
+ #define DMAC_DCMD_ERDM_LOW (0 << DMAC_DCMD_ERDM_BIT)
+ #define DMAC_DCMD_ERDM_FALL (1 << DMAC_DCMD_ERDM_BIT)
+ #define DMAC_DCMD_ERDM_HIGH (2 << DMAC_DCMD_ERDM_BIT)
+ #define DMAC_DCMD_ERDM_RISE (3 << DMAC_DCMD_ERDM_BIT)
+#define DMAC_DCMD_BLAST (1 << 25) /* BCH last */
+#define DMAC_DCMD_SAI (1 << 23) /* source address increment */
+#define DMAC_DCMD_DAI (1 << 22) /* dest address increment */
+#define DMAC_DCMD_RDIL_BIT 16 /* request detection interval length */
+#define DMAC_DCMD_RDIL_MASK (0x0f << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_IGN (0 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_2 (1 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_4 (2 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_8 (3 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_12 (4 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_16 (5 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_20 (6 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_24 (7 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_28 (8 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_32 (9 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_48 (10 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_60 (11 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_64 (12 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_124 (13 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_128 (14 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_200 (15 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_SWDH_BIT 14 /* source port width */
+#define DMAC_DCMD_SWDH_MASK (0x03 << DMAC_DCMD_SWDH_BIT)
+ #define DMAC_DCMD_SWDH_32 (0 << DMAC_DCMD_SWDH_BIT)
+ #define DMAC_DCMD_SWDH_8 (1 << DMAC_DCMD_SWDH_BIT)
+ #define DMAC_DCMD_SWDH_16 (2 << DMAC_DCMD_SWDH_BIT)
+#define DMAC_DCMD_DWDH_BIT 12 /* dest port width */
+#define DMAC_DCMD_DWDH_MASK (0x03 << DMAC_DCMD_DWDH_BIT)
+ #define DMAC_DCMD_DWDH_32 (0 << DMAC_DCMD_DWDH_BIT)
+ #define DMAC_DCMD_DWDH_8 (1 << DMAC_DCMD_DWDH_BIT)
+ #define DMAC_DCMD_DWDH_16 (2 << DMAC_DCMD_DWDH_BIT)
+#define DMAC_DCMD_DS_BIT 8 /* transfer data size of a data unit */
+#define DMAC_DCMD_DS_MASK (0x07 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_32BIT (0 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_8BIT (1 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_16BIT (2 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_16BYTE (3 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_32BYTE (4 << DMAC_DCMD_DS_BIT)
+#define DMAC_DCMD_STDE (1 << 5) /* Stride Disable/Enable */
+#define DMAC_DCMD_DES_V (1 << 4) /* descriptor valid flag */
+#define DMAC_DCMD_DES_VM (1 << 3) /* descriptor valid mask: 1:support V-bit */
+#define DMAC_DCMD_DES_VIE (1 << 2) /* DMA valid error interrupt enable */
+#define DMAC_DCMD_TIE (1 << 1) /* DMA transfer interrupt enable */
+#define DMAC_DCMD_LINK (1 << 0) /* descriptor link enable */
+
+// DMA descriptor address register
+#define DMAC_DDA_BASE_BIT 12 /* descriptor base address */
+#define DMAC_DDA_BASE_MASK (0x0fffff << DMAC_DDA_BASE_BIT)
+#define DMAC_DDA_OFFSET_BIT 4 /* descriptor offset address */
+#define DMAC_DDA_OFFSET_MASK (0x0ff << DMAC_DDA_OFFSET_BIT)
+
+// DMA stride address register
+#define DMAC_DSD_TSD_BIT 16 /* target stride address */
+#define DMAC_DSD_TSD_MASK (0xffff << DMAC_DSD_TSD_BIT)
+#define DMAC_DSD_SSD_BIT 0 /* source stride address */
+#define DMAC_DSD_SSD_MASK (0xffff << DMAC_DSD_SSD_BIT)
+
+// DMA control register
+#define DMAC_DMACR_FMSC (1 << 31) /* MSC Fast DMA mode */
+#define DMAC_DMACR_FSSI (1 << 30) /* SSI Fast DMA mode */
+#define DMAC_DMACR_FTSSI (1 << 29) /* TSSI Fast DMA mode */
+#define DMAC_DMACR_FUART (1 << 28) /* UART Fast DMA mode */
+#define DMAC_DMACR_FAIC (1 << 27) /* AIC Fast DMA mode */
+#define DMAC_DMACR_PR_BIT 8 /* channel priority mode */
+#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_012345 (0 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_120345 (1 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_230145 (2 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_340125 (3 << DMAC_DMACR_PR_BIT)
+#define DMAC_DMACR_HLT (1 << 3) /* DMA halt flag */
+#define DMAC_DMACR_AR (1 << 2) /* address error flag */
+#define DMAC_DMACR_DMAE (1 << 0) /* DMA enable bit */
+
+// DMA doorbell register
+#define DMAC_DMADBR_DB5 (1 << 5) /* doorbell for channel 5 */
+#define DMAC_DMADBR_DB4 (1 << 4) /* doorbell for channel 4 */
+#define DMAC_DMADBR_DB3 (1 << 3) /* doorbell for channel 3 */
+#define DMAC_DMADBR_DB2 (1 << 2) /* doorbell for channel 2 */
+#define DMAC_DMADBR_DB1 (1 << 1) /* doorbell for channel 1 */
+#define DMAC_DMADBR_DB0 (1 << 0) /* doorbell for channel 0 */
+
+// DMA doorbell set register
+#define DMAC_DMADBSR_DBS5 (1 << 5) /* enable doorbell for channel 5 */
+#define DMAC_DMADBSR_DBS4 (1 << 4) /* enable doorbell for channel 4 */
+#define DMAC_DMADBSR_DBS3 (1 << 3) /* enable doorbell for channel 3 */
+#define DMAC_DMADBSR_DBS2 (1 << 2) /* enable doorbell for channel 2 */
+#define DMAC_DMADBSR_DBS1 (1 << 1) /* enable doorbell for channel 1 */
+#define DMAC_DMADBSR_DBS0 (1 << 0) /* enable doorbell for channel 0 */
+
+// DMA interrupt pending register
+#define DMAC_DMAIPR_CIRQ5 (1 << 5) /* irq pending status for channel 5 */
+#define DMAC_DMAIPR_CIRQ4 (1 << 4) /* irq pending status for channel 4 */
+#define DMAC_DMAIPR_CIRQ3 (1 << 3) /* irq pending status for channel 3 */
+#define DMAC_DMAIPR_CIRQ2 (1 << 2) /* irq pending status for channel 2 */
+#define DMAC_DMAIPR_CIRQ1 (1 << 1) /* irq pending status for channel 1 */
+#define DMAC_DMAIPR_CIRQ0 (1 << 0) /* irq pending status for channel 0 */
+
+
+/*************************************************************************
+ * GPIO (General-Purpose I/O Ports)
+ *************************************************************************/
+#define MAX_GPIO_NUM 192
+#define GPIO_WAKEUP (32 * 4 + 30)
+
+//n = 0,1,2,3,4,5 (PORTA, PORTB, PORTC, PORTD, PORTE, PORTF)
+#define GPIO_PXPIN(n) (GPIO_BASE + (0x00 + (n)*0x100)) /* PIN Level Register */
+#define GPIO_PXDAT(n) (GPIO_BASE + (0x10 + (n)*0x100)) /* Port Data Register */
+#define GPIO_PXDATS(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Data Set Register */
+#define GPIO_PXDATC(n) (GPIO_BASE + (0x18 + (n)*0x100)) /* Port Data Clear Register */
+#define GPIO_PXIM(n) (GPIO_BASE + (0x20 + (n)*0x100)) /* Interrupt Mask Register */
+#define GPIO_PXIMS(n) (GPIO_BASE + (0x24 + (n)*0x100)) /* Interrupt Mask Set Reg */
+#define GPIO_PXIMC(n) (GPIO_BASE + (0x28 + (n)*0x100)) /* Interrupt Mask Clear Reg */
+#define GPIO_PXPE(n) (GPIO_BASE + (0x30 + (n)*0x100)) /* Pull Enable Register */
+#define GPIO_PXPES(n) (GPIO_BASE + (0x34 + (n)*0x100)) /* Pull Enable Set Reg. */
+#define GPIO_PXPEC(n) (GPIO_BASE + (0x38 + (n)*0x100)) /* Pull Enable Clear Reg. */
+#define GPIO_PXFUN(n) (GPIO_BASE + (0x40 + (n)*0x100)) /* Function Register */
+#define GPIO_PXFUNS(n) (GPIO_BASE + (0x44 + (n)*0x100)) /* Function Set Register */
+#define GPIO_PXFUNC(n) (GPIO_BASE + (0x48 + (n)*0x100)) /* Function Clear Register */
+#define GPIO_PXSEL(n) (GPIO_BASE + (0x50 + (n)*0x100)) /* Select Register */
+#define GPIO_PXSELS(n) (GPIO_BASE + (0x54 + (n)*0x100)) /* Select Set Register */
+#define GPIO_PXSELC(n) (GPIO_BASE + (0x58 + (n)*0x100)) /* Select Clear Register */
+#define GPIO_PXDIR(n) (GPIO_BASE + (0x60 + (n)*0x100)) /* Direction Register */
+#define GPIO_PXDIRS(n) (GPIO_BASE + (0x64 + (n)*0x100)) /* Direction Set Register */
+#define GPIO_PXDIRC(n) (GPIO_BASE + (0x68 + (n)*0x100)) /* Direction Clear Register */
+#define GPIO_PXTRG(n) (GPIO_BASE + (0x70 + (n)*0x100)) /* Trigger Register */
+#define GPIO_PXTRGS(n) (GPIO_BASE + (0x74 + (n)*0x100)) /* Trigger Set Register */
+#define GPIO_PXTRGC(n) (GPIO_BASE + (0x78 + (n)*0x100)) /* Trigger Set Register */
+#define GPIO_PXFLG(n) (GPIO_BASE + (0x80 + (n)*0x100)) /* Port Flag Register */
+#define GPIO_PXFLGC(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Flag Clear Register */
+
+#define REG_GPIO_PXPIN(n) REG32(GPIO_PXPIN((n))) /* PIN level */
+#define REG_GPIO_PXDAT(n) REG32(GPIO_PXDAT((n))) /* 1: interrupt pending */
+#define REG_GPIO_PXDATS(n) REG32(GPIO_PXDATS((n)))
+#define REG_GPIO_PXDATC(n) REG32(GPIO_PXDATC((n)))
+#define REG_GPIO_PXIM(n) REG32(GPIO_PXIM((n))) /* 1: mask pin interrupt */
+#define REG_GPIO_PXIMS(n) REG32(GPIO_PXIMS((n)))
+#define REG_GPIO_PXIMC(n) REG32(GPIO_PXIMC((n)))
+#define REG_GPIO_PXPE(n) REG32(GPIO_PXPE((n))) /* 1: disable pull up/down */
+#define REG_GPIO_PXPES(n) REG32(GPIO_PXPES((n)))
+#define REG_GPIO_PXPEC(n) REG32(GPIO_PXPEC((n)))
+#define REG_GPIO_PXFUN(n) REG32(GPIO_PXFUN((n))) /* 0:GPIO or intr, 1:FUNC */
+#define REG_GPIO_PXFUNS(n) REG32(GPIO_PXFUNS((n)))
+#define REG_GPIO_PXFUNC(n) REG32(GPIO_PXFUNC((n)))
+#define REG_GPIO_PXSEL(n) REG32(GPIO_PXSEL((n))) /* 0:GPIO/Fun0,1:intr/fun1*/
+#define REG_GPIO_PXSELS(n) REG32(GPIO_PXSELS((n)))
+#define REG_GPIO_PXSELC(n) REG32(GPIO_PXSELC((n)))
+#define REG_GPIO_PXDIR(n) REG32(GPIO_PXDIR((n))) /* 0:input/low-level-trig/falling-edge-trig, 1:output/high-level-trig/rising-edge-trig */
+#define REG_GPIO_PXDIRS(n) REG32(GPIO_PXDIRS((n)))
+#define REG_GPIO_PXDIRC(n) REG32(GPIO_PXDIRC((n)))
+#define REG_GPIO_PXTRG(n) REG32(GPIO_PXTRG((n))) /* 0:level-trigger, 1:edge-trigger */
+#define REG_GPIO_PXTRGS(n) REG32(GPIO_PXTRGS((n)))
+#define REG_GPIO_PXTRGC(n) REG32(GPIO_PXTRGC((n)))
+#define REG_GPIO_PXFLG(n) REG32(GPIO_PXFLG((n))) /* interrupt flag */
+#define REG_GPIO_PXFLGC(n) REG32(GPIO_PXFLGC((n))) /* interrupt flag */
+
+
+/*************************************************************************
+ * UART
+ *************************************************************************/
+
+#define IRDA_BASE UART0_BASE
+#define UART_BASE UART0_BASE
+#define UART_OFF 0x1000
+
+/* Register Offset */
+#define OFF_RDR (0x00) /* R 8b H'xx */
+#define OFF_TDR (0x00) /* W 8b H'xx */
+#define OFF_DLLR (0x00) /* RW 8b H'00 */
+#define OFF_DLHR (0x04) /* RW 8b H'00 */
+#define OFF_IER (0x04) /* RW 8b H'00 */
+#define OFF_ISR (0x08) /* R 8b H'01 */
+#define OFF_FCR (0x08) /* W 8b H'00 */
+#define OFF_LCR (0x0C) /* RW 8b H'00 */
+#define OFF_MCR (0x10) /* RW 8b H'00 */
+#define OFF_LSR (0x14) /* R 8b H'00 */
+#define OFF_MSR (0x18) /* R 8b H'00 */
+#define OFF_SPR (0x1C) /* RW 8b H'00 */
+#define OFF_SIRCR (0x20) /* RW 8b H'00, UART0 */
+#define OFF_UMR (0x24) /* RW 8b H'00, UART M Register */
+#define OFF_UACR (0x28) /* RW 8b H'00, UART Add Cycle Register */
+
+/* Register Address */
+#define UART0_RDR (UART0_BASE + OFF_RDR)
+#define UART0_TDR (UART0_BASE + OFF_TDR)
+#define UART0_DLLR (UART0_BASE + OFF_DLLR)
+#define UART0_DLHR (UART0_BASE + OFF_DLHR)
+#define UART0_IER (UART0_BASE + OFF_IER)
+#define UART0_ISR (UART0_BASE + OFF_ISR)
+#define UART0_FCR (UART0_BASE + OFF_FCR)
+#define UART0_LCR (UART0_BASE + OFF_LCR)
+#define UART0_MCR (UART0_BASE + OFF_MCR)
+#define UART0_LSR (UART0_BASE + OFF_LSR)
+#define UART0_MSR (UART0_BASE + OFF_MSR)
+#define UART0_SPR (UART0_BASE + OFF_SPR)
+#define UART0_SIRCR (UART0_BASE + OFF_SIRCR)
+#define UART0_UMR (UART0_BASE + OFF_UMR)
+#define UART0_UACR (UART0_BASE + OFF_UACR)
+
+#define UART1_RDR (UART1_BASE + OFF_RDR)
+#define UART1_TDR (UART1_BASE + OFF_TDR)
+#define UART1_DLLR (UART1_BASE + OFF_DLLR)
+#define UART1_DLHR (UART1_BASE + OFF_DLHR)
+#define UART1_IER (UART1_BASE + OFF_IER)
+#define UART1_ISR (UART1_BASE + OFF_ISR)
+#define UART1_FCR (UART1_BASE + OFF_FCR)
+#define UART1_LCR (UART1_BASE + OFF_LCR)
+#define UART1_MCR (UART1_BASE + OFF_MCR)
+#define UART1_LSR (UART1_BASE + OFF_LSR)
+#define UART1_MSR (UART1_BASE + OFF_MSR)
+#define UART1_SPR (UART1_BASE + OFF_SPR)
+#define UART1_SIRCR (UART1_BASE + OFF_SIRCR)
+
+#define UART2_RDR (UART2_BASE + OFF_RDR)
+#define UART2_TDR (UART2_BASE + OFF_TDR)
+#define UART2_DLLR (UART2_BASE + OFF_DLLR)
+#define UART2_DLHR (UART2_BASE + OFF_DLHR)
+#define UART2_IER (UART2_BASE + OFF_IER)
+#define UART2_ISR (UART2_BASE + OFF_ISR)
+#define UART2_FCR (UART2_BASE + OFF_FCR)
+#define UART2_LCR (UART2_BASE + OFF_LCR)
+#define UART2_MCR (UART2_BASE + OFF_MCR)
+#define UART2_LSR (UART2_BASE + OFF_LSR)
+#define UART2_MSR (UART2_BASE + OFF_MSR)
+#define UART2_SPR (UART2_BASE + OFF_SPR)
+#define UART2_SIRCR (UART2_BASE + OFF_SIRCR)
+
+#define UART3_RDR (UART3_BASE + OFF_RDR)
+#define UART3_TDR (UART3_BASE + OFF_TDR)
+#define UART3_DLLR (UART3_BASE + OFF_DLLR)
+#define UART3_DLHR (UART3_BASE + OFF_DLHR)
+#define UART3_IER (UART3_BASE + OFF_IER)
+#define UART3_ISR (UART3_BASE + OFF_ISR)
+#define UART3_FCR (UART3_BASE + OFF_FCR)
+#define UART3_LCR (UART3_BASE + OFF_LCR)
+#define UART3_MCR (UART3_BASE + OFF_MCR)
+#define UART3_LSR (UART3_BASE + OFF_LSR)
+#define UART3_MSR (UART3_BASE + OFF_MSR)
+#define UART3_SPR (UART3_BASE + OFF_SPR)
+#define UART3_SIRCR (UART3_BASE + OFF_SIRCR)
+
+
+/*
+ * Define macros for UARTIER
+ * UART Interrupt Enable Register
+ */
+#define UARTIER_RIE (1 << 0) /* 0: receive fifo full interrupt disable */
+#define UARTIER_TIE (1 << 1) /* 0: transmit fifo empty interrupt disable */
+#define UARTIER_RLIE (1 << 2) /* 0: receive line status interrupt disable */
+#define UARTIER_MIE (1 << 3) /* 0: modem status interrupt disable */
+#define UARTIER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */
+
+/*
+ * Define macros for UARTISR
+ * UART Interrupt Status Register
+ */
+#define UARTISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */
+#define UARTISR_IID (7 << 1) /* Source of Interrupt */
+#define UARTISR_IID_MSI (0 << 1) /* Modem status interrupt */
+#define UARTISR_IID_THRI (1 << 1) /* Transmitter holding register empty */
+#define UARTISR_IID_RDI (2 << 1) /* Receiver data interrupt */
+#define UARTISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */
+#define UARTISR_IID_RTO (6 << 1) /* Receive timeout */
+#define UARTISR_FFMS (3 << 6) /* FIFO mode select, set when UARTFCR.FE is set to 1 */
+#define UARTISR_FFMS_NO_FIFO (0 << 6)
+#define UARTISR_FFMS_FIFO_MODE (3 << 6)
+
+/*
+ * Define macros for UARTFCR
+ * UART FIFO Control Register
+ */
+#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */
+#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */
+#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */
+#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */
+#define UARTFCR_UUE (1 << 4) /* 0: disable UART */
+#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */
+#define UARTFCR_RTRG_1 (0 << 6)
+#define UARTFCR_RTRG_4 (1 << 6)
+#define UARTFCR_RTRG_8 (2 << 6)
+#define UARTFCR_RTRG_15 (3 << 6)
+
+/*
+ * Define macros for UARTLCR
+ * UART Line Control Register
+ */
+#define UARTLCR_WLEN (3 << 0) /* word length */
+#define UARTLCR_WLEN_5 (0 << 0)
+#define UARTLCR_WLEN_6 (1 << 0)
+#define UARTLCR_WLEN_7 (2 << 0)
+#define UARTLCR_WLEN_8 (3 << 0)
+#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8
+ 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */
+#define UARTLCR_STOP1 (0 << 2)
+#define UARTLCR_STOP2 (1 << 2)
+#define UARTLCR_PE (1 << 3) /* 0: parity disable */
+#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */
+#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */
+#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */
+#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */
+
+/*
+ * Define macros for UARTLSR
+ * UART Line Status Register
+ */
+#define UARTLSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */
+#define UARTLSR_ORER (1 << 1) /* 0: no overrun error */
+#define UARTLSR_PER (1 << 2) /* 0: no parity error */
+#define UARTLSR_FER (1 << 3) /* 0; no framing error */
+#define UARTLSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */
+#define UARTLSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */
+#define UARTLSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */
+#define UARTLSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */
+
+/*
+ * Define macros for UARTMCR
+ * UART Modem Control Register
+ */
+#define UARTMCR_RTS (1 << 1) /* 0: RTS_ output high, 1: RTS_ output low */
+#define UARTMCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */
+#define UARTMCR_MCE (1 << 7) /* 0: modem function is disable */
+
+/*
+ * Define macros for UARTMSR
+ * UART Modem Status Register
+ */
+#define UARTMSR_CCTS (1 << 0) /* 1: a change on CTS_ pin */
+#define UARTMSR_CTS (1 << 4) /* 0: CTS_ pin is high */
+
+/*
+ * Define macros for SIRCR
+ * Slow IrDA Control Register
+ */
+#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: SIR mode */
+#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: SIR mode */
+#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length
+ 1: 0 pulse width is 1.6us for 115.2Kbps */
+#define SIRCR_TDPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */
+#define SIRCR_RDPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */
+
+
+/*************************************************************************
+ * AIC (AC97/I2S Controller)
+ *************************************************************************/
+#define AIC_FR (AIC_BASE + 0x000)
+#define AIC_CR (AIC_BASE + 0x004)
+#define AIC_ACCR1 (AIC_BASE + 0x008)
+#define AIC_ACCR2 (AIC_BASE + 0x00C)
+#define AIC_I2SCR (AIC_BASE + 0x010)
+#define AIC_SR (AIC_BASE + 0x014)
+#define AIC_ACSR (AIC_BASE + 0x018)
+#define AIC_I2SSR (AIC_BASE + 0x01C)
+#define AIC_ACCAR (AIC_BASE + 0x020)
+#define AIC_ACCDR (AIC_BASE + 0x024)
+#define AIC_ACSAR (AIC_BASE + 0x028)
+#define AIC_ACSDR (AIC_BASE + 0x02C)
+#define AIC_I2SDIV (AIC_BASE + 0x030)
+#define AIC_DR (AIC_BASE + 0x034)
+
+#define REG_AIC_FR REG32(AIC_FR)
+#define REG_AIC_CR REG32(AIC_CR)
+#define REG_AIC_ACCR1 REG32(AIC_ACCR1)
+#define REG_AIC_ACCR2 REG32(AIC_ACCR2)
+#define REG_AIC_I2SCR REG32(AIC_I2SCR)
+#define REG_AIC_SR REG32(AIC_SR)
+#define REG_AIC_ACSR REG32(AIC_ACSR)
+#define REG_AIC_I2SSR REG32(AIC_I2SSR)
+#define REG_AIC_ACCAR REG32(AIC_ACCAR)
+#define REG_AIC_ACCDR REG32(AIC_ACCDR)
+#define REG_AIC_ACSAR REG32(AIC_ACSAR)
+#define REG_AIC_ACSDR REG32(AIC_ACSDR)
+#define REG_AIC_I2SDIV REG32(AIC_I2SDIV)
+#define REG_AIC_DR REG32(AIC_DR)
+
+/* AIC Controller Configuration Register (AIC_FR) */
+
+#define AIC_FR_RFTH_BIT 12 /* Receive FIFO Threshold */
+#define AIC_FR_RFTH_MASK (0xf << AIC_FR_RFTH_BIT)
+#define AIC_FR_TFTH_BIT 8 /* Transmit FIFO Threshold */
+#define AIC_FR_TFTH_MASK (0xf << AIC_FR_TFTH_BIT)
+#define AIC_FR_LSMP (1 << 6) /* Play Zero sample or last sample */
+#define AIC_FR_ICDC (1 << 5) /* External(0) or Internal CODEC(1) */
+#define AIC_FR_AUSEL (1 << 4) /* AC97(0) or I2S/MSB-justified(1) */
+#define AIC_FR_RST (1 << 3) /* AIC registers reset */
+#define AIC_FR_BCKD (1 << 2) /* I2S BIT_CLK direction, 0:input,1:output */
+#define AIC_FR_SYNCD (1 << 1) /* I2S SYNC direction, 0:input,1:output */
+#define AIC_FR_ENB (1 << 0) /* AIC enable bit */
+
+/* AIC Controller Common Control Register (AIC_CR) */
+
+#define AIC_CR_OSS_BIT 19 /* Output Sample Size from memory (AIC V2 only) */
+#define AIC_CR_OSS_MASK (0x7 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_8BIT (0x0 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_16BIT (0x1 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_18BIT (0x2 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_20BIT (0x3 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_24BIT (0x4 << AIC_CR_OSS_BIT)
+#define AIC_CR_ISS_BIT 16 /* Input Sample Size from memory (AIC V2 only) */
+#define AIC_CR_ISS_MASK (0x7 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_8BIT (0x0 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_16BIT (0x1 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_18BIT (0x2 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_20BIT (0x3 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_24BIT (0x4 << AIC_CR_ISS_BIT)
+#define AIC_CR_RDMS (1 << 15) /* Receive DMA enable */
+#define AIC_CR_TDMS (1 << 14) /* Transmit DMA enable */
+#define AIC_CR_M2S (1 << 11) /* Mono to Stereo enable */
+#define AIC_CR_ENDSW (1 << 10) /* Endian switch enable */
+#define AIC_CR_AVSTSU (1 << 9) /* Signed <-> Unsigned toggle enable */
+#define AIC_CR_FLUSH (1 << 8) /* Flush FIFO */
+#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */
+#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */
+#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */
+#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */
+#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */
+#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */
+#define AIC_CR_EREC (1 << 0) /* Enable Record Function */
+
+/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */
+
+#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */
+#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT)
+ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */
+ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */
+ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */
+ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */
+ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */
+ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */
+ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */
+ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */
+ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */
+ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */
+#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */
+#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT)
+ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */
+ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */
+ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */
+ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */
+ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */
+ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */
+ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */
+ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */
+ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */
+ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */
+
+/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */
+
+#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */
+#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */
+#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */
+#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */
+#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT)
+ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */
+ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */
+ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */
+ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */
+#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */
+#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT)
+ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */
+ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */
+ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */
+ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */
+#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */
+#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */
+#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */
+#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */
+
+/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */
+
+#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */
+#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */
+#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT)
+ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */
+ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */
+ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */
+ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */
+ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */
+#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */
+
+/* AIC Controller FIFO Status Register (AIC_SR) */
+
+#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */
+#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT)
+#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */
+#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT)
+#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */
+#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */
+#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */
+#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */
+
+/* AIC Controller AC-link Status Register (AIC_ACSR) */
+
+#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */
+#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */
+#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */
+#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */
+#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */
+#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */
+
+/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */
+
+#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */
+
+/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */
+
+#define AIC_ACCAR_CAR_BIT 0
+#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT)
+
+/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */
+
+#define AIC_ACCDR_CDR_BIT 0
+#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT)
+
+/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */
+
+#define AIC_ACSAR_SAR_BIT 0
+#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT)
+
+/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */
+
+#define AIC_ACSDR_SDR_BIT 0
+#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT)
+
+/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */
+
+#define AIC_I2SDIV_DIV_BIT 0
+#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT)
+ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */
+ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */
+ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */
+ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */
+ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */
+ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */
+
+
+/*************************************************************************
+ * ICDC (Internal CODEC)
+ *************************************************************************/
+
+#define ICDC_CKCFG (ICDC_BASE + 0x00a0) /* Clock Configure Register */
+#define ICDC_RGADW (ICDC_BASE + 0x00a4) /* internal register access control */
+#define ICDC_RGDATA (ICDC_BASE + 0x00a8) /* internal register data output */
+
+#define REG_ICDC_CKCFG REG32(ICDC_CKCFG)
+#define REG_ICDC_RGADW REG32(ICDC_RGADW)
+#define REG_ICDC_RGDATA REG32(ICDC_RGDATA)
+
+/* ICDC Clock Configure Register */
+#define ICDC_CKCFG_CKRDY (1 << 1)
+#define ICDC_CKCFG_SELAD (1 << 0)
+
+/* ICDC internal register access control Register */
+#define ICDC_RGADW_RGWR (1 << 16)
+#define ICDC_RGADW_RGADDR_BIT 8
+#define ICDC_RGADW_RGADDR_MASK (0x7f << ICDC_RGADW_RGADDR_BIT)
+#define ICDC_RGADW_RGDIN_BIT 0
+#define ICDC_RGADW_RGDIN_MASK (0xff << ICDC_RGADW_RGDIN_BIT)
+
+/* ICDC internal register data output Register */
+#define ICDC_RGDATA_IRQ (1 << 8)
+#define ICDC_RGDATA_RGDOUT_BIT 0
+#define ICDC_RGDATA_RGDOUT_MASK (0xff << ICDC_RGDATA_RGDOUT_BIT)
+
+/*************************************************************************
+ * PCM Controller
+ *************************************************************************/
+
+#define PCM_CTL (PCM_BASE + 0x000)
+#define PCM_CFG (PCM_BASE + 0x004)
+#define PCM_DP (PCM_BASE + 0x008)
+#define PCM_INTC (PCM_BASE + 0x00c)
+#define PCM_INTS (PCM_BASE + 0x010)
+#define PCM_DIV (PCM_BASE + 0x014)
+
+#define REG_PCM_CTL REG32(PCM_CTL)
+#define REG_PCM_CFG REG32(PCM_CFG)
+#define REG_PCM_DP REG32(PCM_DP)
+#define REG_PCM_INTC REG32(PCM_INTC)
+#define REG_PCM_INTS REG32(PCM_INTS)
+#define REG_PCM_DIV REG32(PCM_DIV)
+
+/* PCM Controller control Register (PCM_CTL) */
+
+#define PCM_CTL_ERDMA (1 << 9) /* Enable Receive DMA */
+#define PCM_CTL_ETDMA (1 << 8) /* Enable Transmit DMA */
+#define PCM_CTL_LSMP (1 << 7) /* Play Zero sample or last sample */
+#define PCM_CTL_ERPL (1 << 6) /* Enable Playing Back Function */
+#define PCM_CTL_EREC (1 << 5) /* Enable Recording Function */
+#define PCM_CTL_FLUSH (1 << 4) /* FIFO flush */
+#define PCM_CTL_RST (1 << 3) /* Reset PCM */
+#define PCM_CTL_CLKEN (1 << 1) /* Enable the clock division logic */
+#define PCM_CTL_PCMEN (1 << 0) /* Enable PCM module */
+
+/* PCM Controller configure Register (PCM_CFG) */
+
+#define PCM_CFG_SLOT_BIT 13
+#define PCM_CFG_SLOT_MASK (0x3 << PCM_CFG_SLOT_BIT)
+ #define PCM_CFG_SLOT_0 (0 << PCM_CFG_SLOT_BIT) /* Slot is 0 */
+ #define PCM_CFG_SLOT_1 (1 << PCM_CFG_SLOT_BIT) /* Slot is 1 */
+ #define PCM_CFG_SLOT_2 (2 << PCM_CFG_SLOT_BIT) /* Slot is 2 */
+ #define PCM_CFG_SLOT_3 (3 << PCM_CFG_SLOT_BIT) /* Slot is 3 */
+#define PCM_CFG_ISS_BIT 12
+#define PCM_CFG_ISS_MASK (0x1 << PCM_CFG_ISS_BIT)
+ #define PCM_CFG_ISS_8 (0 << PCM_CFG_ISS_BIT)
+ #define PCM_CFG_ISS_16 (1 << PCM_CFG_ISS_BIT)
+#define PCM_CFG_OSS_BIT 11
+#define PCM_CFG_OSS_MASK (0x1 << PCM_CFG_OSS_BIT)
+ #define PCM_CFG_OSS_8 (0 << PCM_CFG_OSS_BIT)
+ #define PCM_CFG_OSS_16 (1 << PCM_CFG_OSS_BIT)
+#define PCM_CFG_IMSBPOS (1 << 10)
+#define PCM_CFG_OMSBPOS (1 << 9)
+#define PCM_CFG_RFTH_BIT 5 /* Receive FIFO Threshold */
+#define PCM_CFG_RFTH_MASK (0xf << PCM_CFG_RFTH_BIT)
+#define PCM_CFG_TFTH_BIT 1 /* Transmit FIFO Threshold */
+#define PCM_CFG_TFTH_MASK (0xf << PCM_CFG_TFTH_BIT)
+#define PCM_CFG_MODE (0x0 << 0)
+
+/* PCM Controller interrupt control Register (PCM_INTC) */
+
+#define PCM_INTC_ETFS (1 << 3)
+#define PCM_INTC_ETUR (1 << 2)
+#define PCM_INTC_ERFS (1 << 1)
+#define PCM_INTC_EROR (1 << 0)
+
+/* PCM Controller interrupt status Register (PCM_INTS) */
+
+#define PCM_INTS_RSTS (1 << 14) /* Reset or flush has not complete */
+#define PCM_INTS_TFL_BIT 9
+#define PCM_INTS_TFL_MASK (0x1f << PCM_INTS_TFL_BIT)
+#define PCM_INTS_TFS (1 << 8) /* Tranmit FIFO Service Request */
+#define PCM_INTS_TUR (1 << 7) /* Transmit FIFO Under Run */
+#define PCM_INTS_RFL_BIT 2
+#define PCM_INTS_RFL_MASK (0x1f << PCM_INTS_RFL_BIT)
+#define PCM_INTS_RFS (1 << 1) /* Receive FIFO Service Request */
+#define PCM_INTS_ROR (1 << 0) /* Receive FIFO Over Run */
+
+/* PCM Controller clock division Register (PCM_DIV) */
+#define PCM_DIV_SYNL_BIT 11
+#define PCM_DIV_SYNL_MASK (0x3f << PCM_DIV_SYNL_BIT)
+#define PCM_DIV_SYNDIV_BIT 6
+#define PCM_DIV_SYNDIV_MASK (0x1f << PCM_DIV_SYNDIV_BIT)
+#define PCM_DIV_CLKDIV_BIT 0
+#define PCM_DIV_CLKDIV_MASK (0x3f << PCM_DIV_CLKDIV_BIT)
+
+
+/*************************************************************************
+ * I2C
+ *************************************************************************/
+#define I2C_DR (I2C_BASE + 0x000)
+#define I2C_CR (I2C_BASE + 0x004)
+#define I2C_SR (I2C_BASE + 0x008)
+#define I2C_GR (I2C_BASE + 0x00C)
+
+#define REG_I2C_DR REG8(I2C_DR)
+#define REG_I2C_CR REG8(I2C_CR)
+#define REG_I2C_SR REG8(I2C_SR)
+#define REG_I2C_GR REG16(I2C_GR)
+
+/* I2C Control Register (I2C_CR) */
+
+#define I2C_CR_IEN (1 << 4)
+#define I2C_CR_STA (1 << 3)
+#define I2C_CR_STO (1 << 2)
+#define I2C_CR_AC (1 << 1)
+#define I2C_CR_I2CE (1 << 0)
+
+/* I2C Status Register (I2C_SR) */
+
+#define I2C_SR_STX (1 << 4)
+#define I2C_SR_BUSY (1 << 3)
+#define I2C_SR_TEND (1 << 2)
+#define I2C_SR_DRF (1 << 1)
+#define I2C_SR_ACKF (1 << 0)
+
+
+/*************************************************************************
+ * SSI (Synchronous Serial Interface)
+ *************************************************************************/
+/* n = 0, 1 (SSI0, SSI1) */
+#define SSI_DR(n) (SSI_BASE + 0x000 + (n)*0x2000)
+#define SSI_CR0(n) (SSI_BASE + 0x004 + (n)*0x2000)
+#define SSI_CR1(n) (SSI_BASE + 0x008 + (n)*0x2000)
+#define SSI_SR(n) (SSI_BASE + 0x00C + (n)*0x2000)
+#define SSI_ITR(n) (SSI_BASE + 0x010 + (n)*0x2000)
+#define SSI_ICR(n) (SSI_BASE + 0x014 + (n)*0x2000)
+#define SSI_GR(n) (SSI_BASE + 0x018 + (n)*0x2000)
+
+#define REG_SSI_DR(n) REG32(SSI_DR(n))
+#define REG_SSI_CR0(n) REG16(SSI_CR0(n))
+#define REG_SSI_CR1(n) REG32(SSI_CR1(n))
+#define REG_SSI_SR(n) REG32(SSI_SR(n))
+#define REG_SSI_ITR(n) REG16(SSI_ITR(n))
+#define REG_SSI_ICR(n) REG8(SSI_ICR(n))
+#define REG_SSI_GR(n) REG16(SSI_GR(n))
+
+/* SSI Data Register (SSI_DR) */
+
+#define SSI_DR_GPC_BIT 0
+#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT)
+
+#define SSI_MAX_FIFO_ENTRIES 128 /* 128 txfifo and 128 rxfifo */
+
+/* SSI Control Register 0 (SSI_CR0) */
+
+#define SSI_CR0_SSIE (1 << 15)
+#define SSI_CR0_TIE (1 << 14)
+#define SSI_CR0_RIE (1 << 13)
+#define SSI_CR0_TEIE (1 << 12)
+#define SSI_CR0_REIE (1 << 11)
+#define SSI_CR0_LOOP (1 << 10)
+#define SSI_CR0_RFINE (1 << 9)
+#define SSI_CR0_RFINC (1 << 8)
+#define SSI_CR0_EACLRUN (1 << 7) /* hardware auto clear underrun when TxFifo no empty */
+#define SSI_CR0_FSEL (1 << 6)
+#define SSI_CR0_TFLUSH (1 << 2)
+#define SSI_CR0_RFLUSH (1 << 1)
+#define SSI_CR0_DISREV (1 << 0)
+
+/* SSI Control Register 1 (SSI_CR1) */
+
+#define SSI_CR1_FRMHL_BIT 30
+#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT)
+ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */
+ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */
+ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */
+ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */
+#define SSI_CR1_TFVCK_BIT 28
+#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT)
+#define SSI_CR1_TCKFI_BIT 26
+#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT)
+#define SSI_CR1_LFST (1 << 25)
+#define SSI_CR1_ITFRM (1 << 24)
+#define SSI_CR1_UNFIN (1 << 23)
+#define SSI_CR1_MULTS (1 << 22)
+#define SSI_CR1_FMAT_BIT 20
+#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT)
+ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */
+ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */
+ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */
+ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */
+#define SSI_CR1_TTRG_BIT 16 /* SSI1 TX trigger */
+#define SSI_CR1_TTRG_MASK (0xf << SSI_CR1_TTRG_BIT)
+#define SSI_CR1_MCOM_BIT 12
+#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT)
+ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */
+ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */
+ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */
+ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */
+ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */
+ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */
+ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */
+ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */
+ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */
+ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */
+ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */
+ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */
+ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */
+ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */
+ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */
+ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */
+#define SSI_CR1_RTRG_BIT 8 /* SSI RX trigger */
+#define SSI_CR1_RTRG_MASK (0xf << SSI_CR1_RTRG_BIT)
+#define SSI_CR1_FLEN_BIT 4
+#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT)
+#define SSI_CR1_PHA (1 << 1)
+#define SSI_CR1_POL (1 << 0)
+
+/* SSI Status Register (SSI_SR) */
+
+#define SSI_SR_TFIFONUM_BIT 16
+#define SSI_SR_TFIFONUM_MASK (0xff << SSI_SR_TFIFONUM_BIT)
+#define SSI_SR_RFIFONUM_BIT 8
+#define SSI_SR_RFIFONUM_MASK (0xff << SSI_SR_RFIFONUM_BIT)
+#define SSI_SR_END (1 << 7)
+#define SSI_SR_BUSY (1 << 6)
+#define SSI_SR_TFF (1 << 5)
+#define SSI_SR_RFE (1 << 4)
+#define SSI_SR_TFHE (1 << 3)
+#define SSI_SR_RFHF (1 << 2)
+#define SSI_SR_UNDR (1 << 1)
+#define SSI_SR_OVER (1 << 0)
+
+/* SSI Interval Time Control Register (SSI_ITR) */
+
+#define SSI_ITR_CNTCLK (1 << 15)
+#define SSI_ITR_IVLTM_BIT 0
+#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT)
+
+
+/*************************************************************************
+ * MSC
+ ************************************************************************/
+/* n = 0, 1 (MSC0, MSC1) */
+#define MSC_STRPCL(n) (MSC_BASE + (n)*0x1000 + 0x000)
+#define MSC_STAT(n) (MSC_BASE + (n)*0x1000 + 0x004)
+#define MSC_CLKRT(n) (MSC_BASE + (n)*0x1000 + 0x008)
+#define MSC_CMDAT(n) (MSC_BASE + (n)*0x1000 + 0x00C)
+#define MSC_RESTO(n) (MSC_BASE + (n)*0x1000 + 0x010)
+#define MSC_RDTO(n) (MSC_BASE + (n)*0x1000 + 0x014)
+#define MSC_BLKLEN(n) (MSC_BASE + (n)*0x1000 + 0x018)
+#define MSC_NOB(n) (MSC_BASE + (n)*0x1000 + 0x01C)
+#define MSC_SNOB(n) (MSC_BASE + (n)*0x1000 + 0x020)
+#define MSC_IMASK(n) (MSC_BASE + (n)*0x1000 + 0x024)
+#define MSC_IREG(n) (MSC_BASE + (n)*0x1000 + 0x028)
+#define MSC_CMD(n) (MSC_BASE + (n)*0x1000 + 0x02C)
+#define MSC_ARG(n) (MSC_BASE + (n)*0x1000 + 0x030)
+#define MSC_RES(n) (MSC_BASE + (n)*0x1000 + 0x034)
+#define MSC_RXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x038)
+#define MSC_TXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x03C)
+#define MSC_LPM(n) (MSC_BASE + (n)*0x1000 + 0x040)
+
+#define REG_MSC_STRPCL(n) REG16(MSC_STRPCL(n))
+#define REG_MSC_STAT(n) REG32(MSC_STAT(n))
+#define REG_MSC_CLKRT(n) REG16(MSC_CLKRT(n))
+#define REG_MSC_CMDAT(n) REG32(MSC_CMDAT(n))
+#define REG_MSC_RESTO(n) REG16(MSC_RESTO(n))
+#define REG_MSC_RDTO(n) REG16(MSC_RDTO(n))
+#define REG_MSC_BLKLEN(n) REG16(MSC_BLKLEN(n))
+#define REG_MSC_NOB(n) REG16(MSC_NOB(n))
+#define REG_MSC_SNOB(n) REG16(MSC_SNOB(n))
+#define REG_MSC_IMASK(n) REG32(MSC_IMASK(n))
+#define REG_MSC_IREG(n) REG16(MSC_IREG(n))
+#define REG_MSC_CMD(n) REG8(MSC_CMD(n))
+#define REG_MSC_ARG(n) REG32(MSC_ARG(n))
+#define REG_MSC_RES(n) REG16(MSC_RES(n))
+#define REG_MSC_RXFIFO(n) REG32(MSC_RXFIFO(n))
+#define REG_MSC_TXFIFO(n) REG32(MSC_TXFIFO(n))
+#define REG_MSC_LPM(n) REG32(MSC_LPM(n))
+
+/* MSC Clock and Control Register (MSC_STRPCL) */
+#define MSC_STRPCL_SEND_CCSD (1 << 15) /*send command completion signal disable to ceata */
+#define MSC_STRPCL_SEND_AS_CCSD (1 << 14) /*send internally generated stop after sending ccsd */
+#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7)
+#define MSC_STRPCL_EXIT_TRANSFER (1 << 6)
+#define MSC_STRPCL_START_READWAIT (1 << 5)
+#define MSC_STRPCL_STOP_READWAIT (1 << 4)
+#define MSC_STRPCL_RESET (1 << 3)
+#define MSC_STRPCL_START_OP (1 << 2)
+#define MSC_STRPCL_CLOCK_CONTROL_BIT 0
+#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT)
+ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */
+ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */
+
+/* MSC Status Register (MSC_STAT) */
+#define MSC_STAT_AUTO_CMD_DONE (1 << 31) /*12 is internally generated by controller has finished */
+#define MSC_STAT_IS_RESETTING (1 << 15)
+#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14)
+#define MSC_STAT_PRG_DONE (1 << 13)
+#define MSC_STAT_DATA_TRAN_DONE (1 << 12)
+#define MSC_STAT_END_CMD_RES (1 << 11)
+#define MSC_STAT_DATA_FIFO_AFULL (1 << 10)
+#define MSC_STAT_IS_READWAIT (1 << 9)
+#define MSC_STAT_CLK_EN (1 << 8)
+#define MSC_STAT_DATA_FIFO_FULL (1 << 7)
+#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6)
+#define MSC_STAT_CRC_RES_ERR (1 << 5)
+#define MSC_STAT_CRC_READ_ERROR (1 << 4)
+#define MSC_STAT_CRC_WRITE_ERROR_BIT 2
+#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT)
+ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */
+ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */
+ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */
+#define MSC_STAT_TIME_OUT_RES (1 << 1)
+#define MSC_STAT_TIME_OUT_READ (1 << 0)
+
+/* MSC Bus Clock Control Register (MSC_CLKRT) */
+#define MSC_CLKRT_CLK_RATE_BIT 0
+#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT)
+ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */
+
+/* MSC Command Sequence Control Register (MSC_CMDAT) */
+#define MSC_CMDAT_CCS_EXPECTED (1 << 31) /* interrupts are enabled in ce-ata */
+#define MSC_CMDAT_READ_CEATA (1 << 30)
+#define MSC_CMDAT_SDIO_PRDT (1 << 17) /* exact 2 cycle */
+#define MSC_CMDAT_SEND_AS_STOP (1 << 16)
+#define MSC_CMDAT_RTRG_BIT 14
+ #define MSC_CMDAT_RTRG_EQUALT_8 (0x0 << MSC_CMDAT_RTRG_BIT)
+ #define MSC_CMDAT_RTRG_EQUALT_16 (0x1 << MSC_CMDAT_RTRG_BIT) /* reset value */
+ #define MSC_CMDAT_RTRG_EQUALT_24 (0x2 << MSC_CMDAT_RTRG_BIT)
+
+#define MSC_CMDAT_TTRG_BIT 12
+ #define MSC_CMDAT_TTRG_LESS_8 (0x0 << MSC_CMDAT_TTRG_BIT)
+ #define MSC_CMDAT_TTRG_LESS_16 (0x1 << MSC_CMDAT_TTRG_BIT) /*reset value */
+ #define MSC_CMDAT_TTRG_LESS_24 (0x2 << MSC_CMDAT_TTRG_BIT)
+#define MSC_CMDAT_STOP_ABORT (1 << 11)
+#define MSC_CMDAT_BUS_WIDTH_BIT 9
+#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT)
+ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */
+ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */
+ #define MSC_CMDAT_BUS_WIDTH_8BIT (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) /* 8-bit data bus */
+#define MSC_CMDAT_DMA_EN (1 << 8)
+#define MSC_CMDAT_INIT (1 << 7)
+#define MSC_CMDAT_BUSY (1 << 6)
+#define MSC_CMDAT_STREAM_BLOCK (1 << 5)
+#define MSC_CMDAT_WRITE (1 << 4)
+#define MSC_CMDAT_READ (0 << 4)
+#define MSC_CMDAT_DATA_EN (1 << 3)
+#define MSC_CMDAT_RESPONSE_BIT 0
+#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT)
+ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */
+ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */
+ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */
+ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */
+ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */
+ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */
+ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */
+
+#define CMDAT_DMA_EN (1 << 8)
+#define CMDAT_INIT (1 << 7)
+#define CMDAT_BUSY (1 << 6)
+#define CMDAT_STREAM (1 << 5)
+#define CMDAT_WRITE (1 << 4)
+#define CMDAT_DATA_EN (1 << 3)
+
+/* MSC Interrupts Mask Register (MSC_IMASK) */
+#define MSC_IMASK_AUTO_CMD_DONE (1 << 8)
+#define MSC_IMASK_SDIO (1 << 7)
+#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6)
+#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5)
+#define MSC_IMASK_END_CMD_RES (1 << 2)
+#define MSC_IMASK_PRG_DONE (1 << 1)
+#define MSC_IMASK_DATA_TRAN_DONE (1 << 0)
+
+/* MSC Interrupts Status Register (MSC_IREG) */
+#define MSC_IREG_AUTO_CMD_DONE (1 << 8)
+#define MSC_IREG_SDIO (1 << 7)
+#define MSC_IREG_TXFIFO_WR_REQ (1 << 6)
+#define MSC_IREG_RXFIFO_RD_REQ (1 << 5)
+#define MSC_IREG_END_CMD_RES (1 << 2)
+#define MSC_IREG_PRG_DONE (1 << 1)
+#define MSC_IREG_DATA_TRAN_DONE (1 << 0)
+
+/* MSC Low Power Mode Register (MSC_LPM) */
+#define MSC_SET_LPM (1 << 0)
+
+/*************************************************************************
+ * EMC (External Memory Controller)
+ *************************************************************************/
+#define EMC_BCR (EMC_BASE + 0x00) /* Bus Control Register */
+#define EMC_SMCR0 (EMC_BASE + 0x10) /* Static Memory Control Register 0 */
+#define EMC_SMCR1 (EMC_BASE + 0x14) /* Static Memory Control Register 1 */
+#define EMC_SMCR2 (EMC_BASE + 0x18) /* Static Memory Control Register 2 */
+#define EMC_SMCR3 (EMC_BASE + 0x1c) /* Static Memory Control Register 3 */
+#define EMC_SMCR4 (EMC_BASE + 0x20) /* Static Memory Control Register 4 */
+#define EMC_SACR0 (EMC_BASE + 0x30) /* Static Memory Bank 0 Addr Config Reg */
+#define EMC_SACR1 (EMC_BASE + 0x34) /* Static Memory Bank 1 Addr Config Reg */
+#define EMC_SACR2 (EMC_BASE + 0x38) /* Static Memory Bank 2 Addr Config Reg */
+#define EMC_SACR3 (EMC_BASE + 0x3c) /* Static Memory Bank 3 Addr Config Reg */
+#define EMC_SACR4 (EMC_BASE + 0x40) /* Static Memory Bank 4 Addr Config Reg */
+
+#define EMC_NFCSR (EMC_BASE + 0x050) /* NAND Flash Control/Status Register */
+
+#define EMC_DMCR (EMC_BASE + 0x80) /* DRAM Control Register */
+#define EMC_RTCSR (EMC_BASE + 0x84) /* Refresh Time Control/Status Register */
+#define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */
+#define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */
+#define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */
+#define EMC_DMAR1 (EMC_BASE + 0x94) /* SDRAM Bank 1 Addr Config Register */
+#define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */
+
+#define REG_EMC_BCR REG32(EMC_BCR)
+#define REG_EMC_SMCR0 REG32(EMC_SMCR0)
+#define REG_EMC_SMCR1 REG32(EMC_SMCR1)
+#define REG_EMC_SMCR2 REG32(EMC_SMCR2)
+#define REG_EMC_SMCR3 REG32(EMC_SMCR3)
+#define REG_EMC_SMCR4 REG32(EMC_SMCR4)
+#define REG_EMC_SACR0 REG32(EMC_SACR0)
+#define REG_EMC_SACR1 REG32(EMC_SACR1)
+#define REG_EMC_SACR2 REG32(EMC_SACR2)
+#define REG_EMC_SACR3 REG32(EMC_SACR3)
+#define REG_EMC_SACR4 REG32(EMC_SACR4)
+
+#define REG_EMC_NFCSR REG32(EMC_NFCSR)
+
+#define REG_EMC_DMCR REG32(EMC_DMCR)
+#define REG_EMC_RTCSR REG16(EMC_RTCSR)
+#define REG_EMC_RTCNT REG16(EMC_RTCNT)
+#define REG_EMC_RTCOR REG16(EMC_RTCOR)
+#define REG_EMC_DMAR0 REG32(EMC_DMAR0)
+#define REG_EMC_DMAR1 REG32(EMC_DMAR1)
+
+/* Bus Control Register */
+#define EMC_BCR_BT_SEL_BIT 30
+#define EMC_BCR_BT_SEL_MASK (0x3 << EMC_BCR_BT_SEL_BIT)
+#define EMC_BCR_PK_SEL (1 << 24)
+#define EMC_BCR_BSR_MASK (1 << 2) /* Nand and SDRAM Bus Share Select: 0, share; 1, unshare */
+ #define EMC_BCR_BSR_SHARE (0 << 2)
+ #define EMC_BCR_BSR_UNSHARE (1 << 2)
+#define EMC_BCR_BRE (1 << 1)
+#define EMC_BCR_ENDIAN (1 << 0)
+
+/* Static Memory Control Register */
+#define EMC_SMCR_STRV_BIT 24
+#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT)
+#define EMC_SMCR_TAW_BIT 20
+#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT)
+#define EMC_SMCR_TBP_BIT 16
+#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT)
+#define EMC_SMCR_TAH_BIT 12
+#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT)
+#define EMC_SMCR_TAS_BIT 8
+#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT)
+#define EMC_SMCR_BW_BIT 6
+#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT)
+#define EMC_SMCR_BCM (1 << 3)
+#define EMC_SMCR_BL_BIT 1
+#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT)
+#define EMC_SMCR_SMT (1 << 0)
+
+/* Static Memory Bank Addr Config Reg */
+#define EMC_SACR_BASE_BIT 8
+#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT)
+#define EMC_SACR_MASK_BIT 0
+#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT)
+
+/* NAND Flash Control/Status Register */
+#define EMC_NFCSR_NFCE4 (1 << 7) /* NAND Flash Enable */
+#define EMC_NFCSR_NFE4 (1 << 6) /* NAND Flash FCE# Assertion Enable */
+#define EMC_NFCSR_NFCE3 (1 << 5)
+#define EMC_NFCSR_NFE3 (1 << 4)
+#define EMC_NFCSR_NFCE2 (1 << 3)
+#define EMC_NFCSR_NFE2 (1 << 2)
+#define EMC_NFCSR_NFCE1 (1 << 1)
+#define EMC_NFCSR_NFE1 (1 << 0)
+
+/* DRAM Control Register */
+#define EMC_DMCR_BW_BIT 31
+#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT)
+#define EMC_DMCR_CA_BIT 26
+#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT)
+#define EMC_DMCR_RMODE (1 << 25)
+#define EMC_DMCR_RFSH (1 << 24)
+#define EMC_DMCR_MRSET (1 << 23)
+#define EMC_DMCR_RA_BIT 20
+#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT)
+#define EMC_DMCR_BA_BIT 19
+#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT)
+#define EMC_DMCR_PDM (1 << 18)
+#define EMC_DMCR_EPIN (1 << 17)
+#define EMC_DMCR_MBSEL (1 << 16)
+#define EMC_DMCR_TRAS_BIT 13
+#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT)
+#define EMC_DMCR_RCD_BIT 11
+#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT)
+#define EMC_DMCR_TPC_BIT 8
+#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT)
+#define EMC_DMCR_TRWL_BIT 5
+#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT)
+#define EMC_DMCR_TRC_BIT 2
+#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT)
+#define EMC_DMCR_TCL_BIT 0
+#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT)
+
+/* Refresh Time Control/Status Register */
+#define EMC_RTCSR_SFR (1 << 8) /* self refresh flag */
+#define EMC_RTCSR_CMF (1 << 7)
+#define EMC_RTCSR_CKS_BIT 0
+#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT)
+
+/* SDRAM Bank Address Configuration Register */
+#define EMC_DMAR_BASE_BIT 8
+#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT)
+#define EMC_DMAR_MASK_BIT 0
+#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT)
+
+/* Mode Register of SDRAM bank 0 */
+#define EMC_SDMR_BM (1 << 9) /* Write Burst Mode */
+#define EMC_SDMR_OM_BIT 7 /* Operating Mode */
+#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT)
+ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT)
+#define EMC_SDMR_CAS_BIT 4 /* CAS Latency */
+#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT)
+#define EMC_SDMR_BT_BIT 3 /* Burst Type */
+#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT)
+ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) /* Sequential */
+ #define EMC_SDMR_BT_INT (1 << EMC_SDMR_BT_BIT) /* Interleave */
+#define EMC_SDMR_BL_BIT 0 /* Burst Length */
+#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT)
+
+#define EMC_SDMR_CAS2_16BIT \
+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2)
+#define EMC_SDMR_CAS2_32BIT \
+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4)
+#define EMC_SDMR_CAS3_16BIT \
+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2)
+#define EMC_SDMR_CAS3_32BIT \
+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4)
+
+
+/*************************************************************************
+ * CIM
+ *************************************************************************/
+#define CIM_CFG (CIM_BASE + 0x0000)
+#define CIM_CTRL (CIM_BASE + 0x0004)
+#define CIM_STATE (CIM_BASE + 0x0008)
+#define CIM_IID (CIM_BASE + 0x000C)
+#define CIM_RXFIFO (CIM_BASE + 0x0010)
+#define CIM_DA (CIM_BASE + 0x0020)
+#define CIM_FA (CIM_BASE + 0x0024)
+#define CIM_FID (CIM_BASE + 0x0028)
+#define CIM_CMD (CIM_BASE + 0x002C)
+#define CIM_SIZE (CIM_BASE + 0x0030)
+#define CIM_OFFSET (CIM_BASE + 0x0034)
+#define CIM_RAM_ADDR (CIM_BASE + 0x1000)
+
+#define REG_CIM_CFG REG32(CIM_CFG)
+#define REG_CIM_CTRL REG32(CIM_CTRL)
+#define REG_CIM_STATE REG32(CIM_STATE)
+#define REG_CIM_IID REG32(CIM_IID)
+#define REG_CIM_RXFIFO REG32(CIM_RXFIFO)
+#define REG_CIM_DA REG32(CIM_DA)
+#define REG_CIM_FA REG32(CIM_FA)
+#define REG_CIM_FID REG32(CIM_FID)
+#define REG_CIM_CMD REG32(CIM_CMD)
+#define REG_CIM_SIZE REG32(CIM_SIZE)
+#define REG_CIM_OFFSET REG32(CIM_OFFSET)
+
+/* CIM Configuration Register (CIM_CFG) */
+
+#define CIM_CFG_ORDER_BIT 18
+#define CIM_CFG_ORDER_MASK (0x3 << CIM_CFG_ORDER_BIT)
+ #define CIM_CFG_ORDER_0 (0x0 << CIM_CFG_ORDER_BIT) /* RG-GB; YUYV; YUV */
+ #define CIM_CFG_ORDER_1 (0x1 << CIM_CFG_ORDER_BIT) /* GR-BG; YVYU; YVU */
+ #define CIM_CFG_ORDER_2 (0x2 << CIM_CFG_ORDER_BIT) /* BG-GR; UYVY; UVY */
+ #define CIM_CFG_ORDER_3 (0x3 << CIM_CFG_ORDER_BIT) /* GB-RG; VYUY; VUY */
+#define CIM_CFG_DF_BIT 16
+#define CIM_CFG_DF_MASK (0x3 << CIM_CFG_DF_BIT)
+ #define CIM_CFG_DF_RGB (0x0 << CIM_CFG_DF_BIT)
+ #define CIM_CFG_DF_RAWRGB CIM_CFG_DF_RGB
+ #define CIM_CFG_DF_BAYERRGB CIM_CFG_DF_RGB
+ #define CIM_CFG_DF_YUV444 (0x1 << CIM_CFG_DF_BIT)
+ #define CIM_CFG_DF_YUV422 (0x2 << CIM_CFG_DF_BIT)
+ #define CIM_CFG_DF_ITU656 (0x3 << CIM_CFG_DF_BIT)
+#define CIM_CFG_INV_DAT (1 << 15)
+#define CIM_CFG_VSP (1 << 14) /* VSYNC Polarity:0-rising edge active,1-falling edge active */
+#define CIM_CFG_HSP (1 << 13) /* HSYNC Polarity:0-rising edge active,1-falling edge active */
+#define CIM_CFG_PCP (1 << 12) /* PCLK working edge: 0-rising, 1-falling */
+#define CIM_CFG_DMA_BURST_TYPE_BIT 10
+#define CIM_CFG_DMA_BURST_TYPE_MASK (0x3 << CIM_CFG_DMA_BURST_TYPE_BIT)
+#define CIM_CFG_DMA_BURST_INCR (0 << CIM_CFG_DMA_BURST_TYPE_BIT)
+#define CIM_CFG_DMA_BURST_INCR4 (1 << CIM_CFG_DMA_BURST_TYPE_BIT)
+#define CIM_CFG_DMA_BURST_INCR8 (2 << CIM_CFG_DMA_BURST_TYPE_BIT)
+#define CIM_CFG_DUMMY_ZERO (1 << 9)
+#define CIM_CFG_EXT_VSYNC (1 << 8)
+#define CIM_CFG_PACK_BIT 4
+#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) /* 11 22 33 44 */
+ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) /* 22 33 44 11 */
+ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) /* 33 44 11 22 */
+ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) /* 44 11 22 33 */
+ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) /* 44 33 22 11 */
+ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) /* 33 22 11 44 */
+ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) /* 22 11 44 33 */
+ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) /* 11 44 33 22 */
+#define CIM_CFG_BYPASS_BIT 2
+#define CIM_CFG_BYPASS_MASK (1 << CIM_CFG_BYPASS_BIT)
+ #define CIM_CFG_BYPASS (1 << CIM_CFG_BYPASS_BIT)
+#define CIM_CFG_DSM_BIT 0
+#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT)
+ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */
+ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */
+ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */
+ #define CIM_CFG_DSM_NGCM (3 << CIM_CFG_DSM_BIT) /* Non-Gated Clock Mode */
+
+/* CIM Control Register (CIM_CTRL) */
+
+#define CIM_CTRL_MCLKDIV_BIT 24
+#define CIM_CTRL_MCLKDIV_MASK (0xff << CIM_CTRL_MCLKDIV_BIT)
+#define CIM_CTRL_FRC_BIT 16
+#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT)
+ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */
+ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */
+ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */
+ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */
+ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */
+ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */
+ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */
+ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */
+ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */
+ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */
+ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */
+ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */
+ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */
+ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */
+ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */
+ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */
+#define CIM_CTRL_SIZEEN_BIT 14
+#define CIM_CTRL_SIZEEN_MASK (0x1 << CIM_CTRL_SIZEEN_BIT)
+#define CIM_CTRL_SIZEEN (0x1 << CIM_CTRL_SIZEEN_BIT)
+#define CIM_CTRL_VDDM (1 << 13) /* VDD interrupt enable */
+#define CIM_CTRL_DMA_SOFM (1 << 12)
+#define CIM_CTRL_DMA_EOFM (1 << 11)
+#define CIM_CTRL_DMA_STOPM (1 << 10)
+#define CIM_CTRL_RXF_TRIGM (1 << 9)
+#define CIM_CTRL_RXF_OFM (1 << 8)
+#define CIM_CTRL_RXF_TRIG_BIT 4
+#define CIM_CTRL_RXF_TRIG_MASK (0x7 << CIM_CTRL_RXF_TRIG_BIT)
+ #define CIM_CTRL_RXF_TRIG_4 (0 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 4 */
+ #define CIM_CTRL_RXF_TRIG_8 (1 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 8 */
+ #define CIM_CTRL_RXF_TRIG_12 (2 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 12 */
+ #define CIM_CTRL_RXF_TRIG_16 (3 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 16 */
+ #define CIM_CTRL_RXF_TRIG_20 (4 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 20 */
+ #define CIM_CTRL_RXF_TRIG_24 (5 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 24 */
+ #define CIM_CTRL_RXF_TRIG_28 (6 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 28 */
+ #define CIM_CTRL_RXF_TRIG_32 (7 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 32 */
+#define CIM_CTRL_FAST_MODE_MASK (1 << 3) /* CIM fast mode mask */
+#define CIM_CTRL_FAST_MODE (1 << 3) /* CIM works in fast mode */
+#define CIM_CTRL_NORMAL_MODE (0 << 3) /* CIM works in normal mode */
+#define CIM_CTRL_DMA_EN (1 << 2) /* Enable DMA */
+#define CIM_CTRL_RXF_RST (1 << 1) /* RxFIFO reset */
+#define CIM_CTRL_ENA (1 << 0) /* Enable CIM */
+
+/* CIM State Register (CIM_STATE) */
+
+#define CIM_STATE_DMA_SOF (1 << 6) /* DMA start irq */
+#define CIM_STATE_DMA_EOF (1 << 5) /* DMA end irq */
+#define CIM_STATE_DMA_STOP (1 << 4) /* DMA stop irq */
+#define CIM_STATE_RXF_OF (1 << 3) /* RXFIFO over flow irq */
+#define CIM_STATE_RXF_TRIG (1 << 2) /* RXFIFO triger meet irq */
+#define CIM_STATE_RXF_EMPTY (1 << 1) /* RXFIFO empty irq */
+#define CIM_STATE_VDD (1 << 0) /* CIM disabled irq */
+
+/* CIM DMA Command Register (CIM_CMD) */
+
+#define CIM_CMD_SOFINT (1 << 31) /* enable DMA start irq */
+#define CIM_CMD_EOFINT (1 << 30) /* enable DMA end irq */
+#define CIM_CMD_STOP (1 << 28) /* enable DMA stop irq */
+#define CIM_CMD_LEN_BIT 0
+#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT)
+
+/* CIM Image Size Register (CIM_SIZE) */
+#define CIM_SIZE_LPF_BIT 16 /* Lines per freame for csc output image */
+#define CIM_SIZE_LPF_MASK (0x1fff << CIM_SIZE_LPF_BIT)
+#define CIM_SIZE_PPL_BIT 0 /* Pixels per line for csc output image, should be an even number */
+#define CIM_SIZE_PPL_MASK (0x1fff << CIM_SIZE_PPL_BIT)
+
+/* CIM Image Offset Register (CIM_OFFSET) */
+#define CIM_OFFSET_V_BIT 16 /* Vertical offset */
+#define CIM_OFFSET_V_MASK (0xfff << CIM_OFFSET_V_BIT)
+#define CIM_OFFSET_H_BIT 0 /* Horizontal offset, should be an enen number */
+#define CIM_OFFSET_H_MASK (0xfff << CIM_OFFSET_H_BIT) /*OFFSET_H should be even number*/
+
+/*************************************************************************
+ * SADC (Smart A/D Controller)
+ *************************************************************************/
+
+#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */
+#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */
+#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */
+#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/
+#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */
+#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */
+#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */
+#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC PBAT Data Register */
+#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC SADCIN Data Register */
+#define SADC_ADCLK (SADC_BASE + 0x28) /* ADC Clock Divide Register */
+
+#define REG_SADC_ENA REG8(SADC_ENA)
+#define REG_SADC_CFG REG32(SADC_CFG)
+#define REG_SADC_CTRL REG8(SADC_CTRL)
+#define REG_SADC_STATE REG8(SADC_STATE)
+#define REG_SADC_SAMETIME REG16(SADC_SAMETIME)
+#define REG_SADC_WAITTIME REG16(SADC_WAITTIME)
+#define REG_SADC_TSDAT REG32(SADC_TSDAT)
+#define REG_SADC_BATDAT REG16(SADC_BATDAT)
+#define REG_SADC_SADDAT REG16(SADC_SADDAT)
+#define REG_SADC_ADCLK REG32(SADC_ADCLK)
+
+/* ADC Enable Register */
+#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */
+#define SADC_ENA_ENTR_SLP (1 << 6) /* Touch Screen Enable */
+#define SADC_ENA_EXIT_SLP (1 << 5) /* Touch Screen Enable */
+#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */
+#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */
+#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */
+
+/* ADC Configure Register */
+#define SADC_CFG_SPZZ (1 << 31)
+#define SADC_CFG_EXIN (1 << 30)
+#define SADC_CFG_CLKOUT_NUM_BIT 16
+#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT)
+#define SADC_CFG_DNUM(x) (((x) - 1) << SADC_CFG_CLKOUT_NUM_BIT)
+#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */
+#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */
+#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT)
+ #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT)
+ #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT)
+ #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT)
+#define SADC_CFG_SNUM_BIT 10 /* Sample Number */
+#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT)
+#define SADC_CFG_SNUM(x) (((x) - 1) << SADC_CFG_SNUM_BIT)
+
+#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */
+#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT)
+#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */
+#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */
+#define SADC_CFG_CMD_BIT 0 /* ADC Command */
+#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT)
+ #define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */
+ #define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */
+ #define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */
+ #define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */
+ #define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */
+ #define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */
+ #define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */
+ #define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */
+ #define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */
+ #define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */
+ #define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */
+ #define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */
+ #define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */
+
+/* ADC Control Register */
+#define SADC_CTRL_SLPENDM (1 << 5) /* sleep Interrupt Mask */
+#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */
+#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */
+#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */
+#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */
+#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */
+
+/* ADC Status Register */
+#define SADC_STATE_SLEEPND (1 << 5) /* Pen Down Interrupt Flag */
+#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */
+#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */
+#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */
+#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */
+#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */
+
+/* ADC Touch Screen Data Register */
+#define SADC_TSDAT_DATA0_BIT 0
+#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT)
+#define SADC_TSDAT_TYPE0 (1 << 15)
+#define SADC_TSDAT_DATA1_BIT 16
+#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT)
+#define SADC_TSDAT_TYPE1 (1 << 31)
+
+/* ADC Clock Divide Register */
+#define SADC_ADCLK_CLKDIV_10_BIT 16
+#define SADC_ADCLK_CLKDIV_10_MASK (0x7f << SADC_ADCLK_CLKDIV_10_BIT)
+#define SADC_ADCLK_CLKDIV_BIT 0
+#define SADC_ADCLK_CLKDIV_MASK (0x3f << SADC_ADCLK_CLKDIV_BIT)
+
+/*************************************************************************
+ * SLCD (Smart LCD Controller)
+ *************************************************************************/
+
+#define SLCD_CFG (SLCD_BASE + 0xA0) /* SLCD Configure Register */
+#define SLCD_CTRL (SLCD_BASE + 0xA4) /* SLCD Control Register */
+#define SLCD_STATE (SLCD_BASE + 0xA8) /* SLCD Status Register */
+#define SLCD_DATA (SLCD_BASE + 0xAC) /* SLCD Data Register */
+
+#define REG_SLCD_CFG REG32(SLCD_CFG)
+#define REG_SLCD_CTRL REG8(SLCD_CTRL)
+#define REG_SLCD_STATE REG8(SLCD_STATE)
+#define REG_SLCD_DATA REG32(SLCD_DATA)
+
+/* SLCD Configure Register */
+#define SLCD_CFG_DWIDTH_BIT 10
+#define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_18BIT (0 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_16BIT (1 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_8BIT_x3 (2 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_8BIT_x2 (3 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_8BIT_x1 (4 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_24BIT (5 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_9BIT_x2 (7 << SLCD_CFG_DWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_BIT (8)
+#define SLCD_CFG_CWIDTH_MASK (0x7 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_16BIT (0 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_8BIT (1 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_18BIT (2 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_24BIT (3 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CS_ACTIVE_LOW (0 << 4)
+#define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4)
+#define SLCD_CFG_RS_CMD_LOW (0 << 3)
+#define SLCD_CFG_RS_CMD_HIGH (1 << 3)
+#define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1)
+#define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1)
+#define SLCD_CFG_TYPE_PARALLEL (0 << 0)
+#define SLCD_CFG_TYPE_SERIAL (1 << 0)
+
+/* SLCD Control Register */
+#define SLCD_CTRL_DMA_EN (1 << 0)
+
+/* SLCD Status Register */
+#define SLCD_STATE_BUSY (1 << 0)
+
+/* SLCD Data Register */
+#define SLCD_DATA_RS_DATA (0 << 31)
+#define SLCD_DATA_RS_COMMAND (1 << 31)
+
+/*************************************************************************
+ * LCD (LCD Controller)
+ *************************************************************************/
+#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */
+#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */
+#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */
+
+#define LCD_OSDC (LCD_BASE + 0x100) /* LCD OSD Configure Register */
+#define LCD_OSDCTRL (LCD_BASE + 0x104) /* LCD OSD Control Register */
+#define LCD_OSDS (LCD_BASE + 0x108) /* LCD OSD Status Register */
+#define LCD_BGC (LCD_BASE + 0x10C) /* LCD Background Color Register */
+#define LCD_KEY0 (LCD_BASE + 0x110) /* LCD Foreground Color Key Register 0 */
+#define LCD_KEY1 (LCD_BASE + 0x114) /* LCD Foreground Color Key Register 1 */
+#define LCD_ALPHA (LCD_BASE + 0x118) /* LCD ALPHA Register */
+#define LCD_IPUR (LCD_BASE + 0x11C) /* LCD IPU Restart Register */
+
+#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */
+#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */
+#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */
+
+#define LCD_XYP0 (LCD_BASE + 0x120) /* Foreground 0 XY Position Register */
+#define LCD_XYP1 (LCD_BASE + 0x124) /* Foreground 1 XY Position Register */
+#define LCD_SIZE0 (LCD_BASE + 0x128) /* Foreground 0 Size Register */
+#define LCD_SIZE1 (LCD_BASE + 0x12C) /* Foreground 1 Size Register */
+#define LCD_RGBC (LCD_BASE + 0x90) /* RGB Controll Register */
+
+#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */
+#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */
+#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */
+#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */
+#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */
+#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */
+#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */
+#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */
+#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */
+#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */
+#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */
+#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */
+#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */
+#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */
+#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */
+
+#define LCD_OFFS0 (LCD_BASE + 0x60) /* DMA Offsize Register 0 */
+#define LCD_PW0 (LCD_BASE + 0x64) /* DMA Page Width Register 0 */
+#define LCD_CNUM0 (LCD_BASE + 0x68) /* DMA Command Counter Register 0 */
+#define LCD_DESSIZE0 (LCD_BASE + 0x6C) /* Foreground Size in Descriptor 0 Register*/
+#define LCD_OFFS1 (LCD_BASE + 0x70) /* DMA Offsize Register 1 */
+#define LCD_PW1 (LCD_BASE + 0x74) /* DMA Page Width Register 1 */
+#define LCD_CNUM1 (LCD_BASE + 0x78) /* DMA Command Counter Register 1 */
+#define LCD_DESSIZE1 (LCD_BASE + 0x7C) /* Foreground Size in Descriptor 1 Register*/
+
+#define REG_LCD_CFG REG32(LCD_CFG)
+#define REG_LCD_CTRL REG32(LCD_CTRL)
+#define REG_LCD_STATE REG32(LCD_STATE)
+
+#define REG_LCD_OSDC REG16(LCD_OSDC)
+#define REG_LCD_OSDCTRL REG16(LCD_OSDCTRL)
+#define REG_LCD_OSDS REG16(LCD_OSDS)
+#define REG_LCD_BGC REG32(LCD_BGC)
+#define REG_LCD_KEY0 REG32(LCD_KEY0)
+#define REG_LCD_KEY1 REG32(LCD_KEY1)
+#define REG_LCD_ALPHA REG8(LCD_ALPHA)
+#define REG_LCD_IPUR REG32(LCD_IPUR)
+
+#define REG_LCD_VAT REG32(LCD_VAT)
+#define REG_LCD_DAH REG32(LCD_DAH)
+#define REG_LCD_DAV REG32(LCD_DAV)
+
+#define REG_LCD_XYP0 REG32(LCD_XYP0)
+#define REG_LCD_XYP1 REG32(LCD_XYP1)
+#define REG_LCD_SIZE0 REG32(LCD_SIZE0)
+#define REG_LCD_SIZE1 REG32(LCD_SIZE1)
+#define REG_LCD_RGBC REG16(LCD_RGBC)
+
+#define REG_LCD_VSYNC REG32(LCD_VSYNC)
+#define REG_LCD_HSYNC REG32(LCD_HSYNC)
+#define REG_LCD_PS REG32(LCD_PS)
+#define REG_LCD_CLS REG32(LCD_CLS)
+#define REG_LCD_SPL REG32(LCD_SPL)
+#define REG_LCD_REV REG32(LCD_REV)
+#define REG_LCD_IID REG32(LCD_IID)
+#define REG_LCD_DA0 REG32(LCD_DA0)
+#define REG_LCD_SA0 REG32(LCD_SA0)
+#define REG_LCD_FID0 REG32(LCD_FID0)
+#define REG_LCD_CMD0 REG32(LCD_CMD0)
+#define REG_LCD_DA1 REG32(LCD_DA1)
+#define REG_LCD_SA1 REG32(LCD_SA1)
+#define REG_LCD_FID1 REG32(LCD_FID1)
+#define REG_LCD_CMD1 REG32(LCD_CMD1)
+
+#define REG_LCD_OFFS0 REG32(LCD_OFFS0)
+#define REG_LCD_PW0 REG32(LCD_PW0)
+#define REG_LCD_CNUM0 REG32(LCD_CNUM0)
+#define REG_LCD_DESSIZE0 REG32(LCD_DESSIZE0)
+#define REG_LCD_OFFS1 REG32(LCD_OFFS1)
+#define REG_LCD_PW1 REG32(LCD_PW1)
+#define REG_LCD_CNUM1 REG32(LCD_CNUM1)
+#define REG_LCD_DESSIZE1 REG32(LCD_DESSIZE1)
+
+/* LCD Configure Register */
+#define LCD_CFG_LCDPIN_BIT 31 /* LCD pins selection */
+#define LCD_CFG_LCDPIN_MASK (0x1 << LCD_CFG_LCDPIN_BIT)
+ #define LCD_CFG_LCDPIN_LCD (0x0 << LCD_CFG_LCDPIN_BIT)
+ #define LCD_CFG_LCDPIN_SLCD (0x1 << LCD_CFG_LCDPIN_BIT)
+#define LCD_CFG_TVEPEH (1 << 30) /* TVE PAL enable extra halfline signal */
+#define LCD_CFG_FUHOLD (1 << 29) /* hold pixel clock when outFIFO underrun */
+#define LCD_CFG_NEWDES (1 << 28) /* use new descripter. old: 4words, new:8words */
+#define LCD_CFG_PALBP (1 << 27) /* bypass data format and alpha blending */
+#define LCD_CFG_TVEN (1 << 26) /* indicate the terminal is lcd or tv */
+#define LCD_CFG_RECOVER (1 << 25) /* Auto recover when output fifo underrun */
+#define LCD_CFG_DITHER (1 << 24) /* Dither function */
+#define LCD_CFG_PSM (1 << 23) /* PS signal mode */
+#define LCD_CFG_CLSM (1 << 22) /* CLS signal mode */
+#define LCD_CFG_SPLM (1 << 21) /* SPL signal mode */
+#define LCD_CFG_REVM (1 << 20) /* REV signal mode */
+#define LCD_CFG_HSYNM (1 << 19) /* HSYNC signal mode */
+#define LCD_CFG_PCLKM (1 << 18) /* PCLK signal mode */
+#define LCD_CFG_INVDAT (1 << 17) /* Inverse output data */
+#define LCD_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */
+#define LCD_CFG_PSP (1 << 15) /* PS pin reset state */
+#define LCD_CFG_CLSP (1 << 14) /* CLS pin reset state */
+#define LCD_CFG_SPLP (1 << 13) /* SPL pin reset state */
+#define LCD_CFG_REVP (1 << 12) /* REV pin reset state */
+#define LCD_CFG_HSP (1 << 11) /* HSYNC polarity:0-active high,1-active low */
+#define LCD_CFG_PCP (1 << 10) /* PCLK polarity:0-rising,1-falling */
+#define LCD_CFG_DEP (1 << 9) /* DE polarity:0-active high,1-active low */
+#define LCD_CFG_VSP (1 << 8) /* VSYNC polarity:0-rising,1-falling */
+#define LCD_CFG_MODE_TFT_18BIT (1 << 7) /* 18bit TFT */
+#define LCD_CFG_MODE_TFT_16BIT (0 << 7) /* 16bit TFT */
+#define LCD_CFG_MODE_TFT_24BIT (1 << 6) /* 24bit TFT */
+#define LCD_CFG_PDW_BIT 4 /* STN pins utilization */
+#define LCD_CFG_PDW_MASK (0x3 << LCD_DEV_PDW_BIT)
+#define LCD_CFG_PDW_1 (0 << LCD_CFG_PDW_BIT) /* LCD_D[0] */
+ #define LCD_CFG_PDW_2 (1 << LCD_CFG_PDW_BIT) /* LCD_D[0:1] */
+ #define LCD_CFG_PDW_4 (2 << LCD_CFG_PDW_BIT) /* LCD_D[0:3]/LCD_D[8:11] */
+ #define LCD_CFG_PDW_8 (3 << LCD_CFG_PDW_BIT) /* LCD_D[0:7]/LCD_D[8:15] */
+#define LCD_CFG_MODE_BIT 0 /* Display Device Mode Select */
+#define LCD_CFG_MODE_MASK (0x0f << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_CFG_MODE_BIT) /* 16,18 bit TFT */
+ #define LCD_CFG_MODE_SPECIAL_TFT_1 (1 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SPECIAL_TFT_2 (2 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SPECIAL_TFT_3 (3 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SERIAL_TFT (12 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_LCM (13 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SLCD LCD_CFG_MODE_LCM
+
+/* LCD Control Register */
+#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */
+#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT)
+ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */
+ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */
+ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */
+ #define LCD_CTRL_BST_32 (3 << LCD_CTRL_BST_BIT) /* 32-word */
+#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode(foreground 0 in OSD mode) */
+#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode(foreground 0 in OSD mode) */
+#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */
+#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */
+#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT)
+ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */
+ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */
+ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */
+#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */
+#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT)
+#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */
+#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */
+#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */
+#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */
+#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */
+#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */
+#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */
+#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */
+#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */
+#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */
+#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */
+#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */
+#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT)
+ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */
+ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */
+ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */
+ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */
+ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */
+ #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */
+
+/* LCD Status Register */
+#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */
+#define LCD_STATE_EOF (1 << 5) /* EOF Flag */
+#define LCD_STATE_SOF (1 << 4) /* SOF Flag */
+#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */
+#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */
+#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */
+#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */
+
+/* OSD Configure Register */
+#define LCD_OSDC_SOFM1 (1 << 15) /* Start of frame interrupt mask for foreground 1 */
+#define LCD_OSDC_EOFM1 (1 << 14) /* End of frame interrupt mask for foreground 1 */
+#define LCD_OSDC_REM1 (1 << 13) /* Real end of frame mask for foreground 1 */
+#define LCD_OSDC_SOFM0 (1 << 11) /* Start of frame interrupt mask for foreground 0 */
+#define LCD_OSDC_EOFM0 (1 << 10) /* End of frame interrupt mask for foreground 0 */
+#define LCD_OSDC_REM0 (1 << 9) /* Real end of frame mask for foreground 0 */
+#define LCD_OSDC_REMB (1 << 7) /* Real end of frame mask for background */
+#define LCD_OSDC_F1EN (1 << 4) /* enable foreground 1 */
+#define LCD_OSDC_F0EN (1 << 3) /* enable foreground 0 */
+#define LCD_OSDC_ALPHAEN (1 << 2) /* enable alpha blending */
+#define LCD_OSDC_ALPHAMD (1 << 1) /* alpha blending mode */
+#define LCD_OSDC_OSDEN (1 << 0) /* OSD mode enable */
+
+/* OSD Controll Register */
+#define LCD_OSDCTRL_IPU (1 << 15) /* input data from IPU */
+#define LCD_OSDCTRL_RGB565 (0 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */
+#define LCD_OSDCTRL_RGB555 (1 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */
+#define LCD_OSDCTRL_CHANGES (1 << 3) /* Change size flag */
+#define LCD_OSDCTRL_OSDBPP_BIT 0 /* Bits Per Pixel of OSD Channel 1 */
+#define LCD_OSDCTRL_OSDBPP_MASK (0x7<<LCD_OSDCTRL_OSDBPP_BIT) /* Bits Per Pixel of OSD Channel 1's MASK */
+ #define LCD_OSDCTRL_OSDBPP_16 (4 << LCD_OSDCTRL_OSDBPP_BIT) /* RGB 15,16 bit*/
+ #define LCD_OSDCTRL_OSDBPP_15_16 (4 << LCD_OSDCTRL_OSDBPP_BIT) /* RGB 15,16 bit*/
+ #define LCD_OSDCTRL_OSDBPP_18_24 (5 << LCD_OSDCTRL_OSDBPP_BIT) /* RGB 18,24 bit*/
+
+/* OSD State Register */
+#define LCD_OSDS_SOF1 (1 << 15) /* Start of frame flag for foreground 1 */
+#define LCD_OSDS_EOF1 (1 << 14) /* End of frame flag for foreground 1 */
+#define LCD_OSDS_SOF0 (1 << 11) /* Start of frame flag for foreground 0 */
+#define LCD_OSDS_EOF0 (1 << 10) /* End of frame flag for foreground 0 */
+#define LCD_OSDS_READY (1 << 0) /* Read for accept the change */
+
+/* Background Color Register */
+#define LCD_BGC_RED_OFFSET (1 << 16) /* Red color offset */
+#define LCD_BGC_RED_MASK (0xFF<<LCD_BGC_RED_OFFSET)
+#define LCD_BGC_GREEN_OFFSET (1 << 8) /* Green color offset */
+#define LCD_BGC_GREEN_MASK (0xFF<<LCD_BGC_GREEN_OFFSET)
+#define LCD_BGC_BLUE_OFFSET (1 << 0) /* Blue color offset */
+#define LCD_BGC_BLUE_MASK (0xFF<<LCD_BGC_BLUE_OFFSET)
+
+/* Foreground Color Key Register 0,1(foreground 0, foreground 1) */
+#define LCD_KEY_KEYEN (1 << 31) /* enable color key */
+#define LCD_KEY_KEYMD (1 << 30) /* color key mode */
+#define LCD_KEY_RED_OFFSET 16 /* Red color offset */
+#define LCD_KEY_RED_MASK (0xFF<<LCD_KEY_RED_OFFSET)
+#define LCD_KEY_GREEN_OFFSET 8 /* Green color offset */
+#define LCD_KEY_GREEN_MASK (0xFF<<LCD_KEY_GREEN_OFFSET)
+#define LCD_KEY_BLUE_OFFSET 0 /* Blue color offset */
+#define LCD_KEY_BLUE_MASK (0xFF<<LCD_KEY_BLUE_OFFSET)
+#define LCD_KEY_MASK (LCD_KEY_RED_MASK|LCD_KEY_GREEN_MASK|LCD_KEY_BLUE_MASK)
+
+/* IPU Restart Register */
+#define LCD_IPUR_IPUREN (1 << 31) /* IPU restart function enable*/
+#define LCD_IPUR_IPURMASK (0xFFFFFF) /* IPU restart value mask*/
+
+/* RGB Control Register */
+#define LCD_RGBC_RGBDM (1 << 15) /* enable RGB Dummy data */
+#define LCD_RGBC_DMM (1 << 14) /* RGB Dummy mode */
+#define LCD_RGBC_YCC (1 << 8) /* RGB to YCC */
+#define LCD_RGBC_ODDRGB_BIT 4 /* odd line serial RGB data arrangement */
+#define LCD_RGBC_ODDRGB_MASK (0x7<<LCD_RGBC_ODDRGB_BIT)
+ #define LCD_RGBC_ODD_RGB 0
+ #define LCD_RGBC_ODD_RBG 1
+ #define LCD_RGBC_ODD_GRB 2
+ #define LCD_RGBC_ODD_GBR 3
+ #define LCD_RGBC_ODD_BRG 4
+ #define LCD_RGBC_ODD_BGR 5
+#define LCD_RGBC_EVENRGB_BIT 0 /* even line serial RGB data arrangement */
+#define LCD_RGBC_EVENRGB_MASK (0x7<<LCD_RGBC_EVENRGB_BIT)
+ #define LCD_RGBC_EVEN_RGB 0
+ #define LCD_RGBC_EVEN_RBG 1
+ #define LCD_RGBC_EVEN_GRB 2
+ #define LCD_RGBC_EVEN_GBR 3
+ #define LCD_RGBC_EVEN_BRG 4
+ #define LCD_RGBC_EVEN_BGR 5
+
+/* Vertical Synchronize Register */
+#define LCD_VSYNC_VPS_BIT 16 /* VSYNC pulse start in line clock, fixed to 0 */
+#define LCD_VSYNC_VPS_MASK (0xffff << LCD_VSYNC_VPS_BIT)
+#define LCD_VSYNC_VPE_BIT 0 /* VSYNC pulse end in line clock */
+#define LCD_VSYNC_VPE_MASK (0xffff << LCD_VSYNC_VPS_BIT)
+
+/* Horizontal Synchronize Register */
+#define LCD_HSYNC_HPS_BIT 16 /* HSYNC pulse start position in dot clock */
+#define LCD_HSYNC_HPS_MASK (0xffff << LCD_HSYNC_HPS_BIT)
+#define LCD_HSYNC_HPE_BIT 0 /* HSYNC pulse end position in dot clock */
+#define LCD_HSYNC_HPE_MASK (0xffff << LCD_HSYNC_HPE_BIT)
+
+/* Virtual Area Setting Register */
+#define LCD_VAT_HT_BIT 16 /* Horizontal Total size in dot clock */
+#define LCD_VAT_HT_MASK (0xffff << LCD_VAT_HT_BIT)
+#define LCD_VAT_VT_BIT 0 /* Vertical Total size in dot clock */
+#define LCD_VAT_VT_MASK (0xffff << LCD_VAT_VT_BIT)
+
+/* Display Area Horizontal Start/End Point Register */
+#define LCD_DAH_HDS_BIT 16 /* Horizontal display area start in dot clock */
+#define LCD_DAH_HDS_MASK (0xffff << LCD_DAH_HDS_BIT)
+#define LCD_DAH_HDE_BIT 0 /* Horizontal display area end in dot clock */
+#define LCD_DAH_HDE_MASK (0xffff << LCD_DAH_HDE_BIT)
+
+/* Display Area Vertical Start/End Point Register */
+#define LCD_DAV_VDS_BIT 16 /* Vertical display area start in line clock */
+#define LCD_DAV_VDS_MASK (0xffff << LCD_DAV_VDS_BIT)
+#define LCD_DAV_VDE_BIT 0 /* Vertical display area end in line clock */
+#define LCD_DAV_VDE_MASK (0xffff << LCD_DAV_VDE_BIT)
+
+/* Foreground XY Position Register */
+#define LCD_XYP_YPOS_BIT 16 /* Y position bit of foreground 0 or 1 */
+#define LCD_XYP_YPOS_MASK (0xffff << LCD_XYP_YPOS_BIT)
+#define LCD_XYP_XPOS_BIT 0 /* X position bit of foreground 0 or 1 */
+#define LCD_XYP_XPOS_MASK (0xffff << LCD_XYP_XPOS_BIT)
+
+/* PS Signal Setting */
+#define LCD_PS_PSS_BIT 16 /* PS signal start position in dot clock */
+#define LCD_PS_PSS_MASK (0xffff << LCD_PS_PSS_BIT)
+#define LCD_PS_PSE_BIT 0 /* PS signal end position in dot clock */
+#define LCD_PS_PSE_MASK (0xffff << LCD_PS_PSE_BIT)
+
+/* CLS Signal Setting */
+#define LCD_CLS_CLSS_BIT 16 /* CLS signal start position in dot clock */
+#define LCD_CLS_CLSS_MASK (0xffff << LCD_CLS_CLSS_BIT)
+#define LCD_CLS_CLSE_BIT 0 /* CLS signal end position in dot clock */
+#define LCD_CLS_CLSE_MASK (0xffff << LCD_CLS_CLSE_BIT)
+
+/* SPL Signal Setting */
+#define LCD_SPL_SPLS_BIT 16 /* SPL signal start position in dot clock */
+#define LCD_SPL_SPLS_MASK (0xffff << LCD_SPL_SPLS_BIT)
+#define LCD_SPL_SPLE_BIT 0 /* SPL signal end position in dot clock */
+#define LCD_SPL_SPLE_MASK (0xffff << LCD_SPL_SPLE_BIT)
+
+/* REV Signal Setting */
+#define LCD_REV_REVS_BIT 16 /* REV signal start position in dot clock */
+#define LCD_REV_REVS_MASK (0xffff << LCD_REV_REVS_BIT)
+
+/* DMA Command Register */
+#define LCD_CMD_SOFINT (1 << 31)
+#define LCD_CMD_EOFINT (1 << 30)
+#define LCD_CMD_CMD (1 << 29) /* indicate command in slcd mode */
+#define LCD_CMD_PAL (1 << 28)
+#define LCD_CMD_LEN_BIT 0
+#define LCD_CMD_LEN_MASK (0xffffff << LCD_CMD_LEN_BIT)
+
+/* DMA Offsize Register 0,1 */
+
+/* DMA Page Width Register 0,1 */
+
+/* DMA Command Counter Register 0,1 */
+
+/* Foreground 0,1 Size Register */
+#define LCD_DESSIZE_HEIGHT_BIT 16 /* height of foreground 1 */
+#define LCD_DESSIZE_HEIGHT_MASK (0xffff << LCD_DESSIZE_HEIGHT_BIT)
+#define LCD_DESSIZE_WIDTH_BIT 0 /* width of foreground 1 */
+#define LCD_DESSIZE_WIDTH_MASK (0xffff << LCD_DESSIZE_WIDTH_BIT)
+
+/*************************************************************************
+ * TVE (TV Encoder Controller)
+ *************************************************************************/
+#define TVE_CTRL (TVE_BASE + 0x40) /* TV Encoder Control register */
+#define TVE_FRCFG (TVE_BASE + 0x44) /* Frame configure register */
+#define TVE_SLCFG1 (TVE_BASE + 0x50) /* TV signal level configure register 1 */
+#define TVE_SLCFG2 (TVE_BASE + 0x54) /* TV signal level configure register 2*/
+#define TVE_SLCFG3 (TVE_BASE + 0x58) /* TV signal level configure register 3*/
+#define TVE_LTCFG1 (TVE_BASE + 0x60) /* Line timing configure register 1 */
+#define TVE_LTCFG2 (TVE_BASE + 0x64) /* Line timing configure register 2 */
+#define TVE_CFREQ (TVE_BASE + 0x70) /* Chrominance sub-carrier frequency configure register */
+#define TVE_CPHASE (TVE_BASE + 0x74) /* Chrominance sub-carrier phase configure register */
+#define TVE_CBCRCFG (TVE_BASE + 0x78) /* Chrominance filter configure register */
+#define TVE_WSSCR (TVE_BASE + 0x80) /* Wide screen signal control register */
+#define TVE_WSSCFG1 (TVE_BASE + 0x84) /* Wide screen signal configure register 1 */
+#define TVE_WSSCFG2 (TVE_BASE + 0x88) /* Wide screen signal configure register 2 */
+#define TVE_WSSCFG3 (TVE_BASE + 0x8c) /* Wide screen signal configure register 3 */
+
+#define REG_TVE_CTRL REG32(TVE_CTRL)
+#define REG_TVE_FRCFG REG32(TVE_FRCFG)
+#define REG_TVE_SLCFG1 REG32(TVE_SLCFG1)
+#define REG_TVE_SLCFG2 REG32(TVE_SLCFG2)
+#define REG_TVE_SLCFG3 REG32(TVE_SLCFG3)
+#define REG_TVE_LTCFG1 REG32(TVE_LTCFG1)
+#define REG_TVE_LTCFG2 REG32(TVE_LTCFG2)
+#define REG_TVE_CFREQ REG32(TVE_CFREQ)
+#define REG_TVE_CPHASE REG32(TVE_CPHASE)
+#define REG_TVE_CBCRCFG REG32(TVE_CBCRCFG)
+#define REG_TVE_WSSCR REG32(TVE_WSSCR)
+#define REG_TVE_WSSCFG1 REG32(TVE_WSSCFG1)
+#define REG_TVE_WSSCFG2 REG32(TVE_WSSCFG2)
+#define REG_TVE_WSSCFG3 REG32(TVE_WSSCFG3)
+
+/* TV Encoder Control register */
+#define TVE_CTRL_ECVBS (1 << 24) /* cvbs_enable */
+#define TVE_CTRL_DAPD3 (1 << 23) /* DAC 3 power down, not exist in jz4750 */
+#define TVE_CTRL_DAPD2 (1 << 22) /* DAC 2 power down */
+#define TVE_CTRL_DAPD1 (1 << 21) /* DAC 1 power down */
+#define TVE_CTRL_DAPD (1 << 20) /* power down all DACs */
+#define TVE_CTRL_YCDLY_BIT 16
+#define TVE_CTRL_YCDLY_MASK (0x7 << TVE_CTRL_YCDLY_BIT)
+#define TVE_CTRL_CGAIN_BIT 14
+#define TVE_CTRL_CGAIN_MASK (0x3 << TVE_CTRL_CGAIN_BIT)
+ #define TVE_CTRL_CGAIN_FULL (0 << TVE_CTRL_CGAIN_BIT) /* gain = 1 */
+ #define TVE_CTRL_CGAIN_QUTR (1 << TVE_CTRL_CGAIN_BIT) /* gain = 1/4 */
+ #define TVE_CTRL_CGAIN_HALF (2 << TVE_CTRL_CGAIN_BIT) /* gain = 1/2 */
+ #define TVE_CTRL_CGAIN_THREE_QURT (3 << TVE_CTRL_CGAIN_BIT) /* gain = 3/4 */
+#define TVE_CTRL_CBW_BIT 12
+#define TVE_CTRL_CBW_MASK (0x3 << TVE_CTRL_CBW_BIT)
+ #define TVE_CTRL_CBW_NARROW (0 << TVE_CTRL_CBW_BIT) /* Narrow band */
+ #define TVE_CTRL_CBW_WIDE (1 << TVE_CTRL_CBW_BIT) /* Wide band */
+ #define TVE_CTRL_CBW_EXTRA (2 << TVE_CTRL_CBW_BIT) /* Extra wide band */
+ #define TVE_CTRL_CBW_ULTRA (3 << TVE_CTRL_CBW_BIT) /* Ultra wide band */
+#define TVE_CTRL_SYNCT (1 << 9)
+#define TVE_CTRL_PAL (1 << 8)
+#define TVE_CTRL_FINV (1 << 7) /* invert_top:1-invert top and bottom fields. */
+#define TVE_CTRL_ZBLACK (1 << 6) /* bypass_yclamp:1-Black of luminance (Y) input is 0.*/
+#define TVE_CTRL_CR1ST (1 << 5) /* uv_order:0-Cb before Cr,1-Cr before Cb */
+#define TVE_CTRL_CLBAR (1 << 4) /* Color bar mode:0-Output input video to TV,1-Output color bar to TV */
+#define TVE_CTRL_SWRST (1 << 0) /* Software reset:1-TVE is reset */
+
+/* Signal level configure register 1 */
+#define TVE_SLCFG1_BLACKL_BIT 0
+#define TVE_SLCFG1_BLACKL_MASK (0x3ff << TVE_SLCFG1_BLACKL_BIT)
+#define TVE_SLCFG1_WHITEL_BIT 16
+#define TVE_SLCFG1_WHITEL_MASK (0x3ff << TVE_SLCFG1_WHITEL_BIT)
+
+/* Signal level configure register 2 */
+#define TVE_SLCFG2_BLANKL_BIT 0
+#define TVE_SLCFG2_BLANKL_MASK (0x3ff << TVE_SLCFG2_BLANKL_BIT)
+#define TVE_SLCFG2_VBLANKL_BIT 16
+#define TVE_SLCFG2_VBLANKL_MASK (0x3ff << TVE_SLCFG2_VBLANKL_BIT)
+
+/* Signal level configure register 3 */
+#define TVE_SLCFG3_SYNCL_BIT 0
+#define TVE_SLCFG3_SYNCL_MASK (0xff << TVE_SLCFG3_SYNCL_BIT)
+
+/* Line timing configure register 1 */
+#define TVE_LTCFG1_BACKP_BIT 0
+#define TVE_LTCFG1_BACKP_MASK (0x7f << TVE_LTCFG1_BACKP_BIT)
+#define TVE_LTCFG1_HSYNCW_BIT 8
+#define TVE_LTCFG1_HSYNCW_MASK (0x7f << TVE_LTCFG1_HSYNCW_BIT)
+#define TVE_LTCFG1_FRONTP_BIT 16
+#define TVE_LTCFG1_FRONTP_MASK (0x1f << TVE_LTCFG1_FRONTP_BIT)
+
+/* Line timing configure register 2 */
+#define TVE_LTCFG2_BURSTW_BIT 0
+#define TVE_LTCFG2_BURSTW_MASK (0x3f << TVE_LTCFG2_BURSTW_BIT)
+#define TVE_LTCFG2_PREBW_BIT 8
+#define TVE_LTCFG2_PREBW_MASK (0x1f << TVE_LTCFG2_PREBW_BIT)
+#define TVE_LTCFG2_ACTLIN_BIT 16
+#define TVE_LTCFG2_ACTLIN_MASK (0x7ff << TVE_LTCFG2_ACTLIN_BIT)
+
+/* Chrominance sub-carrier phase configure register */
+#define TVE_CPHASE_CCRSTP_BIT 0
+#define TVE_CPHASE_CCRSTP_MASK (0x3 << TVE_CPHASE_CCRSTP_BIT)
+ #define TVE_CPHASE_CCRSTP_8 (0 << TVE_CPHASE_CCRSTP_BIT) /* Every 8 field */
+ #define TVE_CPHASE_CCRSTP_4 (1 << TVE_CPHASE_CCRSTP_BIT) /* Every 4 field */
+ #define TVE_CPHASE_CCRSTP_2 (2 << TVE_CPHASE_CCRSTP_BIT) /* Every 2 lines */
+ #define TVE_CPHASE_CCRSTP_0 (3 << TVE_CPHASE_CCRSTP_BIT) /* Never */
+#define TVE_CPHASE_ACTPH_BIT 16
+#define TVE_CPHASE_ACTPH_MASK (0xff << TVE_CPHASE_ACTPH_BIT)
+#define TVE_CPHASE_INITPH_BIT 24
+#define TVE_CPHASE_INITPH_MASK (0xff << TVE_CPHASE_INITPH_BIT)
+
+/* Chrominance filter configure register */
+#define TVE_CBCRCFG_CRGAIN_BIT 0
+#define TVE_CBCRCFG_CRGAIN_MASK (0xff << TVE_CBCRCFG_CRGAIN_BIT)
+#define TVE_CBCRCFG_CBGAIN_BIT 8
+#define TVE_CBCRCFG_CBGAIN_MASK (0xff << TVE_CBCRCFG_CBGAIN_BIT)
+#define TVE_CBCRCFG_CRBA_BIT 16
+#define TVE_CBCRCFG_CRBA_MASK (0xff << TVE_CBCRCFG_CRBA_BIT)
+#define TVE_CBCRCFG_CBBA_BIT 24
+#define TVE_CBCRCFG_CBBA_MASK (0xff << TVE_CBCRCFG_CBBA_BIT)
+
+/* Frame configure register */
+#define TVE_FRCFG_NLINE_BIT 0
+#define TVE_FRCFG_NLINE_MASK (0x3ff << TVE_FRCFG_NLINE_BIT)
+#define TVE_FRCFG_L1ST_BIT 16
+#define TVE_FRCFG_L1ST_MASK (0xff << TVE_FRCFG_L1ST_BIT)
+
+/* Wide screen signal control register */
+#define TVE_WSSCR_EWSS0_BIT 0
+#define TVE_WSSCR_EWSS1_BIT 1
+#define TVE_WSSCR_WSSTP_BIT 2
+#define TVE_WSSCR_WSSCKBP_BIT 3
+#define TVE_WSSCR_WSSEDGE_BIT 4
+#define TVE_WSSCR_WSSEDGE_MASK (0x7 << TVE_WSSCR_WSSEDGE_BIT)
+#define TVE_WSSCR_ENCH_BIT 8
+#define TVE_WSSCR_NCHW_BIT 9
+#define TVE_WSSCR_NCHFREQ_BIT 12
+#define TVE_WSSCR_NCHFREQ_MASK (0x7 << TVE_WSSCR_NCHFREQ_BIT)
+
+/*************************************************************************
+ * USB Device
+ *************************************************************************/
+#define USB_BASE UDC_BASE
+
+#define USB_REG_FADDR (USB_BASE + 0x00) /* Function Address 8-bit */
+#define USB_REG_POWER (USB_BASE + 0x01) /* Power Managemetn 8-bit */
+#define USB_REG_INTRIN (USB_BASE + 0x02) /* Interrupt IN 16-bit */
+#define USB_REG_INTROUT (USB_BASE + 0x04) /* Interrupt OUT 16-bit */
+#define USB_REG_INTRINE (USB_BASE + 0x06) /* Intr IN enable 16-bit */
+#define USB_REG_INTROUTE (USB_BASE + 0x08) /* Intr OUT enable 16-bit */
+#define USB_REG_INTRUSB (USB_BASE + 0x0a) /* Interrupt USB 8-bit */
+#define USB_REG_INTRUSBE (USB_BASE + 0x0b) /* Interrupt USB Enable 8-bit */
+#define USB_REG_FRAME (USB_BASE + 0x0c) /* Frame number 16-bit */
+#define USB_REG_INDEX (USB_BASE + 0x0e) /* Index register 8-bit */
+#define USB_REG_TESTMODE (USB_BASE + 0x0f) /* USB test mode 8-bit */
+
+#define USB_REG_CSR0 (USB_BASE + 0x12) /* EP0 CSR 8-bit */
+#define USB_REG_INMAXP (USB_BASE + 0x10) /* EP1-2 IN Max Pkt Size 16-bit */
+#define USB_REG_INCSR (USB_BASE + 0x12) /* EP1-2 IN CSR LSB 8/16bit */
+#define USB_REG_INCSRH (USB_BASE + 0x13) /* EP1-2 IN CSR MSB 8-bit */
+#define USB_REG_OUTMAXP (USB_BASE + 0x14) /* EP1 OUT Max Pkt Size 16-bit */
+#define USB_REG_OUTCSR (USB_BASE + 0x16) /* EP1 OUT CSR LSB 8/16bit */
+#define USB_REG_OUTCSRH (USB_BASE + 0x17) /* EP1 OUT CSR MSB 8-bit */
+#define USB_REG_OUTCOUNT (USB_BASE + 0x18) /* bytes in EP0/1 OUT FIFO 16-bit */
+
+#define USB_FIFO_EP0 (USB_BASE + 0x20)
+#define USB_FIFO_EP1 (USB_BASE + 0x24)
+#define USB_FIFO_EP2 (USB_BASE + 0x28)
+
+#define USB_REG_EPINFO (USB_BASE + 0x78) /* Endpoint information */
+#define USB_REG_RAMINFO (USB_BASE + 0x79) /* RAM information */
+
+#define USB_REG_INTR (USB_BASE + 0x200) /* DMA pending interrupts */
+#define USB_REG_CNTL1 (USB_BASE + 0x204) /* DMA channel 1 control */
+#define USB_REG_ADDR1 (USB_BASE + 0x208) /* DMA channel 1 AHB memory addr */
+#define USB_REG_COUNT1 (USB_BASE + 0x20c) /* DMA channel 1 byte count */
+#define USB_REG_CNTL2 (USB_BASE + 0x214) /* DMA channel 2 control */
+#define USB_REG_ADDR2 (USB_BASE + 0x218) /* DMA channel 2 AHB memory addr */
+#define USB_REG_COUNT2 (USB_BASE + 0x21c) /* DMA channel 2 byte count */
+
+
+/* Power register bit masks */
+#define USB_POWER_SUSPENDM 0x01
+#define USB_POWER_RESUME 0x04
+#define USB_POWER_HSMODE 0x10
+#define USB_POWER_HSENAB 0x20
+#define USB_POWER_SOFTCONN 0x40
+
+/* Interrupt register bit masks */
+#define USB_INTR_SUSPEND 0x01
+#define USB_INTR_RESUME 0x02
+#define USB_INTR_RESET 0x04
+
+#define USB_INTR_EP0 0x0001
+#define USB_INTR_INEP1 0x0002
+#define USB_INTR_INEP2 0x0004
+#define USB_INTR_OUTEP1 0x0002
+
+/* CSR0 bit masks */
+#define USB_CSR0_OUTPKTRDY 0x01
+#define USB_CSR0_INPKTRDY 0x02
+#define USB_CSR0_SENTSTALL 0x04
+#define USB_CSR0_DATAEND 0x08
+#define USB_CSR0_SETUPEND 0x10
+#define USB_CSR0_SENDSTALL 0x20
+#define USB_CSR0_SVDOUTPKTRDY 0x40
+#define USB_CSR0_SVDSETUPEND 0x80
+
+/* Endpoint CSR register bits */
+#define USB_INCSRH_AUTOSET 0x80
+#define USB_INCSRH_ISO 0x40
+#define USB_INCSRH_MODE 0x20
+#define USB_INCSRH_DMAREQENAB 0x10
+#define USB_INCSRH_DMAREQMODE 0x04
+#define USB_INCSR_CDT 0x40
+#define USB_INCSR_SENTSTALL 0x20
+#define USB_INCSR_SENDSTALL 0x10
+#define USB_INCSR_FF 0x08
+#define USB_INCSR_UNDERRUN 0x04
+#define USB_INCSR_FFNOTEMPT 0x02
+#define USB_INCSR_INPKTRDY 0x01
+#define USB_OUTCSRH_AUTOCLR 0x80
+#define USB_OUTCSRH_ISO 0x40
+#define USB_OUTCSRH_DMAREQENAB 0x20
+#define USB_OUTCSRH_DNYT 0x10
+#define USB_OUTCSRH_DMAREQMODE 0x08
+#define USB_OUTCSR_CDT 0x80
+#define USB_OUTCSR_SENTSTALL 0x40
+#define USB_OUTCSR_SENDSTALL 0x20
+#define USB_OUTCSR_FF 0x10
+#define USB_OUTCSR_DATAERR 0x08
+#define USB_OUTCSR_OVERRUN 0x04
+#define USB_OUTCSR_FFFULL 0x02
+#define USB_OUTCSR_OUTPKTRDY 0x01
+
+/* Testmode register bits */
+#define USB_TEST_SE0NAK 0x01
+#define USB_TEST_J 0x02
+#define USB_TEST_K 0x04
+#define USB_TEST_PACKET 0x08
+
+/* DMA control bits */
+#define USB_CNTL_ENA 0x01
+#define USB_CNTL_DIR_IN 0x02
+#define USB_CNTL_MODE_1 0x04
+#define USB_CNTL_INTR_EN 0x08
+#define USB_CNTL_EP(n) ((n) << 4)
+#define USB_CNTL_BURST_0 (0 << 9)
+#define USB_CNTL_BURST_4 (1 << 9)
+#define USB_CNTL_BURST_8 (2 << 9)
+#define USB_CNTL_BURST_16 (3 << 9)
+
+/*************************************************************************
+ * BCH
+ *************************************************************************/
+#define BCH_CR (BCH_BASE + 0x00) /* BCH Control register */
+#define BCH_CRS (BCH_BASE + 0x04) /* BCH Control Set register */
+#define BCH_CRC (BCH_BASE + 0x08) /* BCH Control Clear register */
+#define BCH_CNT (BCH_BASE + 0x0C) /* BCH ENC/DEC Count register */
+#define BCH_DR (BCH_BASE + 0x10) /* BCH data register */
+#define BCH_PAR0 (BCH_BASE + 0x14) /* BCH Parity 0 register */
+#define BCH_PAR1 (BCH_BASE + 0x18) /* BCH Parity 1 register */
+#define BCH_PAR2 (BCH_BASE + 0x1C) /* BCH Parity 2 register */
+#define BCH_PAR3 (BCH_BASE + 0x20) /* BCH Parity 3 register */
+#define BCH_INTS (BCH_BASE + 0x24) /* BCH Interrupt Status register */
+#define BCH_ERR0 (BCH_BASE + 0x28) /* BCH Error Report 0 register */
+#define BCH_ERR1 (BCH_BASE + 0x2C) /* BCH Error Report 1 register */
+#define BCH_ERR2 (BCH_BASE + 0x30) /* BCH Error Report 2 register */
+#define BCH_ERR3 (BCH_BASE + 0x34) /* BCH Error Report 3 register */
+#define BCH_INTE (BCH_BASE + 0x38) /* BCH Interrupt Enable register */
+#define BCH_INTES (BCH_BASE + 0x3C) /* BCH Interrupt Set register */
+#define BCH_INTEC (BCH_BASE + 0x40) /* BCH Interrupt Clear register */
+
+#define REG_BCH_CR REG32(BCH_CR)
+#define REG_BCH_CRS REG32(BCH_CRS)
+#define REG_BCH_CRC REG32(BCH_CRC)
+#define REG_BCH_CNT REG32(BCH_CNT)
+#define REG_BCH_DR REG8(BCH_DR)
+#define REG_BCH_PAR0 REG32(BCH_PAR0)
+#define REG_BCH_PAR1 REG32(BCH_PAR1)
+#define REG_BCH_PAR2 REG32(BCH_PAR2)
+#define REG_BCH_PAR3 REG32(BCH_PAR3)
+#define REG_BCH_INTS REG32(BCH_INTS)
+#define REG_BCH_ERR0 REG32(BCH_ERR0)
+#define REG_BCH_ERR1 REG32(BCH_ERR1)
+#define REG_BCH_ERR2 REG32(BCH_ERR2)
+#define REG_BCH_ERR3 REG32(BCH_ERR3)
+#define REG_BCH_INTE REG32(BCH_INTE)
+#define REG_BCH_INTEC REG32(BCH_INTEC)
+#define REG_BCH_INTES REG32(BCH_INTES)
+
+/* BCH Control Register*/
+#define BCH_CR_DMAE (1 << 4) /* BCH DMA Enable */
+#define BCH_CR_ENCE (1 << 3) /* BCH Encoding Select */
+#define BCH_CR_DECE (0 << 3) /* BCH Decoding Select */
+#define BCH_CR_BSEL8 (1 << 2) /* 8 Bit BCH Select */
+#define BCH_CR_BSEL4 (0 << 2) /* 4 Bit BCH Select */
+#define BCH_CR_BRST (1 << 1) /* BCH Reset */
+#define BCH_CR_BCHE (1 << 0) /* BCH Enable */
+
+/* BCH Interrupt Status Register */
+#define BCH_INTS_ERRC_BIT 28
+#define BCH_INTS_ERRC_MASK (0xf << BCH_INTS_ERRC_BIT)
+#define BCH_INTS_ALL0 (1 << 5)
+#define BCH_INTS_ALLf (1 << 4)
+#define BCH_INTS_DECF (1 << 3)
+#define BCH_INTS_ENCF (1 << 2)
+#define BCH_INTS_UNCOR (1 << 1)
+#define BCH_INTS_ERR (1 << 0)
+
+/* BCH ENC/DEC Count Register */
+#define BCH_CNT_DEC_BIT 16
+#define BCH_CNT_DEC_MASK (0x3ff << BCH_CNT_DEC_BIT)
+#define BCH_CNT_ENC_BIT 0
+#define BCH_CNT_ENC_MASK (0x3ff << BCH_CNT_ENC_BIT)
+
+/* BCH Error Report Register */
+#define BCH_ERR_INDEX_ODD_BIT 16
+#define BCH_ERR_INDEX_ODD_MASK (0x1fff << BCH_ERR_INDEX_ODD_BIT)
+#define BCH_ERR_INDEX_EVEN_BIT 0
+#define BCH_ERR_INDEX_EVEN_MASK (0x1fff << BCH_ERR_INDEX_EVEN_BIT)
+
+/*************************************************************************
+ * OWI (One-wire Bus Controller )
+ *************************************************************************/
+#define OWI_CFG (OWI_BASE + 0x00) /* OWI Configure Register */
+#define OWI_CTL (OWI_BASE + 0x04) /* OWI Control Register */
+#define OWI_STS (OWI_BASE + 0x08) /* OWI Status Register */
+#define OWI_DAT (OWI_BASE + 0x0c) /* OWI Data Register */
+#define OWI_DIV (OWI_BASE + 0x10) /* OWI Clock Divide Register */
+
+#define REG_OWI_CFG REG8(OWI_CFG)
+#define REG_OWI_CTL REG8(OWI_CTL)
+#define REG_OWI_STS REG8(OWI_STS)
+#define REG_OWI_DAT REG8(OWI_DAT)
+#define REG_OWI_DIV REG8(OWI_DIV)
+
+/* OWI Configure Register */
+#define OWI_CFG_MODE (1 << 7) /* 0: Regular speed mode 1: Overdrive speed mode */
+#define OWI_CFG_RDDATA (1 << 6) /* 1: receive data from one-wire bus and stored in OWDAT*/
+#define OWI_CFG_WRDATA (1 << 5) /* 1: transmit the data in OWDAT */
+#define OWI_CFG_RDST (1 << 4) /* 1: was sampled during a read */
+#define OWI_CFG_WR1RD (1 << 3) /* 1: generate write 1 sequence on line */
+#define OWI_CFG_WR0 (1 << 2) /* 1: generate write 0 sequence on line */
+#define OWI_CFG_RST (1 << 1) /* 1: generate reset pulse and sample slaves presence pulse*/
+#define OWI_CFG_ENA (1 << 0) /* 1: enable the OWI operation */
+
+/* OWI Control Register */
+#define OWI_CTL_EBYTE (1 << 2) /* enable byte write/read interrupt */
+#define OWI_CTL_EBIT (1 << 1) /* enable bit write/read interrupt */
+#define OWI_CTL_ERST (1 << 0) /* enable reset sequence finished interrupt */
+
+/* OWI Status Register */
+#define OWI_STS_PST (1 << 7) /* 1: one-wire bus has device on it */
+#define OWI_STS_BYTE_RDY (1 << 2) /* 1: have received or transmitted a data */
+#define OWI_STS_BIT_RDY (1 << 1) /* 1: have received or transmitted a bit */
+#define OWI_STS_PST_RDY (1 << 0) /* 1: have finished a reset pulse */
+
+/* OWI Clock Divide Register */
+#define OWI_DIV_CLKDIV_BIT 5
+
+
+/*************************************************************************
+ * MC (Motion Compensation)
+ *************************************************************************/
+#define MC_CTRL (MC_BASE + 0x00) /* MC Control Register */
+#define MC_STAT (MC_BASE + 0x04) /* MC Status Register */
+#define MC_REF_ADDR (MC_BASE + 0x08) /* MC Reference Block Address Register */
+#define MC_REF2_ADDR (MC_BASE + 0x0C) /* MC 2nd Reference Block Address Register */
+#define MC_CURR_ADDR (MC_BASE + 0x10) /* MC Current Block Address Register */
+#define MC_REF_STRD (MC_BASE + 0x14) /* MC Reference Frame Stride Register */
+#define MC_CURR_STRD (MC_BASE + 0x18) /* MC Current Frame Stride Register */
+#define MC_ITP_INFO (MC_BASE + 0x1C) /* MC Block Interpolation Information Register */
+#define MC_TAP_COEF1 (MC_BASE + 0x20) /* MC TAP Filter Coefficient 1 Register */
+#define MC_TAP_COEF2 (MC_BASE + 0x24) /* MC TAP Filter Coefficient 2 Register */
+
+#define REG_MC_CTRL REG32(MC_CTRL)
+#define REG_MC_STAT REG32(MC_STAT)
+#define REG_MC_REF_ADDR REG32(MC_REF_ADDR)
+#define REG_MC_REF2_ADDR REG32(MC_REF2_ADDR)
+#define REG_MC_CURR_ADDR REG32(MC_CURR_ADDR)
+#define REG_MC_REF_STRD REG32(MC_REF_STRD)
+#define REG_MC_CURR_STRD REG32(MC_CURR_STRD)
+#define REG_MC_ITP_INFO REG32(MC_ITP_INFO)
+#define REG_MC_TAP_COEF1 REG32(MC_TAP_COEF1)
+#define REG_MC_TAP_COEF2 REG32(MC_TAP_COEF2)
+
+/* MC Control Register */
+#define MC_CTRL_CACHECLR (1 << 2) /* MC Cache clear */
+#define MC_CTRL_RESET (1 << 1) /* MC Reset */
+#define MC_CTRL_ENABLE (1 << 0) /* MC enable */
+
+/* MC Status Register */
+#define MC_STAT_OUT_END (1 << 0) /* Output DMA termination flag */
+
+/* MC Reference Frame Stride Register, unit: byte */
+#define MC_REF_STRD_BIT 16
+#define MC_REF_STRD_MASK (0xfff << MC_REF_STRD_BIT)
+#define MC_REF_STRD2_BIT 0
+#define MC_REF_STRD2_MASK (0xfff << MC_REF_STRD2_BIT)
+
+/* MC Current Frame Stride Register, unit: byte */
+#define MC_CURR_STRD_BIT 0
+#define MC_CURR_STRD_MASK (0xfff << MC_CURR_STRD_BIT)
+
+/* MC Block Interpolation Information Register */
+#define MC_ITP_INFO_RND1_BIT 24 /* Rounding data during interpolation */
+#define MC_ITP_INFO_RND1_MASK (0xff << MC_ITP_INFO_RND1_BIT)
+#define MC_ITP_INFO_RND0_BIT 16 /* Rounding data during interpolation */
+#define MC_ITP_INFO_RND0_MASK (0xff << MC_ITP_INFO_RND0_BIT)
+#define MC_ITP_INFO_AVG (1 << 12) /* 0: output interpolated data directly; 1: doing average operation h 2nd source data after interpolating and output */
+#define MC_ITP_INFO_FMT_BIT 8 /* Indicate current interpolation's type */
+#define MC_ITP_INFO_RMT_MASK (0xf << MC_ITP_INFO_RMT_BIT)
+ #define MC_ITP_INFO_FMT_MPEG_HPEL (0x0 << MC_ITP_INFO_RMT_BIT) /* MPEG Half-pixel interpolation */
+ #define MC_ITP_INFO_FMT_MPEG_QPEL (0x1 << MC_ITP_INFO_RMT_BIT) /* MPEG 8-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_H264_QPEL (0x2 << MC_ITP_INFO_RMT_BIT) /* H264 6-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_H264_EPEL (0x3 << MC_ITP_INFO_RMT_BIT) /* H264 2-tap Eight-pixel interpolation */
+ #define MC_ITP_INFO_FMT_H264_WPDT (0x4 << MC_ITP_INFO_RMT_BIT) /* H264 Weighted-prediction */
+ #define MC_ITP_INFO_FMT_WMV2_QPEL (0x5 << MC_ITP_INFO_RMT_BIT) /* WMV2 4-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_VC1_QPEL (0x6 << MC_ITP_INFO_RMT_BIT) /* VC1 4-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_RV8_TPEL (0x7 << MC_ITP_INFO_RMT_BIT) /* RV8 4-tap Third-pixel interpolation */
+ #define MC_ITP_INFO_FMT_RV8_CHROM (0x8 << MC_ITP_INFO_RMT_BIT) /* RV8 2-tap Third-pixel interpolation */
+ #define MC_ITP_INFO_FMT_RV9_QPEL (0x9 << MC_ITP_INFO_RMT_BIT) /* RV9 6-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_RV9_CHROM (0xa << MC_ITP_INFO_RMT_BIT) /* RV9 2-tap Quarter-pixel interpolation */
+#define MC_ITP_INFO_BLK_W_BIT 6 /* Indicate reference block's width, unit: pixel */
+#define MC_ITP_INFO_BLK_W_MASK (0x3 << MC_ITP_INFO_BLK_W_BIT)
+ #define MC_ITP_INFO_BLK_W_2 (0x0 << MC_ITP_INFO_BLK_W_BIT)
+ #define MC_ITP_INFO_BLK_W_4 (0x1 << MC_ITP_INFO_BLK_W_BIT)
+ #define MC_ITP_INFO_BLK_W_8 (0x2 << MC_ITP_INFO_BLK_W_BIT)
+ #define MC_ITP_INFO_BLK_W_16 (0x3 << MC_ITP_INFO_BLK_W_BIT)
+#define MC_ITP_INFO_BLK_H_BIT 4 /* Indicate reference block's height, unit: pixel */
+#define MC_ITP_INFO_BLK_H_MASK (0x3 << MC_ITP_INFO_BLK_H_BIT)
+ #define MC_ITP_INFO_BLK_H_2 (0x0 << MC_ITP_INFO_BLK_H_BIT)
+ #define MC_ITP_INFO_BLK_H_4 (0x1 << MC_ITP_INFO_BLK_H_BIT)
+ #define MC_ITP_INFO_BLK_H_8 (0x2 << MC_ITP_INFO_BLK_H_BIT)
+ #define MC_ITP_INFO_BLK_H_16 (0x3 << MC_ITP_INFO_BLK_H_BIT)
+#define MC_ITP_INFO_ITP_CASE_BIT 0 /* Indicate interpolation final destination pixel position */
+#define MC_ITP_INFO_ITP_CASE_MASK (0xf << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H0V0 (0x0 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H1V0 (0x1 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H2V0 (0x2 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H3V0 (0x3 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H0V1 (0x4 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H1V1 (0x5 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H2V1 (0x6 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H3V1 (0x7 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H0V2 (0x8 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H1V2 (0x9 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H2V2 (0xa << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H3V2 (0xb << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H0V3 (0xc << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H1V3 (0xd << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H2V3 (0xe << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H3V3 (0xf << MC_ITP_INFO_ITP_CASE_BIT)
+
+/* MC TAP Filter Coefficient 1 Register */
+#define MC_TAP_COEF1_TAP_COEF4_BIT 24
+#define MC_TAP_COEF1_TAP_COEF4_MASK (0xff << MC_TAP_COEF1_TAP_COEF4_BIT)
+#define MC_TAP_COEF1_TAP_COEF3_BIT 16
+#define MC_TAP_COEF1_TAP_COEF3_MASK (0xff << MC_TAP_COEF1_TAP_COEF3_BIT)
+#define MC_TAP_COEF1_TAP_COEF2_BIT 8
+#define MC_TAP_COEF1_TAP_COEF2_MASK (0xff << MC_TAP_COEF1_TAP_COEF2_BIT)
+#define MC_TAP_COEF1_TAP_COEF1_BIT 0
+#define MC_TAP_COEF1_TAP_COEF1_MASK (0xff << MC_TAP_COEF1_TAP_COEF1_BIT)
+
+/* MC TAP Filter Coefficient 2 Register */
+#define MC_TAP_COEF2_TAP_COEF8_BIT 24
+#define MC_TAP_COEF2_TAP_COEF8_MASK (0xff << MC_TAP_COEF2_TAP_COEF8_BIT)
+#define MC_TAP_COEF2_TAP_COEF7_BIT 16
+#define MC_TAP_COEF2_TAP_COEF7_MASK (0xff << MC_TAP_COEF2_TAP_COEF7_BIT)
+#define MC_TAP_COEF2_TAP_COEF6_BIT 8
+#define MC_TAP_COEF2_TAP_COEF6_MASK (0xff << MC_TAP_COEF2_TAP_COEF6_BIT)
+#define MC_TAP_COEF2_TAP_COEF5_BIT 0
+#define MC_TAP_COEF2_TAP_COEF5_MASK (0xff << MC_TAP_COEF2_TAP_COEF5_BIT)
+
+
+/*************************************************************************
+ * ME (Motion Estimation)
+ *************************************************************************/
+#define ME_CTRL (ME_BASE + 0x00) /* ME Control Register */
+#define ME_REF_ADDR (ME_BASE + 0x04) /* ME Reference Block Address Register */
+#define ME_CURR_ADDR (ME_BASE + 0x08) /* ME Current Block Address Register */
+#define ME_DIFF_ADDR (ME_BASE + 0x0C) /* ME Difference Address Register */
+#define ME_REF_STRD (ME_BASE + 0x10) /* ME Reference Frame Stride Register */
+#define ME_CURR_STRD (ME_BASE + 0x14) /* ME Current Frame Stride Register */
+#define ME_DIFF_STRD (ME_BASE + 0x18) /* ME Difference Frame Stride Register */
+#define ME_SETTINGS (ME_BASE + 0x1C) /* ME Settings Register */
+#define ME_MVD (ME_BASE + 0x20) /* ME Motion Vector Difference Register */
+#define ME_FLAG (ME_BASE + 0x24) /* ME Flag Register */
+
+#define REG_ME_CTRL REG32(ME_CTRL)
+#define REG_ME_REF_ADDR REG32(ME_REF_ADDR)
+#define REG_ME_CURR_ADDR REG32(ME_CURR_ADDR)
+#define REG_ME_DIFF_ADDR REG32(ME_DIFF_ADDR)
+#define REG_ME_REF_STRD REG32(ME_REF_STRD)
+#define REG_ME_CURR_STRD REG32(ME_CURR_STRD)
+#define REG_ME_DIFF_STRD REG32(ME_DIFF_STRD)
+#define REG_ME_SETTINGS REG32(ME_SETTINGS)
+#define REG_ME_MVD REG32(ME_MVD)
+#define REG_ME_FLAG REG32(ME_FLAG)
+
+
+/* ME Control Register */
+#define ME_CTRL_FLUSH (1 << 2) /* ME cache clear */
+#define ME_CTRL_RESET (1 << 1) /* ME reset */
+#define ME_CTRL_ENABLE (1 << 0) /* ME enable */
+
+/* ME Settings Register */
+#define ME_SETTINGS_SAD_GATE_BIT 16 /* The max SAD value which can be accepted */
+#define ME_SETTINGS_SAD_GATE_MASK (0xffff << ME_SETTINGS_SAD_GATE_BIT)
+#define ME_SETTINGS_STEP_NUM_BIT 0 /* The max step number the search process can not exceed */
+#define ME_SETTINGS_STEP_NUM_MASK (0x3f << ME_SETTINGS_STEP_NUM_BIT)
+
+/* ME Motion Vector Difference Register */
+#define ME_MVD_MVDY_BIT 16 /* The MVD value of coordinate-Y */
+#define ME_MVD_MVDY_MASK (0xffff << ME_MVD_MVDY_BIT)
+#define ME_MVD_MVDX_BIT 0 /* The MVD value of coordinate-X */
+#define ME_MVD_MVDX_MASK (0xffff << ME_MVD_MVDX_BIT)
+
+/* ME Flag Register */
+#define ME_FLAG_INTRA (1 << 1) /* Indicate the current MB will be predicted in intra mode */
+#define ME_FLAG_COMPLETED (1 << 0) /* The ME of the current part of the MB is completed */
+
+
+/*************************************************************************
+ * OTP (One Time Programmable Module)
+ *************************************************************************/
+#define OTP_ID0 (OTP_BASE + 0x00) /* ID0 Register */
+#define OTP_ID1 (OTP_BASE + 0x04) /* ID1 Register */
+#define OTP_ID2 (OTP_BASE + 0x08) /* ID2 Register */
+#define OTP_ID3 (OTP_BASE + 0x0C) /* ID3 Register */
+#define OTP_BR0 (OTP_BASE + 0x10) /* BOOTROM0 Register */
+#define OTP_BR1 (OTP_BASE + 0x14) /* BOOTROM1 Register */
+#define OTP_HW0 (OTP_BASE + 0x18) /* Chip Hardware 0 Register */
+#define OTP_HW1 (OTP_BASE + 0x1C) /* Chip Hardware 1 Register */
+
+#define REG_OTP_ID0 REG32(OTP_ID0)
+#define REG_OTP_ID1 REG32(OTP_ID1)
+#define REG_OTP_ID2 REG32(OTP_ID2)
+#define REG_OTP_ID3 REG32(OTP_ID3)
+#define REG_OTP_BR0 REG32(OTP_BR0)
+#define REG_OTP_BR1 REG32(OTP_BR1)
+#define REG_OTP_HW0 REG32(OTP_HW0)
+#define REG_OTP_HW1 REG32(OTP_HW1)
+
+/* ID0 Register */
+#define OTP_ID0_WID_BIT 24 /* Wafer ID */
+#define OTP_ID0_WID_MASK (0xff << OTP_ID0_WID_BIT)
+#define OTP_ID0_MID_BIT 16 /* MASK ID */
+#define OTP_ID0_MID_MASK (0xff << OTP_ID0_MID_BIT)
+#define OTP_ID0_FID_BIT 8 /* Foundary ID */
+#define OTP_ID0_FID_MASK (0xff << OTP_ID0_FID_BIT)
+#define OTP_ID0_PID_BIT 0 /* Product ID */
+#define OTP_ID0_PID_MASK (0xff << OTP_ID0_PID_BIT)
+
+/* ID1 Register */
+#define OTP_ID1_LID_BIT 8 /* Lot ID */
+#define OTP_ID1_LID_MASK (0xffffff << OTP_ID1_LID_BIT)
+#define OTP_ID1_TID_BIT 0 /* Test House ID */
+#define OTP_ID1_TID_MASK (0xff << OTP_ID1_TID_BIT)
+
+/* ID2 Register */
+#define OTP_ID2_XADR_BIT 24 /* Die X-dir Address */
+#define OTP_ID2_XADR_MASK (0xff << OTP_ID2_XADR_BIT)
+#define OTP_ID2_YADR_BIT 16 /* Die Y-dir Address */
+#define OTP_ID2_YADR_MASK (0xff << OTP_ID2_YADR_BIT)
+#define OTP_ID2_TDATE_BIT 0 /* Testing Date */
+#define OTP_ID2_TDATE_MASK (0xffff << OTP_ID2_TDATE_BIT)
+
+/* ID3 Register */
+#define OTP_ID3_CID_BIT 16 /* Customer ID */
+#define OTP_ID3_CID_MASK (0xffff << OTP_ID3_CID_BIT)
+#define OTP_ID3_CP_BIT 0 /* Chip Parameters */
+#define OTP_ID3_CP_MASK (0xffff << OTP_ID3_CP_BIT)
+
+/* BOOTROM1 Register */
+#define OTP_BR1_UDCBOOT_BIT 0
+#define OTP_BR1_UDCBOOT_MASK (0xff << OTP_BR1_UDCBOOT_BIT)
+ #define OTP_BR1_UDCBOOT_AUTO (0xf0 << OTP_BR1_UDCBOOT_BIT)
+ #define OTP_BR1_UDCBOOT_24M (0x0f << OTP_BR1_UDCBOOT_BIT) /* 24MHz OSC */
+ #define OTP_BR1_UDCBOOT_13M (0x0c << OTP_BR1_UDCBOOT_BIT) /* 13MHz OSC */
+ #define OTP_BR1_UDCBOOT_26M (0x03 << OTP_BR1_UDCBOOT_BIT) /* 26MHz OSC */
+ #define OTP_BR1_UDCBOOT_27M (0x00 << OTP_BR1_UDCBOOT_BIT) /* 27MHz OSC */
+
+/* Chip Hardware 1 Register */
+#define OTP_HW1_MC_EN (0x3 << 30) /* MC is enabled */
+#define OTP_HW1_ME_EN (0x3 << 28)
+#define OTP_HW1_DE_EN (0x3 << 26)
+#define OTP_HW1_IDCT_EN (0x3 << 24)
+#define OTP_HW1_UART3_EN (0x3 << 22)
+#define OTP_HW1_UART2_EN (0x3 << 20)
+#define OTP_HW1_UART1_EN (0x3 << 18)
+#define OTP_HW1_UART0_EN (0x3 << 16)
+#define OTP_HW1_SSI1_EN (0x3 << 14)
+#define OTP_HW1_SSI0_EN (0x3 << 12)
+#define OTP_HW1_MSC1_EN (0x3 << 10)
+#define OTP_HW1_MSC0_EN (0x3 << 8)
+#define OTP_HW1_UHC_EN (0x3 << 6)
+#define OTP_HW1_TVE_EN (0x3 << 4)
+#define OTP_HW1_TSSI_EN (0x3 << 2)
+#define OTP_HW1_CIM_EN (0x3 << 0)
+
+
+/*************************************************************************
+ * TSSI MPEG 2-TS slave interface
+ *************************************************************************/
+#define TSSI_ENA ( TSSI_BASE + 0x00 ) /* TSSI enable register */
+#define TSSI_CFG ( TSSI_BASE + 0x04 ) /* TSSI configure register */
+#define TSSI_CTRL ( TSSI_BASE + 0x08 ) /* TSSI control register */
+#define TSSI_STAT ( TSSI_BASE + 0x0c ) /* TSSI state register */
+#define TSSI_FIFO ( TSSI_BASE + 0x10 ) /* TSSI FIFO register */
+#define TSSI_PEN ( TSSI_BASE + 0x14 ) /* TSSI PID enable register */
+#define TSSI_PID(n) ( TSSI_BASE + 0x20 + 4*(n) ) /* TSSI PID filter register */
+#define TSSI_PID0 ( TSSI_BASE + 0x20 )
+#define TSSI_PID1 ( TSSI_BASE + 0x24 )
+#define TSSI_PID2 ( TSSI_BASE + 0x28 )
+#define TSSI_PID3 ( TSSI_BASE + 0x2c )
+#define TSSI_PID4 ( TSSI_BASE + 0x30 )
+#define TSSI_PID5 ( TSSI_BASE + 0x34 )
+#define TSSI_PID6 ( TSSI_BASE + 0x38 )
+#define TSSI_PID7 ( TSSI_BASE + 0x3c )
+#define TSSI_PID_MAX 8 /* max PID: 7 */
+
+#define REG_TSSI_ENA REG8( TSSI_ENA )
+#define REG_TSSI_CFG REG16( TSSI_CFG )
+#define REG_TSSI_CTRL REG8( TSSI_CTRL )
+#define REG_TSSI_STAT REG8( TSSI_STAT )
+#define REG_TSSI_FIFO REG32( TSSI_FIFO )
+#define REG_TSSI_PEN REG32( TSSI_PEN )
+#define REG_TSSI_PID(n) REG32( TSSI_PID(n) )
+#define REG_TSSI_PID0 REG32( TSSI_PID0 )
+#define REG_TSSI_PID1 REG32( TSSI_PID1 )
+#define REG_TSSI_PID2 REG32( TSSI_PID2 )
+#define REG_TSSI_PID3 REG32( TSSI_PID3 )
+#define REG_TSSI_PID4 REG32( TSSI_PID4 )
+#define REG_TSSI_PID5 REG32( TSSI_PID5 )
+#define REG_TSSI_PID6 REG32( TSSI_PID6 )
+#define REG_TSSI_PID7 REG32( TSSI_PID7 )
+
+/* TSSI enable register */
+#define TSSI_ENA_SFT_RST ( 1 << 7 ) /* soft reset bit */
+#define TSSI_ENA_PID_EN ( 1 << 2 ) /* soft filtering function enable bit */
+#define TSSI_ENA_DMA_EN ( 1 << 1 ) /* DMA enable bit */
+#define TSSI_ENA_ENA ( 1 << 0 ) /* TSSI enable bit */
+
+/* TSSI configure register */
+#define TSSI_CFG_TRIG_BIT 14 /* fifo trig number */
+#define TSSI_CFG_TRIG_MASK ( 0x3 << TSSI_CFG_TRIG_BIT)
+#define TSSI_CFG_TRIG_4 ( 0 << TSSI_CFG_TRIG_BIT)
+#define TSSI_CFG_TRIG_8 ( 1 << TSSI_CFG_TRIG_BIT)
+#define TSSI_CFG_TRIG_16 ( 2 << TSSI_CFG_TRIG_BIT)
+#define TSSI_CFG_END_WD ( 1 << 9 ) /* order of data in word */
+#define TSSI_CFG_END_BT ( 1 << 8 ) /* order of data in byte */
+#define TSSI_CFG_TSDI_H ( 1 << 7 ) /* data pin polarity */
+#define TSSI_CFG_USE_0 ( 1 << 6 ) /* serial mode data pin select */
+#define TSSI_CFG_USE_TSDI0 ( 0 << 6 ) /* TSDI0 as serial mode data pin */
+#define TSSI_CFG_USE_TSDI7 ( 1 << 6 ) /* TSDI7 as serial mode data pin */
+#define TSSI_CFG_TSCLK_CH ( 1 << 5 ) /* clk channel select */
+#define TSSI_CFG_PARAL ( 1 << 4 ) /* mode select */
+#define TSSI_CFG_PARAL_MODE ( 1 << 4 ) /* parallel select */
+#define TSSI_CFG_SERIAL_MODE ( 0 << 4 ) /* serial select */
+#define TSSI_CFG_TSCLK_P ( 1 << 3 ) /* clk edge select */
+#define TSSI_CFG_TSFRM_H ( 1 << 2 ) /* TSFRM polarity select */
+#define TSSI_CFG_TSSTR_H ( 1 << 1 ) /* TSSTR polarity select */
+#define TSSI_CFG_TSFAIL_H ( 1 << 0 ) /* TSFAIL polarity select */
+
+/* TSSI control register */
+#define TSSI_CTRL_OVRNM ( 1 << 1 ) /* FIFO overrun interrupt mask bit */
+#define TSSI_CTRL_TRIGM ( 1 << 0 ) /* FIFO trigger interrupt mask bit */
+
+/* TSSI state register */
+#define TSSI_STAT_OVRN ( 1 << 1 ) /* FIFO overrun interrupt flag bit */
+#define TSSI_STAT_TRIG ( 1 << 0 ) /* FIFO trigger interrupt flag bit */
+
+/* TSSI PID enable register */
+#define TSSI_PEN_EN00 ( 1 << 0 ) /* enable PID n */
+#define TSSI_PEN_EN10 ( 1 << 1 )
+#define TSSI_PEN_EN20 ( 1 << 2 )
+#define TSSI_PEN_EN30 ( 1 << 3 )
+#define TSSI_PEN_EN40 ( 1 << 4 )
+#define TSSI_PEN_EN50 ( 1 << 5 )
+#define TSSI_PEN_EN60 ( 1 << 6 )
+#define TSSI_PEN_EN70 ( 1 << 7 )
+#define TSSI_PEN_EN01 ( 1 << 16 )
+#define TSSI_PEN_EN11 ( 1 << 17 )
+#define TSSI_PEN_EN21 ( 1 << 18 )
+#define TSSI_PEN_EN31 ( 1 << 19 )
+#define TSSI_PEN_EN41 ( 1 << 20 )
+#define TSSI_PEN_EN51 ( 1 << 21 )
+#define TSSI_PEN_EN61 ( 1 << 22 )
+#define TSSI_PEN_EN71 ( 1 << 23 )
+#define TSSI_PEN_PID0 ( 1 << 31 ) /* PID filter enable PID0 */
+
+/* TSSI PID Filter Registers */
+#define TSSI_PID_PID1_BIT 16
+#define TSSI_PID_PID1_MASK (0x1FFF<<TSSI_PID_PID1_BIT)
+#define TSSI_PID_PID0_BIT 0
+#define TSSI_PID_PID0_MASK (0x1FFF<<TSSI_PID_PID0_BIT)
+
+
+/*************************************************************************
+ * IPU (Image Processing Unit)
+ *************************************************************************/
+#define IPU_V_BASE 0xB3080000
+#define IPU_P_BASE 0x13080000
+
+/* Register offset */
+#define REG_CTRL 0x0 /* IPU Control Register */
+#define REG_STATUS 0x4 /* IPU Status Register */
+#define REG_D_FMT 0x8 /* Data Format Register */
+#define REG_Y_ADDR 0xc /* Input Y or YUV422 Packaged Data Address Register */
+#define REG_U_ADDR 0x10 /* Input U Data Address Register */
+#define REG_V_ADDR 0x14 /* Input V Data Address Register */
+#define REG_IN_FM_GS 0x18 /* Input Geometric Size Register */
+#define REG_Y_STRIDE 0x1c /* Input Y Data Line Stride Register */
+#define REG_UV_STRIDE 0x20 /* Input UV Data Line Stride Register */
+#define REG_OUT_ADDR 0x24 /* Output Frame Start Address Register */
+#define REG_OUT_GS 0x28 /* Output Geometric Size Register */
+#define REG_OUT_STRIDE 0x2c /* Output Data Line Stride Register */
+#define REG_RSZ_COEF_INDEX 0x30 /* Resize Coefficients Table Index Register */
+#define REG_CSC_CO_COEF 0x34 /* CSC C0 Coefficient Register */
+#define REG_CSC_C1_COEF 0x38 /* CSC C1 Coefficient Register */
+#define REG_CSC_C2_COEF 0x3c /* CSC C2 Coefficient Register */
+#define REG_CSC_C3_COEF 0x40 /* CSC C3 Coefficient Register */
+#define REG_CSC_C4_COEF 0x44 /* CSC C4 Coefficient Register */
+#define HRSZ_LUT_BASE 0x48 /* Horizontal Resize Coefficients Look Up Table Register group */
+#define VRSZ_LUT_BASE 0x4c /* Virtical Resize Coefficients Look Up Table Register group */
+#define REG_CSC_OFSET_PARA 0x50 /* CSC Offset Parameter Register */
+#define REG_Y_PHY_T_ADDR 0x54 /* Input Y Physical Table Address Register */
+#define REG_U_PHY_T_ADDR 0x58 /* Input U Physical Table Address Register */
+#define REG_V_PHY_T_ADDR 0x5c /* Input V Physical Table Address Register */
+#define REG_OUT_PHY_T_ADDR 0x60 /* Output Physical Table Address Register */
+
+/* REG_CTRL: IPU Control Register */
+#define IPU_CE_SFT 0x0
+#define IPU_CE_MSK 0x1
+#define IPU_RUN_SFT 0x1
+#define IPU_RUN_MSK 0x1
+#define HRSZ_EN_SFT 0x2
+#define HRSZ_EN_MSK 0x1
+#define VRSZ_EN_SFT 0x3
+#define VRSZ_EN_MSK 0x1
+#define CSC_EN_SFT 0x4
+#define CSC_EN_MSK 0x1
+#define FM_IRQ_EN_SFT 0x5
+#define FM_IRQ_EN_MSK 0x1
+#define IPU_RST_SFT 0x6
+#define IPU_RST_MSK 0x1
+#define H_SCALE_SFT 0x8
+#define H_SCALE_MSK 0x1
+#define V_SCALE_SFT 0x9
+#define V_SCALE_MSK 0x1
+#define PKG_SEL_SFT 0xA
+#define PKG_SEL_MSK 0x1
+#define LCDC_SEL_SFT 0xB
+#define LCDC_SEL_MSK 0x1
+#define SPAGE_MAP_SFT 0xC
+#define SPAGE_MAP_MSK 0x1
+#define DPAGE_SEL_SFT 0xD
+#define DPAGE_SEL_MSK 0x1
+#define DISP_SEL_SFT 0xE
+#define DISP_SEL_MSK 0x1
+#define FIELD_CONF_EN_SFT 15
+#define FIELD_CONF_EN_MSK 1
+#define FIELD_SEL_SFT 16
+#define FIELD_SEL_MSK 1
+#define DFIX_SEL_SFT 17
+#define DFIX_SEL_MSK 1
+
+/* REG_STATUS: IPU Status Register */
+#define OUT_END_SFT 0x0
+#define OUT_END_MSK 0x1
+#define FMT_ERR_SFT 0x1
+#define FMT_ERR_MSK 0x1
+#define SIZE_ERR_SFT 0x2
+#define SIZE_ERR_MSK 0x1
+
+/* D_FMT: Data Format Register */
+#define IN_FMT_SFT 0x0
+#define IN_FMT_MSK 0x3
+#define IN_OFT_SFT 0x2
+#define IN_OFT_MSK 0x3
+#define YUV_PKG_OUT_SFT 0x10
+#define YUV_PKG_OUT_MSK 0x7
+#define OUT_FMT_SFT 0x13
+#define OUT_FMT_MSK 0x3
+#define RGB_OUT_OFT_SFT 0x15
+#define RGB_OUT_OFT_MSK 0x7
+#define RGB888_FMT_SFT 0x18
+#define RGB888_FMT_MSK 0x1
+
+/* IN_FM_GS: Input Geometric Size Register */
+#define IN_FM_H_SFT 0x0
+#define IN_FM_H_MSK 0xFFF
+#define IN_FM_W_SFT 0x10
+#define IN_FM_W_MSK 0xFFF
+
+/* Y_STRIDE: Input Y Data Line Stride Register */
+#define Y_S_SFT 0x0
+#define Y_S_MSK 0x3FFF
+
+/* UV_STRIDE: Input UV Data Line Stride Register */
+#define V_S_SFT 0x0
+#define V_S_MSK 0x1FFF
+#define U_S_SFT 0x10
+#define U_S_MSK 0x1FFF
+
+/* OUT_GS: Output Geometric Size Register */
+#define OUT_FM_H_SFT 0x0
+#define OUT_FM_H_MSK 0x1FFF
+#define OUT_FM_W_SFT 0x10
+#define OUT_FM_W_MSK 0x7FFF
+
+/* OUT_STRIDE: Output Data Line Stride Register */
+#define OUT_S_SFT 0x0
+#define OUT_S_MSK 0xFFFF
+
+/* RSZ_COEF_INDEX: Resize Coefficients Table Index Register */
+#define VE_IDX_SFT 0x0
+#define VE_IDX_MSK 0x1F
+#define HE_IDX_SFT 0x10
+#define HE_IDX_MSK 0x1F
+
+/* CSC_CX_COEF: CSC CX Coefficient Register */
+#define CX_COEF_SFT 0x0
+#define CX_COEF_MSK 0xFFF
+
+/* HRSZ_LUT_BASE, VRSZ_LUT_BASE: Resize Coefficients Look Up Table Register group */
+#define LUT_LEN 20
+
+#define OUT_N_SFT 0x0
+#define OUT_N_MSK 0x1
+#define IN_N_SFT 0x1
+#define IN_N_MSK 0x1
+#define W_COEF_SFT 0x2
+#define W_COEF_MSK 0x3FF
+
+/* CSC_OFSET_PARA: CSC Offset Parameter Register */
+#define CHROM_OF_SFT 0x10
+#define CHROM_OF_MSK 0xFF
+#define LUMA_OF_SFT 0x00
+#define LUMA_OF_MSK 0xFF
+
+
+#endif /* __JZ4750_REGS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750/serial.h b/arch/mips/include/asm/mach-jz4750/serial.h
new file mode 100644
index 00000000000..a6f78a6a48b
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750/serial.h
@@ -0,0 +1,30 @@
+/*
+ * linux/include/asm-mips/mach-jz4750/serial.h
+ *
+ * Ingenic's JZ4750 common include.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_BOARD_SERIAL_H__
+#define __ASM_BOARD_SERIAL_H__
+
+#ifndef CONFIG_SERIAL_MANY_PORTS
+#undef RS_TABLE_SIZE
+#define RS_TABLE_SIZE 1
+#endif
+
+#define JZ_BASE_BAUD (12000000/16)
+
+#define JZ_SERIAL_PORT_DEFNS \
+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \
+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \
+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM },
+
+#endif /* __ASM_BORAD_SERIAL_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750/war.h b/arch/mips/include/asm/mach-jz4750/war.h
new file mode 100644
index 00000000000..3a5bc17e28f
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750/war.h
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H
+#define __ASM_MIPS_MACH_JZ4740_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR 0
+#define R4600_V1_HIT_CACHEOP_WAR 0
+#define R4600_V2_HIT_CACHEOP_WAR 0
+#define R5432_CP0_INTERRUPT_WAR 0
+#define BCM1250_M3_WAR 0
+#define SIBYTE_1956_WAR 0
+#define MIPS4K_ICACHE_REFILL_WAR 0
+#define MIPS_CACHE_SYNC_WAR 0
+#define TX49XX_ICACHE_INDEX_INV_WAR 0
+#define RM9000_CDEX_SMP_WAR 0
+#define ICACHE_REFILLS_WORKAROUND_WAR 0
+#define R10000_LLSC_WAR 0
+#define MIPS34K_MISSED_ITLB_WAR 0
+
+#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */
diff --git a/arch/mips/include/asm/mach-jz4750d/board-cetus.h b/arch/mips/include/asm/mach-jz4750d/board-cetus.h
new file mode 100644
index 00000000000..9a00c992c14
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750d/board-cetus.h
@@ -0,0 +1,263 @@
+/*
+ * linux/include/asm-mips/mach-jz4750d/board-cetus.h
+ *
+ * JZ4750D-based CETUS board ver 1.x definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750D_CETUS_H__
+#define __ASM_JZ4750D_CETUS_H__
+
+/*======================================================================
+ * Frequencies of on-board oscillators
+ */
+#define JZ_EXTAL 24000000
+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
+//#define CFG_DIV 1 /* hclk=pclk=mclk=CFG_EXTAL/CFG_DIV, just for FPGA board */
+
+
+/*======================================================================
+ * GPIO
+ */
+
+#define GPIO_SD0_VCC_EN_N (32*4+0) /* CIM_D0 */
+#define GPIO_SD0_CD_N (32*4+1) /* CIM_D1 */
+#define GPIO_SD0_WP (32*4+2) /* CIM_D2 */
+#define GPIO_SD1_VCC_EN_N (32*4+3) /* CIM_D3 */
+#define GPIO_SD1_CD_N (32*4+4) /* CIM_D4 */
+
+#define GPIO_USB_DETE (32*4+6) /* CIM_D6 */
+#define GPIO_DC_DETE_N (32*4+8) /* CIM_MCLK */
+#define GPIO_CHARG_STAT_N (32*4+10) /* CIM_VSYNC */
+#define GPIO_DISP_OFF_N (32*4+18) /* SDATO */
+#define GPIO_LCD_VCC_EN_N (32*4+19) /* SDATI */
+//#define GPIO_LED_EN 124 /* GPD28 */
+
+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
+
+/*======================================================================
+ * LCD backlight
+ */
+#define GPIO_LCD_PWM (32*4+22) /* GPE22 PWM2 */
+#define LCD_PWM_CHN 2 /* pwm channel */
+
+#define LCD_MAX_BACKLIGHT 100
+#define LCD_MIN_BACKLIGHT 1
+#define LCD_DEFAULT_BACKLIGHT 80
+
+/* LCD Backlight PWM Control - River. */
+#define HAVE_LCD_PWM_CONTROL 1
+
+#ifdef HAVE_LCD_PWM_CONTROL
+static inline void __lcd_pwm_set_backlight_level(int n)
+{
+ __tcu_stop_counter(LCD_PWM_CHN);
+
+ __tcu_set_pwm_output_shutdown_abrupt(LCD_PWM_CHN);
+ __tcu_disable_pwm_output(LCD_PWM_CHN);
+
+ __tcu_set_count(LCD_PWM_CHN, 0);
+ __tcu_set_full_data(LCD_PWM_CHN, LCD_MAX_BACKLIGHT + 1);
+ __tcu_set_half_data(LCD_PWM_CHN, n);
+
+ __tcu_enable_pwm_output(LCD_PWM_CHN);
+ __tcu_start_counter(LCD_PWM_CHN);
+
+ return;
+}
+
+static inline void __lcd_pwm_start(void)
+{
+ __gpio_as_pwm(2);
+
+ __tcu_stop_counter(LCD_PWM_CHN);
+
+ __tcu_select_extalclk(LCD_PWM_CHN);
+ __tcu_select_clk_div4(LCD_PWM_CHN);
+ __tcu_init_pwm_output_high(LCD_PWM_CHN);
+
+ __lcd_pwm_set_backlight_level(LCD_DEFAULT_BACKLIGHT);
+
+ return;
+}
+
+static inline void __lcd_pwm_stop(void)
+{
+ __tcu_stop_counter(LCD_PWM_CHN);
+
+ __tcu_set_pwm_output_shutdown_abrupt(LCD_PWM_CHN);
+ __tcu_disable_pwm_output(LCD_PWM_CHN);
+
+ return;
+}
+
+#define __lcd_set_backlight_level(n) __lcd_pwm_set_backlight_level(n)
+
+#else
+
+/* 100 level: 0,1,...,100 */
+#define __lcd_set_backlight_level(n) \
+do { \
+ __gpio_as_output(GPIO_LCD_PWM); \
+ __gpio_set_pin(GPIO_LCD_PWM); \
+} while (0)
+
+#endif
+
+#define __lcd_close_backlight() \
+do { \
+ __gpio_as_output(GPIO_LCD_PWM); \
+ __gpio_clear_pin(GPIO_LCD_PWM); \
+} while (0)
+
+//20091118
+/*====================================================================
+ * GPIO KEYS and ADKEYS
+ */
+#define GPIO_HOME (32*5+12) // SW4-GPF12 SSI_DR
+#define GPIO_MENU (32*2+31) // SW2-GPC31 boot_sel1
+#define GPIO_BACK (32*5+11) // SW3-GPF11 SSI_DT
+#define GPIO_CALL (32*5+10) // SW5-GPF10 SSI_CLK
+#define GPIO_ENDCALL (32*4+7) // SW6-GPE7 CIM_D7
+#define GPIO_SW10 (32*4+25) // SW10-GPE25 UART1_TXD
+#define GPIO_ADKEY_INT (32*4+11) // KEY_INT-GPE11 CIM_HSYNC
+
+/*====================================================================
+ * ADKEYS LEVEL
+ */
+
+#define DPAD_LEFT_LEVEL 869 //0.7V, 225=0.18105/3.3*4096
+#define DPAD_DOWN_LEVEL 1986 //1.6V
+#define DPAD_UP_LEVEL 2482 //2.0V
+#define DPAD_CENTER_LEVEL 1489 //1.2V
+#define DPAD_RIGHT_LEVEL 186 //0.15V
+
+/*======================================================================
+ * Analog input for VBAT is the battery voltage divided by CFG_PBAT_DIV.
+ */
+#define CFG_PBAT_DIV 1
+
+/*
+ * The GPIO interrupt pin is low voltage or fall edge acitve
+ */
+#define ACTIVE_LOW_HOME 1
+#define ACTIVE_LOW_MENU 1
+#define ACTIVE_LOW_BACK 1
+#define ACTIVE_LOW_CALL 1
+#define ACTIVE_LOW_ENDCALL 1
+#define ACTIVE_LOW_SW10 1
+#define ACTIVE_LOW_ADKEY 1
+#define ACTIVE_LOW_MSC0_CD 1 /* work when GPIO_SD0_CD_N = 0 */
+#define ACTIVE_LOW_MSC1_CD 1 /* work when GPIO_SD1_CD_N = 0 */
+#define ACTIVE_WAKE_UP 1
+
+/*======================================================================
+ * MMC/SD
+ */
+
+#define MSC0_WP_PIN GPIO_SD0_WP
+#define MSC0_HOTPLUG_PIN GPIO_SD0_CD_N
+#define MSC0_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD0_CD_N)
+
+#define MSC1_WP_PIN GPIO_SD1_WP
+#define MSC1_HOTPLUG_PIN GPIO_SD1_CD_N
+#define MSC1_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD1_CD_N)
+
+#define __msc0_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD0_VCC_EN_N); \
+ __gpio_as_input(GPIO_SD0_CD_N); \
+} while (0)
+
+#define __msc0_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD0_VCC_EN_N); \
+} while (0)
+
+#define __msc0_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD0_VCC_EN_N); \
+} while (0)
+
+/*
+#define __msc0_card_detected(s) \
+({ \
+ int detected = 1; \
+ if (__gpio_get_pin(GPIO_SD0_CD_N)) \
+ detected = 0; \
+ detected; \
+})
+*/
+
+#if ACTIVE_LOW_MSC0_CD == 1 /* work when cd is low */
+#define __msc0_card_detected(s) \
+({ \
+ int detected = 1; \
+ if (__gpio_get_pin(GPIO_SD0_CD_N)) \
+ detected = 0; \
+ detected; \
+})
+#else
+#define __msc0_card_detected(s) \
+({ \
+ int detected = 0; \
+ if (__gpio_get_pin(GPIO_SD0_CD_N)) \
+ detected = 1; \
+ detected; \
+})
+#endif /*ACTIVE_LOW_MSC0_CD*/
+
+#define __msc1_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD1_VCC_EN_N); \
+ /* __gpio_as_input(GPIO_SD1_CD_N);*/ \
+} while (0)
+
+#define __msc1_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD1_VCC_EN_N); \
+} while (0)
+
+#define __msc1_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD1_VCC_EN_N); \
+} while (0)
+
+/*
+#define __msc1_card_detected(s) \
+({ \
+ int detected = 0; \
+ if (!(__gpio_get_pin(GPIO_SD1_CD_N))) \
+ detected = 1; \
+ detected; \
+})
+*/
+
+#if ACTIVE_LOW_MSC1_CD == 1 /* work when cd is low */
+#define __msc1_card_detected(s) \
+({ \
+ int detected = 1; \
+ if (__gpio_get_pin(GPIO_SD1_CD_N)) \
+ detected = 0; \
+ detected; \
+})
+#else
+#define __msc1_card_detected(s) \
+({ \
+ int detected = 0; \
+ if (__gpio_get_pin(GPIO_SD1_CD_N)) \
+ detected = 1; \
+ detected; \
+})
+#endif /*ACTIVE_LOW_MSC1_CD*/
+
+
+
+#endif /* __ASM_JZ4750d_CETUS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750d/board-draco.h b/arch/mips/include/asm/mach-jz4750d/board-draco.h
new file mode 100644
index 00000000000..fe04f79567a
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750d/board-draco.h
@@ -0,0 +1,126 @@
+/*
+ * linux/include/asm-mips/mach-jz4750d/board-draco.h
+ *
+ * JZ4750D-based DRACO board ver 1.x definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750D_DRACO_H__
+#define __ASM_JZ4750D_DRACO_H__
+
+//#define CONFIG_FPGA /* fuwa is an FPGA board */
+
+/*======================================================================
+ * Frequencies of on-board oscillators
+ */
+//#define JZ_EXTAL 48000000 /* Main extal freq: 12 MHz */
+#define JZ_EXTAL 24000000
+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
+//#define CFG_DIV 1 /* hclk=pclk=mclk=CFG_EXTAL/CFG_DIV, just for FPGA board */
+
+
+/*======================================================================
+ * GPIO
+ */
+#define GPIO_SD0_VCC_EN_N (32*2+10) /* GPC10 */
+#define GPIO_SD0_CD_N (32*2+11) /* GPC11 */
+#define GPIO_SD0_WP (32*2+12) /* GPC12 */
+//#define GPIO_SD1_VCC_EN_N (32*2+13) /* GPC13 */
+#define GPIO_SD1_VCC_EN_N (32*4+4) /* GPE4 */
+#define GPIO_SD1_CD_N (32*2+14) /* GPC14 */
+#define GPIO_USB_DETE (32*5+12) /* GPF12 */
+#define GPIO_DC_DETE_N 103 /* GPD7 */
+#define GPIO_CHARG_STAT_N 111 /* GPD15 */
+#define GPIO_DISP_OFF_N 121 /* GPD25, LCD_REV */
+//#define GPIO_LED_EN 124 /* GPD28 */
+
+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
+
+/*======================================================================
+ * LCD backlight
+ */
+#define GPIO_LCD_PWM (32*4+20) /* GPE20 */
+
+#define LCD_PWM_CHN 0 /* pwm channel */
+#define LCD_PWM_FULL 101
+/* 100 level: 0,1,...,100 */
+#define __lcd_set_backlight_level(n) \
+do { \
+ __gpio_as_output(GPIO_LCD_PWM); \
+ __gpio_set_pin(GPIO_LCD_PWM); \
+} while (0)
+
+#define __lcd_close_backlight() \
+do { \
+ __gpio_as_output(GPIO_LCD_PWM); \
+ __gpio_clear_pin(GPIO_LCD_PWM); \
+} while (0)
+
+/*======================================================================
+ * MMC/SD
+ */
+
+#define MSC0_WP_PIN GPIO_SD0_WP
+#define MSC0_HOTPLUG_PIN GPIO_SD0_CD_N
+#define MSC0_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD0_CD_N)
+
+#define MSC1_WP_PIN GPIO_SD1_WP
+#define MSC1_HOTPLUG_PIN GPIO_SD1_CD_N
+#define MSC1_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD1_CD_N)
+
+#define __msc0_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD0_VCC_EN_N); \
+ __gpio_as_input(GPIO_SD0_CD_N); \
+} while (0)
+
+#define __msc0_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD0_VCC_EN_N); \
+} while (0)
+
+#define __msc0_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD0_VCC_EN_N); \
+} while (0)
+
+#define __msc0_card_detected(s) \
+({ \
+ int detected = 1; \
+ if (__gpio_get_pin(GPIO_SD0_CD_N)) \
+ detected = 0; \
+ detected; \
+})
+
+#define __msc1_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD1_VCC_EN_N); \
+ /* __gpio_as_input(GPIO_SD1_CD_N);*/ \
+} while (0)
+
+#define __msc1_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD1_VCC_EN_N); \
+} while (0)
+
+#define __msc1_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD1_VCC_EN_N); \
+} while (0)
+
+#define __msc1_card_detected(s) \
+({ \
+ int detected = 0; \
+ if (__gpio_get_pin(GPIO_SD1_CD_N)) \
+ detected = 1; \
+ detected; \
+})
+
+#endif /* __ASM_JZ4750d_DRACO_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750d/board-fuwa1.h b/arch/mips/include/asm/mach-jz4750d/board-fuwa1.h
new file mode 100644
index 00000000000..7b8c6c29f4e
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750d/board-fuwa1.h
@@ -0,0 +1,126 @@
+/*
+ * linux/include/asm-mips/mach-jz4750d/board-fuwa1.h
+ *
+ * JZ4750D-based FUWA1 board ver 1.x definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750D_FUWA1_H__
+#define __ASM_JZ4750D_FUWA1_H__
+
+//#define CONFIG_FPGA /* fuwa is an FPGA board */
+
+/*======================================================================
+ * Frequencies of on-board oscillators
+ */
+//#define JZ_EXTAL 48000000 /* Main extal freq: 12 MHz */
+#define JZ_EXTAL 24000000
+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
+//#define CFG_DIV 1 /* hclk=pclk=mclk=CFG_EXTAL/CFG_DIV, just for FPGA board */
+
+
+/*======================================================================
+ * GPIO
+ */
+#define GPIO_SD0_VCC_EN_N (32*2+10) /* GPC10 */
+#define GPIO_SD0_CD_N (32*2+11) /* GPC11 */
+#define GPIO_SD0_WP (32*2+12) /* GPC12 */
+//#define GPIO_SD1_VCC_EN_N (32*2+13) /* GPC13 */
+#define GPIO_SD1_VCC_EN_N (32*4+4) /* GPE4 */
+#define GPIO_SD1_CD_N (32*2+14) /* GPC14 */
+#define GPIO_USB_DETE 102 /* GPD6 */
+#define GPIO_DC_DETE_N 103 /* GPD7 */
+#define GPIO_CHARG_STAT_N 111 /* GPD15 */
+#define GPIO_DISP_OFF_N 121 /* GPD25, LCD_REV */
+//#define GPIO_LED_EN 124 /* GPD28 */
+
+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
+
+/*======================================================================
+ * LCD backlight
+ */
+#define GPIO_LCD_PWM (32*4+20) /* GPE20 */
+
+#define LCD_PWM_CHN 0 /* pwm channel */
+#define LCD_PWM_FULL 101
+/* 100 level: 0,1,...,100 */
+#define __lcd_set_backlight_level(n) \
+do { \
+ __gpio_as_output(GPIO_LCD_PWM); \
+ __gpio_set_pin(GPIO_LCD_PWM); \
+} while (0)
+
+#define __lcd_close_backlight() \
+do { \
+ __gpio_as_output(GPIO_LCD_PWM); \
+ __gpio_clear_pin(GPIO_LCD_PWM); \
+} while (0)
+
+/*======================================================================
+ * MMC/SD
+ */
+
+#define MSC0_WP_PIN GPIO_SD0_WP
+#define MSC0_HOTPLUG_PIN GPIO_SD0_CD_N
+#define MSC0_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD0_CD_N)
+
+#define MSC1_WP_PIN GPIO_SD1_WP
+#define MSC1_HOTPLUG_PIN GPIO_SD1_CD_N
+#define MSC1_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD1_CD_N)
+
+#define __msc0_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD0_VCC_EN_N); \
+ __gpio_as_input(GPIO_SD0_CD_N); \
+} while (0)
+
+#define __msc0_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD0_VCC_EN_N); \
+} while (0)
+
+#define __msc0_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD0_VCC_EN_N); \
+} while (0)
+
+#define __msc0_card_detected(s) \
+({ \
+ int detected = 1; \
+ if (__gpio_get_pin(GPIO_SD0_CD_N)) \
+ detected = 0; \
+ detected; \
+})
+
+#define __msc1_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD1_VCC_EN_N); \
+ /* __gpio_as_input(GPIO_SD1_CD_N);*/ \
+} while (0)
+
+#define __msc1_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD1_VCC_EN_N); \
+} while (0)
+
+#define __msc1_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD1_VCC_EN_N); \
+} while (0)
+
+#define __msc1_card_detected(s) \
+({ \
+ int detected = 0; \
+ if (__gpio_get_pin(GPIO_SD1_CD_N)) \
+ detected = 1; \
+ detected; \
+})
+
+#endif /* __ASM_JZ4750d_FUWA1_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750d/clock.h b/arch/mips/include/asm/mach-jz4750d/clock.h
new file mode 100644
index 00000000000..a2832d647c3
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750d/clock.h
@@ -0,0 +1,230 @@
+/*
+ * linux/include/asm-mips/mach-jz4750d/clock.h
+ *
+ * JZ4750D clocks definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750D_CLOCK_H__
+#define __ASM_JZ4750D_CLOCK_H__
+
+#ifndef JZ_EXTAL
+#define JZ_EXTAL 12000000 /* 3.6864 MHz */
+#endif
+#ifndef JZ_EXTAL2
+#define JZ_EXTAL2 32768 /* 32.768 KHz */
+#endif
+
+/*
+ * JZ4750D clocks structure
+ */
+typedef struct {
+ unsigned int cclk; /* CPU clock */
+ unsigned int hclk; /* System bus clock */
+ unsigned int pclk; /* Peripheral bus clock */
+ unsigned int mclk; /* Flash/SRAM/SDRAM clock */
+ unsigned int h1clk; /* AHB1 clock */
+ unsigned int pixclk; /* LCD pixel clock */
+ unsigned int i2sclk; /* AIC module clock */
+ unsigned int usbclk; /* USB module clock */
+ unsigned int mscclk; /* MSC module clock */
+ unsigned int extalclk; /* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */
+ unsigned int rtcclk; /* RTC clock for CPM,INTC,RTC,TCU,WDT */
+} jz_clocks_t;
+
+extern jz_clocks_t jz_clocks;
+
+
+/* PLL output frequency */
+static __inline__ unsigned int __cpm_get_pllout(void)
+{
+#if defined(CONFIG_FPGA)
+ return JZ_EXTAL/CFG_DIV;
+#else
+ unsigned long m, n, no, pllout;
+ unsigned long cppcr = REG_CPM_CPPCR;
+ unsigned long od[4] = {1, 2, 2, 4};
+ if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) {
+ m = __cpm_get_pllm() + 2;
+ n = __cpm_get_plln() + 2;
+ no = od[__cpm_get_pllod()];
+ pllout = ((JZ_EXTAL) / (n * no)) * m;
+ } else
+ pllout = JZ_EXTAL;
+ return pllout;
+#endif
+}
+
+/* PLL output frequency for MSC/I2S/LCD/USB */
+static __inline__ unsigned int __cpm_get_pllout2(void)
+{
+#if defined(CONFIG_FPGA)
+ return JZ_EXTAL/CFG_DIV;
+#else
+ if (REG_CPM_CPCCR & CPM_CPCCR_PCS)
+ return __cpm_get_pllout();
+ else
+ return __cpm_get_pllout()/2;
+#endif
+}
+
+/* CPU core clock */
+static __inline__ unsigned int __cpm_get_cclk(void)
+{
+
+#if defined(CONFIG_FGPA)
+ return JZ_EXTAL;
+#else
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ return __cpm_get_pllout() / div[__cpm_get_cdiv()];
+#endif
+}
+
+/* AHB system bus clock */
+static __inline__ unsigned int __cpm_get_hclk(void)
+{
+#if defined(CONFIG_FPGA)
+ return JZ_EXTAL/CFG_DIV;
+#else
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_hdiv()];
+#endif
+
+}
+
+/* Memory bus clock */
+static __inline__ unsigned int __cpm_get_mclk(void)
+{
+#if defined(CONFIG_FPGA)
+ return JZ_EXTAL/CFG_DIV;
+#else
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_mdiv()];
+#endif
+}
+
+/* APB peripheral bus clock */
+static __inline__ unsigned int __cpm_get_pclk(void)
+{
+#if defined(CONFIG_FPGA)
+ return JZ_EXTAL/CFG_DIV;
+#else
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_pdiv()];
+#endif
+}
+
+/* LCDC module clock */
+static __inline__ unsigned int __cpm_get_h1clk(void)
+{
+ return __cpm_get_pllout2() / (__cpm_get_h1div() + 1);
+}
+
+/* LCD pixel clock */
+static __inline__ unsigned int __cpm_get_pixclk(void)
+{
+ return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1);
+}
+
+/* I2S clock */
+static __inline__ unsigned int __cpm_get_i2sclk(void)
+{
+ if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) {
+ return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1);
+ }
+ else {
+ return JZ_EXTAL;
+ }
+}
+
+/* USB clock */
+static __inline__ unsigned int __cpm_get_usbclk(void)
+{
+ if (REG_CPM_CPCCR & CPM_CPCCR_UCS) {
+ return __cpm_get_pllout2() / (__cpm_get_udiv() + 1);
+ }
+ else {
+ return JZ_EXTAL;
+ }
+}
+
+/*
+ * MSC clock
+ * @n: the index of MMC/SD controller
+ */
+static __inline__ unsigned int __cpm_get_mscclk(int n)
+{
+ return __cpm_get_pllout2() / (__cpm_get_mscdiv(n) + 1);
+}
+
+/* EXTAL clock */
+static __inline__ unsigned int __cpm_get_extalclk0(void)
+{
+ return JZ_EXTAL;
+}
+
+/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */
+static __inline__ unsigned int __cpm_get_extalclk(void)
+{
+#if defined(CONFIG_FPGA)
+ return __cpm_get_pllout();
+#else
+ if (REG_CPM_CPCCR & CPM_CPCCR_ECS)
+ return __cpm_get_extalclk0()/2;
+ else
+ return __cpm_get_extalclk0();
+#endif
+
+}
+
+/* RTC clock for CPM,INTC,RTC,TCU,WDT */
+static __inline__ unsigned int __cpm_get_rtcclk(void)
+{
+ return JZ_EXTAL2;
+}
+
+/*
+ * Output 24MHz for SD and 16MHz for MMC.
+ * @n: the index of MMC/SD controller
+ */
+static inline void __cpm_select_msc_clk(int n, int sd)
+{
+ unsigned int pllout2 = __cpm_get_pllout2();
+ unsigned int div = 0;
+
+ if (sd) {
+ div = pllout2 / 24000000;
+ }
+ else {
+ div = pllout2 / 16000000;
+ }
+
+ REG_CPM_MSCCDR(n) = div - 1;
+ REG_CPM_CPCCR |= CPM_CPCCR_CE;
+}
+
+/*
+ * Output 48MHz for high speed card.
+ */
+static inline void __cpm_select_msc_clk_high(int n, int sd)
+{
+ unsigned int pllout2 = __cpm_get_pllout2();
+ unsigned int div = 0;
+
+ div = pllout2 / 48000000;
+
+ REG_CPM_MSCCDR(n) = div - 1;
+ REG_CPM_CPCCR |= CPM_CPCCR_CE;
+}
+
+#endif /* __ASM_JZ4750D_CLOCK_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750d/dma.h b/arch/mips/include/asm/mach-jz4750d/dma.h
new file mode 100644
index 00000000000..3cca844499d
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750d/dma.h
@@ -0,0 +1,307 @@
+/*
+ * linux/include/asm-mips/mach-jz4750d/dma.h
+ *
+ * JZ4750D DMA definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750D_DMA_H__
+#define __ASM_JZ4750D_DMA_H__
+
+#include <linux/interrupt.h>
+#include <asm/io.h> /* need byte IO */
+#include <linux/spinlock.h> /* And spinlocks */
+#include <linux/delay.h>
+#include <asm/system.h>
+
+/*
+ * Descriptor structure for JZ4750D DMA engine
+ * Note: this structure must always be aligned to a 16-bytes boundary.
+ */
+
+/* old descriptor 4-word */
+typedef struct {
+ volatile u32 dcmd; /* DCMD value for the current transfer */
+ volatile u32 dsadr; /* DSAR value for the current transfer */
+ volatile u32 dtadr; /* DTAR value for the current transfer */
+ volatile u32 ddadr; /* Points to the next descriptor + transfer count */
+} jz_dma_desc;
+
+/* new descriptor 8-word */
+typedef struct {
+ volatile u32 dcmd; /* DCMD value for the current transfer */
+ volatile u32 dsadr; /* DSAR value for the current transfer */
+ volatile u32 dtadr; /* DTAR value for the current transfer */
+ volatile u32 ddadr; /* Points to the next descriptor + transfer count */
+ volatile u32 dstrd; /* DMA source and target stride address */
+ volatile u32 dreqt; /* DMA request type for current transfer */
+ volatile u32 reserved0; /* Reserved */
+ volatile u32 reserved1; /* Reserved */
+} jz_dma_desc_8word;
+
+/* DMA Device ID's follow */
+enum {
+ DMA_ID_EXT = 0, /* External request with DREQn */
+ DMA_ID_NAND, /* NAND DMA request */
+ DMA_ID_BCH_ENC, /* BCH Encoding DMA request */
+ DMA_ID_BCH_DEC, /* BCH Decoding DMA request */
+ DMA_ID_AUTO, /* Auto-request */
+// DMA_ID_TSSI_RX, /* TSSI receive fifo full request */
+ DMA_ID_UART3_TX, /* UART3 transmit-fifo-empty request */
+ DMA_ID_UART3_RX, /* UART3 receve-fifo-full request */
+ DMA_ID_UART2_TX, /* UART2 transmit-fifo-empty request */
+ DMA_ID_UART2_RX, /* UART2 receve-fifo-full request */
+ DMA_ID_UART1_TX, /* UART1 transmit-fifo-empty request */
+ DMA_ID_UART1_RX, /* UART1 receve-fifo-full request */
+ DMA_ID_UART0_TX, /* UART0 transmit-fifo-empty request */
+ DMA_ID_UART0_RX, /* UART0 receve-fifo-full request */
+ DMA_ID_SSI0_TX, /* SSI0 transmit-fifo-full request */
+ DMA_ID_SSI0_RX, /* SSI0 receive-fifo-empty request */
+ DMA_ID_AIC_TX, /* AIC transmit-fifo-full request */
+ DMA_ID_AIC_RX, /* AIC receive-fifo-empty request */
+ DMA_ID_MSC0_TX, /* MSC0 transmit-fifo-full request */
+ DMA_ID_MSC0_RX, /* MSC0 receive-fifo-empty request */
+ DMA_ID_TCU_OVERFLOW, /* TCU channel n overflow interrupt */
+ DMA_ID_SADC, /* SADC transfer request */
+ DMA_ID_MSC1_TX, /* MSC1 transmit-fifo-full request */
+ DMA_ID_MSC1_RX, /* MSC1 receive-fifo-empty request */
+ DMA_ID_SSI1_TX, /* SSI1 transmit-fifo-full request */
+ DMA_ID_SSI1_RX, /* SSI1 receive-fifo-empty request */
+ DMA_ID_PCM_TX, /* PM transmit-fifo-full request */
+ DMA_ID_PCM_RX, /* PM receive-fifo-empty request */
+ DMA_ID_RAW_SET,
+ DMA_ID_MAX
+};
+
+/* DMA modes, simulated by sw */
+#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */
+#define DMA_AUTOINIT 0x2
+#define DMA_MODE_MASK 0x3
+
+struct jz_dma_chan {
+ int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */
+ unsigned int io; /* DMA channel number */
+ const char *dev_str; /* string describes the DMA channel */
+ int irq; /* DMA irq number */
+ void *irq_dev; /* DMA private device structure */
+ unsigned int fifo_addr; /* physical fifo address of the requested device */
+ unsigned int cntl; /* DMA controll */
+ unsigned int mode; /* DMA configuration */
+ unsigned int source; /* DMA request source */
+};
+
+extern struct jz_dma_chan jz_dma_table[];
+
+
+#define DMA_8BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_8BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_32_32BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
+#define DMA_AIC_32_16BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_32_16BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BYTE_TX_CMD_UC \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+extern int jz_request_dma(int dev_id,
+ const char *dev_str,
+ irqreturn_t (*irqhandler)(int, void *),
+ unsigned long irqflags,
+ void *irq_dev_id);
+extern void jz_free_dma(unsigned int dmanr);
+
+extern int jz_dma_read_proc(char *buf, char **start, off_t fpos,
+ int length, int *eof, void *data);
+extern void dump_jz_dma_channel(unsigned int dmanr);
+
+extern void enable_dma(unsigned int dmanr);
+extern void disable_dma(unsigned int dmanr);
+extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr);
+extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt);
+extern void set_dma_mode(unsigned int dmanr, unsigned int mode);
+extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
+extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
+extern void jz_set_dma_src_width(int dmanr, int nbit);
+extern void jz_set_dma_dest_width(int dmanr, int nbit);
+extern void jz_set_dma_block_size(int dmanr, int nbyte);
+extern unsigned int get_dma_residue(unsigned int dmanr);
+
+extern spinlock_t dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dma_spin_lock, flags);
+ return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+ spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ */
+#define clear_dma_ff(channel)
+
+static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr)
+{
+ if (dmanr > MAX_DMA_NUM
+ || jz_dma_table[dmanr].dev_id < 0)
+ return NULL;
+ return &jz_dma_table[dmanr];
+}
+
+static __inline__ int dma_halted(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 1;
+ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0;
+}
+
+static __inline__ unsigned int get_dma_mode(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+ return chan->mode;
+}
+
+static __inline__ void clear_dma_done(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+}
+
+static __inline__ void clear_dma_halt(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT);
+ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT);
+}
+
+static __inline__ void clear_dma_flag(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR);
+}
+
+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
+{
+}
+
+static __inline__ unsigned int get_dma_done_status(unsigned int dmanr)
+{
+ unsigned long dccsr;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+ dccsr = REG_DMAC_DCCSR(chan->io);
+ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+}
+
+static __inline__ int get_dma_done_irq(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return -1;
+ return chan->irq;
+}
+
+#endif /* __ASM_JZ4750D_DMA_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750d/jz4750d.h b/arch/mips/include/asm/mach-jz4750d/jz4750d.h
new file mode 100644
index 00000000000..8eff7037e02
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750d/jz4750d.h
@@ -0,0 +1,45 @@
+/*
+ * linux/include/asm-mips/mach-jz4750d/jz4750d.h
+ *
+ * JZ4750 common definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750_H__
+#define __ASM_JZ4750_H__
+
+#include <asm/mach-jz4750d/regs.h>
+#include <asm/mach-jz4750d/ops.h>
+#include <asm/mach-jz4750d/dma.h>
+#include <asm/mach-jz4750d/misc.h>
+
+/*------------------------------------------------------------------
+ * Platform definitions
+ */
+#define JZ_SOC_NAME "JZ4750D"
+
+#ifdef CONFIG_JZ4750D_FUWA1
+#include <asm/mach-jz4750d/board-fuwa1.h>
+#endif
+
+#ifdef CONFIG_JZ4750D_CETUS
+#include <asm/mach-jz4750d/board-cetus.h>
+#endif
+/* Add other platform definition here ... */
+
+
+/*------------------------------------------------------------------
+ * Follows are related to platform definitions
+ */
+
+#include <asm/mach-jz4750d/clock.h>
+#include <asm/mach-jz4750d/serial.h>
+
+#endif /* __ASM_JZ4750_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750d/misc.h b/arch/mips/include/asm/mach-jz4750d/misc.h
new file mode 100644
index 00000000000..cd0b13c8f44
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750d/misc.h
@@ -0,0 +1,44 @@
+/*
+ * linux/include/asm-mips/mach-jz4750d/misc.h
+ *
+ * Ingenic's JZ4750D common include.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750D_MISC_H__
+#define __ASM_JZ4750D_MISC_H__
+
+/*==========================================================
+ * I2C
+ *===========================================================*/
+
+#define I2C_EEPROM_DEV 0xA /* b'1010 */
+#define I2C_RTC_DEV 0xD /* b'1101 */
+#define DIMM0_SPD_ADDR 0
+#define DIMM1_SPD_ADDR 1
+#define DIMM2_SPD_ADDR 2
+#define DIMM3_SPD_ADDR 3
+#define JZ_HCI_ADDR 7
+
+#define DIMM_SPD_LEN 128
+#define JZ_HCI_LEN 512 /* 4K bits E2PROM */
+#define I2C_RTC_LEN 16
+#define HCI_MAC_OFFSET 64
+
+extern void i2c_open(void);
+extern void i2c_close(void);
+extern void i2c_setclk(unsigned int i2cclk);
+
+extern int i2c_read(unsigned char device, unsigned char *buf,
+ unsigned char address, int count);
+extern int i2c_write(unsigned char device, unsigned char *buf,
+ unsigned char address, int count);
+
+#endif /* __ASM_JZ4750D_MISC_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750d/ops.h b/arch/mips/include/asm/mach-jz4750d/ops.h
new file mode 100644
index 00000000000..6950229b430
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750d/ops.h
@@ -0,0 +1,3433 @@
+
+/*
+ * linux/include/asm-mips/mach-jz4750d/ops.h
+ *
+ * JZ4750D register definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#ifndef __JZ4750D_OPS_H__
+#define __JZ4750D_OPS_H__
+
+/*
+ * Definition of Module Operations
+ */
+
+/***************************************************************************
+ * EMC
+ ***************************************************************************/
+#define is_share_mode() (1)
+
+/***************************************************************************
+ * GPIO
+ ***************************************************************************/
+
+//------------------------------------------------------
+// GPIO Pins Description
+//
+// PORT 0:
+//
+// PIN/BIT N FUNC0 FUNC1 NOTE
+// 0 D0 -
+// 1 D1 -
+// 2 D2 -
+// 3 D3 -
+// 4 D4 -
+// 5 D5 -
+// 6 D6 -
+// 7 D7 -
+// 8 D8 -
+// 9 D9 -
+// 10 D10 -
+// 11 D11 -
+// 12 D12 -
+// 13 D13 -
+// 14 D14 -
+// 15 D15 -
+// 16 D16 -
+// 17 D17 -
+// 18 D18 -
+// 19 D19 -
+// 20 D20 -
+// 21 D21 -
+// 22 D22 -
+// 23 D23 -
+// 24 D24 -
+// 25 D25 -
+// 26 D26 -
+// 27 D27 -
+// 28 D28 -
+// 29 D29 -
+// 30 D30 -
+// 31 D31 -
+//
+//------------------------------------------------------
+// PORT 1:
+//
+// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE
+// 0 A0 - -
+// 1 A1 - -
+// 2 A2 - -
+// 3 A3 - -
+// 4 A4 - -
+// 5 A5 - -
+// 6 A6 - -
+// 7 A7 - -
+// 8 A8 - -
+// 9 A9 - -
+// 10 A10 - -
+// 11 A11 - -
+// 12 A12 - -
+// 13 A13 - -
+// 14 A14 - -
+// 15 A15/CLE CL(unshare) MSC0_CLK
+// 16 DCS0# - -
+// 17 RAS# - -
+// 18 CAS# - -
+// 19 SDWE#/BUFD# - -
+// 20 WE0# - -
+// 21 WE1# - -
+// 22 WE2# - -
+// 23 WE3# - -
+// 24 CKO - - Note1
+// 25 CKE - -
+// 26 SSI_CLK MSC1_CLK -
+// 27 SSI_DT MSC1_D1 -
+// 28 SSI_DR MSC1_D0 -
+// 29 SSI_CE0# MSC1_CMD -
+// 30 SSI_GPC MSC1_D2 -
+// 31 SSI_CE1# MSC1_D3 -
+//
+// Note1: BIT24: it is CKO when chip is reset
+//
+//------------------------------------------------------
+// PORT 2:
+//
+// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE
+// 0 SD0 A20 -
+// 1 SD1 A21 -
+// 2 SD2 A22 -
+// 3 SD3 A23 -
+// 4 SD4 A24 -
+// 5 SD5 A25 -
+// 6 SD6 - -
+// 7 SD7 - -
+// 8 SD8 TSDI0 -
+// 9 SD9 TSDI1 -
+// 10 SD10 TSDI2 -
+// 11 SD11 TSDI3 -
+// 12 SD12 TSDI4 -
+// 13 SD13 TSDI5 -
+// 14 SD14 TSDI6 -
+// 15 SD15 TSDI7 -
+// 16 A16/ALE AL(unshare) MSC0_CMD
+// 17 A17 MSC0_D3 -
+// 18 A18 DREQ -
+// 19 A19 DACK -
+// 20 WAIT# - - Note2
+// 21 CS1# - -
+// 22 CS2# - -
+// 23 CS3# - -
+// 24 CS4# - -
+// 25 RD# - -
+// 26 WR# - -
+// 27 FRB# - - Note3
+// 28 FRE# MSC0_D0 -
+// 29 FWE# MSC0_D1 -
+// 30 - - - Note4
+// 31 - - - Note5
+//
+// Note2: BIT20: it is WIAT# pin when chip is reset
+//
+// Note3: BIT27: when NAND is used, it should connect to NANF FRB#.
+//
+// Note4: BIT30: it is BOOT_SEL0 which would be set as input without pulling when chip is reset.
+//
+// Note5: BIT31: it is BOOT_SEL1 which would be set as input without pulling when chip is reset.
+//
+//------------------------------------------------------
+// PORT 3:
+//
+// PIN/BIT N FUNC0 FUNC1 NOTE
+// 0 LCD_B2 -
+// 1 LCD_B3 -
+// 2 LCD_B4 -
+// 3 LCD_B5 -
+// 4 LCD_B6 -
+// 5 LCD_B7 -
+// 6 LCD_G2 -
+// 7 LCD_G3 -
+// 8 LCD_G4 -
+// 9 LCD_G5 -
+// 10 LCD_G6 -
+// 11 LCD_G7 -
+// 12 LCD_R2 -
+// 13 LCD_R3 -
+// 14 LCD_R4 -
+// 15 LCD_R5 -
+// 16 LCD_R6 -
+// 17 LCD_R7 -
+// 18 LCD_PCLK -
+// 19 LCD_HSYNC -
+// 20 LCD_VSYNC -
+// 21 LCD_DE -
+// 22 LCD_CLS LCD_R1
+// 23 LCD_SPL LCD_G0
+// 24 LCD_PS LCD_G1
+// 25 LCD_REV LCD_B1
+// 26 LCD_B0 -
+// 27 LCD_R0 -
+// 28 UART0_RXD TSCLK
+// 29 UART0_TXD TSSTR
+// 30 UART0_CTS TSFRM
+// 31 UART0_RTS TSFAIL
+//
+//------------------------------------------------------
+// PORT 4:
+//
+// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE
+// 0 CIM_D0 TSDI0 -
+// 1 CIM_D1 TSDI1 -
+// 2 CIM_D2 TSDI2 -
+// 3 CIM_D3 TSDI3 -
+// 4 CIM_D4 TSDI4 -
+// 5 CIM_D5 TSDI5 -
+// 6 CIM_D6 TSDI6 -
+// 7 CIM_D7 TSDI7 -
+// 8 CIM_MCLK TSFAIL -
+// 9 CIM_PCLK TSCLK -
+// 10 CIM_VSYNC TSSTR -
+// 11 CIM_HSYNC TSFRM -
+// 12 I2C_SDA - -
+// 13 I2C_SCK - -
+// 18 SDATO - -
+// 19 SDATI - -
+// 20 PWM0 - -
+// 22 PWM2 SYNC -
+// 23 PWM3 UART1_RxD BCLK
+// 24 PWM4 - -
+// 25 PWM5 UART1_TxD SCLK_RSTN
+// 28 DCS1# - -
+// 29 - - - Note6
+// 30 WKUP - - Note7
+// 31 - - - Note8
+//
+// Note6: BIT29: it is BOOT_SEL2 which would be set as input without pulling when chip is reset.
+// Note7: BIT30: it is only used as input and interrupt, and with no pull-up and pull-down
+// Note8: BIT31: it is used to select the function of UART or JTAG set by PESEL[31]
+// PESEL[31] = 0, select JTAG function
+// PESEL[31] = 1, select UART function
+//
+//------------------------------------------------------
+// PORT 5:
+//
+// PIN/BIT N FUNC0 FUNC1 NOTE
+// 10 SSI_CLK -
+// 11 SSI_DT PWM1
+// 12 SSI_DR -
+// 13 SSI_CE0# -
+// 14 SSI_GPC -
+// 15 SSI_CE2# -
+//
+//////////////////////////////////////////////////////////
+
+/*----------------------------------------------------------------
+ * p is the port number (0,1,2,3,4,5)
+ * o is the pin offset (0-31) inside the port
+ * n is the absolute number of a pin (0-127), regardless of the port
+ */
+
+//-------------------------------------------
+// Function Pins Mode
+
+#define __gpio_as_func0(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFUNS(p) = (1 << o); \
+ REG_GPIO_PXTRGC(p) = (1 << o); \
+ REG_GPIO_PXSELC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_func1(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFUNS(p) = (1 << o); \
+ REG_GPIO_PXTRGC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_func2(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFUNS(p) = (1 << o); \
+ REG_GPIO_PXTRGS(p) = (1 << o); \
+ REG_GPIO_PXSELC(p) = (1 << o); \
+} while (0)
+
+/*
+ * D0 ~ D31, A0 ~ A14, DCS0#, RAS#, CAS#,
+ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE#
+ */
+#define __gpio_as_sdram_32bit() \
+do { \
+ REG_GPIO_PXFUNS(0) = 0xffffffff; \
+ REG_GPIO_PXSELC(0) = 0xffffffff; \
+ REG_GPIO_PXPES(0) = 0xffffffff; \
+ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \
+ REG_GPIO_PXSELC(1) = 0x03ff7fff; \
+ REG_GPIO_PXPES(1) = 0x03ff7fff; \
+} while (0)
+
+
+/*
+ * D0 ~ D31, A0 ~ A14, DCS0#, RAS#, CAS#,
+ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE#
+ * !!!!DCS1#
+ */
+#define __gpio_as_sdram_x2_32bit() \
+do { \
+ REG_GPIO_PXFUNS(0) = 0xffffffff; \
+ REG_GPIO_PXSELC(0) = 0xffffffff; \
+ REG_GPIO_PXPES(0) = 0xffffffff; \
+ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \
+ REG_GPIO_PXSELC(1) = 0x03ff7fff; \
+ REG_GPIO_PXPES(1) = 0x03ff7fff; \
+ REG_GPIO_PXFUNS(4) = 0x10000000; \
+ REG_GPIO_PXSELC(4) = 0x10000000; \
+ REG_GPIO_PXPES(4) = 0x10000000; \
+} while (0)
+
+/*
+ * D0 ~ D15, A0 ~ A14, DCS0#, RAS#, CAS#,
+ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE#
+ */
+#define __gpio_as_sdram_16bit() \
+do { \
+ /* 32/16-bit data normal order */ \
+ REG_GPIO_PXFUNS(0) = 0x0000ffff; \
+ REG_GPIO_PXSELC(0) = 0x0000ffff; \
+ REG_GPIO_PXPES(0) = 0x0000ffff; \
+ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \
+ REG_GPIO_PXSELC(1) = 0x03ff7fff; \
+ REG_GPIO_PXPES(1) = 0x03ff7fff; \
+} while (0)
+
+/*
+ * D0 ~ D7, CS1#, CLE, ALE, FRE#, FWE#, FRB#, RDWE#/BUFD#
+ * @n: chip select number(1 ~ 4)
+ */
+#define __gpio_as_nand_8bit(n) \
+do { \
+ /* 32/16-bit data bus */ \
+ REG_GPIO_PXFUNS(0) = 0x000000ff; /* D0~D7 */ \
+ REG_GPIO_PXSELC(0) = 0x000000ff; \
+ REG_GPIO_PXPES(0) = 0x000000ff; \
+ REG_GPIO_PXFUNS(1) = 0x00008000; /* CLE(A15) */ \
+ REG_GPIO_PXSELC(1) = 0x00008000; \
+ REG_GPIO_PXPES(1) = 0x00008000; \
+ REG_GPIO_PXFUNS(2) = 0x00010000; /* ALE(A16) */ \
+ REG_GPIO_PXSELC(2) = 0x00010000; \
+ REG_GPIO_PXPES(2) = 0x00010000; \
+ \
+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \
+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \
+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \
+ \
+ REG_GPIO_PXFUNS(1) = 0x00080000; /* RDWE#/BUFD# */ \
+ REG_GPIO_PXSELC(1) = 0x00080000; \
+ REG_GPIO_PXPES(1) = 0x00080000; \
+ REG_GPIO_PXFUNS(2) = 0x30000000; /* FRE#, FWE# */ \
+ REG_GPIO_PXSELC(2) = 0x30000000; \
+ REG_GPIO_PXPES(2) = 0x30000000; \
+ REG_GPIO_PXFUNC(2) = 0x08000000; /* FRB#(input) */ \
+ REG_GPIO_PXSELC(2) = 0x08000000; \
+ REG_GPIO_PXDIRC(2) = 0x08000000; \
+ REG_GPIO_PXPES(2) = 0x08000000; \
+} while (0)
+
+
+/*
+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D7
+ * @n: chip select number(1 ~ 4)
+ */
+#define __gpio_as_nor_8bit(n) \
+do { \
+ /* 32/16-bit data bus */ \
+ REG_GPIO_PXFUNS(0) = 0x000000ff; \
+ REG_GPIO_PXSELC(0) = 0x000000ff; \
+ REG_GPIO_PXPES(0) = 0x000000ff; \
+ \
+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \
+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \
+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \
+ \
+ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \
+ REG_GPIO_PXSELC(1) = 0x0000ffff; \
+ REG_GPIO_PXPES(1) = 0x0000ffff; \
+ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \
+ REG_GPIO_PXSELC(2) = 0x06110007; \
+ REG_GPIO_PXPES(2) = 0x06110007; \
+ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \
+ REG_GPIO_PXSELS(2) = 0x000e0000; \
+ REG_GPIO_PXPES(2) = 0x000e0000; \
+} while (0)
+
+/*
+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D15
+ * @n: chip select number(1 ~ 4)
+ */
+#define __gpio_as_nor_16bit(n) \
+do { \
+ /* 32/16-bit data normal order */ \
+ REG_GPIO_PXFUNS(0) = 0x0000ffff; \
+ REG_GPIO_PXSELC(0) = 0x0000ffff; \
+ REG_GPIO_PXPES(0) = 0x0000ffff; \
+ \
+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \
+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \
+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \
+ \
+ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \
+ REG_GPIO_PXSELC(1) = 0x0000ffff; \
+ REG_GPIO_PXPES(1) = 0x0000ffff; \
+ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \
+ REG_GPIO_PXSELC(2) = 0x06110007; \
+ REG_GPIO_PXPES(2) = 0x06110007; \
+ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \
+ REG_GPIO_PXSELS(2) = 0x000e0000; \
+ REG_GPIO_PXPES(2) = 0x000e0000; \
+} while (0)
+
+/*
+ * UART0_TxD, UART0_RxD
+ */
+#define __gpio_as_uart0() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x30000000; \
+ REG_GPIO_PXSELC(3) = 0x30000000; \
+ REG_GPIO_PXPES(3) = 0x30000000; \
+} while (0)
+
+/*
+ * UART0_TxD, UART0_RxD, UART0_CTS, UART0_RTS
+ */
+#define __gpio_as_uart0_ctsrts() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0xf0000000; \
+ REG_GPIO_PXSELC(3) = 0xf0000000; \
+ REG_GPIO_PXPES(3) = 0xf0000000; \
+} while (0)
+
+/*
+ * UART1_TxD, UART1_RxD
+ */
+#define __gpio_as_uart1() \
+do { \
+ REG_GPIO_PXTRGC(4) = 0x02800000; \
+ REG_GPIO_PXFUNS(4) = 0x02800000; \
+ REG_GPIO_PXSELS(4) = 0x02800000; \
+ REG_GPIO_PXPES(4) = 0x02800000; \
+} while (0)
+
+/*
+ * TSCLK, TSSTR, TSFRM, TSFAIL, TSDI0~7
+ */
+#define __gpio_as_tssi() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x0000ff00; \
+ REG_GPIO_PXSELS(2) = 0x0000ff00; \
+ REG_GPIO_PXPES(2) = 0x0000ff00; \
+ REG_GPIO_PXFUNS(3) = 0xf0000000; \
+ REG_GPIO_PXSELS(3) = 0xf0000000; \
+ REG_GPIO_PXPES(3) = 0xf0000000; \
+} while (0)
+
+/*
+ * LCD_D0~LCD_D7, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_8bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x003c00ff; \
+ REG_GPIO_PXTRGC(3) = 0x003c00ff; \
+ REG_GPIO_PXSELC(3) = 0x003c00ff; \
+ REG_GPIO_PXPES(3) = 0x003c00ff; \
+} while (0)
+
+/*
+ * LCD_D0~LCD_D15, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_16bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x003cffff; \
+ REG_GPIO_PXTRGC(3) = 0x003cffff; \
+ REG_GPIO_PXSELC(3) = 0x003cffff; \
+ REG_GPIO_PXPES(3) = 0x003cffff; \
+} while (0)
+
+/*
+ * LCD_R2~LCD_R7, LCD_G2~LCD_G7, LCD_B2~LCD_B7,
+ * LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_18bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x003fffff; \
+ REG_GPIO_PXTRGC(3) = 0x003fffff; \
+ REG_GPIO_PXSELC(3) = 0x003fffff; \
+ REG_GPIO_PXPES(3) = 0x003fffff; \
+} while (0)
+
+/*
+ * LCD_R0~LCD_R7, LCD_G0~LCD_G7, LCD_B0~LCD_B7,
+ * LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_24bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x0fffffff; \
+ REG_GPIO_PXTRGC(3) = 0x0fffffff; \
+ REG_GPIO_PXSELC(3) = 0x0c3fffff; \
+ REG_GPIO_PXSELS(3) = 0x03c00000; \
+ REG_GPIO_PXPES(3) = 0x0fffffff; \
+} while (0)
+
+/*
+ * LCD_CLS, LCD_SPL, LCD_PS, LCD_REV
+ */
+#define __gpio_as_lcd_special() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x03C00000; \
+ REG_GPIO_PXSELC(3) = 0x03C00000; \
+ REG_GPIO_PXPES(3) = 0x03C00000; \
+} while (0)
+
+/*
+ * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC
+ */
+#define __gpio_as_cim() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00000fff; \
+ REG_GPIO_PXSELC(4) = 0x00000fff; \
+ REG_GPIO_PXPES(4) = 0x00000fff; \
+} while (0)
+
+/*
+ * SDATO, SDATI, BCLK, SYNC, SCLK_RSTN(gpio sepc) or
+ * SDATA_OUT, SDATA_IN, BIT_CLK, SYNC, SCLK_RESET(aic spec)
+ */
+#define __gpio_as_aic() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x16c00000; \
+ REG_GPIO_PXTRGC(4) = 0x02c00000; \
+ REG_GPIO_PXTRGS(4) = 0x14000000; \
+ REG_GPIO_PXSELC(4) = 0x14c00000; \
+ REG_GPIO_PXSELS(4) = 0x02000000; \
+ REG_GPIO_PXPES(4) = 0x16c00000; \
+} while (0)
+
+/*
+ * MSC0_CMD, MSC0_CLK, MSC0_D0 ~ MSC0_D3
+ */
+#define __gpio_as_msc0_4bit() \
+do { \
+ REG_GPIO_PXFUNS(1) = 0x00008000; \
+ REG_GPIO_PXTRGS(1) = 0x00008000; \
+ REG_GPIO_PXSELC(1) = 0x00008000; \
+ REG_GPIO_PXPES(1) = 0x00008000; \
+ REG_GPIO_PXFUNS(2) = 0x38030000; \
+ REG_GPIO_PXTRGS(2) = 0x00010000; \
+ REG_GPIO_PXTRGC(2) = 0x38020000; \
+ REG_GPIO_PXSELC(2) = 0x08010000; \
+ REG_GPIO_PXSELS(2) = 0x30020000; \
+ REG_GPIO_PXPES(2) = 0x38030000; \
+} while (0)
+
+
+/*
+ * MSC1_CMD, MSC1_CLK, MSC1_D0 ~ MSC1_D3
+ */
+#define __gpio_as_msc1_4bit() \
+do { \
+ REG_GPIO_PXFUNS(1) = 0xfc000000; \
+ REG_GPIO_PXTRGC(1) = 0xfc000000; \
+ REG_GPIO_PXSELS(1) = 0xfc000000; \
+ REG_GPIO_PXPES(1) = 0xfc000000; \
+} while (0)
+
+#define __gpio_as_msc __gpio_as_msc0_4bit /* default as msc0 4bit */
+#define __gpio_as_msc0 __gpio_as_msc0_4bit /* msc0 default as 4bit */
+#define __gpio_as_msc1 __gpio_as_msc1_4bit /* msc1 only support 4bit */
+
+/*
+ * SSI_CE0, SSI_CE1, SSI_GPC, SSI_CLK, SSI_DT, SSI_DR
+ */
+#define __gpio_as_ssi() \
+do { \
+ REG_GPIO_PXFUNS(1) = 0xfc000000; \
+ REG_GPIO_PXTRGC(1) = 0xfc000000; \
+ REG_GPIO_PXSELC(1) = 0xfc000000; \
+ REG_GPIO_PXPES(1) = 0xfc000000; \
+} while (0)
+
+/*
+ * SSI_CE0, SSI_CE2, SSI_GPC, SSI_CLK, SSI_DT, SSI1_DR
+ */
+#define __gpio_as_ssi_1() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x0000fc00; \
+ REG_GPIO_PXTRGC(5) = 0x0000fc00; \
+ REG_GPIO_PXSELC(5) = 0x0000fc00; \
+ REG_GPIO_PXPES(5) = 0x0000fc00; \
+} while (0)
+
+/*
+ * I2C_SCK, I2C_SDA
+ */
+#define __gpio_as_i2c() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00003000; \
+ REG_GPIO_PXSELC(4) = 0x00003000; \
+ REG_GPIO_PXPES(4) = 0x00003000; \
+} while (0)
+
+/*
+ * PWM0
+ */
+#define __gpio_as_pwm0() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00100000; \
+ REG_GPIO_PXSELC(4) = 0x00100000; \
+ REG_GPIO_PXPES(4) = 0x00100000; \
+} while (0)
+
+/*
+ * PWM1
+ */
+#define __gpio_as_pwm1() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x00000800; \
+ REG_GPIO_PXSELC(5) = 0x00000800; \
+ REG_GPIO_PXPES(5) = 0x00000800; \
+} while (0)
+
+/*
+ * PWM2
+ */
+#define __gpio_as_pwm2() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00400000; \
+ REG_GPIO_PXSELC(4) = 0x00400000; \
+ REG_GPIO_PXPES(4) = 0x00400000; \
+} while (0)
+
+/*
+ * PWM3
+ */
+#define __gpio_as_pwm3() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00800000; \
+ REG_GPIO_PXSELC(4) = 0x00800000; \
+ REG_GPIO_PXPES(4) = 0x00800000; \
+} while (0)
+
+/*
+ * PWM4
+ */
+#define __gpio_as_pwm4() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x01000000; \
+ REG_GPIO_PXSELC(4) = 0x01000000; \
+ REG_GPIO_PXPES(4) = 0x01000000; \
+} while (0)
+
+/*
+ * PWM5
+ */
+#define __gpio_as_pwm5() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x02000000; \
+ REG_GPIO_PXSELC(4) = 0x02000000; \
+ REG_GPIO_PXPES(4) = 0x02000000; \
+} while (0)
+
+/*
+ * n = 0 ~ 5
+ */
+#define __gpio_as_pwm(n) __gpio_as_pwm##n()
+
+/*
+ * DREQ
+ */
+#define __gpio_as_dreq() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x00040000; \
+ REG_GPIO_PXSELS(2) = 0x00040000; \
+ REG_GPIO_PXPES(2) = 0x00040000; \
+} while (0)
+
+/*
+ * DACK
+ */
+#define __gpio_as_dack() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x00080000; \
+ REG_GPIO_PXSELS(2) = 0x00080000; \
+ REG_GPIO_PXPES(2) = 0x00080000; \
+} while (0)
+
+/*
+ * GPIO or Interrupt Mode
+ */
+#define __gpio_get_port(p) (REG_GPIO_PXPIN(p))
+
+#define __gpio_port_as_output(p, o) \
+do { \
+ REG_GPIO_PXFUNC(p) = (1 << (o)); \
+ REG_GPIO_PXSELC(p) = (1 << (o)); \
+ REG_GPIO_PXDIRS(p) = (1 << (o)); \
+} while (0)
+
+#define __gpio_port_as_input(p, o) \
+do { \
+ REG_GPIO_PXFUNC(p) = (1 << (o)); \
+ REG_GPIO_PXSELC(p) = (1 << (o)); \
+ REG_GPIO_PXDIRC(p) = (1 << (o)); \
+} while (0)
+
+#define __gpio_as_output(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_as_output(p, o); \
+} while (0)
+
+#define __gpio_as_input(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_as_input(p, o); \
+} while (0)
+
+#define __gpio_set_pin(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXDATS(p) = (1 << o); \
+} while (0)
+
+#define __gpio_clear_pin(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXDATC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_get_pin(n) \
+({ \
+ unsigned int p, o, v; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ if (__gpio_get_port(p) & (1 << o)) \
+ v = 1; \
+ else \
+ v = 0; \
+ v; \
+})
+
+#define __gpio_as_irq_high_level(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGC(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRS(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_irq_low_level(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGC(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRC(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_irq_rise_edge(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGS(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRS(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_irq_fall_edge(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGS(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRC(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_mask_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+} while (0)
+
+#define __gpio_unmask_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_ack_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_get_irq() \
+({ \
+ unsigned int p, i, tmp, v = 0; \
+ for (p = 3; p >= 0; p--) { \
+ tmp = REG_GPIO_PXFLG(p); \
+ for (i = 0; i < 32; i++) \
+ if (tmp & (1 << i)) \
+ v = (32*p + i); \
+ } \
+ v; \
+})
+
+#define __gpio_group_irq(n) \
+({ \
+ register int tmp, i; \
+ tmp = REG_GPIO_PXFLG((n)); \
+ for (i=31;i>=0;i--) \
+ if (tmp & (1 << i)) \
+ break; \
+ i; \
+})
+
+#define __gpio_enable_pull(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXPEC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_disable_pull(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXPES(p) = (1 << o); \
+} while (0)
+
+
+/***************************************************************************
+ * CPM
+ ***************************************************************************/
+#define __cpm_get_pllm() \
+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLM_MASK) >> CPM_CPPCR_PLLM_BIT)
+#define __cpm_get_plln() \
+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLN_MASK) >> CPM_CPPCR_PLLN_BIT)
+#define __cpm_get_pllod() \
+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLOD_MASK) >> CPM_CPPCR_PLLOD_BIT)
+
+#define __cpm_get_cdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_CDIV_MASK) >> CPM_CPCCR_CDIV_BIT)
+#define __cpm_get_hdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_HDIV_MASK) >> CPM_CPCCR_HDIV_BIT)
+#define __cpm_get_pdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_PDIV_MASK) >> CPM_CPCCR_PDIV_BIT)
+#define __cpm_get_mdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT)
+#define __cpm_get_h1div() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_H1DIV_MASK) >> CPM_CPCCR_H1DIV_BIT)
+#define __cpm_get_udiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_UDIV_MASK) >> CPM_CPCCR_UDIV_BIT)
+#define __cpm_get_i2sdiv() \
+ ((REG_CPM_I2SCDR & CPM_I2SCDR_I2SDIV_MASK) >> CPM_I2SCDR_I2SDIV_BIT)
+#define __cpm_get_pixdiv() \
+ ((REG_CPM_LPCDR & CPM_LPCDR_PIXDIV_MASK) >> CPM_LPCDR_PIXDIV_BIT)
+#define __cpm_get_mscdiv(n) \
+ ((REG_CPM_MSCCDR(n) & CPM_MSCCDR_MSCDIV_MASK) >> CPM_MSCCDR_MSCDIV_BIT)
+#define __cpm_get_uhcdiv() \
+ ((REG_CPM_UHCCDR & CPM_UHCCDR_UHCDIV_MASK) >> CPM_UHCCDR_UHCDIV_BIT)
+#define __cpm_get_ssidiv() \
+ ((REG_CPM_SSICCDR & CPM_SSICDR_SSICDIV_MASK) >> CPM_SSICDR_SSIDIV_BIT)
+#define __cpm_get_pcmdiv(v) \
+ ((REG_CPM_PCMCDR & CPM_PCMCDR_PCMCD_MASK) >> CPM_PCMCDR_PCMCD_BIT)
+
+#define __cpm_set_cdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_CDIV_MASK) | ((v) << (CPM_CPCCR_CDIV_BIT)))
+#define __cpm_set_hdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_HDIV_MASK) | ((v) << (CPM_CPCCR_HDIV_BIT)))
+#define __cpm_set_pdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_PDIV_MASK) | ((v) << (CPM_CPCCR_PDIV_BIT)))
+#define __cpm_set_mdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_MDIV_MASK) | ((v) << (CPM_CPCCR_MDIV_BIT)))
+#define __cpm_set_h1div(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_H1DIV_MASK) | ((v) << (CPM_CPCCR_H1DIV_BIT)))
+#define __cpm_set_udiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_UDIV_MASK) | ((v) << (CPM_CPCCR_UDIV_BIT)))
+#define __cpm_set_i2sdiv(v) \
+ (REG_CPM_I2SCDR = (REG_CPM_I2SCDR & ~CPM_I2SCDR_I2SDIV_MASK) | ((v) << (CPM_I2SCDR_I2SDIV_BIT)))
+#define __cpm_set_pixdiv(v) \
+ (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT)))
+#define __cpm_set_mscdiv(n, v) \
+ (REG_CPM_MSCCDR(n) = (REG_CPM_MSCCDR(n) & ~CPM_MSCCDR_MSCDIV_MASK) | ((v) << (CPM_MSCCDR_MSCDIV_BIT)))
+#define __cpm_set_uhcdiv(v) \
+ (REG_CPM_UHCCDR = (REG_CPM_UHCCDR & ~CPM_UHCCDR_UHCDIV_MASK) | ((v) << (CPM_UHCCDR_UHCDIV_BIT)))
+#define __cpm_set_ssidiv(v) \
+ (REG_CPM_SSICDR = (REG_CPM_SSICDR & ~CPM_SSICDR_SSIDIV_MASK) | ((v) << (CPM_SSICDR_SSIDIV_BIT)))
+#define __cpm_set_pcmdiv(v) \
+ (REG_CPM_PCMCDR = (REG_CPM_PCMCDR & ~CPM_PCMCDR_PCMCD_MASK) | ((v) << (CPM_PCMCDR_PCMCD_BIT)))
+
+#define __cpm_select_pcmclk_pll() (REG_CPM_PCMCDR |= CPM_PCMCDR_PCMS)
+#define __cpm_select_pcmclk_exclk() (REG_CPM_PCMCDR &= ~CPM_PCMCDR_PCMS)
+#define __cpm_select_tveclk_exclk() (REG_CPM_LPCDR |= CPM_CPCCR_LSCS)
+#define __cpm_select_tveclk_pll() (REG_CPM_LPCDR &= ~CPM_LPCDR_LSCS)
+#define __cpm_select_pixclk_lcd() (REG_CPM_LPCDR &= ~CPM_LPCDR_LTCS)
+#define __cpm_select_pixclk_tve() (REG_CPM_LPCDR |= CPM_LPCDR_LTCS)
+#define __cpm_select_i2sclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_I2CS)
+#define __cpm_select_i2sclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_I2CS)
+#define __cpm_select_usbclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_UCS)
+#define __cpm_select_usbclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_UCS)
+
+#define __cpm_enable_cko()
+#define __cpm_exclk_direct() (REG_CPM_CPCCR &= ~CPM_CPCCR_ECS)
+#define __cpm_exclk_div2() (REG_CPM_CPCCR |= CPM_CPCCR_ECS)
+#define __cpm_enable_pll_change() (REG_CPM_CPCCR |= CPM_CPCCR_CE)
+#define __cpm_pllout_direct() (REG_CPM_CPCCR |= CPM_CPCCR_PCS)
+#define __cpm_pllout_div2() (REG_CPM_CPCCR &= ~CPM_CPCCR_PCS)
+#define __cpm_pll_enable() (REG_CPM_CPPCR |= CPM_CPPCR_PLLEN)
+
+#define __cpm_pll_is_off() (REG_CPM_CPPSR & CPM_CPPSR_PLLOFF)
+#define __cpm_pll_is_on() (REG_CPM_CPPSR & CPM_CPPSR_PLLON)
+#define __cpm_pll_bypass() (REG_CPM_CPPSR |= CPM_CPPSR_PLLBP)
+
+#define __cpm_get_cclk_doze_duty() \
+ ((REG_CPM_LCR & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT)
+#define __cpm_set_cclk_doze_duty(v) \
+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_DOZE_DUTY_MASK) | ((v) << (CPM_LCR_DOZE_DUTY_BIT)))
+
+#define __cpm_doze_mode() (REG_CPM_LCR |= CPM_LCR_DOZE_ON)
+#define __cpm_idle_mode() \
+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_IDLE)
+#define __cpm_sleep_mode() \
+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_SLEEP)
+
+#define __cpm_stop_all() (REG_CPM_CLKGR = 0x1fffffff)
+#define __cpm_stop_cimram() (REG_CPM_CLKGR |= CPM_CLKGR_CIMRAM)
+#define __cpm_stop_idct() (REG_CPM_CLKGR |= CPM_CLKGR_IDCT)
+#define __cpm_stop_db() (REG_CPM_CLKGR |= CPM_CLKGR_DB)
+#define __cpm_stop_me() (REG_CPM_CLKGR |= CPM_CLKGR_ME)
+#define __cpm_stop_mc() (REG_CPM_CLKGR |= CPM_CLKGR_MC)
+#define __cpm_stop_tve() (REG_CPM_CLKGR |= CPM_CLKGR_TVE)
+#define __cpm_stop_tssi() (REG_CPM_CLKGR |= CPM_CLKGR_TSSI)
+#define __cpm_stop_owi() (REG_CPM_CLKGR |= CPM_CLKGR_OWI)
+#define __cpm_stop_pcm() (REG_CPM_CLKGR |= CPM_CLKGR_PCM)
+#define __cpm_stop_uart3() (REG_CPM_CLKGR |= CPM_CLKGR_UART3)
+#define __cpm_stop_uart2() (REG_CPM_CLKGR |= CPM_CLKGR_UART2)
+#define __cpm_stop_uart1() (REG_CPM_CLKGR |= CPM_CLKGR_UART1)
+#define __cpm_stop_uhc() (REG_CPM_CLKGR |= CPM_CLKGR_UHC)
+#define __cpm_stop_ipu() (REG_CPM_CLKGR |= CPM_CLKGR_IPU)
+#define __cpm_stop_dmac() (REG_CPM_CLKGR |= CPM_CLKGR_DMAC)
+#define __cpm_stop_udc() (REG_CPM_CLKGR |= CPM_CLKGR_UDC)
+#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD)
+#define __cpm_stop_cim() (REG_CPM_CLKGR |= CPM_CLKGR_CIM)
+#define __cpm_stop_sadc() (REG_CPM_CLKGR |= CPM_CLKGR_SADC)
+#define __cpm_stop_msc(n) (REG_CPM_CLKGR |= CPM_CLKGR_MSC##n)
+#define __cpm_stop_aic1() (REG_CPM_CLKGR |= CPM_CLKGR_AIC1)
+#define __cpm_stop_aic2() (REG_CPM_CLKGR |= CPM_CLKGR_AIC2)
+#define __cpm_stop_ssi(n) (REG_CPM_CLKGR |= CPM_CLKGR_SSI##n)
+#define __cpm_stop_i2c() (REG_CPM_CLKGR |= CPM_CLKGR_I2C)
+#define __cpm_stop_rtc() (REG_CPM_CLKGR |= CPM_CLKGR_RTC)
+#define __cpm_stop_tcu() (REG_CPM_CLKGR |= CPM_CLKGR_TCU)
+#define __cpm_stop_uart0() (REG_CPM_CLKGR |= CPM_CLKGR_UART0)
+
+#define __cpm_start_all() (REG_CPM_CLKGR = 0x0)
+#define __cpm_start_cimram() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIMRAM)
+#define __cpm_start_idct() (REG_CPM_CLKGR &= ~CPM_CLKGR_IDCT)
+#define __cpm_start_db() (REG_CPM_CLKGR &= ~CPM_CLKGR_DB)
+#define __cpm_start_me() (REG_CPM_CLKGR &= ~CPM_CLKGR_ME)
+#define __cpm_start_mc() (REG_CPM_CLKGR &= ~CPM_CLKGR_MC)
+#define __cpm_start_tve() (REG_CPM_CLKGR &= ~CPM_CLKGR_TVE)
+#define __cpm_start_tssi() (REG_CPM_CLKGR &= ~CPM_CLKGR_TSSI)
+#define __cpm_start_owi() (REG_CPM_CLKGR &= ~CPM_CLKGR_OWI)
+#define __cpm_start_pcm() (REG_CPM_CLKGR &= ~CPM_CLKGR_PCM)
+#define __cpm_start_uart3() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART3)
+#define __cpm_start_uart2() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART2)
+#define __cpm_start_uart1() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART1)
+#define __cpm_start_uhc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UHC)
+#define __cpm_start_ipu() (REG_CPM_CLKGR &= ~CPM_CLKGR_IPU)
+#define __cpm_start_dmac() (REG_CPM_CLKGR &= ~CPM_CLKGR_DMAC)
+#define __cpm_start_udc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UDC)
+#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD)
+#define __cpm_start_cim() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIM)
+#define __cpm_start_sadc() (REG_CPM_CLKGR &= ~CPM_CLKGR_SADC)
+#define __cpm_start_msc(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_MSC##n)
+#define __cpm_start_aic1() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC1)
+#define __cpm_start_aic2() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC2)
+#define __cpm_start_ssi(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_SSI##n)
+#define __cpm_start_i2c() (REG_CPM_CLKGR &= ~CPM_CLKGR_I2C)
+#define __cpm_start_rtc() (REG_CPM_CLKGR &= ~CPM_CLKGR_RTC)
+#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU)
+#define __cpm_start_uart0() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART0)
+
+#define __cpm_get_o1st() \
+ ((REG_CPM_OPCR & CPM_OPCR_O1ST_MASK) >> CPM_OPCR_O1ST_BIT)
+#define __cpm_set_o1st(v) \
+ (REG_CPM_OPCR = (REG_CPM_OPCR & ~CPM_OPCR_O1ST_MASK) | ((v) << (CPM_OPCR_O1ST_BIT)))
+#define __cpm_enable_uhcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UHCPHY_DISABLE)
+#define __cpm_suspend_uhcphy() (REG_CPM_OPCR |= CPM_OPCR_UHCPHY_DISABLE)
+#define __cpm_enable_udcphy() (REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE)
+#define __cpm_suspend_udcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE)
+#define __cpm_enable_osc_in_sleep() (REG_CPM_OPCR |= CPM_OPCR_OSC_ENABLE)
+#define __cpm_disable_osc_in_sleep() (REG_CPM_OPCR &= ~CPM_OPCR_OSC_ENABLE)
+#define __cpm_select_rtcclk_rtc() (REG_CPM_OPCR |= CPM_OPCR_ERCS)
+#define __cpm_select_rtcclk_exclk() (REG_CPM_OPCR &= ~CPM_OPCR_ERCS)
+
+
+/***************************************************************************
+ * TCU
+ ***************************************************************************/
+// where 'n' is the TCU channel
+#define __tcu_select_extalclk(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_EXT_EN)
+#define __tcu_select_rtcclk(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_RTC_EN)
+#define __tcu_select_pclk(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_PCK_EN)
+#define __tcu_disable_pclk(n) \
+ REG_TCU_TCSR(n) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PCK_EN);
+#define __tcu_select_clk_div1(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1)
+#define __tcu_select_clk_div4(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE4)
+#define __tcu_select_clk_div16(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE16)
+#define __tcu_select_clk_div64(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE64)
+#define __tcu_select_clk_div256(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE256)
+#define __tcu_select_clk_div1024(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1024)
+
+#define __tcu_enable_pwm_output(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_EN)
+#define __tcu_disable_pwm_output(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_EN)
+
+#define __tcu_init_pwm_output_high(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_INITL_HIGH)
+#define __tcu_init_pwm_output_low(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_INITL_HIGH)
+
+#define __tcu_set_pwm_output_shutdown_graceful(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_SD)
+#define __tcu_set_pwm_output_shutdown_abrupt(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_SD)
+
+#define __tcu_clear_counter_to_zero(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_CNT_CLRZ)
+
+#define __tcu_ost_enabled() (REG_TCU_TER & TCU_TER_OSTEN)
+#define __tcu_enable_ost() (REG_TCU_TESR = TCU_TESR_OSTST)
+#define __tcu_disable_ost() (REG_TCU_TECR = TCU_TECR_OSTCL)
+
+#define __tcu_counter_enabled(n) (REG_TCU_TER & (1 << (n)))
+#define __tcu_start_counter(n) (REG_TCU_TESR |= (1 << (n)))
+#define __tcu_stop_counter(n) (REG_TCU_TECR |= (1 << (n)))
+
+#define __tcu_half_match_flag(n) (REG_TCU_TFR & (1 << ((n) + 16)))
+#define __tcu_full_match_flag(n) (REG_TCU_TFR & (1 << (n)))
+#define __tcu_set_half_match_flag(n) (REG_TCU_TFSR = (1 << ((n) + 16)))
+#define __tcu_set_full_match_flag(n) (REG_TCU_TFSR = (1 << (n)))
+#define __tcu_clear_half_match_flag(n) (REG_TCU_TFCR = (1 << ((n) + 16)))
+#define __tcu_clear_full_match_flag(n) (REG_TCU_TFCR = (1 << (n)))
+#define __tcu_mask_half_match_irq(n) (REG_TCU_TMSR = (1 << ((n) + 16)))
+#define __tcu_mask_full_match_irq(n) (REG_TCU_TMSR = (1 << (n)))
+#define __tcu_unmask_half_match_irq(n) (REG_TCU_TMCR = (1 << ((n) + 16)))
+#define __tcu_unmask_full_match_irq(n) (REG_TCU_TMCR = (1 << (n)))
+
+#define __tcu_ost_match_flag() (REG_TCU_TFR & TCU_TFR_OSTFLAG)
+#define __tcu_set_ost_match_flag() (REG_TCU_TFSR = TCU_TFSR_OSTFST)
+#define __tcu_clear_ost_match_flag() (REG_TCU_TFCR = TCU_TFCR_OSTFCL)
+#define __tcu_ost_match_irq_masked() (REG_TCU_TMR & TCU_TMR_OSTMASK)
+#define __tcu_mask_ost_match_irq() (REG_TCU_TMSR = TCU_TMSR_OSTMST)
+#define __tcu_unmask_ost_match_irq() (REG_TCU_TMCR = TCU_TMCR_OSTMCL)
+
+#define __tcu_wdt_clock_stopped() (REG_TCU_TSR & TCU_TSSR_WDTSC)
+#define __tcu_ost_clock_stopped() (REG_TCU_TSR & TCU_TSR_OST)
+#define __tcu_timer_clock_stopped(n) (REG_TCU_TSR & (1 << (n)))
+
+#define __tcu_start_wdt_clock() (REG_TCU_TSCR = TCU_TSSR_WDTSC)
+#define __tcu_start_ost_clock() (REG_TCU_TSCR = TCU_TSCR_OSTSC)
+#define __tcu_start_timer_clock(n) (REG_TCU_TSCR = (1 << (n)))
+
+#define __tcu_stop_wdt_clock() (REG_TCU_TSSR = TCU_TSSR_WDTSC)
+#define __tcu_stop_ost_clock() (REG_TCU_TSSR = TCU_TSSR_OSTSS)
+#define __tcu_stop_timer_clock(n) (REG_TCU_TSSR = (1 << (n)))
+
+#define __tcu_get_count(n) (REG_TCU_TCNT((n)))
+#define __tcu_set_count(n,v) (REG_TCU_TCNT((n)) = (v))
+#define __tcu_set_full_data(n,v) (REG_TCU_TDFR((n)) = (v))
+#define __tcu_set_half_data(n,v) (REG_TCU_TDHR((n)) = (v))
+
+/* TCU2, counter 1, 2*/
+#define __tcu_read_real_value(n) (REG_TCU_TSTR & (1 << ((n) + 16)))
+#define __tcu_read_false_value(n) (REG_TCU_TSTR & (1 << ((n) + 16)))
+#define __tcu_counter_busy(n) (REG_TCU_TSTR & (1 << (n)))
+#define __tcu_counter_ready(n) (REG_TCU_TSTR & (1 << (n)))
+
+#define __tcu_set_read_real_value(n) (REG_TCU_TSTSR = (1 << ((n) + 16)))
+#define __tcu_set_read_false_value(n) (REG_TCU_TSTCR = (1 << ((n) + 16)))
+#define __tcu_set_counter_busy(n) (REG_TCU_TSTSR = (1 << (n)))
+#define __tcu_set_counter_ready(n) (REG_TCU_TSTCR = (1 << (n)))
+
+/* ost counter */
+#define __ostcu_set_pwm_output_shutdown_graceful() (REG_TCU_OSTCSR &= ~TCU_TCSR_PWM_SD)
+#define __ostcu_set_ost_output_shutdown_abrupt() (REG_TCU_OSTCSR |= TCU_TCSR_PWM_SD)
+#define __ostcu_select_clk_div1() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1)
+#define __ostcu_select_clk_div4() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE4)
+#define __ostcu_select_clk_div16() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE16)
+#define __ostcu_select_clk_div64() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE64)
+#define __ostcu_select_clk_div256() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE256)
+#define __ostcu_select_clk_div1024() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1024)
+#define __ostcu_select_rtcclk() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_RTC_EN)
+#define __ostcu_select_extalclk() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_EXT_EN)
+#define __ostcu_select_pclk() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_PCK_EN)
+
+
+/***************************************************************************
+ * WDT
+ ***************************************************************************/
+#define __wdt_start() ( REG_WDT_TCER |= WDT_TCER_TCEN )
+#define __wdt_stop() ( REG_WDT_TCER &= ~WDT_TCER_TCEN )
+#define __wdt_set_count(v) ( REG_WDT_TCNT = (v) )
+#define __wdt_set_data(v) ( REG_WDT_TDR = (v) )
+
+#define __wdt_select_extalclk() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_EXT_EN)
+#define __wdt_select_rtcclk() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_RTC_EN)
+#define __wdt_select_pclk() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_PCK_EN)
+
+#define __wdt_select_clk_div1() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1)
+#define __wdt_select_clk_div4() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE4)
+#define __wdt_select_clk_div16() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE16)
+#define __wdt_select_clk_div64() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE64)
+#define __wdt_select_clk_div256() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE256)
+#define __wdt_select_clk_div1024() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1024)
+
+
+/***************************************************************************
+ * UART
+ ***************************************************************************/
+
+#define __uart_enable(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE )
+#define __uart_disable(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE )
+
+#define __uart_enable_transmit_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE )
+#define __uart_disable_transmit_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE )
+
+#define __uart_enable_receive_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE )
+#define __uart_disable_receive_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) )
+
+#define __uart_enable_loopback(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP )
+#define __uart_disable_loopback(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP )
+
+#define __uart_set_8n1(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 )
+
+#define __uart_set_baud(n, devclk, baud) \
+ do { \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \
+ } while (0)
+
+#define __uart_parity_error(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 )
+
+#define __uart_clear_errors(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) )
+
+#define __uart_transmit_fifo_empty(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 )
+
+#define __uart_transmit_end(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 )
+
+#define __uart_transmit_char(n, ch) \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch)
+
+#define __uart_receive_fifo_full(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 )
+
+#define __uart_receive_ready(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 )
+
+#define __uart_receive_char(n) \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR)
+
+#define __uart_disable_irda() \
+ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) )
+#define __uart_enable_irda() \
+ /* Tx high pulse as 0, Rx low pulse as 0 */ \
+ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS )
+
+
+/***************************************************************************
+ * DMAC
+ ***************************************************************************/
+
+/* m is the DMA controller index (0, 1), n is the DMA channel index (0 - 11) */
+
+#define __dmac_enable_module(m) \
+ ( REG_DMAC_DMACR(m) |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_012345 )
+#define __dmac_disable_module(m) \
+ ( REG_DMAC_DMACR(m) &= ~DMAC_DMACR_DMAE )
+
+/* p=0,1,2,3 */
+#define __dmac_set_priority(m,p) \
+do { \
+ REG_DMAC_DMACR(m) &= ~DMAC_DMACR_PR_MASK; \
+ REG_DMAC_DMACR(m) |= ((p) << DMAC_DMACR_PR_BIT); \
+} while (0)
+
+#define __dmac_test_halt_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_HLT )
+#define __dmac_test_addr_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_AR )
+
+#define __dmac_channel_enable_clk(n) \
+ REG_DMAC_DMACKE((n)/HALF_DMA_NUM) |= 1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM);
+
+#define __dmac_enable_descriptor(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES )
+#define __dmac_disable_descriptor(n) \
+ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES )
+
+#define __dmac_enable_channel(n) \
+do { \
+ REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN; \
+} while (0)
+#define __dmac_disable_channel(n) \
+do { \
+ REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN; \
+} while (0)
+#define __dmac_channel_enabled(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN )
+
+#define __dmac_channel_enable_irq(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE )
+#define __dmac_channel_disable_irq(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE )
+
+#define __dmac_channel_transmit_halt_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT )
+#define __dmac_channel_transmit_end_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT )
+#define __dmac_channel_address_error_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR )
+#define __dmac_channel_count_terminated_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT )
+#define __dmac_channel_descriptor_invalid_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV )
+
+#define __dmac_channel_clear_transmit_halt(n) \
+ do { \
+ /* clear both channel halt error and globle halt error */ \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT; \
+ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_HLT; \
+ } while (0)
+#define __dmac_channel_clear_transmit_end(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT )
+#define __dmac_channel_clear_address_error(n) \
+ do { \
+ REG_DMAC_DDA(n) = 0; /* clear descriptor address register */ \
+ REG_DMAC_DSAR(n) = 0; /* clear source address register */ \
+ REG_DMAC_DTAR(n) = 0; /* clear target address register */ \
+ /* clear both channel addr error and globle address error */ \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR; \
+ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_AR; \
+ } while (0)
+#define __dmac_channel_clear_count_terminated(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT )
+#define __dmac_channel_clear_descriptor_invalid(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV )
+
+#define __dmac_channel_set_transfer_unit_32bit(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_16bit(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_8bit(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_16byte(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_32byte(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \
+} while (0)
+
+/* w=8,16,32 */
+#define __dmac_channel_set_dest_port_width(n,w) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \
+} while (0)
+
+/* w=8,16,32 */
+#define __dmac_channel_set_src_port_width(n,w) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \
+} while (0)
+
+/* v=0-15 */
+#define __dmac_channel_set_rdil(n,v) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \
+ REG_DMAC_DCMD((n) |= ((v) << DMAC_DCMD_RDIL_BIT); \
+} while (0)
+
+#define __dmac_channel_dest_addr_fixed(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI )
+#define __dmac_channel_dest_addr_increment(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI )
+
+#define __dmac_channel_src_addr_fixed(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI )
+#define __dmac_channel_src_addr_increment(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI )
+
+#define __dmac_channel_set_doorbell(n) \
+ ( REG_DMAC_DMADBSR((n)/HALF_DMA_NUM) = (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) )
+
+#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) & (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) )
+#define __dmac_channel_ack_irq(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) &= ~(1 <<((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) )
+
+static __inline__ int __dmac_get_irq(void)
+{
+ int i;
+ for (i = 0; i < MAX_DMA_NUM; i++)
+ if (__dmac_channel_irq_detected(i))
+ return i;
+ return -1;
+}
+
+
+/***************************************************************************
+ * AIC (AC'97 & I2S Controller)
+ ***************************************************************************/
+
+#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB )
+#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB )
+
+#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL )
+#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL )
+
+#define __aic_play_zero() ( REG_AIC_FR &= ~AIC_FR_LSMP )
+#define __aic_play_lastsample() ( REG_AIC_FR |= AIC_FR_LSMP )
+
+#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD )
+#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) )
+#define __aic_reset_status() ( REG_AIC_FR & AIC_FR_RST )
+
+#define __aic_reset() \
+do { \
+ REG_AIC_FR |= AIC_FR_RST; \
+} while(0)
+
+
+#define __aic_set_transmit_trigger(n) \
+do { \
+ REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \
+ REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \
+} while(0)
+
+#define __aic_set_receive_trigger(n) \
+do { \
+ REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \
+ REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \
+} while(0)
+
+#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC )
+#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC )
+#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL )
+#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL )
+#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF )
+#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF )
+
+#define __aic_flush_fifo_rx() ( REG_AIC_CR |= AIC_CR_FLUSH_RX )
+#define __aic_flush_fifo_tx() ( REG_AIC_CR |= AIC_CR_FLUSH_TX )
+#define __aic_unflush_fifo_rx() ( REG_AIC_CR &= ~AIC_CR_FLUSH_RX )
+#define __aic_unflush_fifo_tx() ( REG_AIC_CR &= ~AIC_CR_FLUSH_TX )
+
+#define __aic_enable_transmit_intr() \
+ ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) )
+#define __aic_disable_transmit_intr() \
+ ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) )
+#define __aic_enable_receive_intr() \
+ ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) )
+#define __aic_disable_receive_intr() \
+ ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) )
+
+#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS )
+#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS )
+#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS )
+#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS )
+
+#define __aic_enable_mono2stereo() ( REG_AIC_CR |= AIC_CR_M2S )
+#define __aic_disable_mono2stereo() ( REG_AIC_CR &= ~AIC_CR_M2S )
+#define __aic_enable_byteswap() ( REG_AIC_CR |= AIC_CR_ENDSW )
+#define __aic_disable_byteswap() ( REG_AIC_CR &= ~AIC_CR_ENDSW )
+#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU )
+#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU )
+
+#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3
+#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4
+#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6
+#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7
+#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8
+#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9
+
+#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3
+#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4
+#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6
+#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7
+#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8
+#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9
+
+#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK )
+#define __ac97_set_xs_mono() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \
+} while(0)
+#define __ac97_set_xs_stereo() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \
+} while(0)
+
+/* In fact, only stereo is support now. */
+#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK )
+#define __ac97_set_rs_mono() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \
+} while(0)
+#define __ac97_set_rs_stereo() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \
+} while(0)
+
+#define __ac97_warm_reset_codec() \
+ do { \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SA; \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SS; \
+ udelay(2); \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \
+ } while (0)
+
+#define __ac97_cold_reset_codec() \
+ do { \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SR; \
+ udelay(2); \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \
+ } while (0)
+
+/* n=8,16,18,20 */
+#define __ac97_set_iass(n) \
+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT )
+#define __ac97_set_oass(n) \
+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT )
+
+#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL )
+#define __i2s_select_msbjustified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL )
+
+/* n=8,16,18,20,24 */
+/*#define __i2s_set_sample_size(n) \
+ ( REG_AIC_I2SCR |= (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )*/
+
+#define __i2s_set_oss_sample_size(n) \
+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT )
+#define __i2s_set_iss_sample_size(n) \
+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT )
+
+#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK )
+#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK )
+
+#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS )
+#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS )
+#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR )
+#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR )
+
+#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) )
+
+#define __aic_get_transmit_resident() \
+ ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT )
+#define __aic_get_receive_count() \
+ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT )
+
+#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT )
+#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR )
+#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO )
+#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM )
+#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY )
+#define __ac97_slot_error_detected() ( REG_AIC_ACSR & AIC_ACSR_SLTERR )
+#define __ac97_clear_slot_error() ( REG_AIC_ACSR &= ~AIC_ACSR_SLTERR )
+
+#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY )
+
+#define CODEC_READ_CMD (1 << 19)
+#define CODEC_WRITE_CMD (0 << 19)
+#define CODEC_REG_INDEX_BIT 12
+#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */
+#define CODEC_REG_DATA_BIT 4
+#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */
+
+#define __ac97_out_rcmd_addr(reg) \
+do { \
+ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \
+} while (0)
+
+#define __ac97_out_wcmd_addr(reg) \
+do { \
+ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \
+} while (0)
+
+#define __ac97_out_data(value) \
+do { \
+ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \
+} while (0)
+
+#define __ac97_in_data() \
+ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT )
+
+#define __ac97_in_status_addr() \
+ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT )
+
+#define __i2s_set_sample_rate(i2sclk, sync) \
+ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) )
+
+#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) )
+#define __aic_read_rfifo() ( REG_AIC_DR )
+
+#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC )
+#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC )
+
+//
+// Define next ops for AC97 compatible
+//
+
+#define AC97_ACSR AIC_ACSR
+
+#define __ac97_enable() __aic_enable(); __aic_select_ac97()
+#define __ac97_disable() __aic_disable()
+#define __ac97_reset() __aic_reset()
+
+#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n)
+#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n)
+
+#define __ac97_enable_record() __aic_enable_record()
+#define __ac97_disable_record() __aic_disable_record()
+#define __ac97_enable_replay() __aic_enable_replay()
+#define __ac97_disable_replay() __aic_disable_replay()
+#define __ac97_enable_loopback() __aic_enable_loopback()
+#define __ac97_disable_loopback() __aic_disable_loopback()
+
+#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma()
+#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma()
+#define __ac97_enable_receive_dma() __aic_enable_receive_dma()
+#define __ac97_disable_receive_dma() __aic_disable_receive_dma()
+
+#define __ac97_transmit_request() __aic_transmit_request()
+#define __ac97_receive_request() __aic_receive_request()
+#define __ac97_transmit_underrun() __aic_transmit_underrun()
+#define __ac97_receive_overrun() __aic_receive_overrun()
+
+#define __ac97_clear_errors() __aic_clear_errors()
+
+#define __ac97_get_transmit_resident() __aic_get_transmit_resident()
+#define __ac97_get_receive_count() __aic_get_receive_count()
+
+#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr()
+#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr()
+#define __ac97_enable_receive_intr() __aic_enable_receive_intr()
+#define __ac97_disable_receive_intr() __aic_disable_receive_intr()
+
+#define __ac97_write_tfifo(v) __aic_write_tfifo(v)
+#define __ac97_read_rfifo() __aic_read_rfifo()
+
+//
+// Define next ops for I2S compatible
+//
+
+#define I2S_ACSR AIC_I2SSR
+
+#define __i2s_enable() __aic_enable(); __aic_select_i2s()
+#define __i2s_disable() __aic_disable()
+#define __i2s_reset() __aic_reset()
+
+#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n)
+#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n)
+
+#define __i2s_enable_record() __aic_enable_record()
+#define __i2s_disable_record() __aic_disable_record()
+#define __i2s_enable_replay() __aic_enable_replay()
+#define __i2s_disable_replay() __aic_disable_replay()
+#define __i2s_enable_loopback() __aic_enable_loopback()
+#define __i2s_disable_loopback() __aic_disable_loopback()
+
+#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma()
+#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma()
+#define __i2s_enable_receive_dma() __aic_enable_receive_dma()
+#define __i2s_disable_receive_dma() __aic_disable_receive_dma()
+
+#define __i2s_transmit_request() __aic_transmit_request()
+#define __i2s_receive_request() __aic_receive_request()
+#define __i2s_transmit_underrun() __aic_transmit_underrun()
+#define __i2s_receive_overrun() __aic_receive_overrun()
+
+#define __i2s_clear_errors() __aic_clear_errors()
+
+#define __i2s_get_transmit_resident() __aic_get_transmit_resident()
+#define __i2s_get_receive_count() __aic_get_receive_count()
+
+#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr()
+#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr()
+#define __i2s_enable_receive_intr() __aic_enable_receive_intr()
+#define __i2s_disable_receive_intr() __aic_disable_receive_intr()
+
+#define __i2s_write_tfifo(v) __aic_write_tfifo(v)
+#define __i2s_read_rfifo() __aic_read_rfifo()
+
+#define __i2s_reset_codec() \
+ do { \
+ } while (0)
+
+/*************************************************************************
+ * PCM Controller operation
+ *************************************************************************/
+
+#define __pcm_enable() ( REG_PCM_CTL |= PCM_CTL_PCMEN )
+#define __pcm_disable() ( REG_PCM_CTL &= ~PCM_CTL_PCMEN )
+
+#define __pcm_clk_enable() ( REG_PCM_CTL |= PCM_CTL_CLKEN )
+#define __pcm_clk_disable() ( REG_PCM_CTL &= ~PCM_CTL_CLKEN )
+
+#define __pcm_reset() ( REG_PCM_CTL |= PCM_CTL_RST )
+#define __pcm_flush_fifo() ( REG_PCM_CTL |= PCM_CTL_FLUSH )
+
+#define __pcm_enable_record() ( REG_PCM_CTL |= PCM_CTL_EREC )
+#define __pcm_disable_record() ( REG_PCM_CTL &= ~PCM_CTL_EREC )
+#define __pcm_enable_playback() ( REG_PCM_CTL |= PCM_CTL_ERPL )
+#define __pcm_disable_playback() ( REG_PCM_CTL &= ~PCM_CTL_ERPL )
+
+#define __pcm_enable_rxfifo() __pcm_enable_record()
+#define __pcm_disable_rxfifo() __pcm_disable_record()
+#define __pcm_enable_txfifo() __pcm_enable_playback()
+#define __pcm_disable_txfifo() __pcm_disable_playback()
+
+#define __pcm_last_sample() ( REG_PCM_CTL |= PCM_CTL_LSMP )
+#define __pcm_zero_sample() ( REG_PCM_CTL &= ~PCM_CTL_LSMP )
+
+#define __pcm_enable_transmit_dma() ( REG_PCM_CTL |= PCM_CTL_ETDMA )
+#define __pcm_disable_transmit_dma() ( REG_PCM_CTL &= ~PCM_CTL_ETDMA )
+#define __pcm_enable_receive_dma() ( REG_PCM_CTL |= PCM_CTL_ERDMA )
+#define __pcm_disable_receive_dma() ( REG_PCM_CTL &= ~PCM_CTL_ERDMA )
+
+#define __pcm_as_master() ( REG_PCM_CFG &= PCM_CFG_MODE )
+#define __pcm_as_slave() ( REG_PCM_CFG |= ~PCM_CFG_MODE )
+
+#define __pcm_set_transmit_trigger(n) \
+do { \
+ REG_PCM_CFG &= ~PCM_CFG_TFTH_MASK; \
+ REG_PCM_CFG |= ((n) << PCM_CFG_TFTH_BIT); \
+} while(0)
+
+#define __pcm_set_receive_trigger(n) \
+do { \
+ REG_PCM_CFG &= ~PCM_CFG_RFTH_MASK; \
+ REG_PCM_CFG |= ((n) << PCM_CFG_RFTH_BIT); \
+} while(0)
+
+#define __pcm_omsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_OMSBPOS )
+#define __pcm_omsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_OMSBPOS )
+
+#define __pcm_imsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_IMSBPOS )
+#define __pcm_imsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_IMSBPOS )
+
+/* set input sample size 8 or 16*/
+#define __pcm_set_iss(n) \
+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_ISS_MASK) | PCM_CFG_ISS_##n )
+/* set output sample size 8 or 16*/
+#define __pcm_set_oss(n) \
+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_OSS_MASK) | PCM_CFG_OSS_##n )
+
+#define __pcm_set_valid_slot(n) \
+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_SLOT_MASK) | PCM_CFG_SLOT_##n )
+
+#define __pcm_write_data(v) ( REG_PCM_DP = (v) )
+#define __pcm_read_data() ( REG_PCM_DP )
+
+#define __pcm_enable_tfs_intr() ( REG_PCM_INTC |= PCM_INTC_ETFS )
+#define __pcm_disable_tfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETFS )
+
+#define __pcm_enable_tur_intr() ( REG_PCM_INTC |= PCM_INTC_ETUR )
+#define __pcm_disable_tur_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETUR )
+
+#define __pcm_enable_rfs_intr() ( REG_PCM_INTC |= PCM_INTC_ERFS )
+#define __pcm_disable_rfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ERFS )
+
+#define __pcm_enable_ror_intr() ( REG_PCM_INTC |= PCM_INTC_EROR )
+#define __pcm_disable_ror_intr() ( REG_PCM_INTC &= ~PCM_INTC_EROR )
+
+#define __pcm_ints_valid_tx() \
+( ((REG_PCM_INTS & PCM_INTS_TFL_MASK) >> PCM_INTS_TFL_BIT) )
+#define __pcm_ints_valid_rx() \
+( ((REG_PCM_INTS & PCM_INTS_RFL_MASK) >> PCM_INTS_RFL_BIT) )
+
+#define __pcm_set_clk_div(n) \
+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_CLKDIV_MASK) | ((n) << PCM_DIV_CLKDIV_BIT) )
+
+/* sysclk(cpm_pcm_sysclk) Hz is created by cpm logic, and pcmclk Hz is the pcm in/out clock wanted */
+#define __pcm_set_clk_rate(sysclk, pcmclk) \
+__pcm_set_clk_div(((sysclk) / (pcmclk) - 1))
+
+#define __pcm_set_sync_div(n) \
+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNDIV_MASK) | ((n) << PCM_DIV_SYNDIV_BIT) )
+
+/* pcmclk is source clock Hz, and sync is the frame sync clock Hz wanted */
+#define __pcm_set_sync_rate(pcmclk, sync) \
+__pcm_set_sync_div(((pcmclk) / (8 * (sync)) - 1))
+
+ /* set sync length in pcmclk n = 0 ... 63 */
+#define __pcm_set_sync_len(n) \
+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNL_MASK) | (n << PCM_DIV_SYNL_BIT) )
+
+
+/***************************************************************************
+ * ICDC
+ ***************************************************************************/
+#define __i2s_internal_codec() __aic_internal_codec()
+#define __i2s_external_codec() __aic_external_codec()
+
+#define __icdc_clk_ready() ( REG_ICDC_CKCFG & ICDC_CKCFG_CKRDY )
+#define __icdc_sel_adc() ( REG_ICDC_CKCFG |= ICDC_CKCFG_SELAD )
+#define __icdc_sel_dac() ( REG_ICDC_CKCFG &= ~ICDC_CKCFG_SELAD )
+
+#define __icdc_set_rgwr() ( REG_ICDC_RGADW |= ICDC_RGADW_RGWR )
+#define __icdc_clear_rgwr() ( REG_ICDC_RGADW &= ~ICDC_RGADW_RGWR )
+#define __icdc_rgwr_ready() ( REG_ICDC_RGADW & ICDC_RGADW_RGWR )
+
+#define __icdc_set_addr(n) \
+do { \
+ REG_ICDC_RGADW &= ~ICDC_RGADW_RGADDR_MASK; \
+ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGADDR_BIT; \
+} while(0)
+
+#define __icdc_set_cmd(n) \
+do { \
+ REG_ICDC_RGADW &= ~ICDC_RGADW_RGDIN_MASK; \
+ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGDIN_BIT; \
+} while(0)
+
+#define __icdc_irq_pending() ( REG_ICDC_RGDATA & ICDC_RGDATA_IRQ )
+#define __icdc_get_value() ( REG_ICDC_RGDATA & ICDC_RGDATA_RGDOUT_MASK )
+
+/***************************************************************************
+ * INTC
+ ***************************************************************************/
+#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) )
+#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) )
+#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) /* A dummy ack, as the Pending Register is Read Only. Should we remove __intc_ack_irq() */
+
+
+/***************************************************************************
+ * I2C
+ ***************************************************************************/
+
+#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE )
+#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE )
+
+#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA )
+#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO )
+#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC )
+#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC )
+
+#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF )
+#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF )
+#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF )
+
+#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) )
+#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY )
+#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND )
+
+#define __i2c_set_clk(dev_clk, i2c_clk) \
+ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 )
+
+#define __i2c_read() ( REG_I2C_DR )
+#define __i2c_write(val) ( REG_I2C_DR = (val) )
+
+
+/***************************************************************************
+ * MSC
+ ***************************************************************************/
+/* n = 0, 1 (MSC0, MSC1) */
+
+#define __msc_start_op(n) \
+ ( REG_MSC_STRPCL(n) = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START )
+
+#define __msc_set_resto(n, to) ( REG_MSC_RESTO(n) = to )
+#define __msc_set_rdto(n, to) ( REG_MSC_RDTO(n) = to )
+#define __msc_set_cmd(n, cmd) ( REG_MSC_CMD(n) = cmd )
+#define __msc_set_arg(n, arg) ( REG_MSC_ARG(n) = arg )
+#define __msc_set_nob(n, nob) ( REG_MSC_NOB(n) = nob )
+#define __msc_get_nob(n) ( REG_MSC_NOB(n) )
+#define __msc_set_blklen(n, len) ( REG_MSC_BLKLEN(n) = len )
+#define __msc_set_cmdat(n, cmdat) ( REG_MSC_CMDAT(n) = cmdat )
+#define __msc_set_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_IO_ABORT )
+#define __msc_clear_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_IO_ABORT )
+
+#define __msc_set_cmdat_bus_width1(n) \
+do { \
+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \
+ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_1BIT; \
+} while(0)
+
+#define __msc_set_cmdat_bus_width4(n) \
+do { \
+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \
+ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_4BIT; \
+} while(0)
+
+#define __msc_set_cmdat_dma_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DMA_EN )
+#define __msc_set_cmdat_init(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_INIT )
+#define __msc_set_cmdat_busy(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_BUSY )
+#define __msc_set_cmdat_stream(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_STREAM_BLOCK )
+#define __msc_set_cmdat_block(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_STREAM_BLOCK )
+#define __msc_set_cmdat_read(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_WRITE_READ )
+#define __msc_set_cmdat_write(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_WRITE_READ )
+#define __msc_set_cmdat_data_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DATA_EN )
+
+/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */
+#define __msc_set_cmdat_res_format(n, r) \
+do { \
+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \
+ REG_MSC_CMDAT(n) |= (r); \
+} while(0)
+
+#define __msc_clear_cmdat(n) \
+ REG_MSC_CMDAT(n) &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \
+ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \
+ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK )
+
+#define __msc_get_imask(n) ( REG_MSC_IMASK(n) )
+#define __msc_mask_all_intrs(n) ( REG_MSC_IMASK(n) = 0xff )
+#define __msc_unmask_all_intrs(n) ( REG_MSC_IMASK(n) = 0x00 )
+#define __msc_mask_rd(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_RXFIFO_RD_REQ )
+#define __msc_unmask_rd(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_RXFIFO_RD_REQ )
+#define __msc_mask_wr(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_TXFIFO_WR_REQ )
+#define __msc_unmask_wr(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_TXFIFO_WR_REQ )
+#define __msc_mask_endcmdres(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_END_CMD_RES )
+#define __msc_unmask_endcmdres(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_END_CMD_RES )
+#define __msc_mask_datatrandone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_DATA_TRAN_DONE )
+#define __msc_unmask_datatrandone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_DATA_TRAN_DONE )
+#define __msc_mask_prgdone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_PRG_DONE )
+#define __msc_unmask_prgdone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_PRG_DONE )
+
+/* m=0,1,2,3,4,5,6,7 */
+#define __msc_set_clkrt(n, m) \
+do { \
+ REG_MSC_CLKRT(n) = m; \
+} while(0)
+
+#define __msc_get_ireg(n) ( REG_MSC_IREG(n) )
+#define __msc_ireg_rd(n) ( REG_MSC_IREG(n) & MSC_IREG_RXFIFO_RD_REQ )
+#define __msc_ireg_wr(n) ( REG_MSC_IREG(n) & MSC_IREG_TXFIFO_WR_REQ )
+#define __msc_ireg_end_cmd_res(n) ( REG_MSC_IREG(n) & MSC_IREG_END_CMD_RES )
+#define __msc_ireg_data_tran_done(n) ( REG_MSC_IREG(n) & MSC_IREG_DATA_TRAN_DONE )
+#define __msc_ireg_prg_done(n) ( REG_MSC_IREG(n) & MSC_IREG_PRG_DONE )
+#define __msc_ireg_clear_end_cmd_res(n) ( REG_MSC_IREG(n) = MSC_IREG_END_CMD_RES )
+#define __msc_ireg_clear_data_tran_done(n) ( REG_MSC_IREG(n) = MSC_IREG_DATA_TRAN_DONE )
+#define __msc_ireg_clear_prg_done(n) ( REG_MSC_IREG(n) = MSC_IREG_PRG_DONE )
+
+#define __msc_get_stat(n) ( REG_MSC_STAT(n) )
+#define __msc_stat_not_end_cmd_res(n) ( (REG_MSC_STAT(n) & MSC_STAT_END_CMD_RES) == 0)
+#define __msc_stat_crc_err(n) \
+ ( REG_MSC_STAT(n) & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) )
+#define __msc_stat_res_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_RES_ERR )
+#define __msc_stat_rd_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_READ_ERROR )
+#define __msc_stat_wr_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_WRITE_ERROR_YES )
+#define __msc_stat_resto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_RES )
+#define __msc_stat_rdto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_READ )
+
+#define __msc_rd_resfifo(n) ( REG_MSC_RES(n) )
+#define __msc_rd_rxfifo(n) ( REG_MSC_RXFIFO(n) )
+#define __msc_wr_txfifo(n, v) ( REG_MSC_TXFIFO(n) = v )
+
+#define __msc_reset(n) \
+do { \
+ REG_MSC_STRPCL(n) = MSC_STRPCL_RESET; \
+ while (REG_MSC_STAT(n) & MSC_STAT_IS_RESETTING); \
+} while (0)
+
+#define __msc_start_clk(n) \
+do { \
+ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_START; \
+} while (0)
+
+#define __msc_stop_clk(n) \
+do { \
+ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_STOP; \
+} while (0)
+
+#define MMC_CLK 19169200
+#define SD_CLK 24576000
+
+/* msc_clk should little than pclk and little than clk retrieve from card */
+#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \
+do { \
+ unsigned int rate, pclk, i; \
+ pclk = dev_clk; \
+ rate = type?SD_CLK:MMC_CLK; \
+ if (msc_clk && msc_clk < pclk) \
+ pclk = msc_clk; \
+ i = 0; \
+ while (pclk < rate) \
+ { \
+ i ++; \
+ rate >>= 1; \
+ } \
+ lv = i; \
+} while(0)
+
+/* divide rate to little than or equal to 400kHz */
+#define __msc_calc_slow_clk_divisor(type, lv) \
+do { \
+ unsigned int rate, i; \
+ rate = (type?SD_CLK:MMC_CLK)/1000/400; \
+ i = 0; \
+ while (rate > 0) \
+ { \
+ rate >>= 1; \
+ i ++; \
+ } \
+ lv = i; \
+} while(0)
+
+
+/***************************************************************************
+ * SSI (Synchronous Serial Interface)
+ ***************************************************************************/
+/* n = 0, 1 (SSI0, SSI1) */
+#define __ssi_enable(n) ( REG_SSI_CR0(n) |= SSI_CR0_SSIE )
+#define __ssi_disable(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_SSIE )
+#define __ssi_select_ce(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_FSEL )
+
+#define __ssi_normal_mode(n) ( REG_SSI_ITR(n) &= ~SSI_ITR_IVLTM_MASK )
+
+#define __ssi_select_ce2(n) \
+do { \
+ REG_SSI_CR0(n) |= SSI_CR0_FSEL; \
+ REG_SSI_CR1(n) &= ~SSI_CR1_MULTS; \
+} while (0)
+
+#define __ssi_select_gpc(n) \
+do { \
+ REG_SSI_CR0(n) &= ~SSI_CR0_FSEL; \
+ REG_SSI_CR1(n) |= SSI_CR1_MULTS; \
+} while (0)
+
+#define __ssi_underrun_auto_clear(n) \
+do { \
+ REG_SSI_CR0(n) |= SSI_CR0_EACLRUN; \
+} while (0)
+
+#define __ssi_underrun_clear_manually(n) \
+do { \
+ REG_SSI_CR0(n) &= ~SSI_CR0_EACLRUN; \
+} while (0)
+
+#define __ssi_enable_tx_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_TIE | SSI_CR0_TEIE )
+
+#define __ssi_disable_tx_intr(n) \
+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) )
+
+#define __ssi_enable_rx_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_RIE | SSI_CR0_REIE )
+
+#define __ssi_disable_rx_intr(n) \
+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RIE | SSI_CR0_REIE) )
+
+#define __ssi_enable_txfifo_half_empty_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_TIE )
+#define __ssi_disable_txfifo_half_empty_intr(n) \
+ ( REG_SSI_CR0(n) &= ~SSI_CR0_TIE )
+#define __ssi_enable_tx_error_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_TEIE )
+#define __ssi_disable_tx_error_intr(n) \
+ ( REG_SSI_CR0(n) &= ~SSI_CR0_TEIE )
+#define __ssi_enable_rxfifo_half_full_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_RIE )
+#define __ssi_disable_rxfifo_half_full_intr(n) \
+ ( REG_SSI_CR0(n) &= ~SSI_CR0_RIE )
+#define __ssi_enable_rx_error_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_REIE )
+#define __ssi_disable_rx_error_intr(n) \
+ ( REG_SSI_CR0(n) &= ~SSI_CR0_REIE )
+
+#define __ssi_enable_loopback(n) ( REG_SSI_CR0(n) |= SSI_CR0_LOOP )
+#define __ssi_disable_loopback(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_LOOP )
+
+#define __ssi_enable_receive(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_DISREV )
+#define __ssi_disable_receive(n) ( REG_SSI_CR0(n) |= SSI_CR0_DISREV )
+
+#define __ssi_finish_receive(n) \
+ ( REG_SSI_CR0(n) |= (SSI_CR0_RFINE | SSI_CR0_RFINC) )
+
+#define __ssi_disable_recvfinish(n) \
+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) )
+
+#define __ssi_flush_txfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH )
+#define __ssi_flush_rxfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_RFLUSH )
+
+#define __ssi_flush_fifo(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH )
+
+#define __ssi_finish_transmit(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_UNFIN )
+#define __ssi_wait_transmit(n) ( REG_SSI_CR1(n) |= SSI_CR1_UNFIN )
+#define __ssi_use_busy_wait_mode(n) __ssi_wait_transmit(n)
+#define __ssi_unset_busy_wait_mode(n) __ssi_finish_transmit(n)
+
+#define __ssi_spi_format(n) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \
+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SPI; \
+ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \
+ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \
+ } while (0)
+
+/* TI's SSP format, must clear SSI_CR1.UNFIN */
+#define __ssi_ssp_format(n) \
+ do { \
+ REG_SSI_CR1(n) &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \
+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SSP; \
+ } while (0)
+
+/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */
+#define __ssi_microwire_format(n) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \
+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_MW1; \
+ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \
+ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \
+ REG_SSI_CR0(n) &= ~SSI_CR0_RFINE; \
+ } while (0)
+
+/* CE# level (FRMHL), CE# in interval time (ITFRM),
+ clock phase and polarity (PHA POL),
+ interval time (SSIITR), interval characters/frame (SSIICR) */
+
+/* frmhl,endian,mcom,flen,pha,pol MASK */
+#define SSICR1_MISC_MASK \
+ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \
+ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL )
+
+#define __ssi_spi_set_misc(n,frmhl,endian,flen,mcom,pha,pol) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSICR1_MISC_MASK; \
+ REG_SSI_CR1(n) |= ((frmhl) << 30) | ((endian) << 25) | \
+ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \
+ ((pha) << 1) | (pol); \
+ } while(0)
+
+/* Transfer with MSB or LSB first */
+#define __ssi_set_msb(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_LFST )
+#define __ssi_set_lsb(n) ( REG_SSI_CR1(n) |= SSI_CR1_LFST )
+
+#define __ssi_set_frame_length(n, m) \
+ REG_SSI_CR1(n) = (REG_SSI_CR1(n) & ~SSI_CR1_FLEN_MASK) | (((m) - 2) << 4)
+
+/* m = 1 - 16 */
+#define __ssi_set_microwire_command_length(n,m) \
+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##m##BIT) )
+
+/* Set the clock phase for SPI */
+#define __ssi_set_spi_clock_phase(n, m) \
+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_PHA) | (((m)&0x1)<< 1)))
+
+/* Set the clock polarity for SPI */
+#define __ssi_set_spi_clock_polarity(n, p) \
+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_POL) | ((p)&0x1)) )
+
+/* SSI tx trigger, m = i x 8 */
+#define __ssi_set_tx_trigger(n, m) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSI_CR1_TTRG_MASK; \
+ REG_SSI_CR1(n) |= ((m)/8)<<SSI_CR1_TTRG_BIT; \
+ } while (0)
+
+/* SSI rx trigger, m = i x 8 */
+#define __ssi_set_rx_trigger(n, m) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSI_CR1_RTRG_MASK; \
+ REG_SSI_CR1(n) |= ((m)/8)<<SSI_CR1_RTRG_BIT; \
+ } while (0)
+
+#define __ssi_get_txfifo_count(n) \
+ ( (REG_SSI_SR(n) & SSI_SR_TFIFONUM_MASK) >> SSI_SR_TFIFONUM_BIT )
+
+#define __ssi_get_rxfifo_count(n) \
+ ( (REG_SSI_SR(n) & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT )
+
+#define __ssi_transfer_end(n) ( REG_SSI_SR(n) & SSI_SR_END )
+#define __ssi_is_busy(n) ( REG_SSI_SR(n) & SSI_SR_BUSY )
+
+#define __ssi_txfifo_full(n) ( REG_SSI_SR(n) & SSI_SR_TFF )
+#define __ssi_rxfifo_empty(n) ( REG_SSI_SR(n) & SSI_SR_RFE )
+#define __ssi_rxfifo_half_full(n) ( REG_SSI_SR(n) & SSI_SR_RFHF )
+#define __ssi_txfifo_half_empty(n) ( REG_SSI_SR(n) & SSI_SR_TFHE )
+#define __ssi_underrun(n) ( REG_SSI_SR(n) & SSI_SR_UNDR )
+#define __ssi_overrun(n) ( REG_SSI_SR(n) & SSI_SR_OVER )
+#define __ssi_clear_underrun(n) ( REG_SSI_SR(n) = ~SSI_SR_UNDR )
+#define __ssi_clear_overrun(n) ( REG_SSI_SR(n) = ~SSI_SR_OVER )
+#define __ssi_clear_errors(n) ( REG_SSI_SR(n) &= ~(SSI_SR_UNDR | SSI_SR_OVER) )
+
+#define __ssi_set_clk(n, dev_clk, ssi_clk) \
+ ( REG_SSI_GR(n) = (dev_clk) / (2*(ssi_clk)) - 1 )
+
+#define __ssi_receive_data(n) REG_SSI_DR(n)
+#define __ssi_transmit_data(n, v) (REG_SSI_DR(n) = (v))
+
+
+/***************************************************************************
+ * CIM
+ ***************************************************************************/
+
+#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA )
+#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA )
+
+/* n = 0, 1, 2, 3 */
+#define __cim_set_input_data_stream_order(n) \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_ORDER_MASK; \
+ REG_CIM_CFG |= ((n)<<CIM_CFG_ORDER_BIT)&CIM_CFG_ORDER_MASK; \
+ } while (0)
+
+#define __cim_input_data_format_select_RGB() \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_DF_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DF_RGB; \
+ } while (0)
+
+#define __cim_input_data_format_select_YUV444() \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_DF_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DF_YUV444; \
+ } while (0)
+
+#define __cim_input_data_format_select_YUV422() \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_DF_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DF_YUV422; \
+ } while (0)
+
+#define __cim_input_data_format_select_ITU656() \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_DF_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DF_ITU656; \
+ } while (0)
+
+#define __cim_input_data_inverse() ( REG_CIM_CFG |= CIM_CFG_INV_DAT )
+#define __cim_input_data_normal() ( REG_CIM_CFG &= ~CIM_CFG_INV_DAT )
+
+#define __cim_vsync_active_low() ( REG_CIM_CFG |= CIM_CFG_VSP )
+#define __cim_vsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_VSP )
+
+#define __cim_hsync_active_low() ( REG_CIM_CFG |= CIM_CFG_HSP )
+#define __cim_hsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_HSP )
+
+#define __cim_sample_data_at_pclk_falling_edge() \
+ ( REG_CIM_CFG |= CIM_CFG_PCP )
+#define __cim_sample_data_at_pclk_rising_edge() \
+ ( REG_CIM_CFG &= ~CIM_CFG_PCP )
+
+#define __cim_enable_dummy_zero() ( REG_CIM_CFG |= CIM_CFG_DUMMY_ZERO )
+#define __cim_disable_dummy_zero() ( REG_CIM_CFG &= ~CIM_CFG_DUMMY_ZERO )
+
+#define __cim_select_external_vsync() ( REG_CIM_CFG |= CIM_CFG_EXT_VSYNC )
+#define __cim_select_internal_vsync() ( REG_CIM_CFG &= ~CIM_CFG_EXT_VSYNC )
+
+/* n=0-7 */
+#define __cim_set_data_packing_mode(n) \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_PACK_MASK; \
+ REG_CIM_CFG |= (CIM_CFG_PACK_##n); \
+} while (0)
+
+#define __cim_enable_bypass_func() (REG_CIM_CFG |= CIM_CFG_BYPASS)
+#define __cim_disable_bypass_func() (REG_CIM_CFG &= ~CIM_CFG_BYPASS_MASK)
+
+#define __cim_enable_ccir656_progressive_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_CPM; \
+} while (0)
+
+#define __cim_enable_ccir656_interlace_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_CIM; \
+} while (0)
+
+#define __cim_enable_gated_clock_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_GCM; \
+} while (0)
+
+#define __cim_enable_nongated_clock_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_NGCM; \
+} while (0)
+
+/* sclk:system bus clock
+ * mclk: CIM master clock
+ */
+#define __cim_set_master_clk(sclk, mclk) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_MCLKDIV_MASK; \
+ REG_CIM_CTRL |= (((sclk)/(mclk) - 1) << CIM_CTRL_MCLKDIV_BIT); \
+} while (0)
+/* n=1-16 */
+#define __cim_set_frame_rate(n) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_FRC_MASK; \
+ REG_CIM_CTRL |= CIM_CTRL_FRC_##n; \
+} while (0)
+
+#define __cim_enable_size_func() \
+ ( REG_CIM_CTRL |= CIM_CTRL_SIZEEN )
+#define __cim_disable_size_func() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_SIZEEN_MASK )
+
+#define __cim_enable_vdd_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_VDDM )
+#define __cim_disable_vdd_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_VDDM )
+
+#define __cim_enable_sof_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_SOFM )
+#define __cim_disable_sof_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_SOFM )
+
+#define __cim_enable_eof_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_EOFM )
+#define __cim_disable_eof_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EOFM )
+
+#define __cim_enable_eeof_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_EEOFM )
+#define __cim_disable_eeof_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EEOFM )
+
+#define __cim_enable_stop_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_STOPM )
+#define __cim_disable_stop_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_STOPM )
+
+#define __cim_enable_trig_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_TRIGM )
+#define __cim_disable_trig_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIGM )
+
+#define __cim_enable_rxfifo_overflow_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_OFM )
+#define __cim_disable_rxfifo_overflow_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_OFM )
+
+/* n=4,8,12,16,20,24,28,32 */
+#define __cim_set_rxfifo_trigger(n) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \
+ REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \
+} while (0)
+#define __cim_enable_fast_mode() ( REG_CIM_CTRL |= CIM_CTRL_FAST_MODE )
+#define __cim_disable_fast_mode() ( REG_CIM_CTRL &= ~CIM_CTRL_FAST_MODE )
+#define __cim_use_normal_mode() __cim_disable_fast_mode()
+#define __cim_enable_dma() ( REG_CIM_CTRL |= CIM_CTRL_DMA_EN )
+#define __cim_disable_dma() ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EN )
+#define __cim_reset_rxfifo() ( REG_CIM_CTRL |= CIM_CTRL_RXF_RST )
+#define __cim_unreset_rxfifo() ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_RST )
+
+#define __cim_clear_state() ( REG_CIM_STATE = 0 )
+
+#define __cim_disable_done() ( REG_CIM_STATE & CIM_STATE_VDD )
+#define __cim_rxfifo_empty() ( REG_CIM_STATE & CIM_STATE_RXF_EMPTY )
+#define __cim_rxfifo_reach_trigger() ( REG_CIM_STATE & CIM_STATE_RXF_TRIG )
+#define __cim_rxfifo_overflow() ( REG_CIM_STATE & CIM_STATE_RXF_OF )
+#define __cim_clear_rxfifo_overflow() ( REG_CIM_STATE &= ~CIM_STATE_RXF_OF )
+#define __cim_dma_stop() ( REG_CIM_STATE & CIM_STATE_DMA_STOP )
+#define __cim_dma_eof() ( REG_CIM_STATE & CIM_STATE_DMA_EOF )
+#define __cim_dma_sof() ( REG_CIM_STATE & CIM_STATE_DMA_SOF )
+
+#define __cim_get_iid() ( REG_CIM_IID )
+#define __cim_get_fid() ( REG_CIM_FID )
+#define __cim_get_image_data() ( REG_CIM_RXFIFO )
+#define __cim_get_dma_cmd() ( REG_CIM_CMD )
+
+#define __cim_set_da(a) ( REG_CIM_DA = (a) )
+
+#define __cim_set_line(a) ( REG_CIM_SIZE = (REG_CIM_SIZE&(~CIM_SIZE_LPF_MASK))|((a)<<CIM_SIZE_LPF_BIT) )
+#define __cim_set_pixel(a) ( REG_CIM_SIZE = (REG_CIM_SIZE&(~CIM_SIZE_PPL_MASK))|((a)<<CIM_SIZE_PPL_BIT) )
+#define __cim_get_line() ((REG_CIM_SIZE&CIM_SIZE_LPF_MASK)>>CIM_SIZE_LPF_BIT)
+#define __cim_get_pixel() ((REG_CIM_SIZE&CIM_SIZE_PPL_MASK)>>CIM_SIZE_PPL_BIT)
+
+#define __cim_set_v_offset(a) ( REG_CIM_OFFSET = (REG_CIM_OFFSET&(~CIM_OFFSET_V_MASK)) | ((a)<<CIM_OFFSET_V_BIT) )
+#define __cim_set_h_offset(a) ( REG_CIM_OFFSET = (REG_CIM_OFFSET&(~CIM_OFFSET_H_MASK)) | ((a)<<CIM_OFFSET_H_BIT) )
+#define __cim_get_v_offset() ((REG_CIM_OFFSET&CIM_OFFSET_V_MASK)>>CIM_OFFSET_V_BIT)
+#define __cim_get_h_offset() ((REG_CIM_OFFSET&CIM_OFFSET_H_MASK)>>CIM_OFFSET_H_BIT)
+
+/*************************************************************************
+ * SLCD (Smart LCD Controller)
+ *************************************************************************/
+#define __slcd_set_data_18bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_18BIT )
+#define __slcd_set_data_16bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_16BIT )
+#define __slcd_set_data_8bit_x3() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x3 )
+#define __slcd_set_data_8bit_x2() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x2 )
+#define __slcd_set_data_8bit_x1() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x1 )
+#define __slcd_set_data_24bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_24BIT )
+#define __slcd_set_data_9bit_x2() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_9BIT_x2 )
+
+#define __slcd_set_cmd_16bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_16BIT )
+#define __slcd_set_cmd_8bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_8BIT )
+#define __slcd_set_cmd_18bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_18BIT )
+#define __slcd_set_cmd_24bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_24BIT )
+
+#define __slcd_set_cs_high() ( REG_SLCD_CFG |= SLCD_CFG_CS_ACTIVE_HIGH )
+#define __slcd_set_cs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_CS_ACTIVE_HIGH )
+
+#define __slcd_set_rs_high() ( REG_SLCD_CFG |= SLCD_CFG_RS_CMD_HIGH )
+#define __slcd_set_rs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_RS_CMD_HIGH )
+
+#define __slcd_set_clk_falling() ( REG_SLCD_CFG &= ~SLCD_CFG_CLK_ACTIVE_RISING )
+#define __slcd_set_clk_rising() ( REG_SLCD_CFG |= SLCD_CFG_CLK_ACTIVE_RISING )
+
+#define __slcd_set_parallel_type() ( REG_SLCD_CFG &= ~SLCD_CFG_TYPE_SERIAL )
+#define __slcd_set_serial_type() ( REG_SLCD_CFG |= SLCD_CFG_TYPE_SERIAL )
+
+/* SLCD Control Register */
+#define __slcd_enable_dma() ( REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN )
+#define __slcd_disable_dma() ( REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN )
+
+/* SLCD Status Register */
+#define __slcd_is_busy() ( REG_SLCD_STATE & SLCD_STATE_BUSY )
+
+/* SLCD Data Register */
+#define __slcd_set_cmd_rs() ( REG_SLCD_DATA |= SLCD_DATA_RS_COMMAND)
+#define __slcd_set_data_rs() ( REG_SLCD_DATA &= ~SLCD_DATA_RS_COMMAND)
+
+
+/***************************************************************************
+ * LCD
+ ***************************************************************************/
+
+/***************************************************************************
+ * LCD
+ ***************************************************************************/
+#define __lcd_as_smart_lcd() ( REG_LCD_CFG |= ( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD))
+#define __lcd_as_general_lcd() ( REG_LCD_CFG &= ~( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD))
+
+#define __lcd_enable_tvepeh() ( REG_LCD_CFG |= LCD_CFG_TVEPEH )
+#define __lcd_disable_tvepeh() ( REG_LCD_CFG &= ~LCD_CFG_TVEPEH )
+
+#define __lcd_enable_fuhold() ( REG_LCD_CFG |= LCD_CFG_FUHOLD )
+#define __lcd_disable_fuhold() ( REG_LCD_CFG &= ~LCD_CFG_FUHOLD )
+
+#define __lcd_des_8word() ( REG_LCD_CFG |= LCD_CFG_NEWDES )
+#define __lcd_des_4word() ( REG_LCD_CFG &= ~LCD_CFG_NEWDES )
+
+#define __lcd_enable_bypass_pal() ( REG_LCD_CFG |= LCD_CFG_PALBP )
+#define __lcd_disable_bypass_pal() ( REG_LCD_CFG &= ~LCD_CFG_PALBP )
+
+#define __lcd_set_lcdpnl_term() ( REG_LCD_CFG |= LCD_CFG_TVEN )
+#define __lcd_set_tv_term() ( REG_LCD_CFG &= ~LCD_CFG_TVEN )
+
+#define __lcd_enable_auto_recover() ( REG_LCD_CFG |= LCD_CFG_RECOVER )
+#define __lcd_disable_auto_recover() ( REG_LCD_CFG &= ~LCD_CFG_RECOVER )
+
+#define __lcd_enable_dither() ( REG_LCD_CFG |= LCD_CFG_DITHER )
+#define __lcd_disable_dither() ( REG_LCD_CFG &= ~LCD_CFG_DITHER )
+
+#define __lcd_disable_ps_mode() ( REG_LCD_CFG |= LCD_CFG_PSM )
+#define __lcd_enable_ps_mode() ( REG_LCD_CFG &= ~LCD_CFG_PSM )
+
+#define __lcd_disable_cls_mode() ( REG_LCD_CFG |= LCD_CFG_CLSM )
+#define __lcd_enable_cls_mode() ( REG_LCD_CFG &= ~LCD_CFG_CLSM )
+
+#define __lcd_disable_spl_mode() ( REG_LCD_CFG |= LCD_CFG_SPLM )
+#define __lcd_enable_spl_mode() ( REG_LCD_CFG &= ~LCD_CFG_SPLM )
+
+#define __lcd_disable_rev_mode() ( REG_LCD_CFG |= LCD_CFG_REVM )
+#define __lcd_enable_rev_mode() ( REG_LCD_CFG &= ~LCD_CFG_REVM )
+
+#define __lcd_disable_hsync_mode() ( REG_LCD_CFG |= LCD_CFG_HSYNM )
+#define __lcd_enable_hsync_mode() ( REG_LCD_CFG &= ~LCD_CFG_HSYNM )
+
+#define __lcd_disable_pclk_mode() ( REG_LCD_CFG |= LCD_CFG_PCLKM )
+#define __lcd_enable_pclk_mode() ( REG_LCD_CFG &= ~LCD_CFG_PCLKM )
+
+#define __lcd_normal_outdata() ( REG_LCD_CFG &= ~LCD_CFG_INVDAT )
+#define __lcd_inverse_outdata() ( REG_LCD_CFG |= LCD_CFG_INVDAT )
+
+#define __lcd_sync_input() ( REG_LCD_CFG |= LCD_CFG_SYNDIR_IN )
+#define __lcd_sync_output() ( REG_LCD_CFG &= ~LCD_CFG_SYNDIR_IN )
+
+#define __lcd_hsync_active_high() ( REG_LCD_CFG &= ~LCD_CFG_HSP )
+#define __lcd_hsync_active_low() ( REG_LCD_CFG |= LCD_CFG_HSP )
+
+#define __lcd_pclk_rising() ( REG_LCD_CFG &= ~LCD_CFG_PCP )
+#define __lcd_pclk_falling() ( REG_LCD_CFG |= LCD_CFG_PCP )
+
+#define __lcd_de_active_high() ( REG_LCD_CFG &= ~LCD_CFG_DEP )
+#define __lcd_de_active_low() ( REG_LCD_CFG |= LCD_CFG_DEP )
+
+#define __lcd_vsync_rising() ( REG_LCD_CFG &= ~LCD_CFG_VSP )
+#define __lcd_vsync_falling() ( REG_LCD_CFG |= LCD_CFG_VSP )
+
+#define __lcd_set_16_tftpnl() \
+ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_16BIT )
+
+#define __lcd_set_18_tftpnl() \
+ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_18BIT )
+
+#define __lcd_set_24_tftpnl() ( REG_LCD_CFG |= LCD_CFG_MODE_TFT_24BIT )
+
+/*
+ * n=1,2,4,8 for single mono-STN
+ * n=4,8 for dual mono-STN
+ */
+#define __lcd_set_panel_datawidth(n) \
+do { \
+ REG_LCD_CFG &= ~LCD_CFG_PDW_MASK; \
+ REG_LCD_CFG |= LCD_CFG_PDW_n##; \
+} while (0)
+
+/* m = LCD_CFG_MODE_GENERUIC_TFT_xxx */
+#define __lcd_set_panel_mode(m) \
+do { \
+ REG_LCD_CFG &= ~LCD_CFG_MODE_MASK; \
+ REG_LCD_CFG |= (m); \
+} while(0)
+
+/* n=4,8,16 */
+#define __lcd_set_burst_length(n) \
+do { \
+ REG_LCD_CTRL &= ~LCD_CTRL_BST_MASK; \
+ REG_LCD_CTRL |= LCD_CTRL_BST_n##; \
+} while (0)
+
+#define __lcd_select_rgb565() ( REG_LCD_CTRL &= ~LCD_CTRL_RGB555 )
+#define __lcd_select_rgb555() ( REG_LCD_CTRL |= LCD_CTRL_RGB555 )
+
+#define __lcd_set_ofup() ( REG_LCD_CTRL |= LCD_CTRL_OFUP )
+#define __lcd_clr_ofup() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUP )
+
+/* n=2,4,16 */
+#define __lcd_set_stn_frc(n) \
+do { \
+ REG_LCD_CTRL &= ~LCD_CTRL_FRC_MASK; \
+ REG_LCD_CTRL |= LCD_CTRL_FRC_n##; \
+} while (0)
+
+#define __lcd_enable_eof_intr() ( REG_LCD_CTRL |= LCD_CTRL_EOFM )
+#define __lcd_disable_eof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_EOFM )
+
+#define __lcd_enable_sof_intr() ( REG_LCD_CTRL |= LCD_CTRL_SOFM )
+#define __lcd_disable_sof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_SOFM )
+
+#define __lcd_enable_ofu_intr() ( REG_LCD_CTRL |= LCD_CTRL_OFUM )
+#define __lcd_disable_ofu_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUM )
+
+#define __lcd_enable_ifu0_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM0 )
+#define __lcd_disable_ifu0_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM0 )
+
+#define __lcd_enable_ifu1_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM1 )
+#define __lcd_disable_ifu1_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM1 )
+
+#define __lcd_enable_ldd_intr() ( REG_LCD_CTRL |= LCD_CTRL_LDDM )
+#define __lcd_disable_ldd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_LDDM )
+
+#define __lcd_enable_qd_intr() ( REG_LCD_CTRL |= LCD_CTRL_QDM )
+#define __lcd_disable_qd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_QDM )
+
+#define __lcd_reverse_byte_endian() ( REG_LCD_CTRL |= LCD_CTRL_BEDN )
+#define __lcd_normal_byte_endian() ( REG_LCD_CTRL &= ~LCD_CTRL_BEDN )
+
+#define __lcd_pixel_endian_little() ( REG_LCD_CTRL |= LCD_CTRL_PEDN )
+#define __lcd_pixel_endian_big() ( REG_LCD_CTRL &= ~LCD_CTRL_PEDN )
+
+#define __lcd_set_dis() ( REG_LCD_CTRL |= LCD_CTRL_DIS )
+#define __lcd_clr_dis() ( REG_LCD_CTRL &= ~LCD_CTRL_DIS )
+
+#define __lcd_set_ena() ( REG_LCD_CTRL |= LCD_CTRL_ENA )
+#define __lcd_clr_ena() ( REG_LCD_CTRL &= ~LCD_CTRL_ENA )
+
+/* n=1,2,4,8,16 */
+#define __lcd_set_bpp(n) \
+ ( REG_LCD_CTRL = (REG_LCD_CTRL & ~LCD_CTRL_BPP_MASK) | LCD_CTRL_BPP_##n )
+
+/* LCD status register indication */
+
+#define __lcd_quick_disable_done() ( REG_LCD_STATE & LCD_STATE_QD )
+#define __lcd_disable_done() ( REG_LCD_STATE & LCD_STATE_LDD )
+#define __lcd_infifo0_underrun() ( REG_LCD_STATE & LCD_STATE_IFU0 )
+#define __lcd_infifo1_underrun() ( REG_LCD_STATE & LCD_STATE_IFU1 )
+#define __lcd_outfifo_underrun() ( REG_LCD_STATE & LCD_STATE_OFU )
+#define __lcd_start_of_frame() ( REG_LCD_STATE & LCD_STATE_SOF )
+#define __lcd_end_of_frame() ( REG_LCD_STATE & LCD_STATE_EOF )
+
+#define __lcd_clr_outfifounderrun() ( REG_LCD_STATE &= ~LCD_STATE_OFU )
+#define __lcd_clr_sof() ( REG_LCD_STATE &= ~LCD_STATE_SOF )
+#define __lcd_clr_eof() ( REG_LCD_STATE &= ~LCD_STATE_EOF )
+
+/* OSD functions */
+#define __lcd_enable_osd() (REG_LCD_OSDC |= LCD_OSDC_OSDEN)
+#define __lcd_enable_f0() (REG_LCD_OSDC |= LCD_OSDC_F0EN)
+#define __lcd_enable_f1() (REG_LCD_OSDC |= LCD_OSDC_F1EN)
+#define __lcd_enable_alpha() (REG_LCD_OSDC |= LCD_OSDC_ALPHAEN)
+#define __lcd_enable_alphamd() (REG_LCD_OSDC |= LCD_OSDC_ALPHAMD)
+
+#define __lcd_disable_osd() (REG_LCD_OSDC &= ~LCD_OSDC_OSDEN)
+#define __lcd_disable_f0() (REG_LCD_OSDC &= ~LCD_OSDC_F0EN)
+#define __lcd_disable_f1() (REG_LCD_OSDC &= ~LCD_OSDC_F1EN)
+#define __lcd_disable_alpha() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAEN)
+#define __lcd_disable_alphamd() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAMD)
+
+/* OSD Controll Register */
+#define __lcd_fg1_use_ipu() (REG_LCD_OSDCTRL |= LCD_OSDCTRL_IPU)
+#define __lcd_fg1_use_dma_chan1() (REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_IPU)
+#define __lcd_fg1_unuse_ipu() __lcd_fg1_use_dma_chan1()
+#define __lcd_osd_rgb555_mode() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_RGB555 )
+#define __lcd_osd_rgb565_mode() ( REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_RGB555 )
+#define __lcd_osd_change_size() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES )
+#define __lcd_osd_bpp_15_16() \
+ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_15_16 )
+#define __lcd_osd_bpp_18_24() \
+ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_18_24 )
+
+/* OSD State Register */
+#define __lcd_start_of_fg1() ( REG_LCD_STATE & LCD_OSDS_SOF1 )
+#define __lcd_end_of_fg1() ( REG_LCD_STATE & LCD_OSDS_EOF1 )
+#define __lcd_start_of_fg0() ( REG_LCD_STATE & LCD_OSDS_SOF0 )
+#define __lcd_end_of_fg0() ( REG_LCD_STATE & LCD_OSDS_EOF0 )
+#define __lcd_change_is_rdy() ( REG_LCD_STATE & LCD_OSDS_READY )
+
+/* Foreground Color Key Register 0,1(foreground 0, foreground 1) */
+#define __lcd_enable_colorkey0() (REG_LCD_KEY0 |= LCD_KEY_KEYEN)
+#define __lcd_enable_colorkey1() (REG_LCD_KEY1 |= LCD_KEY_KEYEN)
+#define __lcd_enable_colorkey0_md() (REG_LCD_KEY0 |= LCD_KEY_KEYMD)
+#define __lcd_enable_colorkey1_md() (REG_LCD_KEY1 |= LCD_KEY_KEYMD)
+#define __lcd_set_colorkey0(key) (REG_LCD_KEY0 = (REG_LCD_KEY0&~0xFFFFFF)|(key))
+#define __lcd_set_colorkey1(key) (REG_LCD_KEY1 = (REG_LCD_KEY1&~0xFFFFFF)|(key))
+
+#define __lcd_disable_colorkey0() (REG_LCD_KEY0 &= ~LCD_KEY_KEYEN)
+#define __lcd_disable_colorkey1() (REG_LCD_KEY1 &= ~LCD_KEY_KEYEN)
+#define __lcd_disable_colorkey0_md() (REG_LCD_KEY0 &= ~LCD_KEY_KEYMD)
+#define __lcd_disable_colorkey1_md() (REG_LCD_KEY1 &= ~LCD_KEY_KEYMD)
+
+/* IPU Restart Register */
+#define __lcd_enable_ipu_restart() (REG_LCD_IPUR |= LCD_IPUR_IPUREN)
+#define __lcd_disable_ipu_restart() (REG_LCD_IPUR &= ~LCD_IPUR_IPUREN)
+#define __lcd_set_ipu_restart_triger(n) (REG_LCD_IPUR = (REG_LCD_IPUR&(~0xFFFFFF))|(n))
+
+/* RGB Control Register */
+#define __lcd_enable_rgb_dummy() (REG_LCD_RGBC |= LCD_RGBC_RGBDM)
+#define __lcd_disable_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_RGBDM)
+
+#define __lcd_dummy_rgb() (REG_LCD_RGBC |= LCD_RGBC_DMM)
+#define __lcd_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_DMM)
+
+#define __lcd_rgb2ycc() (REG_LCD_RGBC |= LCD_RGBC_YCC)
+#define __lcd_notrgb2ycc() (REG_LCD_RGBC &= ~LCD_RGBC_YCC)
+
+#define __lcd_odd_mode_rgb() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RGB )
+#define __lcd_odd_mode_rbg() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RBG )
+#define __lcd_odd_mode_grb() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GRB)
+
+#define __lcd_odd_mode_gbr() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GBR)
+#define __lcd_odd_mode_brg() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BRG)
+#define __lcd_odd_mode_bgr() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BGR)
+
+#define __lcd_even_mode_rgb() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RGB )
+#define __lcd_even_mode_rbg() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RBG )
+#define __lcd_even_mode_grb() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GRB)
+
+#define __lcd_even_mode_gbr() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GBR)
+#define __lcd_even_mode_brg() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BRG)
+#define __lcd_even_mode_bgr() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BGR)
+
+/* Vertical Synchronize Register */
+#define __lcd_vsync_get_vps() \
+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPS_MASK) >> LCD_VSYNC_VPS_BIT )
+
+#define __lcd_vsync_get_vpe() \
+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT )
+#define __lcd_vsync_set_vpe(n) \
+do { \
+ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \
+ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \
+} while (0)
+
+#define __lcd_hsync_get_hps() \
+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT )
+#define __lcd_hsync_set_hps(n) \
+do { \
+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \
+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \
+} while (0)
+
+#define __lcd_hsync_get_hpe() \
+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT )
+#define __lcd_hsync_set_hpe(n) \
+do { \
+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \
+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \
+} while (0)
+
+#define __lcd_vat_get_ht() \
+ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT )
+#define __lcd_vat_set_ht(n) \
+do { \
+ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \
+ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \
+} while (0)
+
+#define __lcd_vat_get_vt() \
+ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT )
+#define __lcd_vat_set_vt(n) \
+do { \
+ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \
+ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \
+} while (0)
+
+#define __lcd_dah_get_hds() \
+ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT )
+#define __lcd_dah_set_hds(n) \
+do { \
+ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \
+ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \
+} while (0)
+
+#define __lcd_dah_get_hde() \
+ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT )
+#define __lcd_dah_set_hde(n) \
+do { \
+ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \
+ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \
+} while (0)
+
+#define __lcd_dav_get_vds() \
+ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT )
+#define __lcd_dav_set_vds(n) \
+do { \
+ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \
+ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \
+} while (0)
+
+#define __lcd_dav_get_vde() \
+ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT )
+#define __lcd_dav_set_vde(n) \
+do { \
+ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \
+ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \
+} while (0)
+
+/* DMA Command Register */
+#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT )
+#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT )
+#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT )
+#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT )
+
+#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT )
+#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT )
+#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT )
+#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT )
+
+#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL )
+#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL )
+
+#define __lcd_cmd0_get_len() \
+ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT )
+#define __lcd_cmd1_get_len() \
+ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT )
+
+/*************************************************************************
+ * TVE (TV Encoder Controller) ops
+ *************************************************************************/
+/* TV Encoder Control register ops */
+#define __tve_soft_reset() (REG_TVE_CTRL |= TVE_CTRL_SWRST)
+
+#define __tve_output_colorbar() (REG_TVE_CTRL |= TVE_CTRL_CLBAR)
+#define __tve_output_video() (REG_TVE_CTRL &= ~TVE_CTRL_CLBAR)
+
+#define __tve_input_cr_first() (REG_TVE_CTRL |= TVE_CTRL_CR1ST)
+#define __tve_input_cb_first() (REG_TVE_CTRL &= ~TVE_CTRL_CR1ST)
+
+#define __tve_set_0_as_black() (REG_TVE_CTRL |= TVE_CTRL_ZBLACK)
+#define __tve_set_16_as_black() (REG_TVE_CTRL &= ~TVE_CTRL_ZBLACK)
+
+#define __tve_ena_invert_top_bottom() (REG_TVE_CTRL |= TVE_CTRL_FINV)
+#define __tve_dis_invert_top_bottom() (REG_TVE_CTRL &= ~TVE_CTRL_FINV)
+
+#define __tve_set_pal_mode() (REG_TVE_CTRL |= TVE_CTRL_PAL)
+#define __tve_set_ntsc_mode() (REG_TVE_CTRL &= ~TVE_CTRL_PAL)
+
+#define __tve_set_pal_dura() (REG_TVE_CTRL |= TVE_CTRL_SYNCT)
+#define __tve_set_ntsc_dura() (REG_TVE_CTRL &= ~TVE_CTRL_SYNCT)
+
+/* n = 0 ~ 3 */
+#define __tve_set_c_bandwidth(n) \
+do {\
+ REG_TVE_CTRL &= ~TVE_CTRL_CBW_MASK;\
+ REG_TVE_CTRL |= (n) << TVE_CTRL_CBW_BIT; \
+}while(0)
+
+/* n = 0 ~ 3 */
+#define __tve_set_c_gain(n) \
+do {\
+ REG_TVE_CTRL &= ~TVE_CTRL_CGAIN_MASK;\
+ (REG_TVE_CTRL |= (n) << TVE_CTRL_CGAIN_BIT; \
+}while(0)
+
+/* n = 0 ~ 7 */
+#define __tve_set_yc_delay(n) \
+do { \
+ REG_TVE_CTRL &= ~TVE_CTRL_YCDLY_MASK \
+ REG_TVE_CTRL |= ((n) << TVE_CTRL_YCDLY_BIT); \
+} while(0)
+
+#define __tve_disable_all_dacs() (REG_TVE_CTRL |= TVE_CTRL_DAPD)
+#define __tve_disable_dac1() (REG_TVE_CTRL |= TVE_CTRL_DAPD1)
+#define __tve_enable_dac1() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD1)
+#define __tve_disable_dac2() (REG_TVE_CTRL |= TVE_CTRL_DAPD2)
+#define __tve_enable_dac2() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD2)
+#define __tve_disable_dac3() (REG_TVE_CTRL |= TVE_CTRL_DAPD3)
+#define __tve_enable_dac3() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD3)
+
+#define __tve_enable_svideo_fmt() (REG_TVE_CTRL |= TVE_CTRL_ECVBS)
+#define __tve_enable_cvbs_fmt() (REG_TVE_CTRL &= ~TVE_CTRL_ECVBS)
+
+/* TV Encoder Frame Configure register ops */
+/* n = 0 ~ 255 */
+#define __tve_set_first_video_line(n) \
+do {\
+ REG_TVE_FRCFG &= ~TVE_FRCFG_L1ST_MASK;\
+ REG_TVE_FRCFG |= (n) << TVE_FRCFG_L1ST_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_line_num_per_frm(n) \
+do {\
+ REG_TVE_FRCFG &= ~TVE_FRCFG_NLINE_MASK;\
+ REG_TVE_CFG |= (n) << TVE_FRCFG_NLINE_BIT;\
+} while(0)
+#define __tve_get_video_line_num()\
+ (((REG_TVE_FRCFG & TVE_FRCFG_NLINE_MASK) >> TVE_FRCFG_NLINE_BIT) - 1 - 2 * ((REG_TVE_FRCFG & TVE_FRCFG_L1ST_MASK) >> TVE_FRCFG_L1ST_BIT))
+
+/* TV Encoder Signal Level Configure register ops */
+/* n = 0 ~ 1023 */
+#define __tve_set_white_level(n) \
+do {\
+ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_WHITEL_MASK;\
+ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_WHITEL_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_black_level(n) \
+do {\
+ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_BLACKL_MASK;\
+ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_BLACKL_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_blank_level(n) \
+do {\
+ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_BLANKL_MASK;\
+ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_BLANKL_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_vbi_blank_level(n) \
+do {\
+ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_VBLANKL_MASK;\
+ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_VBLANKL_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_sync_level(n) \
+do {\
+ REG_TVE_SLCFG3 &= ~TVE_SLCFG3_SYNCL_MASK;\
+ REG_TVE_SLCFG3 |= (n) << TVE_SLCFG3_SYNCL_BIT;\
+} while(0)
+
+/* TV Encoder Signal Level Configure register ops */
+/* n = 0 ~ 31 */
+#define __tve_set_front_porch(n) \
+do {\
+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_FRONTP_MASK;\
+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_FRONTP_BIT; \
+} while(0)
+/* n = 0 ~ 127 */
+#define __tve_set_hsync_width(n) \
+do {\
+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_HSYNCW_MASK;\
+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_HSYNCW_BIT; \
+} while(0)
+/* n = 0 ~ 127 */
+#define __tve_set_back_porch(n) \
+do {\
+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_BACKP_MASK;\
+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_BACKP_BIT; \
+} while(0)
+/* n = 0 ~ 2047 */
+#define __tve_set_active_linec(n) \
+do {\
+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_ACTLIN_MASK;\
+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_ACTLIN_BIT; \
+} while(0)
+/* n = 0 ~ 31 */
+#define __tve_set_breezy_way(n) \
+do {\
+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_PREBW_MASK;\
+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_PREBW_BIT; \
+} while(0)
+
+/* n = 0 ~ 127 */
+#define __tve_set_burst_width(n) \
+do {\
+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_BURSTW_MASK;\
+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_BURSTW_BIT; \
+} while(0)
+
+/* TV Encoder Chrominance filter and Modulation register ops */
+/* n = 0 ~ (2^32-1) */
+#define __tve_set_c_sub_carrier_freq(n) REG_TVE_CFREQ = (n)
+/* n = 0 ~ 255 */
+#define __tve_set_c_sub_carrier_init_phase(n) \
+do { \
+ REG_TVE_CPHASE &= ~TVE_CPHASE_INITPH_MASK; \
+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_INITPH_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_c_sub_carrier_act_phase(n) \
+do { \
+ REG_TVE_CPHASE &= ~TVE_CPHASE_ACTPH_MASK; \
+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_ACTPH_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_c_phase_rst_period(n) \
+do { \
+ REG_TVE_CPHASE &= ~TVE_CPHASE_CCRSTP_MASK; \
+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_CCRSTP_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_cb_burst_amp(n) \
+do { \
+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBBA_MASK; \
+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBBA_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_cr_burst_amp(n) \
+do { \
+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRBA_MASK; \
+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRBA_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_cb_gain_amp(n) \
+do { \
+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBGAIN_MASK; \
+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBGAIN_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_cr_gain_amp(n) \
+do { \
+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRGAIN_MASK; \
+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRGAIN_BIT; \
+} while(0)
+
+/* TV Encoder Wide Screen Signal Control register ops */
+/* n = 0 ~ 7 */
+#define __tve_set_notch_freq(n) \
+do { \
+ REG_TVE_WSSCR &= ~TVE_WSSCR_NCHFREQ_MASK; \
+ REG_TVE_WSSCR |= (n) << TVE_WSSCR_NCHFREQ_BIT; \
+} while(0)
+/* n = 0 ~ 7 */
+#define __tve_set_notch_width() (REG_TVE_WSSCR |= TVE_WSSCR_NCHW_BIT)
+#define __tve_clear_notch_width() (REG_TVE_WSSCR &= ~TVE_WSSCR_NCHW_BIT)
+#define __tve_enable_notch() (REG_TVE_WSSCR |= TVE_WSSCR_ENCH_BIT)
+#define __tve_disable_notch() (REG_TVE_WSSCR &= ~TVE_WSSCR_ENCH_BIT)
+/* n = 0 ~ 7 */
+#define __tve_set_wss_edge(n) \
+do { \
+ REG_TVE_WSSCR &= ~TVE_WSSCR_WSSEDGE_MASK; \
+ REG_TVE_WSSCR |= (n) << TVE_WSSCR_WSSEDGE_BIT; \
+} while(0)
+#define __tve_set_wss_clkbyp() (REG_TVE_WSSCR |= TVE_WSSCR_WSSCKBP_BIT)
+#define __tve_set_wss_type() (REG_TVE_WSSCR |= TVE_WSSCR_WSSTP_BIT)
+#define __tve_enable_wssf1() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS1_BIT)
+#define __tve_enable_wssf0() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS0_BIT)
+
+/* TV Encoder Wide Screen Signal Configure register 1, 2 and 3 ops */
+/* n = 0 ~ 1023 */
+#define __tve_set_wss_level(n) \
+do { \
+ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSL_MASK; \
+ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSL_BIT; \
+} while(0)
+/* n = 0 ~ 4095 */
+#define __tve_set_wss_freq(n) \
+do { \
+ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSFREQ_MASK; \
+ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSFREQ_BIT; \
+} while(0)
+/* n = 0, 1; l = 0 ~ 255 */
+#define __tve_set_wss_line(n,v) \
+do { \
+ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \
+ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \
+} while(0)
+/* n = 0, 1; d = 0 ~ (2^20-1) */
+#define __tve_set_wss_data(n, v) \
+do { \
+ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \
+ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \
+} while(0)
+
+/***************************************************************************
+ * RTC ops
+ ***************************************************************************/
+
+#define __rtc_write_ready() ( (REG_RTC_RCR & RTC_RCR_WRDY) >> RTC_RCR_WRDY_BIT )
+#define __rtc_enabled() ( REG_RTC_RCR |= RTC_RCR_RTCE )
+#define __rtc_disabled() ( REG_RTC_RCR &= ~RTC_RCR_RTCE )
+#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE )
+#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE )
+#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE )
+#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE )
+#define __rtc_enable_1Hz_irq() ( REG_RTC_RCR |= RTC_RCR_1HZIE )
+#define __rtc_disable_1Hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_1HZIE )
+
+#define __rtc_get_1Hz_flag() ( (REG_RTC_RCR >> RTC_RCR_1HZ_BIT) & 0x1 )
+#define __rtc_clear_1Hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_1HZ )
+#define __rtc_get_alarm_flag() ( (REG_RTC_RCR >> RTC_RCR_AF_BIT) & 0x1 )
+#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF )
+
+#define __rtc_get_second() ( REG_RTC_RSR )
+#define __rtc_set_second(v) ( REG_RTC_RSR = v )
+
+#define __rtc_get_alarm_second() ( REG_RTC_RSAR )
+#define __rtc_set_alarm_second(v) ( REG_RTC_RSAR = v )
+
+#define __rtc_RGR_is_locked() ( (REG_RTC_RGR >> RTC_RGR_LOCK) )
+#define __rtc_lock_RGR() ( REG_RTC_RGR |= RTC_RGR_LOCK )
+#define __rtc_unlock_RGR() ( REG_RTC_RGR &= ~RTC_RGR_LOCK )
+#define __rtc_get_adjc_val() ( (REG_RTC_RGR & RTC_RGR_ADJC_MASK) >> RTC_RGR_ADJC_BIT )
+#define __rtc_set_adjc_val(v) \
+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_ADJC_MASK) | (v << RTC_RGR_ADJC_BIT) ))
+#define __rtc_get_nc1Hz_val() ( (REG_RTC_RGR & RTC_RGR_NC1HZ_MASK) >> RTC_RGR_NC1HZ_BIT )
+#define __rtc_set_nc1Hz_val(v) \
+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_NC1HZ_MASK) | (v << RTC_RGR_NC1HZ_BIT) ))
+
+#define __rtc_power_down() ( REG_RTC_HCR |= RTC_HCR_PD )
+
+#define __rtc_get_hwfcr_val() ( REG_RTC_HWFCR & RTC_HWFCR_MASK )
+#define __rtc_set_hwfcr_val(v) ( REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK )
+#define __rtc_get_hrcr_val() ( REG_RTC_HRCR & RTC_HRCR_MASK )
+#define __rtc_set_hrcr_val(v) ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK )
+
+#define __rtc_enable_alarm_wakeup() ( REG_RTC_HWCR |= RTC_HWCR_EALM )
+#define __rtc_disable_alarm_wakeup() ( REG_RTC_HWCR &= ~RTC_HWCR_EALM )
+
+#define __rtc_status_hib_reset_occur() ( REG_RTC_HWRSR & RTC_HWRSR_HR )
+#define __rtc_status_ppr_reset_occur() ( REG_RTC_HWRSR & RTC_HWRSR_PPR )
+#define __rtc_status_wakeup_pin_waken_up() ( REG_RTC_HWRSR & RTC_HWRSR_PIN )
+#define __rtc_status_alarm_waken_up() ( REG_RTC_HWRSR & RTC_HWRSR_ALM )
+#define __rtc_clear_hib_stat_all() ( REG_RTC_HWRSR = 0 )
+
+#define __rtc_get_scratch_pattern() (REG_RTC_HSPR)
+#define __rtc_set_scratch_pattern(n) (REG_RTC_HSPR = n )
+
+/*************************************************************************
+ * BCH
+ *************************************************************************/
+#define __ecc_encoding_4bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \
+ REG_BCH_CRC = BCH_CR_BSEL8; \
+} while(0)
+#define __ecc_decoding_4bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BCHE; \
+ REG_BCH_CRC = BCH_CR_ENCE | BCH_CR_BSEL8; \
+} while(0)
+#define __ecc_encoding_8bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \
+} while(0)
+#define __ecc_decoding_8bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \
+ REG_BCH_CRC = BCH_CR_ENCE; \
+} while(0)
+#define __ecc_dma_enable() ( REG_BCH_CRS = BCH_CR_DMAE )
+#define __ecc_dma_disable() ( REG_BCH_CRC = BCH_CR_DMAE )
+#define __ecc_disable() ( REG_BCH_CRC = BCH_CR_BCHE )
+#define __ecc_encode_sync() while (!(REG_BCH_INTS & BCH_INTS_ENCF))
+#define __ecc_decode_sync() while (!(REG_BCH_INTS & BCH_INTS_DECF))
+#define __ecc_cnt_dec(n) \
+do { \
+ REG_BCH_CNT &= ~(BCH_CNT_DEC_MASK << BCH_CNT_DEC_BIT); \
+ REG_BCH_CNT = (n) << BCH_CNT_DEC_BIT; \
+} while(0)
+#define __ecc_cnt_enc(n) \
+do { \
+ REG_BCH_CNT &= ~(BCH_CNT_ENC_MASK << BCH_CNT_ENC_BIT); \
+ REG_BCH_CNT = (n) << BCH_CNT_ENC_BIT; \
+} while(0)
+
+/***************************************************************************
+ * OWI (one-wire bus) ops
+ ***************************************************************************/
+
+/* OW control register ops */
+#define __owi_enable_all_interrupts() ( REG_OWI_CTL = (OWI_CTL_EBYTE | OWI_CTL_EBIT | OWI_CTL_ERST) )
+#define __owi_disable_all_interrupts() ( REG_OWI_CTL = 0 )
+
+#define __owi_enable_byte_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBYTE )
+#define __owi_disable_byte_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBYTE )
+#define __owi_enable_bit_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBIT )
+#define __owi_disable_bit_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBIT )
+#define __owi_enable_rst_interrupt() ( REG_OWI_CTL |= OWI_CTL_ERST )
+#define __owi_disable_rst_interrupt() ( REG_OWI_CTL &=~OWI_CTL_ERST )
+
+/* OW configure register ops */
+#define __owi_select_regular_mode() ( REG_OWI_CFG &= ~OWI_CFG_MODE )
+#define __owi_select_overdrive_mode() ( REG_OWI_CFG |= OWI_CFG_MODE )
+
+#define __owi_set_rddata() ( REG_OWI_CFG |= OWI_CFG_RDDATA )
+#define __owi_clr_rddata() ( REG_OWI_CFG &= ~OWI_CFG_RDDATA )
+#define __owi_get_rddata() ( REG_OWI_CFG & OWI_CFG_RDDATA )
+
+#define __owi_set_wrdata() ( REG_OWI_CFG |= OWI_CFG_WRDATA )
+#define __owi_clr_wrdata() ( REG_OWI_CFG &= ~OWI_CFG_WRDATA )
+#define __owi_get_wrdata() ( REG_OWI_CFG & OWI_CFG_WRDATA )
+
+#define __owi_get_rdst() ( REG_OWI_CFG & OWI_CFG_RDST )
+
+#define __owi_set_wr1rd() ( REG_OWI_CFG |= OWI_CFG_WR1RD )
+#define __owi_clr_wr1rd() ( REG_OWI_CFG &= ~OWI_CFG_WR1RD )
+#define __owi_get_wr1rd() ( REG_OWI_CFG & OWI_CFG_WR1RD )
+
+#define __owi_set_wr0() ( REG_OWI_CFG |= OWI_CFG_WR0 )
+#define __owi_clr_wr0() ( REG_OWI_CFG &= ~OWI_CFG_WR0 )
+#define __owi_get_wr0() ( REG_OWI_CFG & OWI_CFG_WR0 )
+
+#define __owi_set_rst() ( REG_OWI_CFG |= OWI_CFG_RST )
+#define __owi_clr_rst() ( REG_OWI_CFG &= ~OWI_CFG_RST )
+#define __owi_get_rst() ( REG_OWI_CFG & OWI_CFG_RST )
+
+#define __owi_enable_ow_ops() ( REG_OWI_CFG |= OWI_CFG_ENA )
+#define __owi_disable_ow_ops() ( REG_OWI_CFG &= ~OWI_CFG_ENA )
+#define __owi_get_enable() ( REG_OWI_CFG & OWI_CFG_ENA )
+
+#define __owi_wait_ops_rdy() \
+ do { \
+ while(__owi_get_enable()); \
+ udelay(1); \
+ } while(0);
+
+/* OW status register ops */
+#define __owi_clr_sts() ( REG_OWI_STS = 0 )
+#define __owi_get_sts_pst() ( REG_OWI_STS & OWI_STS_PST )
+#define __owi_get_sts_byte_rdy() ( REG_OWI_STS & OWI_STS_BYTE_RDY )
+#define __owi_get_sts_bit_rdy() ( REG_OWI_STS & OWI_STS_BIT_RDY )
+#define __owi_get_sts_pst_rdy() ( REG_OWI_STS & OWI_STS_PST_RDY )
+
+/*************************************************************************
+ * TSSI MPEG 2-TS slave interface operation
+ *************************************************************************/
+#define __tssi_enable() ( REG_TSSI_ENA |= TSSI_ENA_ENA )
+#define __tssi_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_ENA )
+#define __tssi_soft_reset() ( REG_TSSI_ENA |= TSSI_ENA_SFT_RST )
+#define __tssi_dma_enable() ( REG_TSSI_ENA |= TSSI_ENA_DMA_EN )
+#define __tssi_dma_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_DMA_EN )
+#define __tssi_filter_enable() ( REG_TSSI_ENA |= TSSI_ENA_PID_EN )
+#define __tssi_filter_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_PID_EN )
+
+/* n = 4, 8, 16 */
+#define __tssi_set_tigger_num(n) \
+ do { \
+ REG_TSSI_CFG &= ~TSSI_CFG_TRIG_MASK; \
+ REG_TSSI_CFG |= TSSI_CFG_TRIG_##n; \
+ } while (0)
+
+#define __tssi_set_wd_1() ( REG_TSSI_CFG |= TSSI_CFG_END_WD )
+#define __tssi_set_wd_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_WD )
+
+#define __tssi_set_bt_1() ( REG_TSSI_CFG |= TSSI_CFG_END_BD )
+#define __tssi_set_bt_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_BD )
+
+#define __tssi_set_data_pola_high() ( REG_TSSI_CFG |= TSSI_CFG_TSDI_H )
+#define __tssi_set_data_pola_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSDI_H )
+
+#define __tssi_set_data_use_data0() ( REG_TSSI_CFG |= TSSI_CFG_USE_0 )
+#define __tssi_set_data_use_data7() ( REG_TSSI_CFG &= ~TSSI_CFG_USE_0 )
+
+#define __tssi_select_clk_fast() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_CH )
+#define __tssi_select_clk_slow() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_CH )
+
+#define __tssi_select_serail_mode() ( REG_TSSI_CFG &= ~TSSI_CFG_PARAL )
+#define __tssi_select_paral_mode() ( REG_TSSI_CFG |= TSSI_CFG_PARAL )
+
+#define __tssi_select_clk_nega_edge() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_P )
+#define __tssi_select_clk_posi_edge() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_P )
+
+#define __tssi_select_frm_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFRM_H )
+#define __tssi_select_frm_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFRM_H )
+
+#define __tssi_select_str_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSSTR_H )
+#define __tssi_select_str_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSSTR_H )
+
+#define __tssi_select_fail_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFAIL_H )
+#define __tssi_select_fail_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFAIL_H )
+
+#define __tssi_enable_ovrn_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_OVRNM )
+#define __tssi_disable_ovrn_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_OVRNM )
+
+#define __tssi_enable_trig_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_TRIGM )
+#define __tssi_disable_trig_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_TRIGM )
+
+#define __tssi_state_is_overrun() ( REG_TSSI_STAT & TSSI_STAT_OVRN )
+#define __tssi_state_trigger_meet() ( REG_TSSI_STAT & TSSI_STAT_TRIG )
+#define __tssi_clear_state() ( REG_TSSI_STAT = 0 ) /* write 0??? */
+#define __tssi_state_clear_overrun() ( REG_TSSI_STAT = TSSI_STAT_OVRN )
+
+#define __tssi_enable_filte_pid0() ( REG_TSSI_PEN |= TSSI_PEN_PID0 )
+#define __tssi_disable_filte_pid0() ( REG_TSSI_PEN &= ~TSSI_PEN_PID0 )
+
+/* m = 0, ..., 15 */
+#define __tssi_enable_pid_filter(m) \
+ do { \
+ int n = (m); \
+ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \
+ if ( n >= TSSI_PID_MAX ) n += 8; \
+ REG_TSSI_PEN |= ( 1 << n ); \
+ } \
+ } while (0)
+
+/* m = 0, ..., 15 */
+#define __tssi_disable_pid_filter(m) \
+ do { \
+ int n = (m); \
+ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \
+ if ( n >= TSSI_PID_MAX ) n += 8; \
+ REG_TSSI_PEN &= ~( 1 << n ); \
+ } \
+ } while (0)
+
+/* n = 0, ..., 7 */
+#define __tssi_set_pid0(n, pid0) \
+ do { \
+ REG_TSSI_PID(n) &= ~TSSI_PID_PID0_MASK; \
+ REG_TSSI_PID(n) |= ((pid0)<<TSSI_PID_PID0_BIT)&TSSI_PID_PID0_MASK; \
+ }while (0)
+/* n = 0, ..., 7 */
+#define __tssi_set_pid1(n, pid1) \
+ do { \
+ REG_TSSI_PID(n) &= ~TSSI_PID_PID1_MASK; \
+ REG_TSSI_PID(n) |= ((pid1)<<TSSI_PID_PID1_BIT)&TSSI_PID_PID1_MASK; \
+ }while (0)
+
+/* n = 0, ..., 15 */
+#define __tssi_set_pid(n, pid) \
+ do { \
+ if ( n>=0 && n < TSSI_PID_MAX*2) { \
+ if ( n < TSSI_PID_MAX ) \
+ __tssi_set_pid0(n, pid); \
+ else \
+ __tssi_set_pid1(n-TSSI_PID_MAX, pid); \
+ } \
+ }while (0)
+
+
+#if 0
+/*************************************************************************
+ * IPU (Image Processing Unit)
+ *************************************************************************/
+#define u32 volatile unsigned long
+
+#define write_reg(reg, val) \
+do { \
+ *(u32 *)(reg) = (val); \
+} while(0)
+
+#define read_reg(reg, off) (*(u32 *)((reg)+(off)))
+
+
+#define set_ipu_fmt(rgb_888_out_fmt, rgb_out_oft, out_fmt, yuv_pkg_out, in_oft, in_fmt ) \
+({ write_reg( (IPU_V_BASE + REG_D_FMT), ((in_fmt) & IN_FMT_MSK)<<IN_FMT_SFT \
+| ((in_oft) & IN_OFT_MSK)<< IN_OFT_SFT \
+| ((out_fmt) & OUT_FMT_MSK)<<OUT_FMT_SFT \
+| ((yuv_pkg_out) & YUV_PKG_OUT_MSK ) << YUV_PKG_OUT_SFT \
+| ((rgb_888_out_fmt) & RGB888_FMT_MSK ) << RGB888_FMT_SFT \
+| ((rgb_out_oft) & RGB_OUT_OFT_MSK ) << RGB_OUT_OFT_SFT); \
+})
+#define set_y_addr(y_addr) \
+({ write_reg( (IPU_V_BASE + REG_Y_ADDR), y_addr); \
+})
+#define set_u_addr(u_addr) \
+({ write_reg( (IPU_V_BASE + REG_U_ADDR), u_addr); \
+})
+
+#define set_v_addr(v_addr) \
+({ write_reg( (IPU_V_BASE + REG_V_ADDR), v_addr); \
+})
+
+#define set_y_phy_t_addr(y_phy_t_addr) \
+({ write_reg( (IPU_V_BASE + REG_Y_PHY_T_ADDR), y_phy_t_addr); \
+})
+
+#define set_u_phy_t_addr(u_phy_t_addr) \
+({ write_reg( (IPU_V_BASE + REG_U_PHY_T_ADDR), u_phy_t_addr); \
+})
+
+#define set_v_phy_t_addr(v_phy_t_addr) \
+({ write_reg( (IPU_V_BASE + REG_V_PHY_T_ADDR), v_phy_t_addr); \
+})
+
+#define set_out_phy_t_addr(out_phy_t_addr) \
+({ write_reg( (IPU_V_BASE + REG_OUT_PHY_T_ADDR), out_phy_t_addr); \
+})
+
+#define set_inframe_gsize(width, height, y_stride, u_stride, v_stride) \
+({ write_reg( (IPU_V_BASE + REG_IN_FM_GS), ((width) & IN_FM_W_MSK)<<IN_FM_W_SFT \
+| ((height) & IN_FM_H_MSK)<<IN_FM_H_SFT); \
+ write_reg( (IPU_V_BASE + REG_Y_STRIDE), ((y_stride) & Y_S_MSK)<<Y_S_SFT); \
+ write_reg( (IPU_V_BASE + REG_UV_STRIDE), ((u_stride) & U_S_MSK)<<U_S_SFT \
+| ((v_stride) & V_S_MSK)<<V_S_SFT); \
+})
+#define set_out_addr(out_addr) \
+({ write_reg( (IPU_V_BASE + REG_OUT_ADDR), out_addr); \
+})
+#define set_outframe_gsize(width, height, o_stride) \
+({ write_reg( (IPU_V_BASE + REG_OUT_GS), ((width) & OUT_FM_W_MSK)<<OUT_FM_W_SFT \
+| ((height) & OUT_FM_H_MSK)<<OUT_FM_H_SFT); \
+ write_reg( (IPU_V_BASE + REG_OUT_STRIDE), ((o_stride) & OUT_S_MSK)<<OUT_S_SFT); \
+})
+#define set_rsz_lut_end(h_end, v_end) \
+({ write_reg( (IPU_V_BASE + REG_RSZ_COEF_INDEX), ((h_end) & HE_IDX_MSK)<<HE_IDX_SFT \
+| ((v_end) & VE_IDX_MSK)<<VE_IDX_SFT); \
+})
+#define set_csc_c0(c0_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_CO_COEF), ((c0_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_csc_c1(c1_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_C1_COEF), ((c1_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_csc_c2(c2_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_C2_COEF), ((c2_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_csc_c3(c3_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_C3_COEF), ((c3_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_csc_c4(c4_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_C4_COEF), ((c4_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_hrsz_lut_coef(coef, in_n, out_n) \
+({ write_reg( (IPU_V_BASE + HRSZ_LUT_BASE ), ((coef) & W_COEF_MSK)<<W_COEF_SFT \
+| ((in_n) & IN_N_MSK)<<IN_N_SFT | ((out_n) & OUT_N_MSK)<<OUT_N_SFT); \
+})
+#define set_vrsz_lut_coef(coef, in_n, out_n) \
+({ write_reg( (IPU_V_BASE + VRSZ_LUT_BASE), ((coef) & W_COEF_MSK)<<W_COEF_SFT \
+| ((in_n) & IN_N_MSK)<<IN_N_SFT | ((out_n) & OUT_N_MSK)<<OUT_N_SFT); \
+})
+
+#define set_primary_ctrl(vrsz_en, hrsz_en,csc_en, irq_en) \
+({ write_reg( (IPU_V_BASE + REG_CTRL), ((irq_en) & FM_IRQ_EN_MSK)<<FM_IRQ_EN_SFT \
+| ((vrsz_en) & VRSZ_EN_MSK)<<VRSZ_EN_SFT \
+| ((hrsz_en) & HRSZ_EN_MSK)<<HRSZ_EN_SFT \
+| ((csc_en) & CSC_EN_MSK)<<CSC_EN_SFT \
+| (read_reg(IPU_V_BASE, REG_CTRL)) \
+& ~(CSC_EN_MSK<<CSC_EN_SFT | FM_IRQ_EN_MSK<<FM_IRQ_EN_SFT | VRSZ_EN_MSK<<VRSZ_EN_SFT | HRSZ_EN_MSK<<HRSZ_EN_SFT ) ); \
+})
+
+#define set_source_ctrl(pkg_sel, spage_sel) \
+({ write_reg( (IPU_V_BASE + REG_CTRL), ((pkg_sel) & PKG_SEL_MSK )<< PKG_SEL_SFT \
+| ((spage_sel) & SPAGE_MAP_MSK )<< SPAGE_MAP_SFT \
+| (read_reg(IPU_V_BASE, REG_CTRL)) \
+& ~(SPAGE_MAP_MSK << SPAGE_MAP_SFT | PKG_SEL_MSK << PKG_SEL_SFT ) ) ; \
+})
+
+#define set_out_ctrl(lcdc_sel, dpage_sel, disp_sel) \
+({ write_reg( (IPU_V_BASE + REG_CTRL), ((lcdc_sel) & LCDC_SEL_MSK )<< LCDC_SEL_SFT \
+| ((dpage_sel) & DPAGE_SEL_MSK )<< DPAGE_SEL_SFT \
+| ((disp_sel) & DISP_SEL_MSK )<< DISP_SEL_SFT \
+| (read_reg(IPU_V_BASE, REG_CTRL)) \
+& ~(LCDC_SEL_MSK<< LCDC_SEL_SFT | DPAGE_SEL_MSK << DPAGE_SEL_SFT | DISP_SEL_MSK << DISP_SEL_SFT ) ); \
+})
+
+#define set_scale_ctrl(v_scal, h_scal) \
+({ write_reg( (IPU_V_BASE + REG_CTRL), ((v_scal) & V_SCALE_MSK)<<V_SCALE_SFT \
+| ((h_scal) & H_SCALE_MSK)<<H_SCALE_SFT \
+| (read_reg(IPU_V_BASE, REG_CTRL)) & ~(V_SCALE_MSK<<V_SCALE_SFT | H_SCALE_MSK<<H_SCALE_SFT ) ); \
+})
+
+
+#define set_csc_ofset_para(chrom_oft, luma_oft) \
+({ write_reg( (IPU_V_BASE + REG_CSC_OFSET_PARA ), ((chrom_oft) & CHROM_OF_MSK ) << CHROM_OF_SFT \
+| ((luma_oft) & LUMA_OF_MSK ) << LUMA_OF_SFT ) ; \
+})
+
+#define sw_reset_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) \
+| IPU_RST_MSK<<IPU_RST_SFT); \
+})
+#define enable_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) | 0x1); \
+})
+#define disable_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) & ~0x1); \
+})
+#define run_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) | 0x2); \
+})
+#define stop_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) & ~0x2); \
+})
+
+#define polling_end_flag() \
+({ (read_reg(IPU_V_BASE, REG_STATUS)) & 0x01; \
+})
+
+#define start_vlut_coef_write() \
+({ write_reg( (IPU_V_BASE + VRSZ_LUT_BASE), ( 0x1<<12 ) ); \
+})
+
+#define start_hlut_coef_write() \
+({ write_reg( (IPU_V_BASE + HRSZ_LUT_BASE), ( 0x01<<12 ) ); \
+})
+
+#define clear_end_flag() \
+({ write_reg( (IPU_V_BASE + REG_STATUS), 0); \
+})
+#endif /* #if 0 */
+
+
+#endif /* __JZ4750D_OPS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750d/regs.h b/arch/mips/include/asm/mach-jz4750d/regs.h
new file mode 100644
index 00000000000..fd8e46c99ba
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750d/regs.h
@@ -0,0 +1,3400 @@
+/*
+ * linux/include/asm-mips/mach-jz4750d/regs.h
+ *
+ * JZ4750D register definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __JZ4750D_REGS_H__
+#define __JZ4750D_REGS_H__
+
+#if defined(__ASSEMBLY__) || defined(__LANGUAGE_ASSEMBLY)
+#define REG8(addr) (addr)
+#define REG16(addr) (addr)
+#define REG32(addr) (addr)
+#else
+#define REG8(addr) *((volatile unsigned char *)(addr))
+#define REG16(addr) *((volatile unsigned short *)(addr))
+#define REG32(addr) *((volatile unsigned int *)(addr))
+#endif
+
+/*
+ * Define the module base addresses
+ */
+#define CPM_BASE 0xB0000000
+#define INTC_BASE 0xB0001000
+#define TCU_BASE 0xB0002000
+#define WDT_BASE 0xB0002000
+#define RTC_BASE 0xB0003000
+#define GPIO_BASE 0xB0010000
+#define AIC_BASE 0xB0020000
+#define ICDC_BASE 0xB0020000
+#define MSC_BASE 0xB0021000
+#define UART0_BASE 0xB0030000
+#define UART1_BASE 0xB0031000
+#define UART2_BASE 0xB0032000
+#define UART3_BASE 0xB0033000
+#define I2C_BASE 0xB0042000
+#define SSI_BASE 0xB0043000
+#define SADC_BASE 0xB0070000
+#define PCM_BASE 0xB0071000
+#define EMC_BASE 0xB3010000
+#define DMAC_BASE 0xB3020000
+#define UHC_BASE 0xB3030000
+#define UDC_BASE 0xB3040000
+#define LCD_BASE 0xB3050000
+#define SLCD_BASE 0xB3050000
+#define TVE_BASE 0xB3050100
+#define CIM_BASE 0xB3060000
+#define IPU_BASE 0xB3080000
+#define ME_BASE 0xB3090000
+#define MC_BASE 0xB30A0000
+#define BCH_BASE 0xB30D0000
+#define ETH_BASE 0xB3100000
+#define TCSM_BASE 0xF4000000
+#define OWI_BASE 0XB0072000
+#define OTP_BASE 0xB3012000
+#define TSSI_BASE 0xB0073000
+
+/*************************************************************************
+ * INTC (Interrupt Controller)
+ *************************************************************************/
+#define INTC_ISR (INTC_BASE + 0x00)
+#define INTC_IMR (INTC_BASE + 0x04)
+#define INTC_IMSR (INTC_BASE + 0x08)
+#define INTC_IMCR (INTC_BASE + 0x0c)
+#define INTC_IPR (INTC_BASE + 0x10)
+#define INTC_ISSR (INTC_BASE + 0x18) /* Interrupt Controller Source Set Register */
+#define INTC_ISCR (INTC_BASE + 0x1c) /* Interrupt Controller Source Clear Register */
+
+#define REG_INTC_ISR REG32(INTC_ISR)
+#define REG_INTC_IMR REG32(INTC_IMR)
+#define REG_INTC_IMSR REG32(INTC_IMSR)
+#define REG_INTC_IMCR REG32(INTC_IMCR)
+#define REG_INTC_IPR REG32(INTC_IPR)
+#define REG_INTC_ISSR REG32(INTC_ISSR)
+#define REG_INTC_ISCR REG32(INTC_ISCR)
+
+// 1st-level interrupts
+#define IRQ_ETH 0
+#define IRQ_SFT 4
+#define IRQ_I2C 5
+#define IRQ_RTC 6
+#define IRQ_UART2 7
+#define IRQ_UART1 8
+#define IRQ_UART0 9
+#define IRQ_AIC 10
+#define IRQ_GPIO5 11
+#define IRQ_GPIO4 12
+#define IRQ_GPIO3 13
+#define IRQ_GPIO2 14
+#define IRQ_GPIO1 15
+#define IRQ_GPIO0 16
+#define IRQ_BCH 17
+#define IRQ_SADC 18
+#define IRQ_CIM 19
+#define IRQ_TSSI 20
+#define IRQ_TCU2 21
+#define IRQ_TCU1 22
+#define IRQ_TCU0 23
+#define IRQ_MSC1 24
+#define IRQ_MSC0 25
+#define IRQ_SSI 26
+#define IRQ_UDC 27
+#define IRQ_DMAC1 28
+#define IRQ_DMAC0 29
+#define IRQ_IPU 30
+#define IRQ_LCD 31
+
+// 2nd-level interrupts
+#define IRQ_DMA_0 32 /* 32 to 43 for DMAC0's 0-5 and DMAC1's 0-5 */
+#define IRQ_GPIO_0 48 /* 48 to 240 for GPIO pin 0 to 192 */
+
+#define NUM_DMA MAX_DMA_NUM /* 12 */
+#define NUM_GPIO MAX_GPIO_NUM /* GPIO NUM: 192, Jz4750D real num GPIO 178 */
+
+
+/*************************************************************************
+ * RTC
+ *************************************************************************/
+#define RTC_RCR (RTC_BASE + 0x00) /* RTC Control Register */
+#define RTC_RSR (RTC_BASE + 0x04) /* RTC Second Register */
+#define RTC_RSAR (RTC_BASE + 0x08) /* RTC Second Alarm Register */
+#define RTC_RGR (RTC_BASE + 0x0c) /* RTC Regulator Register */
+
+#define RTC_HCR (RTC_BASE + 0x20) /* Hibernate Control Register */
+#define RTC_HWFCR (RTC_BASE + 0x24) /* Hibernate Wakeup Filter Counter Reg */
+#define RTC_HRCR (RTC_BASE + 0x28) /* Hibernate Reset Counter Register */
+#define RTC_HWCR (RTC_BASE + 0x2c) /* Hibernate Wakeup Control Register */
+#define RTC_HWRSR (RTC_BASE + 0x30) /* Hibernate Wakeup Status Register */
+#define RTC_HSPR (RTC_BASE + 0x34) /* Hibernate Scratch Pattern Register */
+
+#define REG_RTC_RCR REG32(RTC_RCR)
+#define REG_RTC_RSR REG32(RTC_RSR)
+#define REG_RTC_RSAR REG32(RTC_RSAR)
+#define REG_RTC_RGR REG32(RTC_RGR)
+#define REG_RTC_HCR REG32(RTC_HCR)
+#define REG_RTC_HWFCR REG32(RTC_HWFCR)
+#define REG_RTC_HRCR REG32(RTC_HRCR)
+#define REG_RTC_HWCR REG32(RTC_HWCR)
+#define REG_RTC_HWRSR REG32(RTC_HWRSR)
+#define REG_RTC_HSPR REG32(RTC_HSPR)
+
+/* RTC Control Register */
+#define RTC_RCR_WRDY_BIT 7
+#define RTC_RCR_WRDY (1 << 7) /* Write Ready Flag */
+#define RTC_RCR_1HZ_BIT 6
+#define RTC_RCR_1HZ (1 << RTC_RCR_1HZ_BIT) /* 1Hz Flag */
+#define RTC_RCR_1HZIE (1 << 5) /* 1Hz Interrupt Enable */
+#define RTC_RCR_AF_BIT 4
+#define RTC_RCR_AF (1 << RTC_RCR_AF_BIT) /* Alarm Flag */
+#define RTC_RCR_AIE (1 << 3) /* Alarm Interrupt Enable */
+#define RTC_RCR_AE (1 << 2) /* Alarm Enable */
+#define RTC_RCR_RTCE (1 << 0) /* RTC Enable */
+
+/* RTC Regulator Register */
+#define RTC_RGR_LOCK (1 << 31) /* Lock Bit */
+#define RTC_RGR_ADJC_BIT 16
+#define RTC_RGR_ADJC_MASK (0x3ff << RTC_RGR_ADJC_BIT)
+#define RTC_RGR_NC1HZ_BIT 0
+#define RTC_RGR_NC1HZ_MASK (0xffff << RTC_RGR_NC1HZ_BIT)
+
+/* Hibernate Control Register */
+#define RTC_HCR_PD (1 << 0) /* Power Down */
+
+/* Hibernate Wakeup Filter Counter Register */
+#define RTC_HWFCR_BIT 5
+#define RTC_HWFCR_MASK (0x7ff << RTC_HWFCR_BIT)
+
+/* Hibernate Reset Counter Register */
+#define RTC_HRCR_BIT 5
+#define RTC_HRCR_MASK (0x7f << RTC_HRCR_BIT)
+
+/* Hibernate Wakeup Control Register */
+#define RTC_HWCR_EALM (1 << 0) /* RTC alarm wakeup enable */
+
+/* Hibernate Wakeup Status Register */
+#define RTC_HWRSR_HR (1 << 5) /* Hibernate reset */
+#define RTC_HWRSR_PPR (1 << 4) /* PPR reset */
+#define RTC_HWRSR_PIN (1 << 1) /* Wakeup pin status bit */
+#define RTC_HWRSR_ALM (1 << 0) /* RTC alarm status bit */
+
+
+/*************************************************************************
+ * CPM (Clock reset and Power control Management)
+ *************************************************************************/
+#define CPM_CPCCR (CPM_BASE+0x00)
+#define CPM_CPPCR (CPM_BASE+0x10)
+#define CPM_CPPSR (CPM_BASE+0x14) /* PLL Switch and Status Register */
+#define CPM_I2SCDR (CPM_BASE+0x60)
+#define CPM_LPCDR (CPM_BASE+0x64)
+#define CPM_MSCCDR(n) (CPM_BASE+0x68) /* MSC0(n=0) or MSC1(n=1) device clock divider Register */
+#define CPM_UHCCDR (CPM_BASE+0x6C)
+#define CPM_SSICDR (CPM_BASE+0x74)
+#define CPM_PCMCDR (CPM_BASE+0x7C) /* PCM device clock divider Register */
+
+#define CPM_LCR (CPM_BASE+0x04)
+#define CPM_CLKGR (CPM_BASE+0x20)
+#define CPM_OPCR (CPM_BASE+0x24) /* Oscillator and Power Control Register */
+
+#define CPM_RSR (CPM_BASE+0x08)
+
+#define REG_CPM_CPCCR REG32(CPM_CPCCR)
+#define REG_CPM_CPPCR REG32(CPM_CPPCR)
+#define REG_CPM_CPPSR REG32(CPM_CPPSR)
+#define REG_CPM_I2SCDR REG32(CPM_I2SCDR)
+#define REG_CPM_LPCDR REG32(CPM_LPCDR)
+#define REG_CPM_MSCCDR(n) REG32(CPM_MSCCDR(n))
+#define REG_CPM_UHCCDR REG32(CPM_UHCCDR)
+#define REG_CPM_SSICDR REG32(CPM_SSICDR)
+#define REG_CPM_PCMCDR REG32(CPM_PCMCDR)
+
+#define REG_CPM_LCR REG32(CPM_LCR)
+#define REG_CPM_CLKGR REG32(CPM_CLKGR)
+#define REG_CPM_OPCR REG32(CPM_OPCR)
+
+#define REG_CPM_RSR REG32(CPM_RSR)
+
+/* Clock Control Register */
+#define CPM_CPCCR_I2CS (1 << 31)
+#define CPM_CPCCR_ECS (1 << 30) /* Select the between EXCLK and EXCLK/2 output */
+#define CPM_CPCCR_UCS (1 << 29)
+#define CPM_CPCCR_UDIV_BIT 23
+#define CPM_CPCCR_UDIV_MASK (0x3f << CPM_CPCCR_UDIV_BIT)
+#define CPM_CPCCR_CE (1 << 22)
+#define CPM_CPCCR_PCS (1 << 21)
+#define CPM_CPCCR_H1DIV_BIT 16
+#define CPM_CPCCR_H1DIV_MASK (0x1f << CPM_CPCCR_H1DIV_BIT)
+#define CPM_CPCCR_MDIV_BIT 12
+#define CPM_CPCCR_MDIV_MASK (0x0f << CPM_CPCCR_MDIV_BIT)
+#define CPM_CPCCR_PDIV_BIT 8
+#define CPM_CPCCR_PDIV_MASK (0x0f << CPM_CPCCR_PDIV_BIT)
+#define CPM_CPCCR_HDIV_BIT 4
+#define CPM_CPCCR_HDIV_MASK (0x0f << CPM_CPCCR_HDIV_BIT)
+#define CPM_CPCCR_CDIV_BIT 0
+#define CPM_CPCCR_CDIV_MASK (0x0f << CPM_CPCCR_CDIV_BIT)
+
+/* PLL Switch and Status Register */
+#define CPM_CPPSR_PLLOFF (1<<31)
+#define CPM_CPPSR_PLLBP (1<<30)
+#define CPM_CPPSR_PLLON (1<<29)
+#define CPM_CPPSR_PS (1<<28) /* Indicate whether the PLL parameters' change has finished */
+#define CPM_CPPSR_FS (1<<27) /* Indicate whether the main clock's change has finished */
+#define CPM_CPPSR_CS (1<<26) /* Indicate whether the clock switch has finished */
+#define CPM_CPPSR_PM (1<<1) /* Clock switch mode */
+#define CPM_CPPSR_FM (1<<0) /* Clock frequency change mode */
+
+/* I2S Clock Divider Register */
+#define CPM_I2SCDR_I2SDIV_BIT 0
+#define CPM_I2SCDR_I2SDIV_MASK (0x1ff << CPM_I2SCDR_I2SDIV_BIT)
+
+/* LCD Pixel Clock Divider Register */
+#define CPM_LPCDR_LSCS (1<<31) /* TV encoder Source Pixel Clock Selection */
+#define CPM_LPCDR_LTCS (1<<30) /* LCD TV Encoder or Panel pix clock Selection */
+#define CPM_LPCDR_PIXDIV_BIT 0
+#define CPM_LPCDR_PIXDIV_MASK (0x7ff << CPM_LPCDR_PIXDIV_BIT)
+
+/* MSC Clock Divider Register */
+#define CPM_MSCCDR_MSCDIV_BIT 0
+#define CPM_MSCCDR_MSCDIV_MASK (0x1f << CPM_MSCCDR_MSCDIV_BIT)
+
+/* UHC Clock Divider Register */
+#define CPM_UHCCDR_UHCDIV_BIT 0
+#define CPM_UHCCDR_UHCDIV_MASK (0xf << CPM_UHCCDR_UHCDIV_BIT)
+
+/* SSI Clock Divider Register */
+#define CPM_SSICDR_SSIDIV_BIT 0
+#define CPM_SSICDR_SSIDIV_MASK (0xf << CPM_SSICDR_SSIDIV_BIT)
+
+/* PCM device clock divider Register */
+#define CPM_PCMCDR_PCMS 31 /* PCM source clock Selection */
+#define CPM_PCMCDR_PCMCD_BIT 0
+#define CPM_PCMCDR_PCMCD_MASK (0x1ff << CPM_PCMCDR_PCMCD_BIT)
+
+/* PLL Control Register */
+#define CPM_CPPCR_PLLM_BIT 23
+#define CPM_CPPCR_PLLM_MASK (0x1ff << CPM_CPPCR_PLLM_BIT)
+#define CPM_CPPCR_PLLN_BIT 18
+#define CPM_CPPCR_PLLN_MASK (0x1f << CPM_CPPCR_PLLN_BIT)
+#define CPM_CPPCR_PLLOD_BIT 16
+#define CPM_CPPCR_PLLOD_MASK (0x03 << CPM_CPPCR_PLLOD_BIT)
+#define CPM_CPPCR_PLLS (1 << 10) /* obsolete, replaced by CPM_CPPSR_PLLON */
+#define CPM_CPPCR_PLLBP (1 << 9)
+#define CPM_CPPCR_PLLEN (1 << 8)
+#define CPM_CPPCR_PLLST_BIT 0
+#define CPM_CPPCR_PLLST_MASK (0xff << CPM_CPPCR_PLLST_BIT)
+
+/* Low Power Control Register */
+#define CPM_LCR_DOZE_DUTY_BIT 3
+#define CPM_LCR_DOZE_DUTY_MASK (0x1f << CPM_LCR_DOZE_DUTY_BIT)
+#define CPM_LCR_DOZE_ON (1 << 2)
+#define CPM_LCR_LPM_BIT 0
+#define CPM_LCR_LPM_MASK (0x3 << CPM_LCR_LPM_BIT)
+ #define CPM_LCR_LPM_IDLE (0x0 << CPM_LCR_LPM_BIT)
+ #define CPM_LCR_LPM_SLEEP (0x1 << CPM_LCR_LPM_BIT)
+
+/* Clock Gate Register */
+#define CPM_CLKGR_AUX_CPU (1 << 24)
+#define CPM_CLKGR_AHB1 (1 << 23)
+#define CPM_CLKGR_IDCT (1 << 22)
+#define CPM_CLKGR_DB (1 << 21)
+#define CPM_CLKGR_ME (1 << 20)
+#define CPM_CLKGR_MC (1 << 19)
+#define CPM_CLKGR_TVE (1 << 18)
+#define CPM_CLKGR_TSSI (1 << 17)
+#define CPM_CLKGR_MSC1 (1 << 16)
+#define CPM_CLKGR_UART2 (1 << 15)
+#define CPM_CLKGR_UART1 (1 << 14)
+#define CPM_CLKGR_IPU (1 << 13)
+#define CPM_CLKGR_DMAC (1 << 12)
+#define CPM_CLKGR_BCH (1 << 11)
+#define CPM_CLKGR_UDC (1 << 10)
+#define CPM_CLKGR_LCD (1 << 9)
+#define CPM_CLKGR_CIM (1 << 8)
+#define CPM_CLKGR_SADC (1 << 7)
+#define CPM_CLKGR_MSC0 (1 << 6)
+#define CPM_CLKGR_AIC (1 << 5)
+#define CPM_CLKGR_SSI (1 << 4)
+#define CPM_CLKGR_I2C (1 << 3)
+#define CPM_CLKGR_RTC (1 << 2)
+#define CPM_CLKGR_TCU (1 << 1)
+#define CPM_CLKGR_UART0 (1 << 0)
+
+/* Oscillator and Power Control Register */
+#define CPM_OPCR_O1ST_BIT 8
+#define CPM_OPCR_O1ST_MASK (0xff << CPM_SCR_O1ST_BIT)
+#define CPM_OPCR_UHCPHY_DISABLE (1 << 7)
+#define CPM_OPCR_UDCPHY_ENABLE (1 << 6)
+#define CPM_OPCR_OSC_ENABLE (1 << 4)
+#define CPM_OPCR_ERCS (1 << 2) /* EXCLK/512 clock and RTCLK clock selection */
+#define CPM_OPCR_MOSE (1 << 1) /* Main Oscillator Enable */
+#define CPM_OPCR_MCS (1 << 0) /* Main clock source select register */
+
+/* Reset Status Register */
+#define CPM_RSR_HR (1 << 2)
+#define CPM_RSR_WR (1 << 1)
+#define CPM_RSR_PR (1 << 0)
+
+
+/*************************************************************************
+ * TCU (Timer Counter Unit)
+ *************************************************************************/
+#define TCU_TSTR (TCU_BASE + 0xF0) /* Timer Status Register,Only Used In Tcu2 Mode */
+#define TCU_TSTSR (TCU_BASE + 0xF4) /* Timer Status Set Register */
+#define TCU_TSTCR (TCU_BASE + 0xF8) /* Timer Status Clear Register */
+#define TCU_TSR (TCU_BASE + 0x1C) /* Timer Stop Register */
+#define TCU_TSSR (TCU_BASE + 0x2C) /* Timer Stop Set Register */
+#define TCU_TSCR (TCU_BASE + 0x3C) /* Timer Stop Clear Register */
+#define TCU_TER (TCU_BASE + 0x10) /* Timer Counter Enable Register */
+#define TCU_TESR (TCU_BASE + 0x14) /* Timer Counter Enable Set Register */
+#define TCU_TECR (TCU_BASE + 0x18) /* Timer Counter Enable Clear Register */
+#define TCU_TFR (TCU_BASE + 0x20) /* Timer Flag Register */
+#define TCU_TFSR (TCU_BASE + 0x24) /* Timer Flag Set Register */
+#define TCU_TFCR (TCU_BASE + 0x28) /* Timer Flag Clear Register */
+#define TCU_TMR (TCU_BASE + 0x30) /* Timer Mask Register */
+#define TCU_TMSR (TCU_BASE + 0x34) /* Timer Mask Set Register */
+#define TCU_TMCR (TCU_BASE + 0x38) /* Timer Mask Clear Register */
+
+#define TCU_TDFR0 (TCU_BASE + 0x40) /* Timer Data Full Register */
+#define TCU_TDHR0 (TCU_BASE + 0x44) /* Timer Data Half Register */
+#define TCU_TCNT0 (TCU_BASE + 0x48) /* Timer Counter Register */
+#define TCU_TCSR0 (TCU_BASE + 0x4C) /* Timer Control Register */
+#define TCU_TDFR1 (TCU_BASE + 0x50)
+#define TCU_TDHR1 (TCU_BASE + 0x54)
+#define TCU_TCNT1 (TCU_BASE + 0x58)
+#define TCU_TCSR1 (TCU_BASE + 0x5C)
+#define TCU_TDFR2 (TCU_BASE + 0x60)
+#define TCU_TDHR2 (TCU_BASE + 0x64)
+#define TCU_TCNT2 (TCU_BASE + 0x68)
+#define TCU_TCSR2 (TCU_BASE + 0x6C)
+#define TCU_TDFR3 (TCU_BASE + 0x70)
+#define TCU_TDHR3 (TCU_BASE + 0x74)
+#define TCU_TCNT3 (TCU_BASE + 0x78)
+#define TCU_TCSR3 (TCU_BASE + 0x7C)
+#define TCU_TDFR4 (TCU_BASE + 0x80)
+#define TCU_TDHR4 (TCU_BASE + 0x84)
+#define TCU_TCNT4 (TCU_BASE + 0x88)
+#define TCU_TCSR4 (TCU_BASE + 0x8C)
+#define TCU_TDFR5 (TCU_BASE + 0x90)
+#define TCU_TDHR5 (TCU_BASE + 0x94)
+#define TCU_TCNT5 (TCU_BASE + 0x98)
+#define TCU_TCSR5 (TCU_BASE + 0x9C)
+
+#define REG_TCU_TSTR REG32(TCU_TSTR)
+#define REG_TCU_TSTSR REG32(TCU_TSTSR)
+#define REG_TCU_TSTCR REG32(TCU_TSTCR)
+#define REG_TCU_TSR REG32(TCU_TSR)
+#define REG_TCU_TSSR REG32(TCU_TSSR)
+#define REG_TCU_TSCR REG32(TCU_TSCR)
+#define REG_TCU_TER REG16(TCU_TER)
+#define REG_TCU_TESR REG32(TCU_TESR)
+#define REG_TCU_TECR REG32(TCU_TECR)
+#define REG_TCU_TFR REG32(TCU_TFR)
+#define REG_TCU_TFSR REG32(TCU_TFSR)
+#define REG_TCU_TFCR REG32(TCU_TFCR)
+#define REG_TCU_TMR REG32(TCU_TMR)
+#define REG_TCU_TMSR REG32(TCU_TMSR)
+#define REG_TCU_TMCR REG32(TCU_TMCR)
+#define REG_TCU_TDFR0 REG16(TCU_TDFR0)
+#define REG_TCU_TDHR0 REG16(TCU_TDHR0)
+#define REG_TCU_TCNT0 REG16(TCU_TCNT0)
+#define REG_TCU_TCSR0 REG16(TCU_TCSR0)
+#define REG_TCU_TDFR1 REG16(TCU_TDFR1)
+#define REG_TCU_TDHR1 REG16(TCU_TDHR1)
+#define REG_TCU_TCNT1 REG16(TCU_TCNT1)
+#define REG_TCU_TCSR1 REG16(TCU_TCSR1)
+#define REG_TCU_TDFR2 REG16(TCU_TDFR2)
+#define REG_TCU_TDHR2 REG16(TCU_TDHR2)
+#define REG_TCU_TCNT2 REG16(TCU_TCNT2)
+#define REG_TCU_TCSR2 REG16(TCU_TCSR2)
+#define REG_TCU_TDFR3 REG16(TCU_TDFR3)
+#define REG_TCU_TDHR3 REG16(TCU_TDHR3)
+#define REG_TCU_TCNT3 REG16(TCU_TCNT3)
+#define REG_TCU_TCSR3 REG16(TCU_TCSR3)
+#define REG_TCU_TDFR4 REG16(TCU_TDFR4)
+#define REG_TCU_TDHR4 REG16(TCU_TDHR4)
+#define REG_TCU_TCNT4 REG16(TCU_TCNT4)
+#define REG_TCU_TCSR4 REG16(TCU_TCSR4)
+
+// n = 0,1,2,3,4,5
+#define TCU_TDFR(n) (TCU_BASE + (0x40 + (n)*0x10)) /* Timer Data Full Reg */
+#define TCU_TDHR(n) (TCU_BASE + (0x44 + (n)*0x10)) /* Timer Data Half Reg */
+#define TCU_TCNT(n) (TCU_BASE + (0x48 + (n)*0x10)) /* Timer Counter Reg */
+#define TCU_TCSR(n) (TCU_BASE + (0x4C + (n)*0x10)) /* Timer Control Reg */
+#define TCU_OSTDR (TCU_BASE + 0xe0) /* Operating System Timer Data Reg */
+#define TCU_OSTCNT (TCU_BASE + 0xe8) /* Operating System Timer Counter Reg */
+#define TCU_OSTCSR (TCU_BASE + 0xeC) /* Operating System Timer Control Reg */
+
+#define REG_TCU_TDFR(n) REG16(TCU_TDFR((n)))
+#define REG_TCU_TDHR(n) REG16(TCU_TDHR((n)))
+#define REG_TCU_TCNT(n) REG16(TCU_TCNT((n)))
+#define REG_TCU_TCSR(n) REG16(TCU_TCSR((n)))
+#define REG_TCU_OSTDR REG32(TCU_OSTDR)
+#define REG_TCU_OSTCNT REG32(TCU_OSTCNT)
+#define REG_TCU_OSTCSR REG32(TCU_OSTCSR)
+
+// Register definitions
+#define TCU_TSTR_REAL2 (1 << 18) /* only used in TCU2 mode */
+#define TCU_TSTR_REAL1 (1 << 17) /* only used in TCU2 mode */
+#define TCU_TSTR_BUSY2 (1 << 2) /* only used in TCU2 mode */
+#define TCU_TSTR_BUSY1 (1 << 1) /* only used in TCU2 mode */
+
+#define TCU_TSTSR_REAL2 (1 << 18)
+#define TCU_TSTSR_REAL1 (1 << 17)
+#define TCU_TSTSR_BUSY2 (1 << 2)
+#define TCU_TSTSR_BUSY1 (1 << 1)
+
+#define TCU_TSTCR_REAL2 (1 << 18)
+#define TCU_TSTCR_REAL1 (1 << 17)
+#define TCU_TSTCR_BUSY2 (1 << 2)
+#define TCU_TSTCR_BUSY1 (1 << 1)
+
+#define TCU_TSR_WDTS (1 << 16) /*the clock supplies to wdt is stopped */
+#define TCU_TSR_OSTS (1 << 15) /*the clock supplies to osts is stopped */
+#define TCU_TSR_STOP5 (1 << 5) /*the clock supplies to timer5 is stopped */
+#define TCU_TSR_STOP4 (1 << 4) /*the clock supplies to timer4 is stopped */
+#define TCU_TSR_STOP3 (1 << 3) /*the clock supplies to timer3 is stopped */
+#define TCU_TSR_STOP2 (1 << 2) /*the clock supplies to timer2 is stopped */
+#define TCU_TSR_STOP1 (1 << 1) /*the clock supplies to timer1 is stopped */
+#define TCU_TSR_STOP0 (1 << 0) /*the clock supplies to timer0 is stopped */
+
+#define TCU_TSSR_WDTSS (1 << 16)
+#define TCU_TSSR_OSTSS (1 << 15)
+#define TCU_TSSR_STPS5 (1 << 5)
+#define TCU_TSSR_STPS4 (1 << 4)
+#define TCU_TSSR_STPS3 (1 << 3)
+#define TCU_TSSR_STPS2 (1 << 2)
+#define TCU_TSSR_STPS1 (1 << 1)
+#define TCU_TSSR_STPS0 (1 << 0)
+
+#define TCU_TSCR_WDTSC (1 << 16)
+#define TCU_TSCR_OSTSC (1 << 15)
+#define TCU_TSCR_STPC5 (1 << 5)
+#define TCU_TSCR_STPC4 (1 << 4)
+#define TCU_TSCR_STPC3 (1 << 3)
+#define TCU_TSCR_STPC2 (1 << 2)
+#define TCU_TSCR_STPC1 (1 << 1)
+#define TCU_TSCR_STPC0 (1 << 0)
+
+#define TCU_TER_OSTEN (1 << 15) /* enable the counter in ost */
+#define TCU_TER_TCEN5 (1 << 5) /* enable the counter in timer5 */
+#define TCU_TER_TCEN4 (1 << 4)
+#define TCU_TER_TCEN3 (1 << 3)
+#define TCU_TER_TCEN2 (1 << 2)
+#define TCU_TER_TCEN1 (1 << 1)
+#define TCU_TER_TCEN0 (1 << 0)
+
+#define TCU_TESR_OSTST (1 << 15)
+#define TCU_TESR_TCST5 (1 << 5)
+#define TCU_TESR_TCST4 (1 << 4)
+#define TCU_TESR_TCST3 (1 << 3)
+#define TCU_TESR_TCST2 (1 << 2)
+#define TCU_TESR_TCST1 (1 << 1)
+#define TCU_TESR_TCST0 (1 << 0)
+
+#define TCU_TECR_OSTCL (1 << 15)
+#define TCU_TECR_TCCL5 (1 << 5)
+#define TCU_TECR_TCCL4 (1 << 4)
+#define TCU_TECR_TCCL3 (1 << 3)
+#define TCU_TECR_TCCL2 (1 << 2)
+#define TCU_TECR_TCCL1 (1 << 1)
+#define TCU_TECR_TCCL0 (1 << 0)
+
+#define TCU_TFR_HFLAG5 (1 << 21) /* half comparison match flag */
+#define TCU_TFR_HFLAG4 (1 << 20)
+#define TCU_TFR_HFLAG3 (1 << 19)
+#define TCU_TFR_HFLAG2 (1 << 18)
+#define TCU_TFR_HFLAG1 (1 << 17)
+#define TCU_TFR_HFLAG0 (1 << 16)
+#define TCU_TFR_OSTFLAG (1 << 15) /* ost comparison match flag */
+#define TCU_TFR_FFLAG5 (1 << 5) /* full comparison match flag */
+#define TCU_TFR_FFLAG4 (1 << 4)
+#define TCU_TFR_FFLAG3 (1 << 3)
+#define TCU_TFR_FFLAG2 (1 << 2)
+#define TCU_TFR_FFLAG1 (1 << 1)
+#define TCU_TFR_FFLAG0 (1 << 0)
+
+#define TCU_TFSR_HFST5 (1 << 21)
+#define TCU_TFSR_HFST4 (1 << 20)
+#define TCU_TFSR_HFST3 (1 << 19)
+#define TCU_TFSR_HFST2 (1 << 18)
+#define TCU_TFSR_HFST1 (1 << 17)
+#define TCU_TFSR_HFST0 (1 << 16)
+#define TCU_TFSR_OSTFST (1 << 15)
+#define TCU_TFSR_FFST5 (1 << 5)
+#define TCU_TFSR_FFST4 (1 << 4)
+#define TCU_TFSR_FFST3 (1 << 3)
+#define TCU_TFSR_FFST2 (1 << 2)
+#define TCU_TFSR_FFST1 (1 << 1)
+#define TCU_TFSR_FFST0 (1 << 0)
+
+#define TCU_TFCR_HFCL5 (1 << 21)
+#define TCU_TFCR_HFCL4 (1 << 20)
+#define TCU_TFCR_HFCL3 (1 << 19)
+#define TCU_TFCR_HFCL2 (1 << 18)
+#define TCU_TFCR_HFCL1 (1 << 17)
+#define TCU_TFCR_HFCL0 (1 << 16)
+#define TCU_TFCR_OSTFCL (1 << 15)
+#define TCU_TFCR_FFCL5 (1 << 5)
+#define TCU_TFCR_FFCL4 (1 << 4)
+#define TCU_TFCR_FFCL3 (1 << 3)
+#define TCU_TFCR_FFCL2 (1 << 2)
+#define TCU_TFCR_FFCL1 (1 << 1)
+#define TCU_TFCR_FFCL0 (1 << 0)
+
+#define TCU_TMR_HMASK5 (1 << 21) /* half comparison match interrupt mask */
+#define TCU_TMR_HMASK4 (1 << 20)
+#define TCU_TMR_HMASK3 (1 << 19)
+#define TCU_TMR_HMASK2 (1 << 18)
+#define TCU_TMR_HMASK1 (1 << 17)
+#define TCU_TMR_HMASK0 (1 << 16)
+#define TCU_TMR_OSTMASK (1 << 15) /* ost comparison match interrupt mask */
+#define TCU_TMR_FMASK5 (1 << 5) /* full comparison match interrupt mask */
+#define TCU_TMR_FMASK4 (1 << 4)
+#define TCU_TMR_FMASK3 (1 << 3)
+#define TCU_TMR_FMASK2 (1 << 2)
+#define TCU_TMR_FMASK1 (1 << 1)
+#define TCU_TMR_FMASK0 (1 << 0)
+
+#define TCU_TMSR_HMST5 (1 << 21)
+#define TCU_TMSR_HMST4 (1 << 20)
+#define TCU_TMSR_HMST3 (1 << 19)
+#define TCU_TMSR_HMST2 (1 << 18)
+#define TCU_TMSR_HMST1 (1 << 17)
+#define TCU_TMSR_HMST0 (1 << 16)
+#define TCU_TMSR_OSTMST (1 << 15)
+#define TCU_TMSR_FMST5 (1 << 5)
+#define TCU_TMSR_FMST4 (1 << 4)
+#define TCU_TMSR_FMST3 (1 << 3)
+#define TCU_TMSR_FMST2 (1 << 2)
+#define TCU_TMSR_FMST1 (1 << 1)
+#define TCU_TMSR_FMST0 (1 << 0)
+
+#define TCU_TMCR_HMCL5 (1 << 21)
+#define TCU_TMCR_HMCL4 (1 << 20)
+#define TCU_TMCR_HMCL3 (1 << 19)
+#define TCU_TMCR_HMCL2 (1 << 18)
+#define TCU_TMCR_HMCL1 (1 << 17)
+#define TCU_TMCR_HMCL0 (1 << 16)
+#define TCU_TMCR_OSTMCL (1 << 15)
+#define TCU_TMCR_FMCL5 (1 << 5)
+#define TCU_TMCR_FMCL4 (1 << 4)
+#define TCU_TMCR_FMCL3 (1 << 3)
+#define TCU_TMCR_FMCL2 (1 << 2)
+#define TCU_TMCR_FMCL1 (1 << 1)
+#define TCU_TMCR_FMCL0 (1 << 0)
+
+#define TCU_TCSR_CNT_CLRZ (1 << 10) /* clear counter to 0, only used in TCU2 mode */
+#define TCU_TCSR_PWM_SD (1 << 9) /* shut down the pwm output only used in TCU1 mode */
+#define TCU_TCSR_PWM_INITL_HIGH (1 << 8) /* selects an initial output level for pwm output */
+#define TCU_TCSR_PWM_EN (1 << 7) /* pwm pin output enable */
+#define TCU_TCSR_PRESCALE_BIT 3 /* select the tcnt count clock frequency*/
+#define TCU_TCSR_PRESCALE_MASK (0x7 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE1 (0x0 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE4 (0x1 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE16 (0x2 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE64 (0x3 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE256 (0x4 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE1024 (0x5 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_EXT_EN (1 << 2) /* select extal as the timer clock input */
+#define TCU_TCSR_RTC_EN (1 << 1) /* select rtcclk as the timer clock input */
+#define TCU_TCSR_PCK_EN (1 << 0) /* select pclk as the timer clock input */
+
+#define TCU_TSTR_REAL2 (1 << 18) /* the value read from counter 2 is a real value */
+#define TCU_TSTR_REAL1 (1 << 17)
+#define TCU_TSTR_BUSY2 (1 << 2) /* the counter 2 is busy now */
+#define TCU_TSTR_BUSY1 (1 << 1)
+
+#define TCU_TSTSR_REALS2 (1 << 18)
+#define TCU_TSTSR_REALS1 (1 << 17)
+#define TCU_TSTSR_BUSYS2 (1 << 2)
+#define TCU_TSTSR_BUSYS1 (1 << 1)
+
+#define TCU_TSTCR_REALC2 (1 << 18)
+#define TCU_TSTCR_REALC1 (1 << 17)
+#define TCU_TSTCR_BUSYC2 (1 << 2)
+#define TCU_TSTCR_BUSYC1 (1 << 1)
+
+#define TCU_OSTCR_CNT_MD (1 << 15) /* when the value counter is equal to compare value,the counter is go on increasing till overflow,and then icrease from 0 */
+#define TCU_OSTCR_PWM_SD (1 << 9) /* shut down the pwm output, only used in TCU1 mode */
+#define TCU_OSTCSR_PRESCALE_BIT 3
+#define TCU_OSTCSR_PRESCALE_MASK (0x7 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE1 (0x0 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE4 (0x1 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE16 (0x2 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE64 (0x3 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE256 (0x4 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE1024 (0x5 << TCU_OSTCSR_PRESCALE_BIT)
+#define TCU_OSTCSR_EXT_EN (1 << 2) /* select extal as the timer clock input */
+#define TCU_OSTCSR_RTC_EN (1 << 1) /* select rtcclk as the timer clock input */
+#define TCU_OSTCSR_PCK_EN (1 << 0) /* select pclk as the timer clock input */
+
+/*************************************************************************
+ * WDT (WatchDog Timer)
+ *************************************************************************/
+#define WDT_TDR (WDT_BASE + 0x00)
+#define WDT_TCER (WDT_BASE + 0x04)
+#define WDT_TCNT (WDT_BASE + 0x08)
+#define WDT_TCSR (WDT_BASE + 0x0C)
+
+#define REG_WDT_TDR REG16(WDT_TDR)
+#define REG_WDT_TCER REG8(WDT_TCER)
+#define REG_WDT_TCNT REG16(WDT_TCNT)
+#define REG_WDT_TCSR REG16(WDT_TCSR)
+
+// Register definition
+#define WDT_TCSR_PRESCALE_BIT 3
+#define WDT_TCSR_PRESCALE_MASK (0x7 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE1 (0x0 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE4 (0x1 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE16 (0x2 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE64 (0x3 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE256 (0x4 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE1024 (0x5 << WDT_TCSR_PRESCALE_BIT)
+#define WDT_TCSR_EXT_EN (1 << 2)
+#define WDT_TCSR_RTC_EN (1 << 1)
+#define WDT_TCSR_PCK_EN (1 << 0)
+
+#define WDT_TCER_TCEN (1 << 0)
+
+
+/*************************************************************************
+ * DMAC (DMA Controller)
+ *************************************************************************/
+
+#define MAX_DMA_NUM 8 /* max 8 channels */
+#define HALF_DMA_NUM 4 /* the number of one dma controller's channels */
+
+/* m is the DMA controller index (0, 1), n is the DMA channel index (0 - 11) */
+
+#define DMAC_DSAR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x00 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA source address */
+#define DMAC_DTAR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x04 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA target address */
+#define DMAC_DTCR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x08 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA transfer count */
+#define DMAC_DRSR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x0c + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA request source */
+#define DMAC_DCCSR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x10 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA control/status */
+#define DMAC_DCMD(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x14 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA command */
+#define DMAC_DDA(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x18 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA descriptor address */
+#define DMAC_DSD(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0xc0 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x04)) /* DMA Stride Address */
+
+#define DMAC_DMACR(m) (DMAC_BASE + 0x0300 + 0x100 * (m)) /* DMA control register */
+#define DMAC_DMAIPR(m) (DMAC_BASE + 0x0304 + 0x100 * (m)) /* DMA interrupt pending */
+#define DMAC_DMADBR(m) (DMAC_BASE + 0x0308 + 0x100 * (m)) /* DMA doorbell */
+#define DMAC_DMADBSR(m) (DMAC_BASE + 0x030C + 0x100 * (m)) /* DMA doorbell set */
+#define DMAC_DMACKE(m) (DMAC_BASE + 0x0310 + 0x100 * (m))
+
+#define REG_DMAC_DSAR(n) REG32(DMAC_DSAR((n)))
+#define REG_DMAC_DTAR(n) REG32(DMAC_DTAR((n)))
+#define REG_DMAC_DTCR(n) REG32(DMAC_DTCR((n)))
+#define REG_DMAC_DRSR(n) REG32(DMAC_DRSR((n)))
+#define REG_DMAC_DCCSR(n) REG32(DMAC_DCCSR((n)))
+#define REG_DMAC_DCMD(n) REG32(DMAC_DCMD((n)))
+#define REG_DMAC_DDA(n) REG32(DMAC_DDA((n)))
+#define REG_DMAC_DSD(n) REG32(DMAC_DSD(n))
+#define REG_DMAC_DMACR(m) REG32(DMAC_DMACR(m))
+#define REG_DMAC_DMAIPR(m) REG32(DMAC_DMAIPR(m))
+#define REG_DMAC_DMADBR(m) REG32(DMAC_DMADBR(m))
+#define REG_DMAC_DMADBSR(m) REG32(DMAC_DMADBSR(m))
+#define REG_DMAC_DMACKE(m) REG32(DMAC_DMACKE(m))
+
+// DMA request source register
+#define DMAC_DRSR_RS_BIT 0
+#define DMAC_DRSR_RS_MASK (0x3f << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_EXT (0 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_NAND (1 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_BCH_ENC (2 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_BCH_DEC (3 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_TSSIIN (9 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART3OUT (14 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART3IN (15 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART2OUT (16 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART2IN (17 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART1OUT (18 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART1IN (19 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSI0OUT (22 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSI0IN (23 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSC0OUT (26 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSC0IN (27 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_TCU (28 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SADC (29 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSC1OUT (30 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSC1IN (31 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSI1OUT (32 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSI1IN (33 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_PMOUT (34 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_PMIN (35 << DMAC_DRSR_RS_BIT)
+
+// DMA channel control/status register
+#define DMAC_DCCSR_NDES (1 << 31) /* descriptor (0) or not (1) ? */
+#define DMAC_DCCSR_DES8 (1 << 30) /* Descriptor 8 Word */
+#define DMAC_DCCSR_DES4 (0 << 30) /* Descriptor 4 Word */
+#define DMAC_DCCSR_CDOA_BIT 16 /* copy of DMA offset address */
+#define DMAC_DCCSR_CDOA_MASK (0xff << DMAC_DCCSR_CDOA_BIT)
+#define DMAC_DCCSR_BERR (1 << 7) /* BCH error within this transfer, Only for channel 0 */
+#define DMAC_DCCSR_INV (1 << 6) /* descriptor invalid */
+#define DMAC_DCCSR_AR (1 << 4) /* address error */
+#define DMAC_DCCSR_TT (1 << 3) /* transfer terminated */
+#define DMAC_DCCSR_HLT (1 << 2) /* DMA halted */
+#define DMAC_DCCSR_CT (1 << 1) /* count terminated */
+#define DMAC_DCCSR_EN (1 << 0) /* channel enable bit */
+
+// DMA channel command register
+#define DMAC_DCMD_EACKS_LOW (1 << 31) /* External DACK Output Level Select, active low */
+#define DMAC_DCMD_EACKS_HIGH (0 << 31) /* External DACK Output Level Select, active high */
+#define DMAC_DCMD_EACKM_WRITE (1 << 30) /* External DACK Output Mode Select, output in write cycle */
+#define DMAC_DCMD_EACKM_READ (0 << 30) /* External DACK Output Mode Select, output in read cycle */
+#define DMAC_DCMD_ERDM_BIT 28 /* External DREQ Detection Mode Select */
+#define DMAC_DCMD_ERDM_MASK (0x03 << DMAC_DCMD_ERDM_BIT)
+ #define DMAC_DCMD_ERDM_LOW (0 << DMAC_DCMD_ERDM_BIT)
+ #define DMAC_DCMD_ERDM_FALL (1 << DMAC_DCMD_ERDM_BIT)
+ #define DMAC_DCMD_ERDM_HIGH (2 << DMAC_DCMD_ERDM_BIT)
+ #define DMAC_DCMD_ERDM_RISE (3 << DMAC_DCMD_ERDM_BIT)
+#define DMAC_DCMD_BLAST (1 << 25) /* BCH last */
+#define DMAC_DCMD_SAI (1 << 23) /* source address increment */
+#define DMAC_DCMD_DAI (1 << 22) /* dest address increment */
+#define DMAC_DCMD_RDIL_BIT 16 /* request detection interval length */
+#define DMAC_DCMD_RDIL_MASK (0x0f << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_IGN (0 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_2 (1 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_4 (2 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_8 (3 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_12 (4 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_16 (5 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_20 (6 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_24 (7 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_28 (8 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_32 (9 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_48 (10 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_60 (11 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_64 (12 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_124 (13 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_128 (14 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_200 (15 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_SWDH_BIT 14 /* source port width */
+#define DMAC_DCMD_SWDH_MASK (0x03 << DMAC_DCMD_SWDH_BIT)
+ #define DMAC_DCMD_SWDH_32 (0 << DMAC_DCMD_SWDH_BIT)
+ #define DMAC_DCMD_SWDH_8 (1 << DMAC_DCMD_SWDH_BIT)
+ #define DMAC_DCMD_SWDH_16 (2 << DMAC_DCMD_SWDH_BIT)
+#define DMAC_DCMD_DWDH_BIT 12 /* dest port width */
+#define DMAC_DCMD_DWDH_MASK (0x03 << DMAC_DCMD_DWDH_BIT)
+ #define DMAC_DCMD_DWDH_32 (0 << DMAC_DCMD_DWDH_BIT)
+ #define DMAC_DCMD_DWDH_8 (1 << DMAC_DCMD_DWDH_BIT)
+ #define DMAC_DCMD_DWDH_16 (2 << DMAC_DCMD_DWDH_BIT)
+#define DMAC_DCMD_DS_BIT 8 /* transfer data size of a data unit */
+#define DMAC_DCMD_DS_MASK (0x07 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_32BIT (0 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_8BIT (1 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_16BIT (2 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_16BYTE (3 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_32BYTE (4 << DMAC_DCMD_DS_BIT)
+#define DMAC_DCMD_STDE (1 << 5) /* Stride Disable/Enable */
+#define DMAC_DCMD_DES_V (1 << 4) /* descriptor valid flag */
+#define DMAC_DCMD_DES_VM (1 << 3) /* descriptor valid mask: 1:support V-bit */
+#define DMAC_DCMD_DES_VIE (1 << 2) /* DMA valid error interrupt enable */
+#define DMAC_DCMD_TIE (1 << 1) /* DMA transfer interrupt enable */
+#define DMAC_DCMD_LINK (1 << 0) /* descriptor link enable */
+
+// DMA descriptor address register
+#define DMAC_DDA_BASE_BIT 12 /* descriptor base address */
+#define DMAC_DDA_BASE_MASK (0x0fffff << DMAC_DDA_BASE_BIT)
+#define DMAC_DDA_OFFSET_BIT 4 /* descriptor offset address */
+#define DMAC_DDA_OFFSET_MASK (0x0ff << DMAC_DDA_OFFSET_BIT)
+
+// DMA stride address register
+#define DMAC_DSD_TSD_BIT 16 /* target stride address */
+#define DMAC_DSD_TSD_MASK (0xffff << DMAC_DSD_TSD_BIT)
+#define DMAC_DSD_SSD_BIT 0 /* source stride address */
+#define DMAC_DSD_SSD_MASK (0xffff << DMAC_DSD_SSD_BIT)
+
+// DMA control register
+#define DMAC_DMACR_FMSC (1 << 31) /* MSC Fast DMA mode */
+#define DMAC_DMACR_FSSI (1 << 30) /* SSI Fast DMA mode */
+#define DMAC_DMACR_FTSSI (1 << 29) /* TSSI Fast DMA mode */
+#define DMAC_DMACR_FUART (1 << 28) /* UART Fast DMA mode */
+#define DMAC_DMACR_FAIC (1 << 27) /* AIC Fast DMA mode */
+#define DMAC_DMACR_PR_BIT 8 /* channel priority mode */
+#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_012345 (0 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_120345 (1 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_230145 (2 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_340125 (3 << DMAC_DMACR_PR_BIT)
+#define DMAC_DMACR_HLT (1 << 3) /* DMA halt flag */
+#define DMAC_DMACR_AR (1 << 2) /* address error flag */
+#define DMAC_DMACR_DMAE (1 << 0) /* DMA enable bit */
+
+// DMA doorbell register
+#define DMAC_DMADBR_DB5 (1 << 5) /* doorbell for channel 5 */
+#define DMAC_DMADBR_DB4 (1 << 4) /* doorbell for channel 4 */
+#define DMAC_DMADBR_DB3 (1 << 3) /* doorbell for channel 3 */
+#define DMAC_DMADBR_DB2 (1 << 2) /* doorbell for channel 2 */
+#define DMAC_DMADBR_DB1 (1 << 1) /* doorbell for channel 1 */
+#define DMAC_DMADBR_DB0 (1 << 0) /* doorbell for channel 0 */
+
+// DMA doorbell set register
+#define DMAC_DMADBSR_DBS5 (1 << 5) /* enable doorbell for channel 5 */
+#define DMAC_DMADBSR_DBS4 (1 << 4) /* enable doorbell for channel 4 */
+#define DMAC_DMADBSR_DBS3 (1 << 3) /* enable doorbell for channel 3 */
+#define DMAC_DMADBSR_DBS2 (1 << 2) /* enable doorbell for channel 2 */
+#define DMAC_DMADBSR_DBS1 (1 << 1) /* enable doorbell for channel 1 */
+#define DMAC_DMADBSR_DBS0 (1 << 0) /* enable doorbell for channel 0 */
+
+// DMA interrupt pending register
+#define DMAC_DMAIPR_CIRQ5 (1 << 5) /* irq pending status for channel 5 */
+#define DMAC_DMAIPR_CIRQ4 (1 << 4) /* irq pending status for channel 4 */
+#define DMAC_DMAIPR_CIRQ3 (1 << 3) /* irq pending status for channel 3 */
+#define DMAC_DMAIPR_CIRQ2 (1 << 2) /* irq pending status for channel 2 */
+#define DMAC_DMAIPR_CIRQ1 (1 << 1) /* irq pending status for channel 1 */
+#define DMAC_DMAIPR_CIRQ0 (1 << 0) /* irq pending status for channel 0 */
+
+
+/*************************************************************************
+ * GPIO (General-Purpose I/O Ports)
+ *************************************************************************/
+#define MAX_GPIO_NUM 192
+#define GPIO_WAKEUP (32 * 4 + 30)
+
+//n = 0,1,2,3,4,5 (PORTA, PORTB, PORTC, PORTD, PORTE, PORTF)
+#define GPIO_PXPIN(n) (GPIO_BASE + (0x00 + (n)*0x100)) /* PIN Level Register */
+#define GPIO_PXDAT(n) (GPIO_BASE + (0x10 + (n)*0x100)) /* Port Data Register */
+#define GPIO_PXDATS(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Data Set Register */
+#define GPIO_PXDATC(n) (GPIO_BASE + (0x18 + (n)*0x100)) /* Port Data Clear Register */
+#define GPIO_PXIM(n) (GPIO_BASE + (0x20 + (n)*0x100)) /* Interrupt Mask Register */
+#define GPIO_PXIMS(n) (GPIO_BASE + (0x24 + (n)*0x100)) /* Interrupt Mask Set Reg */
+#define GPIO_PXIMC(n) (GPIO_BASE + (0x28 + (n)*0x100)) /* Interrupt Mask Clear Reg */
+#define GPIO_PXPE(n) (GPIO_BASE + (0x30 + (n)*0x100)) /* Pull Enable Register */
+#define GPIO_PXPES(n) (GPIO_BASE + (0x34 + (n)*0x100)) /* Pull Enable Set Reg. */
+#define GPIO_PXPEC(n) (GPIO_BASE + (0x38 + (n)*0x100)) /* Pull Enable Clear Reg. */
+#define GPIO_PXFUN(n) (GPIO_BASE + (0x40 + (n)*0x100)) /* Function Register */
+#define GPIO_PXFUNS(n) (GPIO_BASE + (0x44 + (n)*0x100)) /* Function Set Register */
+#define GPIO_PXFUNC(n) (GPIO_BASE + (0x48 + (n)*0x100)) /* Function Clear Register */
+#define GPIO_PXSEL(n) (GPIO_BASE + (0x50 + (n)*0x100)) /* Select Register */
+#define GPIO_PXSELS(n) (GPIO_BASE + (0x54 + (n)*0x100)) /* Select Set Register */
+#define GPIO_PXSELC(n) (GPIO_BASE + (0x58 + (n)*0x100)) /* Select Clear Register */
+#define GPIO_PXDIR(n) (GPIO_BASE + (0x60 + (n)*0x100)) /* Direction Register */
+#define GPIO_PXDIRS(n) (GPIO_BASE + (0x64 + (n)*0x100)) /* Direction Set Register */
+#define GPIO_PXDIRC(n) (GPIO_BASE + (0x68 + (n)*0x100)) /* Direction Clear Register */
+#define GPIO_PXTRG(n) (GPIO_BASE + (0x70 + (n)*0x100)) /* Trigger Register */
+#define GPIO_PXTRGS(n) (GPIO_BASE + (0x74 + (n)*0x100)) /* Trigger Set Register */
+#define GPIO_PXTRGC(n) (GPIO_BASE + (0x78 + (n)*0x100)) /* Trigger Set Register */
+#define GPIO_PXFLG(n) (GPIO_BASE + (0x80 + (n)*0x100)) /* Port Flag Register */
+#define GPIO_PXFLGC(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Flag Clear Register */
+
+#define REG_GPIO_PXPIN(n) REG32(GPIO_PXPIN((n))) /* PIN level */
+#define REG_GPIO_PXDAT(n) REG32(GPIO_PXDAT((n))) /* 1: interrupt pending */
+#define REG_GPIO_PXDATS(n) REG32(GPIO_PXDATS((n)))
+#define REG_GPIO_PXDATC(n) REG32(GPIO_PXDATC((n)))
+#define REG_GPIO_PXIM(n) REG32(GPIO_PXIM((n))) /* 1: mask pin interrupt */
+#define REG_GPIO_PXIMS(n) REG32(GPIO_PXIMS((n)))
+#define REG_GPIO_PXIMC(n) REG32(GPIO_PXIMC((n)))
+#define REG_GPIO_PXPE(n) REG32(GPIO_PXPE((n))) /* 1: disable pull up/down */
+#define REG_GPIO_PXPES(n) REG32(GPIO_PXPES((n)))
+#define REG_GPIO_PXPEC(n) REG32(GPIO_PXPEC((n)))
+#define REG_GPIO_PXFUN(n) REG32(GPIO_PXFUN((n))) /* 0:GPIO or intr, 1:FUNC */
+#define REG_GPIO_PXFUNS(n) REG32(GPIO_PXFUNS((n)))
+#define REG_GPIO_PXFUNC(n) REG32(GPIO_PXFUNC((n)))
+#define REG_GPIO_PXSEL(n) REG32(GPIO_PXSEL((n))) /* 0:GPIO/Fun0,1:intr/fun1*/
+#define REG_GPIO_PXSELS(n) REG32(GPIO_PXSELS((n)))
+#define REG_GPIO_PXSELC(n) REG32(GPIO_PXSELC((n)))
+#define REG_GPIO_PXDIR(n) REG32(GPIO_PXDIR((n))) /* 0:input/low-level-trig/falling-edge-trig, 1:output/high-level-trig/rising-edge-trig */
+#define REG_GPIO_PXDIRS(n) REG32(GPIO_PXDIRS((n)))
+#define REG_GPIO_PXDIRC(n) REG32(GPIO_PXDIRC((n)))
+#define REG_GPIO_PXTRG(n) REG32(GPIO_PXTRG((n))) /* 0:level-trigger, 1:edge-trigger */
+#define REG_GPIO_PXTRGS(n) REG32(GPIO_PXTRGS((n)))
+#define REG_GPIO_PXTRGC(n) REG32(GPIO_PXTRGC((n)))
+#define REG_GPIO_PXFLG(n) REG32(GPIO_PXFLG((n))) /* interrupt flag */
+#define REG_GPIO_PXFLGC(n) REG32(GPIO_PXFLGC((n))) /* interrupt flag */
+
+
+/*************************************************************************
+ * UART
+ *************************************************************************/
+
+#define IRDA_BASE UART0_BASE
+#define UART_BASE UART0_BASE
+#define UART_OFF 0x1000
+
+/* Register Offset */
+#define OFF_RDR (0x00) /* R 8b H'xx */
+#define OFF_TDR (0x00) /* W 8b H'xx */
+#define OFF_DLLR (0x00) /* RW 8b H'00 */
+#define OFF_DLHR (0x04) /* RW 8b H'00 */
+#define OFF_IER (0x04) /* RW 8b H'00 */
+#define OFF_ISR (0x08) /* R 8b H'01 */
+#define OFF_FCR (0x08) /* W 8b H'00 */
+#define OFF_LCR (0x0C) /* RW 8b H'00 */
+#define OFF_MCR (0x10) /* RW 8b H'00 */
+#define OFF_LSR (0x14) /* R 8b H'00 */
+#define OFF_MSR (0x18) /* R 8b H'00 */
+#define OFF_SPR (0x1C) /* RW 8b H'00 */
+#define OFF_SIRCR (0x20) /* RW 8b H'00, UART0 */
+#define OFF_UMR (0x24) /* RW 8b H'00, UART M Register */
+#define OFF_UACR (0x28) /* RW 8b H'00, UART Add Cycle Register */
+
+/* Register Address */
+#define UART0_RDR (UART0_BASE + OFF_RDR)
+#define UART0_TDR (UART0_BASE + OFF_TDR)
+#define UART0_DLLR (UART0_BASE + OFF_DLLR)
+#define UART0_DLHR (UART0_BASE + OFF_DLHR)
+#define UART0_IER (UART0_BASE + OFF_IER)
+#define UART0_ISR (UART0_BASE + OFF_ISR)
+#define UART0_FCR (UART0_BASE + OFF_FCR)
+#define UART0_LCR (UART0_BASE + OFF_LCR)
+#define UART0_MCR (UART0_BASE + OFF_MCR)
+#define UART0_LSR (UART0_BASE + OFF_LSR)
+#define UART0_MSR (UART0_BASE + OFF_MSR)
+#define UART0_SPR (UART0_BASE + OFF_SPR)
+#define UART0_SIRCR (UART0_BASE + OFF_SIRCR)
+#define UART0_UMR (UART0_BASE + OFF_UMR)
+#define UART0_UACR (UART0_BASE + OFF_UACR)
+
+#define UART1_RDR (UART1_BASE + OFF_RDR)
+#define UART1_TDR (UART1_BASE + OFF_TDR)
+#define UART1_DLLR (UART1_BASE + OFF_DLLR)
+#define UART1_DLHR (UART1_BASE + OFF_DLHR)
+#define UART1_IER (UART1_BASE + OFF_IER)
+#define UART1_ISR (UART1_BASE + OFF_ISR)
+#define UART1_FCR (UART1_BASE + OFF_FCR)
+#define UART1_LCR (UART1_BASE + OFF_LCR)
+#define UART1_MCR (UART1_BASE + OFF_MCR)
+#define UART1_LSR (UART1_BASE + OFF_LSR)
+#define UART1_MSR (UART1_BASE + OFF_MSR)
+#define UART1_SPR (UART1_BASE + OFF_SPR)
+#define UART1_SIRCR (UART1_BASE + OFF_SIRCR)
+
+#define UART2_RDR (UART2_BASE + OFF_RDR)
+#define UART2_TDR (UART2_BASE + OFF_TDR)
+#define UART2_DLLR (UART2_BASE + OFF_DLLR)
+#define UART2_DLHR (UART2_BASE + OFF_DLHR)
+#define UART2_IER (UART2_BASE + OFF_IER)
+#define UART2_ISR (UART2_BASE + OFF_ISR)
+#define UART2_FCR (UART2_BASE + OFF_FCR)
+#define UART2_LCR (UART2_BASE + OFF_LCR)
+#define UART2_MCR (UART2_BASE + OFF_MCR)
+#define UART2_LSR (UART2_BASE + OFF_LSR)
+#define UART2_MSR (UART2_BASE + OFF_MSR)
+#define UART2_SPR (UART2_BASE + OFF_SPR)
+#define UART2_SIRCR (UART2_BASE + OFF_SIRCR)
+
+#define UART3_RDR (UART3_BASE + OFF_RDR)
+#define UART3_TDR (UART3_BASE + OFF_TDR)
+#define UART3_DLLR (UART3_BASE + OFF_DLLR)
+#define UART3_DLHR (UART3_BASE + OFF_DLHR)
+#define UART3_IER (UART3_BASE + OFF_IER)
+#define UART3_ISR (UART3_BASE + OFF_ISR)
+#define UART3_FCR (UART3_BASE + OFF_FCR)
+#define UART3_LCR (UART3_BASE + OFF_LCR)
+#define UART3_MCR (UART3_BASE + OFF_MCR)
+#define UART3_LSR (UART3_BASE + OFF_LSR)
+#define UART3_MSR (UART3_BASE + OFF_MSR)
+#define UART3_SPR (UART3_BASE + OFF_SPR)
+#define UART3_SIRCR (UART3_BASE + OFF_SIRCR)
+
+
+/*
+ * Define macros for UARTIER
+ * UART Interrupt Enable Register
+ */
+#define UARTIER_RIE (1 << 0) /* 0: receive fifo full interrupt disable */
+#define UARTIER_TIE (1 << 1) /* 0: transmit fifo empty interrupt disable */
+#define UARTIER_RLIE (1 << 2) /* 0: receive line status interrupt disable */
+#define UARTIER_MIE (1 << 3) /* 0: modem status interrupt disable */
+#define UARTIER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */
+
+/*
+ * Define macros for UARTISR
+ * UART Interrupt Status Register
+ */
+#define UARTISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */
+#define UARTISR_IID (7 << 1) /* Source of Interrupt */
+#define UARTISR_IID_MSI (0 << 1) /* Modem status interrupt */
+#define UARTISR_IID_THRI (1 << 1) /* Transmitter holding register empty */
+#define UARTISR_IID_RDI (2 << 1) /* Receiver data interrupt */
+#define UARTISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */
+#define UARTISR_IID_RTO (6 << 1) /* Receive timeout */
+#define UARTISR_FFMS (3 << 6) /* FIFO mode select, set when UARTFCR.FE is set to 1 */
+#define UARTISR_FFMS_NO_FIFO (0 << 6)
+#define UARTISR_FFMS_FIFO_MODE (3 << 6)
+
+/*
+ * Define macros for UARTFCR
+ * UART FIFO Control Register
+ */
+#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */
+#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */
+#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */
+#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */
+#define UARTFCR_UUE (1 << 4) /* 0: disable UART */
+#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */
+#define UARTFCR_RTRG_1 (0 << 6)
+#define UARTFCR_RTRG_4 (1 << 6)
+#define UARTFCR_RTRG_8 (2 << 6)
+#define UARTFCR_RTRG_15 (3 << 6)
+
+/*
+ * Define macros for UARTLCR
+ * UART Line Control Register
+ */
+#define UARTLCR_WLEN (3 << 0) /* word length */
+#define UARTLCR_WLEN_5 (0 << 0)
+#define UARTLCR_WLEN_6 (1 << 0)
+#define UARTLCR_WLEN_7 (2 << 0)
+#define UARTLCR_WLEN_8 (3 << 0)
+#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8
+ 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */
+#define UARTLCR_STOP1 (0 << 2)
+#define UARTLCR_STOP2 (1 << 2)
+#define UARTLCR_PE (1 << 3) /* 0: parity disable */
+#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */
+#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */
+#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */
+#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */
+
+/*
+ * Define macros for UARTLSR
+ * UART Line Status Register
+ */
+#define UARTLSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */
+#define UARTLSR_ORER (1 << 1) /* 0: no overrun error */
+#define UARTLSR_PER (1 << 2) /* 0: no parity error */
+#define UARTLSR_FER (1 << 3) /* 0; no framing error */
+#define UARTLSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */
+#define UARTLSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */
+#define UARTLSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */
+#define UARTLSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */
+
+/*
+ * Define macros for UARTMCR
+ * UART Modem Control Register
+ */
+#define UARTMCR_RTS (1 << 1) /* 0: RTS_ output high, 1: RTS_ output low */
+#define UARTMCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */
+#define UARTMCR_MCE (1 << 7) /* 0: modem function is disable */
+
+/*
+ * Define macros for UARTMSR
+ * UART Modem Status Register
+ */
+#define UARTMSR_CCTS (1 << 0) /* 1: a change on CTS_ pin */
+#define UARTMSR_CTS (1 << 4) /* 0: CTS_ pin is high */
+
+/*
+ * Define macros for SIRCR
+ * Slow IrDA Control Register
+ */
+#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: SIR mode */
+#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: SIR mode */
+#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length
+ 1: 0 pulse width is 1.6us for 115.2Kbps */
+#define SIRCR_TDPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */
+#define SIRCR_RDPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */
+
+
+/*************************************************************************
+ * AIC (AC97/I2S Controller)
+ *************************************************************************/
+#define AIC_FR (AIC_BASE + 0x000)
+#define AIC_CR (AIC_BASE + 0x004)
+#define AIC_ACCR1 (AIC_BASE + 0x008)
+#define AIC_ACCR2 (AIC_BASE + 0x00C)
+#define AIC_I2SCR (AIC_BASE + 0x010)
+#define AIC_SR (AIC_BASE + 0x014)
+#define AIC_ACSR (AIC_BASE + 0x018)
+#define AIC_I2SSR (AIC_BASE + 0x01C)
+#define AIC_ACCAR (AIC_BASE + 0x020)
+#define AIC_ACCDR (AIC_BASE + 0x024)
+#define AIC_ACSAR (AIC_BASE + 0x028)
+#define AIC_ACSDR (AIC_BASE + 0x02C)
+#define AIC_I2SDIV (AIC_BASE + 0x030)
+#define AIC_DR (AIC_BASE + 0x034)
+
+#define REG_AIC_FR REG32(AIC_FR)
+#define REG_AIC_CR REG32(AIC_CR)
+#define REG_AIC_ACCR1 REG32(AIC_ACCR1)
+#define REG_AIC_ACCR2 REG32(AIC_ACCR2)
+#define REG_AIC_I2SCR REG32(AIC_I2SCR)
+#define REG_AIC_SR REG32(AIC_SR)
+#define REG_AIC_ACSR REG32(AIC_ACSR)
+#define REG_AIC_I2SSR REG32(AIC_I2SSR)
+#define REG_AIC_ACCAR REG32(AIC_ACCAR)
+#define REG_AIC_ACCDR REG32(AIC_ACCDR)
+#define REG_AIC_ACSAR REG32(AIC_ACSAR)
+#define REG_AIC_ACSDR REG32(AIC_ACSDR)
+#define REG_AIC_I2SDIV REG32(AIC_I2SDIV)
+#define REG_AIC_DR REG32(AIC_DR)
+
+/* AIC Controller Configuration Register (AIC_FR) */
+
+#define AIC_FR_RFTH_BIT 12 /* Receive FIFO Threshold */
+#define AIC_FR_RFTH_MASK (0xf << AIC_FR_RFTH_BIT)
+#define AIC_FR_TFTH_BIT 8 /* Transmit FIFO Threshold */
+#define AIC_FR_TFTH_MASK (0xf << AIC_FR_TFTH_BIT)
+#define AIC_FR_LSMP (1 << 6) /* Play Zero sample or last sample */
+#define AIC_FR_ICDC (1 << 5) /* External(0) or Internal CODEC(1) */
+#define AIC_FR_AUSEL (1 << 4) /* AC97(0) or I2S/MSB-justified(1) */
+#define AIC_FR_RST (1 << 3) /* AIC registers reset */
+#define AIC_FR_BCKD (1 << 2) /* I2S BIT_CLK direction, 0:input,1:output */
+#define AIC_FR_SYNCD (1 << 1) /* I2S SYNC direction, 0:input,1:output */
+#define AIC_FR_ENB (1 << 0) /* AIC enable bit */
+
+/* AIC Controller Common Control Register (AIC_CR) */
+
+#define AIC_CR_OSS_BIT 19 /* Output Sample Size from memory (AIC V2 only) */
+#define AIC_CR_OSS_MASK (0x7 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_8BIT (0x0 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_16BIT (0x1 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_18BIT (0x2 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_20BIT (0x3 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_24BIT (0x4 << AIC_CR_OSS_BIT)
+#define AIC_CR_ISS_BIT 16 /* Input Sample Size from memory (AIC V2 only) */
+#define AIC_CR_ISS_MASK (0x7 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_8BIT (0x0 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_16BIT (0x1 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_18BIT (0x2 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_20BIT (0x3 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_24BIT (0x4 << AIC_CR_ISS_BIT)
+#define AIC_CR_RDMS (1 << 15) /* Receive DMA enable */
+#define AIC_CR_TDMS (1 << 14) /* Transmit DMA enable */
+#define AIC_CR_M2S (1 << 11) /* Mono to Stereo enable */
+#define AIC_CR_ENDSW (1 << 10) /* Endian switch enable */
+#define AIC_CR_AVSTSU (1 << 9) /* Signed <-> Unsigned toggle enable */
+#define AIC_CR_FLUSH_TX (1 << 8) /* Flush TX FIFO */
+#define AIC_CR_FLUSH_RX (1 << 7) /* Flush RX FIFO */
+#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */
+#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */
+#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */
+#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */
+#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */
+#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */
+#define AIC_CR_EREC (1 << 0) /* Enable Record Function */
+
+/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */
+
+#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */
+#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT)
+ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */
+ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */
+ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */
+ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */
+ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */
+ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */
+ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */
+ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */
+ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */
+ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */
+#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */
+#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT)
+ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */
+ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */
+ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */
+ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */
+ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */
+ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */
+ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */
+ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */
+ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */
+ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */
+
+/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */
+
+#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */
+#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */
+#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */
+#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */
+#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT)
+ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */
+ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */
+ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */
+ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */
+#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */
+#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT)
+ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */
+ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */
+ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */
+ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */
+#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */
+#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */
+#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */
+#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */
+
+/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */
+
+#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */
+#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */
+#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT)
+ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */
+ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */
+ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */
+ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */
+ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */
+#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */
+
+/* AIC Controller FIFO Status Register (AIC_SR) */
+
+#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */
+#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT)
+#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */
+#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT)
+#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */
+#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */
+#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */
+#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */
+
+/* AIC Controller AC-link Status Register (AIC_ACSR) */
+
+#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */
+#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */
+#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */
+#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */
+#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */
+#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */
+
+/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */
+
+#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */
+
+/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */
+
+#define AIC_ACCAR_CAR_BIT 0
+#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT)
+
+/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */
+
+#define AIC_ACCDR_CDR_BIT 0
+#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT)
+
+/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */
+
+#define AIC_ACSAR_SAR_BIT 0
+#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT)
+
+/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */
+
+#define AIC_ACSDR_SDR_BIT 0
+#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT)
+
+/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */
+
+#define AIC_I2SDIV_DIV_BIT 0
+#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT)
+ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */
+ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */
+ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */
+ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */
+ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */
+ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */
+
+
+/*************************************************************************
+ * ICDC (Internal CODEC)
+ *************************************************************************/
+
+#define ICDC_CKCFG (ICDC_BASE + 0x00a0) /* Clock Configure Register */
+#define ICDC_RGADW (ICDC_BASE + 0x00a4) /* internal register access control */
+#define ICDC_RGDATA (ICDC_BASE + 0x00a8) /* internal register data output */
+
+#define REG_ICDC_CKCFG REG32(ICDC_CKCFG)
+#define REG_ICDC_RGADW REG32(ICDC_RGADW)
+#define REG_ICDC_RGDATA REG32(ICDC_RGDATA)
+
+/* ICDC Clock Configure Register */
+#define ICDC_CKCFG_CKRDY (1 << 1)
+#define ICDC_CKCFG_SELAD (1 << 0)
+
+/* ICDC internal register access control Register */
+#define ICDC_RGADW_RGWR (1 << 16)
+#define ICDC_RGADW_RGADDR_BIT 8
+#define ICDC_RGADW_RGADDR_MASK (0x7f << ICDC_RGADW_RGADDR_BIT)
+#define ICDC_RGADW_RGDIN_BIT 0
+#define ICDC_RGADW_RGDIN_MASK (0xff << ICDC_RGADW_RGDIN_BIT)
+
+/* ICDC internal register data output Register */
+#define ICDC_RGDATA_IRQ (1 << 8)
+#define ICDC_RGDATA_RGDOUT_BIT 0
+#define ICDC_RGDATA_RGDOUT_MASK (0xff << ICDC_RGDATA_RGDOUT_BIT)
+
+/*************************************************************************
+ * PCM Controller
+ *************************************************************************/
+
+#define PCM_CTL (PCM_BASE + 0x000)
+#define PCM_CFG (PCM_BASE + 0x004)
+#define PCM_DP (PCM_BASE + 0x008)
+#define PCM_INTC (PCM_BASE + 0x00c)
+#define PCM_INTS (PCM_BASE + 0x010)
+#define PCM_DIV (PCM_BASE + 0x014)
+
+#define REG_PCM_CTL REG32(PCM_CTL)
+#define REG_PCM_CFG REG32(PCM_CFG)
+#define REG_PCM_DP REG32(PCM_DP)
+#define REG_PCM_INTC REG32(PCM_INTC)
+#define REG_PCM_INTS REG32(PCM_INTS)
+#define REG_PCM_DIV REG32(PCM_DIV)
+
+/* PCM Controller control Register (PCM_CTL) */
+
+#define PCM_CTL_ERDMA (1 << 9) /* Enable Receive DMA */
+#define PCM_CTL_ETDMA (1 << 8) /* Enable Transmit DMA */
+#define PCM_CTL_LSMP (1 << 7) /* Play Zero sample or last sample */
+#define PCM_CTL_ERPL (1 << 6) /* Enable Playing Back Function */
+#define PCM_CTL_EREC (1 << 5) /* Enable Recording Function */
+#define PCM_CTL_FLUSH (1 << 4) /* FIFO flush */
+#define PCM_CTL_RST (1 << 3) /* Reset PCM */
+#define PCM_CTL_CLKEN (1 << 1) /* Enable the clock division logic */
+#define PCM_CTL_PCMEN (1 << 0) /* Enable PCM module */
+
+/* PCM Controller configure Register (PCM_CFG) */
+
+#define PCM_CFG_SLOT_BIT 13
+#define PCM_CFG_SLOT_MASK (0x3 << PCM_CFG_SLOT_BIT)
+ #define PCM_CFG_SLOT_0 (0 << PCM_CFG_SLOT_BIT) /* Slot is 0 */
+ #define PCM_CFG_SLOT_1 (1 << PCM_CFG_SLOT_BIT) /* Slot is 1 */
+ #define PCM_CFG_SLOT_2 (2 << PCM_CFG_SLOT_BIT) /* Slot is 2 */
+ #define PCM_CFG_SLOT_3 (3 << PCM_CFG_SLOT_BIT) /* Slot is 3 */
+#define PCM_CFG_ISS_BIT 12
+#define PCM_CFG_ISS_MASK (0x1 << PCM_CFG_ISS_BIT)
+ #define PCM_CFG_ISS_8 (0 << PCM_CFG_ISS_BIT)
+ #define PCM_CFG_ISS_16 (1 << PCM_CFG_ISS_BIT)
+#define PCM_CFG_OSS_BIT 11
+#define PCM_CFG_OSS_MASK (0x1 << PCM_CFG_OSS_BIT)
+ #define PCM_CFG_OSS_8 (0 << PCM_CFG_OSS_BIT)
+ #define PCM_CFG_OSS_16 (1 << PCM_CFG_OSS_BIT)
+#define PCM_CFG_IMSBPOS (1 << 10)
+#define PCM_CFG_OMSBPOS (1 << 9)
+#define PCM_CFG_RFTH_BIT 5 /* Receive FIFO Threshold */
+#define PCM_CFG_RFTH_MASK (0xf << PCM_CFG_RFTH_BIT)
+#define PCM_CFG_TFTH_BIT 1 /* Transmit FIFO Threshold */
+#define PCM_CFG_TFTH_MASK (0xf << PCM_CFG_TFTH_BIT)
+#define PCM_CFG_MODE (0x0 << 0)
+
+/* PCM Controller interrupt control Register (PCM_INTC) */
+
+#define PCM_INTC_ETFS (1 << 3)
+#define PCM_INTC_ETUR (1 << 2)
+#define PCM_INTC_ERFS (1 << 1)
+#define PCM_INTC_EROR (1 << 0)
+
+/* PCM Controller interrupt status Register (PCM_INTS) */
+
+#define PCM_INTS_RSTS (1 << 14) /* Reset or flush has not complete */
+#define PCM_INTS_TFL_BIT 9
+#define PCM_INTS_TFL_MASK (0x1f << PCM_INTS_TFL_BIT)
+#define PCM_INTS_TFS (1 << 8) /* Tranmit FIFO Service Request */
+#define PCM_INTS_TUR (1 << 7) /* Transmit FIFO Under Run */
+#define PCM_INTS_RFL_BIT 2
+#define PCM_INTS_RFL_MASK (0x1f << PCM_INTS_RFL_BIT)
+#define PCM_INTS_RFS (1 << 1) /* Receive FIFO Service Request */
+#define PCM_INTS_ROR (1 << 0) /* Receive FIFO Over Run */
+
+/* PCM Controller clock division Register (PCM_DIV) */
+#define PCM_DIV_SYNL_BIT 11
+#define PCM_DIV_SYNL_MASK (0x3f << PCM_DIV_SYNL_BIT)
+#define PCM_DIV_SYNDIV_BIT 6
+#define PCM_DIV_SYNDIV_MASK (0x1f << PCM_DIV_SYNDIV_BIT)
+#define PCM_DIV_CLKDIV_BIT 0
+#define PCM_DIV_CLKDIV_MASK (0x3f << PCM_DIV_CLKDIV_BIT)
+
+
+/*************************************************************************
+ * I2C
+ *************************************************************************/
+#define I2C_DR (I2C_BASE + 0x000)
+#define I2C_CR (I2C_BASE + 0x004)
+#define I2C_SR (I2C_BASE + 0x008)
+#define I2C_GR (I2C_BASE + 0x00C)
+
+#define REG_I2C_DR REG8(I2C_DR)
+#define REG_I2C_CR REG8(I2C_CR)
+#define REG_I2C_SR REG8(I2C_SR)
+#define REG_I2C_GR REG16(I2C_GR)
+
+/* I2C Control Register (I2C_CR) */
+
+#define I2C_CR_IEN (1 << 4)
+#define I2C_CR_STA (1 << 3)
+#define I2C_CR_STO (1 << 2)
+#define I2C_CR_AC (1 << 1)
+#define I2C_CR_I2CE (1 << 0)
+
+/* I2C Status Register (I2C_SR) */
+
+#define I2C_SR_STX (1 << 4)
+#define I2C_SR_BUSY (1 << 3)
+#define I2C_SR_TEND (1 << 2)
+#define I2C_SR_DRF (1 << 1)
+#define I2C_SR_ACKF (1 << 0)
+
+
+/*************************************************************************
+ * SSI (Synchronous Serial Interface)
+ *************************************************************************/
+/* n = 0, 1 (SSI0, SSI1) */
+#define SSI_DR(n) (SSI_BASE + 0x000 + (n)*0x2000)
+#define SSI_CR0(n) (SSI_BASE + 0x004 + (n)*0x2000)
+#define SSI_CR1(n) (SSI_BASE + 0x008 + (n)*0x2000)
+#define SSI_SR(n) (SSI_BASE + 0x00C + (n)*0x2000)
+#define SSI_ITR(n) (SSI_BASE + 0x010 + (n)*0x2000)
+#define SSI_ICR(n) (SSI_BASE + 0x014 + (n)*0x2000)
+#define SSI_GR(n) (SSI_BASE + 0x018 + (n)*0x2000)
+
+#define REG_SSI_DR(n) REG32(SSI_DR(n))
+#define REG_SSI_CR0(n) REG16(SSI_CR0(n))
+#define REG_SSI_CR1(n) REG32(SSI_CR1(n))
+#define REG_SSI_SR(n) REG32(SSI_SR(n))
+#define REG_SSI_ITR(n) REG16(SSI_ITR(n))
+#define REG_SSI_ICR(n) REG8(SSI_ICR(n))
+#define REG_SSI_GR(n) REG16(SSI_GR(n))
+
+/* SSI Data Register (SSI_DR) */
+
+#define SSI_DR_GPC_BIT 0
+#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT)
+
+#define SSI_MAX_FIFO_ENTRIES 128 /* 128 txfifo and 128 rxfifo */
+
+/* SSI Control Register 0 (SSI_CR0) */
+
+#define SSI_CR0_SSIE (1 << 15)
+#define SSI_CR0_TIE (1 << 14)
+#define SSI_CR0_RIE (1 << 13)
+#define SSI_CR0_TEIE (1 << 12)
+#define SSI_CR0_REIE (1 << 11)
+#define SSI_CR0_LOOP (1 << 10)
+#define SSI_CR0_RFINE (1 << 9)
+#define SSI_CR0_RFINC (1 << 8)
+#define SSI_CR0_EACLRUN (1 << 7) /* hardware auto clear underrun when TxFifo no empty */
+#define SSI_CR0_FSEL (1 << 6)
+#define SSI_CR0_TFLUSH (1 << 2)
+#define SSI_CR0_RFLUSH (1 << 1)
+#define SSI_CR0_DISREV (1 << 0)
+
+/* SSI Control Register 1 (SSI_CR1) */
+
+#define SSI_CR1_FRMHL_BIT 30
+#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT)
+ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */
+ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */
+ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */
+ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */
+#define SSI_CR1_TFVCK_BIT 28
+#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT)
+#define SSI_CR1_TCKFI_BIT 26
+#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT)
+#define SSI_CR1_LFST (1 << 25)
+#define SSI_CR1_ITFRM (1 << 24)
+#define SSI_CR1_UNFIN (1 << 23)
+#define SSI_CR1_MULTS (1 << 22)
+#define SSI_CR1_FMAT_BIT 20
+#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT)
+ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */
+ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */
+ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */
+ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */
+#define SSI_CR1_TTRG_BIT 16 /* SSI1 TX trigger */
+#define SSI_CR1_TTRG_MASK (0xf << SSI_CR1_TTRG_BIT)
+#define SSI_CR1_MCOM_BIT 12
+#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT)
+ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */
+ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */
+ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */
+ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */
+ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */
+ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */
+ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */
+ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */
+ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */
+ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */
+ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */
+ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */
+ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */
+ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */
+ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */
+ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */
+#define SSI_CR1_RTRG_BIT 8 /* SSI RX trigger */
+#define SSI_CR1_RTRG_MASK (0xf << SSI_CR1_RTRG_BIT)
+#define SSI_CR1_FLEN_BIT 4
+#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT)
+#define SSI_CR1_PHA (1 << 1)
+#define SSI_CR1_POL (1 << 0)
+
+/* SSI Status Register (SSI_SR) */
+
+#define SSI_SR_TFIFONUM_BIT 16
+#define SSI_SR_TFIFONUM_MASK (0xff << SSI_SR_TFIFONUM_BIT)
+#define SSI_SR_RFIFONUM_BIT 8
+#define SSI_SR_RFIFONUM_MASK (0xff << SSI_SR_RFIFONUM_BIT)
+#define SSI_SR_END (1 << 7)
+#define SSI_SR_BUSY (1 << 6)
+#define SSI_SR_TFF (1 << 5)
+#define SSI_SR_RFE (1 << 4)
+#define SSI_SR_TFHE (1 << 3)
+#define SSI_SR_RFHF (1 << 2)
+#define SSI_SR_UNDR (1 << 1)
+#define SSI_SR_OVER (1 << 0)
+
+/* SSI Interval Time Control Register (SSI_ITR) */
+
+#define SSI_ITR_CNTCLK (1 << 15)
+#define SSI_ITR_IVLTM_BIT 0
+#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT)
+
+
+/*************************************************************************
+ * MSC
+ ************************************************************************/
+/* n = 0, 1 (MSC0, MSC1) */
+#define MSC_STRPCL(n) (MSC_BASE + (n)*0x1000 + 0x000)
+#define MSC_STAT(n) (MSC_BASE + (n)*0x1000 + 0x004)
+#define MSC_CLKRT(n) (MSC_BASE + (n)*0x1000 + 0x008)
+#define MSC_CMDAT(n) (MSC_BASE + (n)*0x1000 + 0x00C)
+#define MSC_RESTO(n) (MSC_BASE + (n)*0x1000 + 0x010)
+#define MSC_RDTO(n) (MSC_BASE + (n)*0x1000 + 0x014)
+#define MSC_BLKLEN(n) (MSC_BASE + (n)*0x1000 + 0x018)
+#define MSC_NOB(n) (MSC_BASE + (n)*0x1000 + 0x01C)
+#define MSC_SNOB(n) (MSC_BASE + (n)*0x1000 + 0x020)
+#define MSC_IMASK(n) (MSC_BASE + (n)*0x1000 + 0x024)
+#define MSC_IREG(n) (MSC_BASE + (n)*0x1000 + 0x028)
+#define MSC_CMD(n) (MSC_BASE + (n)*0x1000 + 0x02C)
+#define MSC_ARG(n) (MSC_BASE + (n)*0x1000 + 0x030)
+#define MSC_RES(n) (MSC_BASE + (n)*0x1000 + 0x034)
+#define MSC_RXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x038)
+#define MSC_TXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x03C)
+#define MSC_LPM(n) (MSC_BASE + (n)*0x1000 + 0x040)
+
+#define REG_MSC_STRPCL(n) REG16(MSC_STRPCL(n))
+#define REG_MSC_STAT(n) REG32(MSC_STAT(n))
+#define REG_MSC_CLKRT(n) REG16(MSC_CLKRT(n))
+#define REG_MSC_CMDAT(n) REG32(MSC_CMDAT(n))
+#define REG_MSC_RESTO(n) REG16(MSC_RESTO(n))
+#define REG_MSC_RDTO(n) REG16(MSC_RDTO(n))
+#define REG_MSC_BLKLEN(n) REG16(MSC_BLKLEN(n))
+#define REG_MSC_NOB(n) REG16(MSC_NOB(n))
+#define REG_MSC_SNOB(n) REG16(MSC_SNOB(n))
+#define REG_MSC_IMASK(n) REG32(MSC_IMASK(n))
+#define REG_MSC_IREG(n) REG16(MSC_IREG(n))
+#define REG_MSC_CMD(n) REG8(MSC_CMD(n))
+#define REG_MSC_ARG(n) REG32(MSC_ARG(n))
+#define REG_MSC_RES(n) REG16(MSC_RES(n))
+#define REG_MSC_RXFIFO(n) REG32(MSC_RXFIFO(n))
+#define REG_MSC_TXFIFO(n) REG32(MSC_TXFIFO(n))
+#define REG_MSC_LPM(n) REG32(MSC_LPM(n))
+
+/* MSC Clock and Control Register (MSC_STRPCL) */
+#define MSC_STRPCL_SEND_CCSD (1 << 15) /*send command completion signal disable to ceata */
+#define MSC_STRPCL_SEND_AS_CCSD (1 << 14) /*send internally generated stop after sending ccsd */
+#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7)
+#define MSC_STRPCL_EXIT_TRANSFER (1 << 6)
+#define MSC_STRPCL_START_READWAIT (1 << 5)
+#define MSC_STRPCL_STOP_READWAIT (1 << 4)
+#define MSC_STRPCL_RESET (1 << 3)
+#define MSC_STRPCL_START_OP (1 << 2)
+#define MSC_STRPCL_CLOCK_CONTROL_BIT 0
+#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT)
+ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */
+ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */
+
+/* MSC Status Register (MSC_STAT) */
+#define MSC_STAT_AUTO_CMD_DONE (1 << 31) /*12 is internally generated by controller has finished */
+#define MSC_STAT_IS_RESETTING (1 << 15)
+#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14)
+#define MSC_STAT_PRG_DONE (1 << 13)
+#define MSC_STAT_DATA_TRAN_DONE (1 << 12)
+#define MSC_STAT_END_CMD_RES (1 << 11)
+#define MSC_STAT_DATA_FIFO_AFULL (1 << 10)
+#define MSC_STAT_IS_READWAIT (1 << 9)
+#define MSC_STAT_CLK_EN (1 << 8)
+#define MSC_STAT_DATA_FIFO_FULL (1 << 7)
+#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6)
+#define MSC_STAT_CRC_RES_ERR (1 << 5)
+#define MSC_STAT_CRC_READ_ERROR (1 << 4)
+#define MSC_STAT_CRC_WRITE_ERROR_BIT 2
+#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT)
+ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */
+ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */
+ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */
+#define MSC_STAT_TIME_OUT_RES (1 << 1)
+#define MSC_STAT_TIME_OUT_READ (1 << 0)
+
+/* MSC Bus Clock Control Register (MSC_CLKRT) */
+#define MSC_CLKRT_CLK_RATE_BIT 0
+#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT)
+ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */
+
+/* MSC Command Sequence Control Register (MSC_CMDAT) */
+#define MSC_CMDAT_CCS_EXPECTED (1 << 31) /* interrupts are enabled in ce-ata */
+#define MSC_CMDAT_READ_CEATA (1 << 30)
+#define MSC_CMDAT_SDIO_PRDT (1 << 17) /* exact 2 cycle */
+#define MSC_CMDAT_SEND_AS_STOP (1 << 16)
+#define MSC_CMDAT_RTRG_BIT 14
+ #define MSC_CMDAT_RTRG_EQUALT_8 (0x0 << MSC_CMDAT_RTRG_BIT)
+ #define MSC_CMDAT_RTRG_EQUALT_16 (0x1 << MSC_CMDAT_RTRG_BIT) /* reset value */
+ #define MSC_CMDAT_RTRG_EQUALT_24 (0x2 << MSC_CMDAT_RTRG_BIT)
+
+#define MSC_CMDAT_TTRG_BIT 12
+ #define MSC_CMDAT_TTRG_LESS_8 (0x0 << MSC_CMDAT_TTRG_BIT)
+ #define MSC_CMDAT_TTRG_LESS_16 (0x1 << MSC_CMDAT_TTRG_BIT) /*reset value */
+ #define MSC_CMDAT_TTRG_LESS_24 (0x2 << MSC_CMDAT_TTRG_BIT)
+#define MSC_CMDAT_STOP_ABORT (1 << 11)
+#define MSC_CMDAT_BUS_WIDTH_BIT 9
+#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT)
+ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */
+ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */
+ #define MSC_CMDAT_BUS_WIDTH_8BIT (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) /* 8-bit data bus */
+#define MSC_CMDAT_DMA_EN (1 << 8)
+#define MSC_CMDAT_INIT (1 << 7)
+#define MSC_CMDAT_BUSY (1 << 6)
+#define MSC_CMDAT_STREAM_BLOCK (1 << 5)
+#define MSC_CMDAT_WRITE (1 << 4)
+#define MSC_CMDAT_READ (0 << 4)
+#define MSC_CMDAT_DATA_EN (1 << 3)
+#define MSC_CMDAT_RESPONSE_BIT 0
+#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT)
+ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */
+ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */
+ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */
+ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */
+ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */
+ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */
+ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */
+
+#define CMDAT_DMA_EN (1 << 8)
+#define CMDAT_INIT (1 << 7)
+#define CMDAT_BUSY (1 << 6)
+#define CMDAT_STREAM (1 << 5)
+#define CMDAT_WRITE (1 << 4)
+#define CMDAT_DATA_EN (1 << 3)
+
+/* MSC Interrupts Mask Register (MSC_IMASK) */
+#define MSC_IMASK_AUTO_CMD_DONE (1 << 8)
+#define MSC_IMASK_SDIO (1 << 7)
+#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6)
+#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5)
+#define MSC_IMASK_END_CMD_RES (1 << 2)
+#define MSC_IMASK_PRG_DONE (1 << 1)
+#define MSC_IMASK_DATA_TRAN_DONE (1 << 0)
+
+/* MSC Interrupts Status Register (MSC_IREG) */
+#define MSC_IREG_AUTO_CMD_DONE (1 << 8)
+#define MSC_IREG_SDIO (1 << 7)
+#define MSC_IREG_TXFIFO_WR_REQ (1 << 6)
+#define MSC_IREG_RXFIFO_RD_REQ (1 << 5)
+#define MSC_IREG_END_CMD_RES (1 << 2)
+#define MSC_IREG_PRG_DONE (1 << 1)
+#define MSC_IREG_DATA_TRAN_DONE (1 << 0)
+
+/* MSC Low Power Mode Register (MSC_LPM) */
+#define MSC_SET_LPM (1 << 0)
+
+/*************************************************************************
+ * EMC (External Memory Controller)
+ *************************************************************************/
+#define EMC_BCR (EMC_BASE + 0x00) /* Bus Control Register */
+#define EMC_SMCR0 (EMC_BASE + 0x10) /* Static Memory Control Register 0 */
+#define EMC_SMCR1 (EMC_BASE + 0x14) /* Static Memory Control Register 1 */
+#define EMC_SMCR2 (EMC_BASE + 0x18) /* Static Memory Control Register 2 */
+#define EMC_SMCR3 (EMC_BASE + 0x1c) /* Static Memory Control Register 3 */
+#define EMC_SMCR4 (EMC_BASE + 0x20) /* Static Memory Control Register 4 */
+#define EMC_SACR0 (EMC_BASE + 0x30) /* Static Memory Bank 0 Addr Config Reg */
+#define EMC_SACR1 (EMC_BASE + 0x34) /* Static Memory Bank 1 Addr Config Reg */
+#define EMC_SACR2 (EMC_BASE + 0x38) /* Static Memory Bank 2 Addr Config Reg */
+#define EMC_SACR3 (EMC_BASE + 0x3c) /* Static Memory Bank 3 Addr Config Reg */
+#define EMC_SACR4 (EMC_BASE + 0x40) /* Static Memory Bank 4 Addr Config Reg */
+
+#define EMC_NFCSR (EMC_BASE + 0x050) /* NAND Flash Control/Status Register */
+
+#define EMC_DMCR (EMC_BASE + 0x80) /* DRAM Control Register */
+#define EMC_RTCSR (EMC_BASE + 0x84) /* Refresh Time Control/Status Register */
+#define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */
+#define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */
+#define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */
+#define EMC_DMAR1 (EMC_BASE + 0x94) /* SDRAM Bank 1 Addr Config Register */
+#define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */
+
+#define REG_EMC_BCR REG32(EMC_BCR)
+#define REG_EMC_SMCR0 REG32(EMC_SMCR0)
+#define REG_EMC_SMCR1 REG32(EMC_SMCR1)
+#define REG_EMC_SMCR2 REG32(EMC_SMCR2)
+#define REG_EMC_SMCR3 REG32(EMC_SMCR3)
+#define REG_EMC_SMCR4 REG32(EMC_SMCR4)
+#define REG_EMC_SACR0 REG32(EMC_SACR0)
+#define REG_EMC_SACR1 REG32(EMC_SACR1)
+#define REG_EMC_SACR2 REG32(EMC_SACR2)
+#define REG_EMC_SACR3 REG32(EMC_SACR3)
+#define REG_EMC_SACR4 REG32(EMC_SACR4)
+
+#define REG_EMC_NFCSR REG32(EMC_NFCSR)
+
+#define REG_EMC_DMCR REG32(EMC_DMCR)
+#define REG_EMC_RTCSR REG16(EMC_RTCSR)
+#define REG_EMC_RTCNT REG16(EMC_RTCNT)
+#define REG_EMC_RTCOR REG16(EMC_RTCOR)
+#define REG_EMC_DMAR0 REG32(EMC_DMAR0)
+#define REG_EMC_DMAR1 REG32(EMC_DMAR1)
+
+/* Bus Control Register */
+#define EMC_BCR_BT_SEL_BIT 30
+#define EMC_BCR_BT_SEL_MASK (0x3 << EMC_BCR_BT_SEL_BIT)
+#define EMC_BCR_PK_SEL (1 << 24)
+#define EMC_BCR_BSR_MASK (1 << 2) /* Nand and SDRAM Bus Share Select: 0, share; 1, unshare */
+ #define EMC_BCR_BSR_SHARE (0 << 2)
+ #define EMC_BCR_BSR_UNSHARE (1 << 2)
+#define EMC_BCR_BRE (1 << 1)
+#define EMC_BCR_ENDIAN (1 << 0)
+
+/* Static Memory Control Register */
+#define EMC_SMCR_STRV_BIT 24
+#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT)
+#define EMC_SMCR_TAW_BIT 20
+#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT)
+#define EMC_SMCR_TBP_BIT 16
+#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT)
+#define EMC_SMCR_TAH_BIT 12
+#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT)
+#define EMC_SMCR_TAS_BIT 8
+#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT)
+#define EMC_SMCR_BW_BIT 6
+#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT)
+#define EMC_SMCR_BCM (1 << 3)
+#define EMC_SMCR_BL_BIT 1
+#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT)
+#define EMC_SMCR_SMT (1 << 0)
+
+/* Static Memory Bank Addr Config Reg */
+#define EMC_SACR_BASE_BIT 8
+#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT)
+#define EMC_SACR_MASK_BIT 0
+#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT)
+
+/* NAND Flash Control/Status Register */
+#define EMC_NFCSR_NFCE4 (1 << 7) /* NAND Flash Enable */
+#define EMC_NFCSR_NFE4 (1 << 6) /* NAND Flash FCE# Assertion Enable */
+#define EMC_NFCSR_NFCE3 (1 << 5)
+#define EMC_NFCSR_NFE3 (1 << 4)
+#define EMC_NFCSR_NFCE2 (1 << 3)
+#define EMC_NFCSR_NFE2 (1 << 2)
+#define EMC_NFCSR_NFCE1 (1 << 1)
+#define EMC_NFCSR_NFE1 (1 << 0)
+
+/* DRAM Control Register */
+#define EMC_DMCR_BW_BIT 31
+#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT)
+#define EMC_DMCR_CA_BIT 26
+#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT)
+#define EMC_DMCR_RMODE (1 << 25)
+#define EMC_DMCR_RFSH (1 << 24)
+#define EMC_DMCR_MRSET (1 << 23)
+#define EMC_DMCR_RA_BIT 20
+#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT)
+#define EMC_DMCR_BA_BIT 19
+#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT)
+#define EMC_DMCR_PDM (1 << 18)
+#define EMC_DMCR_EPIN (1 << 17)
+#define EMC_DMCR_MBSEL (1 << 16)
+#define EMC_DMCR_TRAS_BIT 13
+#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT)
+#define EMC_DMCR_RCD_BIT 11
+#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT)
+#define EMC_DMCR_TPC_BIT 8
+#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT)
+#define EMC_DMCR_TRWL_BIT 5
+#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT)
+#define EMC_DMCR_TRC_BIT 2
+#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT)
+#define EMC_DMCR_TCL_BIT 0
+#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT)
+
+/* Refresh Time Control/Status Register */
+#define EMC_RTCSR_SFR (1 << 8) /* self refresh flag */
+#define EMC_RTCSR_CMF (1 << 7)
+#define EMC_RTCSR_CKS_BIT 0
+#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT)
+
+/* SDRAM Bank Address Configuration Register */
+#define EMC_DMAR_BASE_BIT 8
+#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT)
+#define EMC_DMAR_MASK_BIT 0
+#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT)
+
+/* Mode Register of SDRAM bank 0 */
+#define EMC_SDMR_BM (1 << 9) /* Write Burst Mode */
+#define EMC_SDMR_OM_BIT 7 /* Operating Mode */
+#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT)
+ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT)
+#define EMC_SDMR_CAS_BIT 4 /* CAS Latency */
+#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT)
+#define EMC_SDMR_BT_BIT 3 /* Burst Type */
+#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT)
+ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) /* Sequential */
+ #define EMC_SDMR_BT_INT (1 << EMC_SDMR_BT_BIT) /* Interleave */
+#define EMC_SDMR_BL_BIT 0 /* Burst Length */
+#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT)
+
+#define EMC_SDMR_CAS2_16BIT \
+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2)
+#define EMC_SDMR_CAS2_32BIT \
+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4)
+#define EMC_SDMR_CAS3_16BIT \
+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2)
+#define EMC_SDMR_CAS3_32BIT \
+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4)
+
+
+/*************************************************************************
+ * CIM
+ *************************************************************************/
+#define CIM_CFG (CIM_BASE + 0x0000)
+#define CIM_CTRL (CIM_BASE + 0x0004)
+#define CIM_STATE (CIM_BASE + 0x0008)
+#define CIM_IID (CIM_BASE + 0x000C)
+#define CIM_RXFIFO (CIM_BASE + 0x0010)
+#define CIM_DA (CIM_BASE + 0x0020)
+#define CIM_FA (CIM_BASE + 0x0024)
+#define CIM_FID (CIM_BASE + 0x0028)
+#define CIM_CMD (CIM_BASE + 0x002C)
+#define CIM_SIZE (CIM_BASE + 0x0030)
+#define CIM_OFFSET (CIM_BASE + 0x0034)
+#define CIM_RAM_ADDR (CIM_BASE + 0x1000)
+
+#define REG_CIM_CFG REG32(CIM_CFG)
+#define REG_CIM_CTRL REG32(CIM_CTRL)
+#define REG_CIM_STATE REG32(CIM_STATE)
+#define REG_CIM_IID REG32(CIM_IID)
+#define REG_CIM_RXFIFO REG32(CIM_RXFIFO)
+#define REG_CIM_DA REG32(CIM_DA)
+#define REG_CIM_FA REG32(CIM_FA)
+#define REG_CIM_FID REG32(CIM_FID)
+#define REG_CIM_CMD REG32(CIM_CMD)
+#define REG_CIM_SIZE REG32(CIM_SIZE)
+#define REG_CIM_OFFSET REG32(CIM_OFFSET)
+
+#define CIM_CFG_ORDER_BIT 18
+#define CIM_CFG_ORDER_MASK (0x3 << CIM_CFG_ORDER_BIT)
+ #define CIM_CFG_ORDER_0 (0x0 << CIM_CFG_ORDER_BIT) /* Y0CbY1Cr; YCbCr */
+ #define CIM_CFG_ORDER_1 (0x1 << CIM_CFG_ORDER_BIT) /* Y0CrY1Cb; YCrCb */
+ #define CIM_CFG_ORDER_2 (0x2 << CIM_CFG_ORDER_BIT) /* CbY0CrY1; CbCrY */
+ #define CIM_CFG_ORDER_3 (0x3 << CIM_CFG_ORDER_BIT) /* CrY0CbY1; CrCbY */
+#define CIM_CFG_DF_BIT 16
+#define CIM_CFG_DF_MASK (0x3 << CIM_CFG_DF_BIT)
+ #define CIM_CFG_DF_YUV444 (0x1 << CIM_CFG_DF_BIT) /* YCbCr444 */
+ #define CIM_CFG_DF_YUV422 (0x2 << CIM_CFG_DF_BIT) /* YCbCr422 */
+ #define CIM_CFG_DF_ITU656 (0x3 << CIM_CFG_DF_BIT) /* ITU656 YCbCr422 */
+#define CIM_CFG_INV_DAT (1 << 15)
+#define CIM_CFG_VSP (1 << 14) /* VSYNC Polarity:0-rising edge active,1-falling edge active */
+#define CIM_CFG_HSP (1 << 13) /* HSYNC Polarity:0-rising edge active,1-falling edge active */
+#define CIM_CFG_PCP (1 << 12) /* PCLK working edge: 0-rising, 1-falling */
+#define CIM_CFG_DMA_BURST_TYPE_BIT 10
+#define CIM_CFG_DMA_BURST_TYPE_MASK (0x3 << CIM_CFG_DMA_BURST_TYPE_BIT)
+ #define CIM_CFG_DMA_BURST_INCR4 (0 << CIM_CFG_DMA_BURST_TYPE_BIT)
+ #define CIM_CFG_DMA_BURST_INCR8 (1 << CIM_CFG_DMA_BURST_TYPE_BIT) /* Suggested */
+ #define CIM_CFG_DMA_BURST_INCR16 (2 << CIM_CFG_DMA_BURST_TYPE_BIT) /* Suggested High speed AHB*/
+#define CIM_CFG_DUMMY_ZERO (1 << 9)
+#define CIM_CFG_EXT_VSYNC (1 << 8) /* Only for ITU656 Progressive mode */
+#define CIM_CFG_PACK_BIT 4
+#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) /* 11 22 33 44 0xY0CbY1Cr */
+ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) /* 22 33 44 11 0xCbY1CrY0 */
+ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) /* 33 44 11 22 0xY1CrY0Cb */
+ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) /* 44 11 22 33 0xCrY0CbY1 */
+ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) /* 44 33 22 11 0xCrY1CbY0 */
+ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) /* 33 22 11 44 0xY1CbY0Cr */
+ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) /* 22 11 44 33 0xCbY0CrY1 */
+ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) /* 11 44 33 22 0xY0CrY1Cb */
+#define CIM_CFG_BYPASS_BIT 2
+#define CIM_CFG_BYPASS_MASK (1 << CIM_CFG_BYPASS_BIT)
+ #define CIM_CFG_BYPASS (1 << CIM_CFG_BYPASS_BIT)
+#define CIM_CFG_DSM_BIT 0
+#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT)
+ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */
+ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */
+ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */
+
+/* CIM Control Register (CIM_CTRL) */
+#define CIM_CTRL_EEOF_LINE_BIT 20
+#define CIM_CTRL_EEOF_LINE_MASK (0xfff << CIM_CTRL_EEOF_LINE_BIT)
+#define CIM_CTRL_FRC_BIT 16
+#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT)
+ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */
+ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */
+ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */
+ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */
+ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */
+ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */
+ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */
+ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */
+ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */
+ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */
+ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */
+ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */
+ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */
+ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */
+ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */
+ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */
+
+#define CIM_CTRL_DMA_EEOF (1 << 15) /* Enable EEOF interrupt */
+#define CIM_CTRL_WIN_EN (1 << 14)
+#define CIM_CTRL_VDDM (1 << 13) /* VDD interrupt enable */
+#define CIM_CTRL_DMA_SOFM (1 << 12)
+#define CIM_CTRL_DMA_EOFM (1 << 11)
+#define CIM_CTRL_DMA_STOPM (1 << 10)
+#define CIM_CTRL_RXF_TRIGM (1 << 9)
+#define CIM_CTRL_RXF_OFM (1 << 8)
+#define CIM_CTRL_DMA_SYNC (1 << 7) /*when change DA, do frame sync */
+#define CIM_CTRL_RXF_TRIG_BIT 3
+#define CIM_CTRL_RXF_TRIG_MASK (0xf << CIM_CTRL_RXF_TRIG_BIT) /* trigger value = (n+1)*burst_type */
+
+#define CIM_CTRL_DMA_EN (1 << 2) /* Enable DMA */
+#define CIM_CTRL_RXF_RST (1 << 1) /* RxFIFO reset */
+#define CIM_CTRL_ENA (1 << 0) /* Enable CIM */
+
+/* CIM State Register (CIM_STATE) */
+#define CIM_STATE_DMA_EEOF (1 << 7) /* DMA Line EEOf irq */
+#define CIM_STATE_DMA_SOF (1 << 6) /* DMA start irq */
+#define CIM_STATE_DMA_EOF (1 << 5) /* DMA end irq */
+#define CIM_STATE_DMA_STOP (1 << 4) /* DMA stop irq */
+#define CIM_STATE_RXF_OF (1 << 3) /* RXFIFO over flow irq */
+#define CIM_STATE_RXF_TRIG (1 << 2) /* RXFIFO triger meet irq */
+#define CIM_STATE_RXF_EMPTY (1 << 1) /* RXFIFO empty irq */
+#define CIM_STATE_VDD (1 << 0) /* CIM disabled irq */
+
+/* CIM DMA Command Register (CIM_CMD) */
+
+#define CIM_CMD_SOFINT (1 << 31) /* enable DMA start irq */
+#define CIM_CMD_EOFINT (1 << 30) /* enable DMA end irq */
+#define CIM_CMD_EEOFINT (1 << 29) /* enable DMA EEOF irq */
+#define CIM_CMD_STOP (1 << 28) /* enable DMA stop irq */
+#define CIM_CMD_OFRCV (1 << 27) /* enable recovery when TXFiFo overflow */
+#define CIM_CMD_LEN_BIT 0
+#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT)
+
+/* CIM Window-Image Size Register (CIM_SIZE) */
+#define CIM_SIZE_LPF_BIT 16 /* Lines per freame for csc output image */
+#define CIM_SIZE_LPF_MASK (0x1fff << CIM_SIZE_LPF_BIT)
+#define CIM_SIZE_PPL_BIT 0 /* Pixels per line for csc output image, should be an even number */
+#define CIM_SIZE_PPL_MASK (0x1fff << CIM_SIZE_PPL_BIT)
+
+/* CIM Image Offset Register (CIM_OFFSET) */
+#define CIM_OFFSET_V_BIT 16 /* Vertical offset */
+#define CIM_OFFSET_V_MASK (0xfff << CIM_OFFSET_V_BIT)
+#define CIM_OFFSET_H_BIT 0 /* Horizontal offset, should be an enen number */
+#define CIM_OFFSET_H_MASK (0xfff << CIM_OFFSET_H_BIT) /*OFFSET_H should be even number*/
+
+/*************************************************************************
+ * SADC (Smart A/D Controller)
+ *************************************************************************/
+
+#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */
+#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */
+#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */
+#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/
+#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */
+#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */
+#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */
+#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC PBAT Data Register */
+#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC SADCIN Data Register */
+#define SADC_ADCLK (SADC_BASE + 0x28) /* ADC Clock Divide Register */
+
+#define REG_SADC_ENA REG8(SADC_ENA)
+#define REG_SADC_CFG REG32(SADC_CFG)
+#define REG_SADC_CTRL REG8(SADC_CTRL)
+#define REG_SADC_STATE REG8(SADC_STATE)
+#define REG_SADC_SAMETIME REG16(SADC_SAMETIME)
+#define REG_SADC_WAITTIME REG16(SADC_WAITTIME)
+#define REG_SADC_TSDAT REG32(SADC_TSDAT)
+#define REG_SADC_BATDAT REG16(SADC_BATDAT)
+#define REG_SADC_SADDAT REG16(SADC_SADDAT)
+#define REG_SADC_ADCLK REG32(SADC_ADCLK)
+
+/* ADC Enable Register */
+#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */
+#define SADC_ENA_ENTR_SLP (1 << 6) /* Touch Screen Enable */
+#define SADC_ENA_EXIT_SLP (1 << 5) /* Touch Screen Enable */
+#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */
+#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */
+#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */
+
+/* ADC Configure Register */
+#define SADC_CFG_SPZZ (1 << 31) //added
+#define SADC_CFG_EXIN (1 << 30)
+#define SADC_CFG_CLKOUT_NUM_BIT 16
+#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT)
+#define SADC_CFG_DNUM(x) (((x) - 1) << SADC_CFG_CLKOUT_NUM_BIT)
+#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */
+#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */
+#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT)
+ #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT)
+ #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT)
+ #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT)
+#define SADC_CFG_SNUM_BIT 10 /* Sample Number */
+#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT)
+#define SADC_CFG_SNUM(x) (((x) - 1) << SADC_CFG_SNUM_BIT)//added
+#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */
+#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT)
+#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */
+#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */
+#define SADC_CFG_CMD_BIT 0 /* ADC Command */
+#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT)
+ #define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */
+ #define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */
+ #define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */
+ #define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */
+ #define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */
+ #define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */
+ #define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */
+ #define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */
+ #define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */
+ #define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */
+ #define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */
+ #define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */
+ #define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */
+
+/* ADC Control Register */
+#define SADC_CTRL_SLPENDM (1 << 5) /* sleep Interrupt Mask */
+#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */
+#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */
+#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */
+#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */
+#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */
+
+/* ADC Status Register */
+#define SADC_STATE_SLEEPND (1 << 5) /* Pen Down Interrupt Flag */
+#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */
+#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */
+#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */
+#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */
+#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */
+
+/* ADC Touch Screen Data Register */
+#define SADC_TSDAT_DATA0_BIT 0
+#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT)
+#define SADC_TSDAT_TYPE0 (1 << 15)
+#define SADC_TSDAT_DATA1_BIT 16
+#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT)
+#define SADC_TSDAT_TYPE1 (1 << 31)
+
+/* ADC Clock Divide Register */
+#define SADC_ADCLK_CLKDIV_10_BIT 16
+#define SADC_ADCLK_CLKDIV_10_MASK (0x7f << SADC_ADCLK_CLKDIV_10_BIT)
+#define SADC_ADCLK_CLKDIV_BIT 0
+#define SADC_ADCLK_CLKDIV_MASK (0x3f << SADC_ADCLK_CLKDIV_BIT)
+
+/*************************************************************************
+ * SLCD (Smart LCD Controller)
+ *************************************************************************/
+
+#define SLCD_CFG (SLCD_BASE + 0xA0) /* SLCD Configure Register */
+#define SLCD_CTRL (SLCD_BASE + 0xA4) /* SLCD Control Register */
+#define SLCD_STATE (SLCD_BASE + 0xA8) /* SLCD Status Register */
+#define SLCD_DATA (SLCD_BASE + 0xAC) /* SLCD Data Register */
+
+#define REG_SLCD_CFG REG32(SLCD_CFG)
+#define REG_SLCD_CTRL REG8(SLCD_CTRL)
+#define REG_SLCD_STATE REG8(SLCD_STATE)
+#define REG_SLCD_DATA REG32(SLCD_DATA)
+
+/* SLCD Configure Register */
+#define SLCD_CFG_DWIDTH_BIT 10
+#define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_18BIT (0 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_16BIT (1 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_8BIT_x3 (2 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_8BIT_x2 (3 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_8BIT_x1 (4 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_24BIT (5 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_9BIT_x2 (7 << SLCD_CFG_DWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_BIT (8)
+#define SLCD_CFG_CWIDTH_MASK (0x7 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_16BIT (0 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_8BIT (1 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_18BIT (2 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_24BIT (3 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CS_ACTIVE_LOW (0 << 4)
+#define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4)
+#define SLCD_CFG_RS_CMD_LOW (0 << 3)
+#define SLCD_CFG_RS_CMD_HIGH (1 << 3)
+#define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1)
+#define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1)
+#define SLCD_CFG_TYPE_PARALLEL (0 << 0)
+#define SLCD_CFG_TYPE_SERIAL (1 << 0)
+
+/* SLCD Control Register */
+#define SLCD_CTRL_DMA_MODE (1 << 2)
+#define SLCD_CTRL_DMA_START (1 << 1)
+#define SLCD_CTRL_DMA_EN (1 << 0)
+
+/* SLCD Status Register */
+#define SLCD_STATE_BUSY (1 << 0)
+
+/* SLCD Data Register */
+#define SLCD_DATA_RS_DATA (0 << 31)
+#define SLCD_DATA_RS_COMMAND (1 << 31)
+
+/*************************************************************************
+ * LCD (LCD Controller)
+ *************************************************************************/
+#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */
+#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */
+#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */
+
+#define LCD_OSDC (LCD_BASE + 0x100) /* LCD OSD Configure Register */
+#define LCD_OSDCTRL (LCD_BASE + 0x104) /* LCD OSD Control Register */
+#define LCD_OSDS (LCD_BASE + 0x108) /* LCD OSD Status Register */
+#define LCD_BGC (LCD_BASE + 0x10C) /* LCD Background Color Register */
+#define LCD_KEY0 (LCD_BASE + 0x110) /* LCD Foreground Color Key Register 0 */
+#define LCD_KEY1 (LCD_BASE + 0x114) /* LCD Foreground Color Key Register 1 */
+#define LCD_ALPHA (LCD_BASE + 0x118) /* LCD ALPHA Register */
+#define LCD_IPUR (LCD_BASE + 0x11C) /* LCD IPU Restart Register */
+
+#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */
+#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */
+#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */
+
+#define LCD_XYP0 (LCD_BASE + 0x120) /* Foreground 0 XY Position Register */
+#define LCD_XYP1 (LCD_BASE + 0x124) /* Foreground 1 XY Position Register */
+#define LCD_SIZE0 (LCD_BASE + 0x128) /* Foreground 0 Size Register */
+#define LCD_SIZE1 (LCD_BASE + 0x12C) /* Foreground 1 Size Register */
+#define LCD_RGBC (LCD_BASE + 0x90) /* RGB Controll Register */
+
+#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */
+#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */
+#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */
+#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */
+#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */
+#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */
+#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */
+#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */
+#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */
+#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */
+#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */
+#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */
+#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */
+#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */
+#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */
+
+#define LCD_OFFS0 (LCD_BASE + 0x60) /* DMA Offsize Register 0 */
+#define LCD_PW0 (LCD_BASE + 0x64) /* DMA Page Width Register 0 */
+#define LCD_CNUM0 (LCD_BASE + 0x68) /* DMA Command Counter Register 0 */
+#define LCD_DESSIZE0 (LCD_BASE + 0x6C) /* Foreground Size in Descriptor 0 Register*/
+#define LCD_OFFS1 (LCD_BASE + 0x70) /* DMA Offsize Register 1 */
+#define LCD_PW1 (LCD_BASE + 0x74) /* DMA Page Width Register 1 */
+#define LCD_CNUM1 (LCD_BASE + 0x78) /* DMA Command Counter Register 1 */
+#define LCD_DESSIZE1 (LCD_BASE + 0x7C) /* Foreground Size in Descriptor 1 Register*/
+
+#define REG_LCD_CFG REG32(LCD_CFG)
+#define REG_LCD_CTRL REG32(LCD_CTRL)
+#define REG_LCD_STATE REG32(LCD_STATE)
+
+#define REG_LCD_OSDC REG16(LCD_OSDC)
+#define REG_LCD_OSDCTRL REG16(LCD_OSDCTRL)
+#define REG_LCD_OSDS REG16(LCD_OSDS)
+#define REG_LCD_BGC REG32(LCD_BGC)
+#define REG_LCD_KEY0 REG32(LCD_KEY0)
+#define REG_LCD_KEY1 REG32(LCD_KEY1)
+#define REG_LCD_ALPHA REG8(LCD_ALPHA)
+#define REG_LCD_IPUR REG32(LCD_IPUR)
+
+#define REG_LCD_VAT REG32(LCD_VAT)
+#define REG_LCD_DAH REG32(LCD_DAH)
+#define REG_LCD_DAV REG32(LCD_DAV)
+
+#define REG_LCD_XYP0 REG32(LCD_XYP0)
+#define REG_LCD_XYP1 REG32(LCD_XYP1)
+#define REG_LCD_SIZE0 REG32(LCD_SIZE0)
+#define REG_LCD_SIZE1 REG32(LCD_SIZE1)
+#define REG_LCD_RGBC REG16(LCD_RGBC)
+
+#define REG_LCD_VSYNC REG32(LCD_VSYNC)
+#define REG_LCD_HSYNC REG32(LCD_HSYNC)
+#define REG_LCD_PS REG32(LCD_PS)
+#define REG_LCD_CLS REG32(LCD_CLS)
+#define REG_LCD_SPL REG32(LCD_SPL)
+#define REG_LCD_REV REG32(LCD_REV)
+#define REG_LCD_IID REG32(LCD_IID)
+#define REG_LCD_DA0 REG32(LCD_DA0)
+#define REG_LCD_SA0 REG32(LCD_SA0)
+#define REG_LCD_FID0 REG32(LCD_FID0)
+#define REG_LCD_CMD0 REG32(LCD_CMD0)
+#define REG_LCD_DA1 REG32(LCD_DA1)
+#define REG_LCD_SA1 REG32(LCD_SA1)
+#define REG_LCD_FID1 REG32(LCD_FID1)
+#define REG_LCD_CMD1 REG32(LCD_CMD1)
+
+#define REG_LCD_OFFS0 REG32(LCD_OFFS0)
+#define REG_LCD_PW0 REG32(LCD_PW0)
+#define REG_LCD_CNUM0 REG32(LCD_CNUM0)
+#define REG_LCD_DESSIZE0 REG32(LCD_DESSIZE0)
+#define REG_LCD_OFFS1 REG32(LCD_OFFS1)
+#define REG_LCD_PW1 REG32(LCD_PW1)
+#define REG_LCD_CNUM1 REG32(LCD_CNUM1)
+#define REG_LCD_DESSIZE1 REG32(LCD_DESSIZE1)
+
+/* LCD Configure Register */
+#define LCD_CFG_LCDPIN_BIT 31 /* LCD pins selection */
+#define LCD_CFG_LCDPIN_MASK (0x1 << LCD_CFG_LCDPIN_BIT)
+ #define LCD_CFG_LCDPIN_LCD (0x0 << LCD_CFG_LCDPIN_BIT)
+ #define LCD_CFG_LCDPIN_SLCD (0x1 << LCD_CFG_LCDPIN_BIT)
+#define LCD_CFG_TVEPEH (1 << 30) /* TVE PAL enable extra halfline signal */
+#define LCD_CFG_FUHOLD (1 << 29) /* hold pixel clock when outFIFO underrun */
+#define LCD_CFG_NEWDES (1 << 28) /* use new descripter. old: 4words, new:8words */
+#define LCD_CFG_PALBP (1 << 27) /* bypass data format and alpha blending */
+#define LCD_CFG_TVEN (1 << 26) /* indicate the terminal is lcd or tv */
+#define LCD_CFG_RECOVER (1 << 25) /* Auto recover when output fifo underrun */
+#define LCD_CFG_DITHER (1 << 24) /* Dither function */
+#define LCD_CFG_PSM (1 << 23) /* PS signal mode */
+#define LCD_CFG_CLSM (1 << 22) /* CLS signal mode */
+#define LCD_CFG_SPLM (1 << 21) /* SPL signal mode */
+#define LCD_CFG_REVM (1 << 20) /* REV signal mode */
+#define LCD_CFG_HSYNM (1 << 19) /* HSYNC signal mode */
+#define LCD_CFG_PCLKM (1 << 18) /* PCLK signal mode */
+#define LCD_CFG_INVDAT (1 << 17) /* Inverse output data */
+#define LCD_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */
+#define LCD_CFG_PSP (1 << 15) /* PS pin reset state */
+#define LCD_CFG_CLSP (1 << 14) /* CLS pin reset state */
+#define LCD_CFG_SPLP (1 << 13) /* SPL pin reset state */
+#define LCD_CFG_REVP (1 << 12) /* REV pin reset state */
+#define LCD_CFG_HSP (1 << 11) /* HSYNC polarity:0-active high,1-active low */
+#define LCD_CFG_PCP (1 << 10) /* PCLK polarity:0-rising,1-falling */
+#define LCD_CFG_DEP (1 << 9) /* DE polarity:0-active high,1-active low */
+#define LCD_CFG_VSP (1 << 8) /* VSYNC polarity:0-rising,1-falling */
+#define LCD_CFG_MODE_TFT_18BIT (1 << 7) /* 18bit TFT */
+#define LCD_CFG_MODE_TFT_16BIT (0 << 7) /* 16bit TFT */
+#define LCD_CFG_MODE_TFT_24BIT (1 << 6) /* 24bit TFT */
+#define LCD_CFG_PDW_BIT 4 /* STN pins utilization */
+#define LCD_CFG_PDW_MASK (0x3 << LCD_DEV_PDW_BIT)
+#define LCD_CFG_PDW_1 (0 << LCD_CFG_PDW_BIT) /* LCD_D[0] */
+ #define LCD_CFG_PDW_2 (1 << LCD_CFG_PDW_BIT) /* LCD_D[0:1] */
+ #define LCD_CFG_PDW_4 (2 << LCD_CFG_PDW_BIT) /* LCD_D[0:3]/LCD_D[8:11] */
+ #define LCD_CFG_PDW_8 (3 << LCD_CFG_PDW_BIT) /* LCD_D[0:7]/LCD_D[8:15] */
+#define LCD_CFG_MODE_BIT 0 /* Display Device Mode Select */
+#define LCD_CFG_MODE_MASK (0x0f << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_CFG_MODE_BIT) /* 16,18 bit TFT */
+ #define LCD_CFG_MODE_SPECIAL_TFT_1 (1 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SPECIAL_TFT_2 (2 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SPECIAL_TFT_3 (3 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SERIAL_TFT (12 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_LCM (13 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SLCD LCD_CFG_MODE_LCM
+
+/* LCD Control Register */
+#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */
+#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT)
+ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */
+ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */
+ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */
+ #define LCD_CTRL_BST_32 (3 << LCD_CTRL_BST_BIT) /* 32-word */
+#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode(foreground 0 in OSD mode) */
+#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode(foreground 0 in OSD mode) */
+#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */
+#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */
+#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT)
+ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */
+ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */
+ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */
+#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */
+#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT)
+#define LCD_CTRL_VGA (1 << 15) /* VGA interface enable */
+#define LCD_CTRL_DACTE (1 << 14) /* DAC loop back test */
+#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */
+#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */
+#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */
+#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */
+#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */
+#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */
+#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */
+#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */
+#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */
+#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */
+#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */
+#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */
+#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT)
+ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */
+ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */
+ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */
+ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */
+ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */
+ #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */
+ #define LCD_CTRL_BPP_CMPS_24 (6 << LCD_CTRL_BPP_BIT) /* 24 compress bpp */
+
+/* LCD Status Register */
+#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */
+#define LCD_STATE_EOF (1 << 5) /* EOF Flag */
+#define LCD_STATE_SOF (1 << 4) /* SOF Flag */
+#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */
+#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */
+#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */
+#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */
+
+/* OSD Configure Register */
+#define LCD_OSDC_SOFM1 (1 << 15) /* Start of frame interrupt mask for foreground 1 */
+#define LCD_OSDC_EOFM1 (1 << 14) /* End of frame interrupt mask for foreground 1 */
+#define LCD_OSDC_SOFM0 (1 << 11) /* Start of frame interrupt mask for foreground 0 */
+#define LCD_OSDC_EOFM0 (1 << 10) /* End of frame interrupt mask for foreground 0 */
+#define LCD_OSDC_F1EN (1 << 4) /* enable foreground 1 */
+#define LCD_OSDC_F0EN (1 << 3) /* enable foreground 0 */
+#define LCD_OSDC_ALPHAEN (1 << 2) /* enable alpha blending */
+#define LCD_OSDC_ALPHAMD (1 << 1) /* alpha blending mode */
+#define LCD_OSDC_OSDEN (1 << 0) /* OSD mode enable */
+
+/* OSD Controll Register */
+#define LCD_OSDCTRL_IPU (1 << 15) /* input data from IPU */
+#define LCD_OSDCTRL_RGB565 (0 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */
+#define LCD_OSDCTRL_RGB555 (1 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */
+#define LCD_OSDCTRL_CHANGES (1 << 3) /* Change size flag */
+#define LCD_OSDCTRL_OSDBPP_BIT 0 /* Bits Per Pixel of OSD Channel 1 */
+#define LCD_OSDCTRL_OSDBPP_MASK (0x7<<LCD_OSDCTRL_OSDBPP_BIT) /* Bits Per Pixel of OSD Channel 1's MASK */
+ #define LCD_OSDCTRL_OSDBPP_16 (4 << LCD_OSDCTRL_OSDBPP_BIT) /* RGB 15,16 bit*/
+ #define LCD_OSDCTRL_OSDBPP_15_16 (4 << LCD_OSDCTRL_OSDBPP_BIT) /* RGB 15,16 bit*/
+ #define LCD_OSDCTRL_OSDBPP_18_24 (5 << LCD_OSDCTRL_OSDBPP_BIT) /* RGB 18,24 bit*/
+ #define LCD_OSDCTRL_OSDBPP_CMPS_24 (6 << LCD_OSDCTRL_OSDBPP_BIT) /* RGB 18,24 bit*/
+
+/* OSD State Register */
+#define LCD_OSDS_SOF1 (1 << 15) /* Start of frame flag for foreground 1 */
+#define LCD_OSDS_EOF1 (1 << 14) /* End of frame flag for foreground 1 */
+#define LCD_OSDS_SOF0 (1 << 11) /* Start of frame flag for foreground 0 */
+#define LCD_OSDS_EOF0 (1 << 10) /* End of frame flag for foreground 0 */
+#define LCD_OSDS_READY (1 << 0) /* Read for accept the change */
+
+/* Background Color Register */
+#define LCD_BGC_RED_OFFSET (1 << 16) /* Red color offset */
+#define LCD_BGC_RED_MASK (0xFF<<LCD_BGC_RED_OFFSET)
+#define LCD_BGC_GREEN_OFFSET (1 << 8) /* Green color offset */
+#define LCD_BGC_GREEN_MASK (0xFF<<LCD_BGC_GREEN_OFFSET)
+#define LCD_BGC_BLUE_OFFSET (1 << 0) /* Blue color offset */
+#define LCD_BGC_BLUE_MASK (0xFF<<LCD_BGC_BLUE_OFFSET)
+
+/* Foreground Color Key Register 0,1(foreground 0, foreground 1) */
+#define LCD_KEY_KEYEN (1 << 31) /* enable color key */
+#define LCD_KEY_KEYMD (1 << 30) /* color key mode */
+#define LCD_KEY_RED_OFFSET 16 /* Red color offset */
+#define LCD_KEY_RED_MASK (0xFF<<LCD_KEY_RED_OFFSET)
+#define LCD_KEY_GREEN_OFFSET 8 /* Green color offset */
+#define LCD_KEY_GREEN_MASK (0xFF<<LCD_KEY_GREEN_OFFSET)
+#define LCD_KEY_BLUE_OFFSET 0 /* Blue color offset */
+#define LCD_KEY_BLUE_MASK (0xFF<<LCD_KEY_BLUE_OFFSET)
+#define LCD_KEY_MASK (LCD_KEY_RED_MASK|LCD_KEY_GREEN_MASK|LCD_KEY_BLUE_MASK)
+
+/* IPU Restart Register */
+#define LCD_IPUR_IPUREN (1 << 31) /* IPU restart function enable*/
+#define LCD_IPUR_IPURMASK (0xFFFFFF) /* IPU restart value mask*/
+
+/* RGB Control Register */
+#define LCD_RGBC_RGBDM (1 << 15) /* enable RGB Dummy data */
+#define LCD_RGBC_DMM (1 << 14) /* RGB Dummy mode */
+#define LCD_RGBC_YCC (1 << 8) /* RGB to YCC */
+#define LCD_RGBC_ODDRGB_BIT 4 /* odd line serial RGB data arrangement */
+#define LCD_RGBC_ODDRGB_MASK (0x7<<LCD_RGBC_ODDRGB_BIT)
+ #define LCD_RGBC_ODD_RGB 0
+ #define LCD_RGBC_ODD_RBG 1
+ #define LCD_RGBC_ODD_GRB 2
+ #define LCD_RGBC_ODD_GBR 3
+ #define LCD_RGBC_ODD_BRG 4
+ #define LCD_RGBC_ODD_BGR 5
+#define LCD_RGBC_EVENRGB_BIT 0 /* even line serial RGB data arrangement */
+#define LCD_RGBC_EVENRGB_MASK (0x7<<LCD_RGBC_EVENRGB_BIT)
+ #define LCD_RGBC_EVEN_RGB 0
+ #define LCD_RGBC_EVEN_RBG 1
+ #define LCD_RGBC_EVEN_GRB 2
+ #define LCD_RGBC_EVEN_GBR 3
+ #define LCD_RGBC_EVEN_BRG 4
+ #define LCD_RGBC_EVEN_BGR 5
+
+/* Vertical Synchronize Register */
+#define LCD_VSYNC_VPS_BIT 16 /* VSYNC pulse start in line clock, fixed to 0 */
+#define LCD_VSYNC_VPS_MASK (0xffff << LCD_VSYNC_VPS_BIT)
+#define LCD_VSYNC_VPE_BIT 0 /* VSYNC pulse end in line clock */
+#define LCD_VSYNC_VPE_MASK (0xffff << LCD_VSYNC_VPS_BIT)
+
+/* Horizontal Synchronize Register */
+#define LCD_HSYNC_HPS_BIT 16 /* HSYNC pulse start position in dot clock */
+#define LCD_HSYNC_HPS_MASK (0xffff << LCD_HSYNC_HPS_BIT)
+#define LCD_HSYNC_HPE_BIT 0 /* HSYNC pulse end position in dot clock */
+#define LCD_HSYNC_HPE_MASK (0xffff << LCD_HSYNC_HPE_BIT)
+
+/* Virtual Area Setting Register */
+#define LCD_VAT_HT_BIT 16 /* Horizontal Total size in dot clock */
+#define LCD_VAT_HT_MASK (0xffff << LCD_VAT_HT_BIT)
+#define LCD_VAT_VT_BIT 0 /* Vertical Total size in dot clock */
+#define LCD_VAT_VT_MASK (0xffff << LCD_VAT_VT_BIT)
+
+/* Display Area Horizontal Start/End Point Register */
+#define LCD_DAH_HDS_BIT 16 /* Horizontal display area start in dot clock */
+#define LCD_DAH_HDS_MASK (0xffff << LCD_DAH_HDS_BIT)
+#define LCD_DAH_HDE_BIT 0 /* Horizontal display area end in dot clock */
+#define LCD_DAH_HDE_MASK (0xffff << LCD_DAH_HDE_BIT)
+
+/* Display Area Vertical Start/End Point Register */
+#define LCD_DAV_VDS_BIT 16 /* Vertical display area start in line clock */
+#define LCD_DAV_VDS_MASK (0xffff << LCD_DAV_VDS_BIT)
+#define LCD_DAV_VDE_BIT 0 /* Vertical display area end in line clock */
+#define LCD_DAV_VDE_MASK (0xffff << LCD_DAV_VDE_BIT)
+
+/* Foreground XY Position Register */
+#define LCD_XYP_YPOS_BIT 16 /* Y position bit of foreground 0 or 1 */
+#define LCD_XYP_YPOS_MASK (0xffff << LCD_XYP_YPOS_BIT)
+#define LCD_XYP_XPOS_BIT 0 /* X position bit of foreground 0 or 1 */
+#define LCD_XYP_XPOS_MASK (0xffff << LCD_XYP_XPOS_BIT)
+
+/* PS Signal Setting */
+#define LCD_PS_PSS_BIT 16 /* PS signal start position in dot clock */
+#define LCD_PS_PSS_MASK (0xffff << LCD_PS_PSS_BIT)
+#define LCD_PS_PSE_BIT 0 /* PS signal end position in dot clock */
+#define LCD_PS_PSE_MASK (0xffff << LCD_PS_PSE_BIT)
+
+/* CLS Signal Setting */
+#define LCD_CLS_CLSS_BIT 16 /* CLS signal start position in dot clock */
+#define LCD_CLS_CLSS_MASK (0xffff << LCD_CLS_CLSS_BIT)
+#define LCD_CLS_CLSE_BIT 0 /* CLS signal end position in dot clock */
+#define LCD_CLS_CLSE_MASK (0xffff << LCD_CLS_CLSE_BIT)
+
+/* SPL Signal Setting */
+#define LCD_SPL_SPLS_BIT 16 /* SPL signal start position in dot clock */
+#define LCD_SPL_SPLS_MASK (0xffff << LCD_SPL_SPLS_BIT)
+#define LCD_SPL_SPLE_BIT 0 /* SPL signal end position in dot clock */
+#define LCD_SPL_SPLE_MASK (0xffff << LCD_SPL_SPLE_BIT)
+
+/* REV Signal Setting */
+#define LCD_REV_REVS_BIT 16 /* REV signal start position in dot clock */
+#define LCD_REV_REVS_MASK (0xffff << LCD_REV_REVS_BIT)
+
+/* DMA Command Register */
+#define LCD_CMD_SOFINT (1 << 31)
+#define LCD_CMD_EOFINT (1 << 30)
+#define LCD_CMD_CMD (1 << 29) /* indicate command in slcd mode */
+#define LCD_CMD_PAL (1 << 28)
+#define LCD_CMD_LEN_BIT 0
+#define LCD_CMD_LEN_MASK (0xffffff << LCD_CMD_LEN_BIT)
+
+/* DMA Offsize Register 0,1 */
+
+/* DMA Page Width Register 0,1 */
+
+/* DMA Command Counter Register 0,1 */
+
+/* Foreground 0,1 Size Register */
+#define LCD_DESSIZE_HEIGHT_BIT 16 /* height of foreground 1 */
+#define LCD_DESSIZE_HEIGHT_MASK (0xffff << LCD_DESSIZE_HEIGHT_BIT)
+#define LCD_DESSIZE_WIDTH_BIT 0 /* width of foreground 1 */
+#define LCD_DESSIZE_WIDTH_MASK (0xffff << LCD_DESSIZE_WIDTH_BIT)
+
+/*************************************************************************
+ * TVE (TV Encoder Controller)
+ *************************************************************************/
+#define TVE_CTRL (TVE_BASE + 0x40) /* TV Encoder Control register */
+#define TVE_FRCFG (TVE_BASE + 0x44) /* Frame configure register */
+#define TVE_SLCFG1 (TVE_BASE + 0x50) /* TV signal level configure register 1 */
+#define TVE_SLCFG2 (TVE_BASE + 0x54) /* TV signal level configure register 2*/
+#define TVE_SLCFG3 (TVE_BASE + 0x58) /* TV signal level configure register 3*/
+#define TVE_LTCFG1 (TVE_BASE + 0x60) /* Line timing configure register 1 */
+#define TVE_LTCFG2 (TVE_BASE + 0x64) /* Line timing configure register 2 */
+#define TVE_CFREQ (TVE_BASE + 0x70) /* Chrominance sub-carrier frequency configure register */
+#define TVE_CPHASE (TVE_BASE + 0x74) /* Chrominance sub-carrier phase configure register */
+#define TVE_CBCRCFG (TVE_BASE + 0x78) /* Chrominance filter configure register */
+#define TVE_WSSCR (TVE_BASE + 0x80) /* Wide screen signal control register */
+#define TVE_WSSCFG1 (TVE_BASE + 0x84) /* Wide screen signal configure register 1 */
+#define TVE_WSSCFG2 (TVE_BASE + 0x88) /* Wide screen signal configure register 2 */
+#define TVE_WSSCFG3 (TVE_BASE + 0x8c) /* Wide screen signal configure register 3 */
+
+#define REG_TVE_CTRL REG32(TVE_CTRL)
+#define REG_TVE_FRCFG REG32(TVE_FRCFG)
+#define REG_TVE_SLCFG1 REG32(TVE_SLCFG1)
+#define REG_TVE_SLCFG2 REG32(TVE_SLCFG2)
+#define REG_TVE_SLCFG3 REG32(TVE_SLCFG3)
+#define REG_TVE_LTCFG1 REG32(TVE_LTCFG1)
+#define REG_TVE_LTCFG2 REG32(TVE_LTCFG2)
+#define REG_TVE_CFREQ REG32(TVE_CFREQ)
+#define REG_TVE_CPHASE REG32(TVE_CPHASE)
+#define REG_TVE_CBCRCFG REG32(TVE_CBCRCFG)
+#define REG_TVE_WSSCR REG32(TVE_WSSCR)
+#define REG_TVE_WSSCFG1 REG32(TVE_WSSCFG1)
+#define REG_TVE_WSSCFG2 REG32(TVE_WSSCFG2)
+#define REG_TVE_WSSCFG3 REG32(TVE_WSSCFG3)
+
+/* TV Encoder Control register */
+#define TVE_CTRL_EYCBCR (1 << 25) /* YCbCr_enable */
+#define TVE_CTRL_ECVBS (1 << 24) /* cvbs_enable */
+#define TVE_CTRL_DAPD3 (1 << 23) /* DAC 3 power down */
+#define TVE_CTRL_DAPD2 (1 << 22) /* DAC 2 power down */
+#define TVE_CTRL_DAPD1 (1 << 21) /* DAC 1 power down */
+#define TVE_CTRL_DAPD (1 << 20) /* power down all DACs */
+#define TVE_CTRL_YCDLY_BIT 16
+#define TVE_CTRL_YCDLY_MASK (0x7 << TVE_CTRL_YCDLY_BIT)
+#define TVE_CTRL_CGAIN_BIT 14
+#define TVE_CTRL_CGAIN_MASK (0x3 << TVE_CTRL_CGAIN_BIT)
+ #define TVE_CTRL_CGAIN_FULL (0 << TVE_CTRL_CGAIN_BIT) /* gain = 1 */
+ #define TVE_CTRL_CGAIN_QUTR (1 << TVE_CTRL_CGAIN_BIT) /* gain = 1/4 */
+ #define TVE_CTRL_CGAIN_HALF (2 << TVE_CTRL_CGAIN_BIT) /* gain = 1/2 */
+ #define TVE_CTRL_CGAIN_THREE_QURT (3 << TVE_CTRL_CGAIN_BIT) /* gain = 3/4 */
+#define TVE_CTRL_CBW_BIT 12
+#define TVE_CTRL_CBW_MASK (0x3 << TVE_CTRL_CBW_BIT)
+ #define TVE_CTRL_CBW_NARROW (0 << TVE_CTRL_CBW_BIT) /* Narrow band */
+ #define TVE_CTRL_CBW_WIDE (1 << TVE_CTRL_CBW_BIT) /* Wide band */
+ #define TVE_CTRL_CBW_EXTRA (2 << TVE_CTRL_CBW_BIT) /* Extra wide band */
+ #define TVE_CTRL_CBW_ULTRA (3 << TVE_CTRL_CBW_BIT) /* Ultra wide band */
+#define TVE_CTRL_SYNCT (1 << 9)
+#define TVE_CTRL_PAL (1 << 8)
+#define TVE_CTRL_FINV (1 << 7) /* invert_top:1-invert top and bottom fields. */
+#define TVE_CTRL_ZBLACK (1 << 6) /* bypass_yclamp:1-Black of luminance (Y) input is 0.*/
+#define TVE_CTRL_CR1ST (1 << 5) /* uv_order:0-Cb before Cr,1-Cr before Cb */
+#define TVE_CTRL_CLBAR (1 << 4) /* Color bar mode:0-Output input video to TV,1-Output color bar to TV */
+#define TVE_CTRL_SWRST (1 << 0) /* Software reset:1-TVE is reset */
+
+/* Signal level configure register 1 */
+#define TVE_SLCFG1_BLACKL_BIT 0
+#define TVE_SLCFG1_BLACKL_MASK (0x3ff << TVE_SLCFG1_BLACKL_BIT)
+#define TVE_SLCFG1_WHITEL_BIT 16
+#define TVE_SLCFG1_WHITEL_MASK (0x3ff << TVE_SLCFG1_WHITEL_BIT)
+
+/* Signal level configure register 2 */
+#define TVE_SLCFG2_BLANKL_BIT 0
+#define TVE_SLCFG2_BLANKL_MASK (0x3ff << TVE_SLCFG2_BLANKL_BIT)
+#define TVE_SLCFG2_VBLANKL_BIT 16
+#define TVE_SLCFG2_VBLANKL_MASK (0x3ff << TVE_SLCFG2_VBLANKL_BIT)
+
+/* Signal level configure register 3 */
+#define TVE_SLCFG3_SYNCL_BIT 0
+#define TVE_SLCFG3_SYNCL_MASK (0xff << TVE_SLCFG3_SYNCL_BIT)
+
+/* Line timing configure register 1 */
+#define TVE_LTCFG1_BACKP_BIT 0
+#define TVE_LTCFG1_BACKP_MASK (0x7f << TVE_LTCFG1_BACKP_BIT)
+#define TVE_LTCFG1_HSYNCW_BIT 8
+#define TVE_LTCFG1_HSYNCW_MASK (0x7f << TVE_LTCFG1_HSYNCW_BIT)
+#define TVE_LTCFG1_FRONTP_BIT 16
+#define TVE_LTCFG1_FRONTP_MASK (0x1f << TVE_LTCFG1_FRONTP_BIT)
+
+/* Line timing configure register 2 */
+#define TVE_LTCFG2_BURSTW_BIT 0
+#define TVE_LTCFG2_BURSTW_MASK (0x3f << TVE_LTCFG2_BURSTW_BIT)
+#define TVE_LTCFG2_PREBW_BIT 8
+#define TVE_LTCFG2_PREBW_MASK (0x1f << TVE_LTCFG2_PREBW_BIT)
+#define TVE_LTCFG2_ACTLIN_BIT 16
+#define TVE_LTCFG2_ACTLIN_MASK (0x7ff << TVE_LTCFG2_ACTLIN_BIT)
+
+/* Chrominance sub-carrier phase configure register */
+#define TVE_CPHASE_CCRSTP_BIT 0
+#define TVE_CPHASE_CCRSTP_MASK (0x3 << TVE_CPHASE_CCRSTP_BIT)
+ #define TVE_CPHASE_CCRSTP_8 (0 << TVE_CPHASE_CCRSTP_BIT) /* Every 8 field */
+ #define TVE_CPHASE_CCRSTP_4 (1 << TVE_CPHASE_CCRSTP_BIT) /* Every 4 field */
+ #define TVE_CPHASE_CCRSTP_2 (2 << TVE_CPHASE_CCRSTP_BIT) /* Every 2 lines */
+ #define TVE_CPHASE_CCRSTP_0 (3 << TVE_CPHASE_CCRSTP_BIT) /* Never */
+#define TVE_CPHASE_ACTPH_BIT 16
+#define TVE_CPHASE_ACTPH_MASK (0xff << TVE_CPHASE_ACTPH_BIT)
+#define TVE_CPHASE_INITPH_BIT 24
+#define TVE_CPHASE_INITPH_MASK (0xff << TVE_CPHASE_INITPH_BIT)
+
+/* Chrominance filter configure register */
+#define TVE_CBCRCFG_CRGAIN_BIT 0
+#define TVE_CBCRCFG_CRGAIN_MASK (0xff << TVE_CBCRCFG_CRGAIN_BIT)
+#define TVE_CBCRCFG_CBGAIN_BIT 8
+#define TVE_CBCRCFG_CBGAIN_MASK (0xff << TVE_CBCRCFG_CBGAIN_BIT)
+#define TVE_CBCRCFG_CRBA_BIT 16
+#define TVE_CBCRCFG_CRBA_MASK (0xff << TVE_CBCRCFG_CRBA_BIT)
+#define TVE_CBCRCFG_CBBA_BIT 24
+#define TVE_CBCRCFG_CBBA_MASK (0xff << TVE_CBCRCFG_CBBA_BIT)
+
+/* Frame configure register */
+#define TVE_FRCFG_NLINE_BIT 0
+#define TVE_FRCFG_NLINE_MASK (0x3ff << TVE_FRCFG_NLINE_BIT)
+#define TVE_FRCFG_L1ST_BIT 16
+#define TVE_FRCFG_L1ST_MASK (0xff << TVE_FRCFG_L1ST_BIT)
+
+/* Wide screen signal control register */
+#define TVE_WSSCR_EWSS0_BIT 0
+#define TVE_WSSCR_EWSS1_BIT 1
+#define TVE_WSSCR_WSSTP_BIT 2
+#define TVE_WSSCR_WSSCKBP_BIT 3
+#define TVE_WSSCR_WSSEDGE_BIT 4
+#define TVE_WSSCR_WSSEDGE_MASK (0x7 << TVE_WSSCR_WSSEDGE_BIT)
+#define TVE_WSSCR_ENCH_BIT 8
+#define TVE_WSSCR_NCHW_BIT 9
+#define TVE_WSSCR_NCHFREQ_BIT 12
+#define TVE_WSSCR_NCHFREQ_MASK (0x7 << TVE_WSSCR_NCHFREQ_BIT)
+
+/*************************************************************************
+ * USB Device
+ *************************************************************************/
+#define USB_BASE UDC_BASE
+
+#define USB_REG_FADDR (USB_BASE + 0x00) /* Function Address 8-bit */
+#define USB_REG_POWER (USB_BASE + 0x01) /* Power Managemetn 8-bit */
+#define USB_REG_INTRIN (USB_BASE + 0x02) /* Interrupt IN 16-bit */
+#define USB_REG_INTROUT (USB_BASE + 0x04) /* Interrupt OUT 16-bit */
+#define USB_REG_INTRINE (USB_BASE + 0x06) /* Intr IN enable 16-bit */
+#define USB_REG_INTROUTE (USB_BASE + 0x08) /* Intr OUT enable 16-bit */
+#define USB_REG_INTRUSB (USB_BASE + 0x0a) /* Interrupt USB 8-bit */
+#define USB_REG_INTRUSBE (USB_BASE + 0x0b) /* Interrupt USB Enable 8-bit */
+#define USB_REG_FRAME (USB_BASE + 0x0c) /* Frame number 16-bit */
+#define USB_REG_INDEX (USB_BASE + 0x0e) /* Index register 8-bit */
+#define USB_REG_TESTMODE (USB_BASE + 0x0f) /* USB test mode 8-bit */
+
+#define USB_REG_CSR0 (USB_BASE + 0x12) /* EP0 CSR 8-bit */
+#define USB_REG_INMAXP (USB_BASE + 0x10) /* EP1-2 IN Max Pkt Size 16-bit */
+#define USB_REG_INCSR (USB_BASE + 0x12) /* EP1-2 IN CSR LSB 8/16bit */
+#define USB_REG_INCSRH (USB_BASE + 0x13) /* EP1-2 IN CSR MSB 8-bit */
+#define USB_REG_OUTMAXP (USB_BASE + 0x14) /* EP1 OUT Max Pkt Size 16-bit */
+#define USB_REG_OUTCSR (USB_BASE + 0x16) /* EP1 OUT CSR LSB 8/16bit */
+#define USB_REG_OUTCSRH (USB_BASE + 0x17) /* EP1 OUT CSR MSB 8-bit */
+#define USB_REG_OUTCOUNT (USB_BASE + 0x18) /* bytes in EP0/1 OUT FIFO 16-bit */
+
+#define USB_FIFO_EP0 (USB_BASE + 0x20)
+#define USB_FIFO_EP1 (USB_BASE + 0x24)
+#define USB_FIFO_EP2 (USB_BASE + 0x28)
+
+#define USB_REG_EPINFO (USB_BASE + 0x78) /* Endpoint information */
+#define USB_REG_RAMINFO (USB_BASE + 0x79) /* RAM information */
+
+#define USB_REG_INTR (USB_BASE + 0x200) /* DMA pending interrupts */
+#define USB_REG_CNTL1 (USB_BASE + 0x204) /* DMA channel 1 control */
+#define USB_REG_ADDR1 (USB_BASE + 0x208) /* DMA channel 1 AHB memory addr */
+#define USB_REG_COUNT1 (USB_BASE + 0x20c) /* DMA channel 1 byte count */
+#define USB_REG_CNTL2 (USB_BASE + 0x214) /* DMA channel 2 control */
+#define USB_REG_ADDR2 (USB_BASE + 0x218) /* DMA channel 2 AHB memory addr */
+#define USB_REG_COUNT2 (USB_BASE + 0x21c) /* DMA channel 2 byte count */
+
+
+/* Power register bit masks */
+#define USB_POWER_SUSPENDM 0x01
+#define USB_POWER_RESUME 0x04
+#define USB_POWER_HSMODE 0x10
+#define USB_POWER_HSENAB 0x20
+#define USB_POWER_SOFTCONN 0x40
+
+/* Interrupt register bit masks */
+#define USB_INTR_SUSPEND 0x01
+#define USB_INTR_RESUME 0x02
+#define USB_INTR_RESET 0x04
+
+#define USB_INTR_EP0 0x0001
+#define USB_INTR_INEP1 0x0002
+#define USB_INTR_INEP2 0x0004
+#define USB_INTR_OUTEP1 0x0002
+
+/* CSR0 bit masks */
+#define USB_CSR0_OUTPKTRDY 0x01
+#define USB_CSR0_INPKTRDY 0x02
+#define USB_CSR0_SENTSTALL 0x04
+#define USB_CSR0_DATAEND 0x08
+#define USB_CSR0_SETUPEND 0x10
+#define USB_CSR0_SENDSTALL 0x20
+#define USB_CSR0_SVDOUTPKTRDY 0x40
+#define USB_CSR0_SVDSETUPEND 0x80
+
+/* Endpoint CSR register bits */
+#define USB_INCSRH_AUTOSET 0x80
+#define USB_INCSRH_ISO 0x40
+#define USB_INCSRH_MODE 0x20
+#define USB_INCSRH_DMAREQENAB 0x10
+#define USB_INCSRH_DMAREQMODE 0x04
+#define USB_INCSR_CDT 0x40
+#define USB_INCSR_SENTSTALL 0x20
+#define USB_INCSR_SENDSTALL 0x10
+#define USB_INCSR_FF 0x08
+#define USB_INCSR_UNDERRUN 0x04
+#define USB_INCSR_FFNOTEMPT 0x02
+#define USB_INCSR_INPKTRDY 0x01
+#define USB_OUTCSRH_AUTOCLR 0x80
+#define USB_OUTCSRH_ISO 0x40
+#define USB_OUTCSRH_DMAREQENAB 0x20
+#define USB_OUTCSRH_DNYT 0x10
+#define USB_OUTCSRH_DMAREQMODE 0x08
+#define USB_OUTCSR_CDT 0x80
+#define USB_OUTCSR_SENTSTALL 0x40
+#define USB_OUTCSR_SENDSTALL 0x20
+#define USB_OUTCSR_FF 0x10
+#define USB_OUTCSR_DATAERR 0x08
+#define USB_OUTCSR_OVERRUN 0x04
+#define USB_OUTCSR_FFFULL 0x02
+#define USB_OUTCSR_OUTPKTRDY 0x01
+
+/* Testmode register bits */
+#define USB_TEST_SE0NAK 0x01
+#define USB_TEST_J 0x02
+#define USB_TEST_K 0x04
+#define USB_TEST_PACKET 0x08
+
+/* DMA control bits */
+#define USB_CNTL_ENA 0x01
+#define USB_CNTL_DIR_IN 0x02
+#define USB_CNTL_MODE_1 0x04
+#define USB_CNTL_INTR_EN 0x08
+#define USB_CNTL_EP(n) ((n) << 4)
+#define USB_CNTL_BURST_0 (0 << 9)
+#define USB_CNTL_BURST_4 (1 << 9)
+#define USB_CNTL_BURST_8 (2 << 9)
+#define USB_CNTL_BURST_16 (3 << 9)
+
+/*************************************************************************
+ * BCH
+ *************************************************************************/
+#define BCH_CR (BCH_BASE + 0x00) /* BCH Control register */
+#define BCH_CRS (BCH_BASE + 0x04) /* BCH Control Set register */
+#define BCH_CRC (BCH_BASE + 0x08) /* BCH Control Clear register */
+#define BCH_CNT (BCH_BASE + 0x0C) /* BCH ENC/DEC Count register */
+#define BCH_DR (BCH_BASE + 0x10) /* BCH data register */
+#define BCH_PAR0 (BCH_BASE + 0x14) /* BCH Parity 0 register */
+#define BCH_PAR1 (BCH_BASE + 0x18) /* BCH Parity 1 register */
+#define BCH_PAR2 (BCH_BASE + 0x1C) /* BCH Parity 2 register */
+#define BCH_PAR3 (BCH_BASE + 0x20) /* BCH Parity 3 register */
+#define BCH_INTS (BCH_BASE + 0x24) /* BCH Interrupt Status register */
+#define BCH_ERR0 (BCH_BASE + 0x28) /* BCH Error Report 0 register */
+#define BCH_ERR1 (BCH_BASE + 0x2C) /* BCH Error Report 1 register */
+#define BCH_ERR2 (BCH_BASE + 0x30) /* BCH Error Report 2 register */
+#define BCH_ERR3 (BCH_BASE + 0x34) /* BCH Error Report 3 register */
+#define BCH_INTE (BCH_BASE + 0x38) /* BCH Interrupt Enable register */
+#define BCH_INTES (BCH_BASE + 0x3C) /* BCH Interrupt Set register */
+#define BCH_INTEC (BCH_BASE + 0x40) /* BCH Interrupt Clear register */
+
+#define REG_BCH_CR REG32(BCH_CR)
+#define REG_BCH_CRS REG32(BCH_CRS)
+#define REG_BCH_CRC REG32(BCH_CRC)
+#define REG_BCH_CNT REG32(BCH_CNT)
+#define REG_BCH_DR REG8(BCH_DR)
+#define REG_BCH_PAR0 REG32(BCH_PAR0)
+#define REG_BCH_PAR1 REG32(BCH_PAR1)
+#define REG_BCH_PAR2 REG32(BCH_PAR2)
+#define REG_BCH_PAR3 REG32(BCH_PAR3)
+#define REG_BCH_INTS REG32(BCH_INTS)
+#define REG_BCH_ERR0 REG32(BCH_ERR0)
+#define REG_BCH_ERR1 REG32(BCH_ERR1)
+#define REG_BCH_ERR2 REG32(BCH_ERR2)
+#define REG_BCH_ERR3 REG32(BCH_ERR3)
+#define REG_BCH_INTE REG32(BCH_INTE)
+#define REG_BCH_INTEC REG32(BCH_INTEC)
+#define REG_BCH_INTES REG32(BCH_INTES)
+
+/* BCH Control Register*/
+#define BCH_CR_DMAE (1 << 4) /* BCH DMA Enable */
+#define BCH_CR_ENCE (1 << 3) /* BCH Encoding Select */
+#define BCH_CR_DECE (0 << 3) /* BCH Decoding Select */
+#define BCH_CR_BSEL8 (1 << 2) /* 8 Bit BCH Select */
+#define BCH_CR_BSEL4 (0 << 2) /* 4 Bit BCH Select */
+#define BCH_CR_BRST (1 << 1) /* BCH Reset */
+#define BCH_CR_BCHE (1 << 0) /* BCH Enable */
+
+/* BCH Interrupt Status Register */
+#define BCH_INTS_ERRC_BIT 28
+#define BCH_INTS_ERRC_MASK (0xf << BCH_INTS_ERRC_BIT)
+#define BCH_INTS_ALL0 (1 << 5)
+#define BCH_INTS_ALLf (1 << 4)
+#define BCH_INTS_DECF (1 << 3)
+#define BCH_INTS_ENCF (1 << 2)
+#define BCH_INTS_UNCOR (1 << 1)
+#define BCH_INTS_ERR (1 << 0)
+
+/* BCH ENC/DEC Count Register */
+#define BCH_CNT_DEC_BIT 16
+#define BCH_CNT_DEC_MASK (0x3ff << BCH_CNT_DEC_BIT)
+#define BCH_CNT_ENC_BIT 0
+#define BCH_CNT_ENC_MASK (0x3ff << BCH_CNT_ENC_BIT)
+
+/* BCH Error Report Register */
+#define BCH_ERR_INDEX_ODD_BIT 16
+#define BCH_ERR_INDEX_ODD_MASK (0x1fff << BCH_ERR_INDEX_ODD_BIT)
+#define BCH_ERR_INDEX_EVEN_BIT 0
+#define BCH_ERR_INDEX_EVEN_MASK (0x1fff << BCH_ERR_INDEX_EVEN_BIT)
+
+/*************************************************************************
+ * OWI (One-wire Bus Controller )
+ *************************************************************************/
+#define OWI_CFG (OWI_BASE + 0x00) /* OWI Configure Register */
+#define OWI_CTL (OWI_BASE + 0x04) /* OWI Control Register */
+#define OWI_STS (OWI_BASE + 0x08) /* OWI Status Register */
+#define OWI_DAT (OWI_BASE + 0x0c) /* OWI Data Register */
+#define OWI_DIV (OWI_BASE + 0x10) /* OWI Clock Divide Register */
+
+#define REG_OWI_CFG REG8(OWI_CFG)
+#define REG_OWI_CTL REG8(OWI_CTL)
+#define REG_OWI_STS REG8(OWI_STS)
+#define REG_OWI_DAT REG8(OWI_DAT)
+#define REG_OWI_DIV REG8(OWI_DIV)
+
+/* OWI Configure Register */
+#define OWI_CFG_MODE (1 << 7) /* 0: Regular speed mode 1: Overdrive speed mode */
+#define OWI_CFG_RDDATA (1 << 6) /* 1: receive data from one-wire bus and stored in OWDAT*/
+#define OWI_CFG_WRDATA (1 << 5) /* 1: transmit the data in OWDAT */
+#define OWI_CFG_RDST (1 << 4) /* 1: was sampled during a read */
+#define OWI_CFG_WR1RD (1 << 3) /* 1: generate write 1 sequence on line */
+#define OWI_CFG_WR0 (1 << 2) /* 1: generate write 0 sequence on line */
+#define OWI_CFG_RST (1 << 1) /* 1: generate reset pulse and sample slaves presence pulse*/
+#define OWI_CFG_ENA (1 << 0) /* 1: enable the OWI operation */
+
+/* OWI Control Register */
+#define OWI_CTL_EBYTE (1 << 2) /* enable byte write/read interrupt */
+#define OWI_CTL_EBIT (1 << 1) /* enable bit write/read interrupt */
+#define OWI_CTL_ERST (1 << 0) /* enable reset sequence finished interrupt */
+
+/* OWI Status Register */
+#define OWI_STS_PST (1 << 7) /* 1: one-wire bus has device on it */
+#define OWI_STS_BYTE_RDY (1 << 2) /* 1: have received or transmitted a data */
+#define OWI_STS_BIT_RDY (1 << 1) /* 1: have received or transmitted a bit */
+#define OWI_STS_PST_RDY (1 << 0) /* 1: have finished a reset pulse */
+
+/* OWI Clock Divide Register */
+#define OWI_DIV_CLKDIV_BIT 5
+
+
+/*************************************************************************
+ * MC (Motion Compensation)
+ *************************************************************************/
+#define MC_CTRL (MC_BASE + 0x00) /* MC Control Register */
+#define MC_STAT (MC_BASE + 0x04) /* MC Status Register */
+#define MC_REF_ADDR (MC_BASE + 0x08) /* MC Reference Block Address Register */
+#define MC_REF2_ADDR (MC_BASE + 0x0C) /* MC 2nd Reference Block Address Register */
+#define MC_CURR_ADDR (MC_BASE + 0x10) /* MC Current Block Address Register */
+#define MC_REF_STRD (MC_BASE + 0x14) /* MC Reference Frame Stride Register */
+#define MC_CURR_STRD (MC_BASE + 0x18) /* MC Current Frame Stride Register */
+#define MC_ITP_INFO (MC_BASE + 0x1C) /* MC Block Interpolation Information Register */
+#define MC_TAP_COEF1 (MC_BASE + 0x20) /* MC TAP Filter Coefficient 1 Register */
+#define MC_TAP_COEF2 (MC_BASE + 0x24) /* MC TAP Filter Coefficient 2 Register */
+
+#define REG_MC_CTRL REG32(MC_CTRL)
+#define REG_MC_STAT REG32(MC_STAT)
+#define REG_MC_REF_ADDR REG32(MC_REF_ADDR)
+#define REG_MC_REF2_ADDR REG32(MC_REF2_ADDR)
+#define REG_MC_CURR_ADDR REG32(MC_CURR_ADDR)
+#define REG_MC_REF_STRD REG32(MC_REF_STRD)
+#define REG_MC_CURR_STRD REG32(MC_CURR_STRD)
+#define REG_MC_ITP_INFO REG32(MC_ITP_INFO)
+#define REG_MC_TAP_COEF1 REG32(MC_TAP_COEF1)
+#define REG_MC_TAP_COEF2 REG32(MC_TAP_COEF2)
+
+/* MC Control Register */
+#define MC_CTRL_CACHECLR (1 << 2) /* MC Cache clear */
+#define MC_CTRL_RESET (1 << 1) /* MC Reset */
+#define MC_CTRL_ENABLE (1 << 0) /* MC enable */
+
+/* MC Status Register */
+#define MC_STAT_OUT_END (1 << 0) /* Output DMA termination flag */
+
+/* MC Reference Frame Stride Register, unit: byte */
+#define MC_REF_STRD_BIT 16
+#define MC_REF_STRD_MASK (0xfff << MC_REF_STRD_BIT)
+#define MC_REF_STRD2_BIT 0
+#define MC_REF_STRD2_MASK (0xfff << MC_REF_STRD2_BIT)
+
+/* MC Current Frame Stride Register, unit: byte */
+#define MC_CURR_STRD_BIT 0
+#define MC_CURR_STRD_MASK (0xfff << MC_CURR_STRD_BIT)
+
+/* MC Block Interpolation Information Register */
+#define MC_ITP_INFO_RND1_BIT 24 /* Rounding data during interpolation */
+#define MC_ITP_INFO_RND1_MASK (0xff << MC_ITP_INFO_RND1_BIT)
+#define MC_ITP_INFO_RND0_BIT 16 /* Rounding data during interpolation */
+#define MC_ITP_INFO_RND0_MASK (0xff << MC_ITP_INFO_RND0_BIT)
+#define MC_ITP_INFO_AVG (1 << 12) /* 0: output interpolated data directly; 1: doing average operation with 2nd source data after interpolating and output */
+#define MC_ITP_INFO_FMT_BIT 8 /* Indicate current interpolation's type */
+#define MC_ITP_INFO_RMT_MASK (0xf << MC_ITP_INFO_RMT_BIT)
+ #define MC_ITP_INFO_FMT_MPEG_HPEL (0x0 << MC_ITP_INFO_RMT_BIT) /* MPEG Half-pixel interpolation */
+ #define MC_ITP_INFO_FMT_MPEG_QPEL (0x1 << MC_ITP_INFO_RMT_BIT) /* MPEG 8-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_H264_QPEL (0x2 << MC_ITP_INFO_RMT_BIT) /* H264 6-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_H264_EPEL (0x3 << MC_ITP_INFO_RMT_BIT) /* H264 2-tap Eight-pixel interpolation */
+ #define MC_ITP_INFO_FMT_H264_WPDT (0x4 << MC_ITP_INFO_RMT_BIT) /* H264 Weighted-prediction */
+ #define MC_ITP_INFO_FMT_WMV2_QPEL (0x5 << MC_ITP_INFO_RMT_BIT) /* WMV2 4-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_VC1_QPEL (0x6 << MC_ITP_INFO_RMT_BIT) /* VC1 4-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_RV8_TPEL (0x7 << MC_ITP_INFO_RMT_BIT) /* RV8 4-tap Third-pixel interpolation */
+ #define MC_ITP_INFO_FMT_RV8_CHROM (0x8 << MC_ITP_INFO_RMT_BIT) /* RV8 2-tap Third-pixel interpolation */
+ #define MC_ITP_INFO_FMT_RV9_QPEL (0x9 << MC_ITP_INFO_RMT_BIT) /* RV9 6-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_RV9_CHROM (0xa << MC_ITP_INFO_RMT_BIT) /* RV9 2-tap Quarter-pixel interpolation */
+#define MC_ITP_INFO_BLK_W_BIT 6 /* Indicate reference block's width, unit: pixel */
+#define MC_ITP_INFO_BLK_W_MASK (0x3 << MC_ITP_INFO_BLK_W_BIT)
+ #define MC_ITP_INFO_BLK_W_2 (0x0 << MC_ITP_INFO_BLK_W_BIT)
+ #define MC_ITP_INFO_BLK_W_4 (0x1 << MC_ITP_INFO_BLK_W_BIT)
+ #define MC_ITP_INFO_BLK_W_8 (0x2 << MC_ITP_INFO_BLK_W_BIT)
+ #define MC_ITP_INFO_BLK_W_16 (0x3 << MC_ITP_INFO_BLK_W_BIT)
+#define MC_ITP_INFO_BLK_H_BIT 4 /* Indicate reference block's height, unit: pixel */
+#define MC_ITP_INFO_BLK_H_MASK (0x3 << MC_ITP_INFO_BLK_H_BIT)
+ #define MC_ITP_INFO_BLK_H_2 (0x0 << MC_ITP_INFO_BLK_H_BIT)
+ #define MC_ITP_INFO_BLK_H_4 (0x1 << MC_ITP_INFO_BLK_H_BIT)
+ #define MC_ITP_INFO_BLK_H_8 (0x2 << MC_ITP_INFO_BLK_H_BIT)
+ #define MC_ITP_INFO_BLK_H_16 (0x3 << MC_ITP_INFO_BLK_H_BIT)
+#define MC_ITP_INFO_ITP_CASE_BIT 0 /* Indicate interpolation final destination pixel position */
+#define MC_ITP_INFO_ITP_CASE_MASK (0xf << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H0V0 (0x0 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H1V0 (0x1 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H2V0 (0x2 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H3V0 (0x3 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H0V1 (0x4 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H1V1 (0x5 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H2V1 (0x6 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H3V1 (0x7 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H0V2 (0x8 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H1V2 (0x9 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H2V2 (0xa << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H3V2 (0xb << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H0V3 (0xc << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H1V3 (0xd << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H2V3 (0xe << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H3V3 (0xf << MC_ITP_INFO_ITP_CASE_BIT)
+
+/* MC TAP Filter Coefficient 1 Register */
+#define MC_TAP_COEF1_TAP_COEF4_BIT 24
+#define MC_TAP_COEF1_TAP_COEF4_MASK (0xff << MC_TAP_COEF1_TAP_COEF4_BIT)
+#define MC_TAP_COEF1_TAP_COEF3_BIT 16
+#define MC_TAP_COEF1_TAP_COEF3_MASK (0xff << MC_TAP_COEF1_TAP_COEF3_BIT)
+#define MC_TAP_COEF1_TAP_COEF2_BIT 8
+#define MC_TAP_COEF1_TAP_COEF2_MASK (0xff << MC_TAP_COEF1_TAP_COEF2_BIT)
+#define MC_TAP_COEF1_TAP_COEF1_BIT 0
+#define MC_TAP_COEF1_TAP_COEF1_MASK (0xff << MC_TAP_COEF1_TAP_COEF1_BIT)
+
+/* MC TAP Filter Coefficient 2 Register */
+#define MC_TAP_COEF2_TAP_COEF8_BIT 24
+#define MC_TAP_COEF2_TAP_COEF8_MASK (0xff << MC_TAP_COEF2_TAP_COEF8_BIT)
+#define MC_TAP_COEF2_TAP_COEF7_BIT 16
+#define MC_TAP_COEF2_TAP_COEF7_MASK (0xff << MC_TAP_COEF2_TAP_COEF7_BIT)
+#define MC_TAP_COEF2_TAP_COEF6_BIT 8
+#define MC_TAP_COEF2_TAP_COEF6_MASK (0xff << MC_TAP_COEF2_TAP_COEF6_BIT)
+#define MC_TAP_COEF2_TAP_COEF5_BIT 0
+#define MC_TAP_COEF2_TAP_COEF5_MASK (0xff << MC_TAP_COEF2_TAP_COEF5_BIT)
+
+
+/*************************************************************************
+ * ME (Motion Estimation)
+ *************************************************************************/
+#define ME_CTRL (ME_BASE + 0x00) /* ME Control Register */
+#define ME_REF_ADDR (ME_BASE + 0x04) /* ME Reference Block Address Register */
+#define ME_CURR_ADDR (ME_BASE + 0x08) /* ME Current Block Address Register */
+#define ME_DIFF_ADDR (ME_BASE + 0x0C) /* ME Difference Address Register */
+#define ME_REF_STRD (ME_BASE + 0x10) /* ME Reference Frame Stride Register */
+#define ME_CURR_STRD (ME_BASE + 0x14) /* ME Current Frame Stride Register */
+#define ME_DIFF_STRD (ME_BASE + 0x18) /* ME Difference Frame Stride Register */
+#define ME_SETTINGS (ME_BASE + 0x1C) /* ME Settings Register */
+#define ME_MVD (ME_BASE + 0x20) /* ME Motion Vector Difference Register */
+#define ME_FLAG (ME_BASE + 0x24) /* ME Flag Register */
+
+#define REG_ME_CTRL REG32(ME_CTRL)
+#define REG_ME_REF_ADDR REG32(ME_REF_ADDR)
+#define REG_ME_CURR_ADDR REG32(ME_CURR_ADDR)
+#define REG_ME_DIFF_ADDR REG32(ME_DIFF_ADDR)
+#define REG_ME_REF_STRD REG32(ME_REF_STRD)
+#define REG_ME_CURR_STRD REG32(ME_CURR_STRD)
+#define REG_ME_DIFF_STRD REG32(ME_DIFF_STRD)
+#define REG_ME_SETTINGS REG32(ME_SETTINGS)
+#define REG_ME_MVD REG32(ME_MVD)
+#define REG_ME_FLAG REG32(ME_FLAG)
+
+
+/* ME Control Register */
+#define ME_CTRL_FLUSH (1 << 2) /* ME cache clear */
+#define ME_CTRL_RESET (1 << 1) /* ME reset */
+#define ME_CTRL_ENABLE (1 << 0) /* ME enable */
+
+/* ME Settings Register */
+#define ME_SETTINGS_SAD_GATE_BIT 16 /* The max SAD value which can be accepted */
+#define ME_SETTINGS_SAD_GATE_MASK (0xffff << ME_SETTINGS_SAD_GATE_BIT)
+#define ME_SETTINGS_STEP_NUM_BIT 0 /* The max step number the search process can not exceed */
+#define ME_SETTINGS_STEP_NUM_MASK (0x3f << ME_SETTINGS_STEP_NUM_BIT)
+
+/* ME Motion Vector Difference Register */
+#define ME_MVD_MVDY_BIT 16 /* The MVD value of coordinate-Y */
+#define ME_MVD_MVDY_MASK (0xffff << ME_MVD_MVDY_BIT)
+#define ME_MVD_MVDX_BIT 0 /* The MVD value of coordinate-X */
+#define ME_MVD_MVDX_MASK (0xffff << ME_MVD_MVDX_BIT)
+
+/* ME Flag Register */
+#define ME_FLAG_INTRA (1 << 1) /* Indicate the current MB will be predicted in intra mode */
+#define ME_FLAG_COMPLETED (1 << 0) /* The ME of the current part of the MB is completed */
+
+
+/*************************************************************************
+ * OTP (One Time Programmable Module)
+ *************************************************************************/
+#define OTP_ID0 (OTP_BASE + 0x00) /* ID0 Register */
+#define OTP_ID1 (OTP_BASE + 0x04) /* ID1 Register */
+#define OTP_ID2 (OTP_BASE + 0x08) /* ID2 Register */
+#define OTP_ID3 (OTP_BASE + 0x0C) /* ID3 Register */
+#define OTP_BR0 (OTP_BASE + 0x10) /* BOOTROM0 Register */
+#define OTP_BR1 (OTP_BASE + 0x14) /* BOOTROM1 Register */
+#define OTP_HW0 (OTP_BASE + 0x18) /* Chip Hardware 0 Register */
+#define OTP_HW1 (OTP_BASE + 0x1C) /* Chip Hardware 1 Register */
+
+#define REG_OTP_ID0 REG32(OTP_ID0)
+#define REG_OTP_ID1 REG32(OTP_ID1)
+#define REG_OTP_ID2 REG32(OTP_ID2)
+#define REG_OTP_ID3 REG32(OTP_ID3)
+#define REG_OTP_BR0 REG32(OTP_BR0)
+#define REG_OTP_BR1 REG32(OTP_BR1)
+#define REG_OTP_HW0 REG32(OTP_HW0)
+#define REG_OTP_HW1 REG32(OTP_HW1)
+
+/* ID0 Register */
+#define OTP_ID0_WID_BIT 24 /* Wafer ID */
+#define OTP_ID0_WID_MASK (0xff << OTP_ID0_WID_BIT)
+#define OTP_ID0_MID_BIT 16 /* MASK ID */
+#define OTP_ID0_MID_MASK (0xff << OTP_ID0_MID_BIT)
+#define OTP_ID0_FID_BIT 8 /* Foundary ID */
+#define OTP_ID0_FID_MASK (0xff << OTP_ID0_FID_BIT)
+#define OTP_ID0_PID_BIT 0 /* Product ID */
+#define OTP_ID0_PID_MASK (0xff << OTP_ID0_PID_BIT)
+
+/* ID1 Register */
+#define OTP_ID1_LID_BIT 8 /* Lot ID */
+#define OTP_ID1_LID_MASK (0xffffff << OTP_ID1_LID_BIT)
+#define OTP_ID1_TID_BIT 0 /* Test House ID */
+#define OTP_ID1_TID_MASK (0xff << OTP_ID1_TID_BIT)
+
+/* ID2 Register */
+#define OTP_ID2_XADR_BIT 24 /* Die X-dir Address */
+#define OTP_ID2_XADR_MASK (0xff << OTP_ID2_XADR_BIT)
+#define OTP_ID2_YADR_BIT 16 /* Die Y-dir Address */
+#define OTP_ID2_YADR_MASK (0xff << OTP_ID2_YADR_BIT)
+#define OTP_ID2_TDATE_BIT 0 /* Testing Date */
+#define OTP_ID2_TDATE_MASK (0xffff << OTP_ID2_TDATE_BIT)
+
+/* ID3 Register */
+#define OTP_ID3_CID_BIT 16 /* Customer ID */
+#define OTP_ID3_CID_MASK (0xffff << OTP_ID3_CID_BIT)
+#define OTP_ID3_CP_BIT 0 /* Chip Parameters */
+#define OTP_ID3_CP_MASK (0xffff << OTP_ID3_CP_BIT)
+
+/* BOOTROM1 Register */
+#define OTP_BR1_UDCBOOT_BIT 0
+#define OTP_BR1_UDCBOOT_MASK (0xff << OTP_BR1_UDCBOOT_BIT)
+ #define OTP_BR1_UDCBOOT_AUTO (0xf0 << OTP_BR1_UDCBOOT_BIT)
+ #define OTP_BR1_UDCBOOT_24M (0x0f << OTP_BR1_UDCBOOT_BIT) /* 24MHz OSC */
+ #define OTP_BR1_UDCBOOT_13M (0x0c << OTP_BR1_UDCBOOT_BIT) /* 13MHz OSC */
+ #define OTP_BR1_UDCBOOT_26M (0x03 << OTP_BR1_UDCBOOT_BIT) /* 26MHz OSC */
+ #define OTP_BR1_UDCBOOT_27M (0x00 << OTP_BR1_UDCBOOT_BIT) /* 27MHz OSC */
+
+/* Chip Hardware 1 Register */
+#define OTP_HW1_MC_EN (0x3 << 30) /* MC is enabled */
+#define OTP_HW1_ME_EN (0x3 << 28)
+#define OTP_HW1_DE_EN (0x3 << 26)
+#define OTP_HW1_IDCT_EN (0x3 << 24)
+#define OTP_HW1_UART3_EN (0x3 << 22)
+#define OTP_HW1_UART2_EN (0x3 << 20)
+#define OTP_HW1_UART1_EN (0x3 << 18)
+#define OTP_HW1_UART0_EN (0x3 << 16)
+#define OTP_HW1_SSI1_EN (0x3 << 14)
+#define OTP_HW1_SSI0_EN (0x3 << 12)
+#define OTP_HW1_MSC1_EN (0x3 << 10)
+#define OTP_HW1_MSC0_EN (0x3 << 8)
+#define OTP_HW1_UHC_EN (0x3 << 6)
+#define OTP_HW1_TVE_EN (0x3 << 4)
+#define OTP_HW1_TSSI_EN (0x3 << 2)
+#define OTP_HW1_CIM_EN (0x3 << 0)
+
+
+/*************************************************************************
+ * TSSI MPEG 2-TS slave interface
+ *************************************************************************/
+#define TSSI_ENA ( TSSI_BASE + 0x00 ) /* TSSI enable register */
+#define TSSI_CFG ( TSSI_BASE + 0x04 ) /* TSSI configure register */
+#define TSSI_CTRL ( TSSI_BASE + 0x08 ) /* TSSI control register */
+#define TSSI_STAT ( TSSI_BASE + 0x0c ) /* TSSI state register */
+#define TSSI_FIFO ( TSSI_BASE + 0x10 ) /* TSSI FIFO register */
+#define TSSI_PEN ( TSSI_BASE + 0x14 ) /* TSSI PID enable register */
+#define TSSI_PID(n) ( TSSI_BASE + 0x20 + 4*(n) ) /* TSSI PID filter register */
+#define TSSI_PID0 ( TSSI_BASE + 0x20 )
+#define TSSI_PID1 ( TSSI_BASE + 0x24 )
+#define TSSI_PID2 ( TSSI_BASE + 0x28 )
+#define TSSI_PID3 ( TSSI_BASE + 0x2c )
+#define TSSI_PID4 ( TSSI_BASE + 0x30 )
+#define TSSI_PID5 ( TSSI_BASE + 0x34 )
+#define TSSI_PID6 ( TSSI_BASE + 0x38 )
+#define TSSI_PID7 ( TSSI_BASE + 0x3c )
+#define TSSI_PID_MAX 8 /* max PID: 7 */
+
+#define REG_TSSI_ENA REG8( TSSI_ENA )
+#define REG_TSSI_CFG REG16( TSSI_CFG )
+#define REG_TSSI_CTRL REG8( TSSI_CTRL )
+#define REG_TSSI_STAT REG8( TSSI_STAT )
+#define REG_TSSI_FIFO REG32( TSSI_FIFO )
+#define REG_TSSI_PEN REG32( TSSI_PEN )
+#define REG_TSSI_PID(n) REG32( TSSI_PID(n) )
+#define REG_TSSI_PID0 REG32( TSSI_PID0 )
+#define REG_TSSI_PID1 REG32( TSSI_PID1 )
+#define REG_TSSI_PID2 REG32( TSSI_PID2 )
+#define REG_TSSI_PID3 REG32( TSSI_PID3 )
+#define REG_TSSI_PID4 REG32( TSSI_PID4 )
+#define REG_TSSI_PID5 REG32( TSSI_PID5 )
+#define REG_TSSI_PID6 REG32( TSSI_PID6 )
+#define REG_TSSI_PID7 REG32( TSSI_PID7 )
+
+/* TSSI enable register */
+#define TSSI_ENA_SFT_RST ( 1 << 7 ) /* soft reset bit */
+#define TSSI_ENA_PID_EN ( 1 << 2 ) /* soft filtering function enable bit */
+#define TSSI_ENA_DMA_EN ( 1 << 1 ) /* DMA enable bit */
+#define TSSI_ENA_ENA ( 1 << 0 ) /* TSSI enable bit */
+
+/* TSSI configure register */
+#define TSSI_CFG_TRIG_BIT 14 /* fifo trig number */
+#define TSSI_CFG_TRIG_MASK ( 0x3 << TSSI_CFG_TRIG_BIT)
+#define TSSI_CFG_TRIG_4 ( 0 << TSSI_CFG_TRIG_BIT)
+#define TSSI_CFG_TRIG_8 ( 1 << TSSI_CFG_TRIG_BIT)
+#define TSSI_CFG_TRIG_16 ( 2 << TSSI_CFG_TRIG_BIT)
+#define TSSI_CFG_END_WD ( 1 << 9 ) /* order of data in word */
+#define TSSI_CFG_END_BT ( 1 << 8 ) /* order of data in byte */
+#define TSSI_CFG_TSDI_H ( 1 << 7 ) /* data pin polarity */
+#define TSSI_CFG_USE_0 ( 1 << 6 ) /* serial mode data pin select */
+#define TSSI_CFG_USE_TSDI0 ( 0 << 6 ) /* TSDI0 as serial mode data pin */
+#define TSSI_CFG_USE_TSDI7 ( 1 << 6 ) /* TSDI7 as serial mode data pin */
+#define TSSI_CFG_TSCLK_CH ( 1 << 5 ) /* clk channel select */
+#define TSSI_CFG_PARAL ( 1 << 4 ) /* mode select */
+#define TSSI_CFG_PARAL_MODE ( 1 << 4 ) /* parallel select */
+#define TSSI_CFG_SERIAL_MODE ( 0 << 4 ) /* serial select */
+#define TSSI_CFG_TSCLK_P ( 1 << 3 ) /* clk edge select */
+#define TSSI_CFG_TSFRM_H ( 1 << 2 ) /* TSFRM polarity select */
+#define TSSI_CFG_TSSTR_H ( 1 << 1 ) /* TSSTR polarity select */
+#define TSSI_CFG_TSFAIL_H ( 1 << 0 ) /* TSFAIL polarity select */
+
+/* TSSI control register */
+#define TSSI_CTRL_OVRNM ( 1 << 1 ) /* FIFO overrun interrupt mask bit */
+#define TSSI_CTRL_TRIGM ( 1 << 0 ) /* FIFO trigger interrupt mask bit */
+
+/* TSSI state register */
+#define TSSI_STAT_OVRN ( 1 << 1 ) /* FIFO overrun interrupt flag bit */
+#define TSSI_STAT_TRIG ( 1 << 0 ) /* FIFO trigger interrupt flag bit */
+
+/* TSSI PID enable register */
+#define TSSI_PEN_EN00 ( 1 << 0 ) /* enable PID n */
+#define TSSI_PEN_EN10 ( 1 << 1 )
+#define TSSI_PEN_EN20 ( 1 << 2 )
+#define TSSI_PEN_EN30 ( 1 << 3 )
+#define TSSI_PEN_EN40 ( 1 << 4 )
+#define TSSI_PEN_EN50 ( 1 << 5 )
+#define TSSI_PEN_EN60 ( 1 << 6 )
+#define TSSI_PEN_EN70 ( 1 << 7 )
+#define TSSI_PEN_EN01 ( 1 << 16 )
+#define TSSI_PEN_EN11 ( 1 << 17 )
+#define TSSI_PEN_EN21 ( 1 << 18 )
+#define TSSI_PEN_EN31 ( 1 << 19 )
+#define TSSI_PEN_EN41 ( 1 << 20 )
+#define TSSI_PEN_EN51 ( 1 << 21 )
+#define TSSI_PEN_EN61 ( 1 << 22 )
+#define TSSI_PEN_EN71 ( 1 << 23 )
+#define TSSI_PEN_PID0 ( 1 << 31 ) /* PID filter enable PID0 */
+
+/* TSSI PID Filter Registers */
+#define TSSI_PID_PID1_BIT 16
+#define TSSI_PID_PID1_MASK (0x1FFF<<TSSI_PID_PID1_BIT)
+#define TSSI_PID_PID0_BIT 0
+#define TSSI_PID_PID0_MASK (0x1FFF<<TSSI_PID_PID0_BIT)
+
+
+/*************************************************************************
+ * IPU (Image Processing Unit)
+ *************************************************************************/
+#define IPU_V_BASE 0xB3080000
+#define IPU_P_BASE 0x13080000
+
+/* Register offset */
+#define REG_CTRL 0x0 /* IPU Control Register */
+#define REG_STATUS 0x4 /* IPU Status Register */
+#define REG_D_FMT 0x8 /* Data Format Register */
+#define REG_Y_ADDR 0xc /* Input Y or YUV422 Packaged Data Address Register */
+#define REG_U_ADDR 0x10 /* Input U Data Address Register */
+#define REG_V_ADDR 0x14 /* Input V Data Address Register */
+#define REG_IN_FM_GS 0x18 /* Input Geometric Size Register */
+#define REG_Y_STRIDE 0x1c /* Input Y Data Line Stride Register */
+#define REG_UV_STRIDE 0x20 /* Input UV Data Line Stride Register */
+#define REG_OUT_ADDR 0x24 /* Output Frame Start Address Register */
+#define REG_OUT_GS 0x28 /* Output Geometric Size Register */
+#define REG_OUT_STRIDE 0x2c /* Output Data Line Stride Register */
+#define REG_RSZ_COEF_INDEX 0x30 /* Resize Coefficients Table Index Register */
+#define REG_CSC_CO_COEF 0x34 /* CSC C0 Coefficient Register */
+#define REG_CSC_C1_COEF 0x38 /* CSC C1 Coefficient Register */
+#define REG_CSC_C2_COEF 0x3c /* CSC C2 Coefficient Register */
+#define REG_CSC_C3_COEF 0x40 /* CSC C3 Coefficient Register */
+#define REG_CSC_C4_COEF 0x44 /* CSC C4 Coefficient Register */
+#define HRSZ_LUT_BASE 0x48 /* Horizontal Resize Coefficients Look Up Table Register group */
+#define VRSZ_LUT_BASE 0x4c /* Virtical Resize Coefficients Look Up Table Register group */
+#define REG_CSC_OFSET_PARA 0x50 /* CSC Offset Parameter Register */
+#define REG_Y_PHY_T_ADDR 0x54 /* Input Y Physical Table Address Register */
+#define REG_U_PHY_T_ADDR 0x58 /* Input U Physical Table Address Register */
+#define REG_V_PHY_T_ADDR 0x5c /* Input V Physical Table Address Register */
+#define REG_OUT_PHY_T_ADDR 0x60 /* Output Physical Table Address Register */
+
+/* REG_CTRL: IPU Control Register */
+#define IPU_CE_SFT 0x0
+#define IPU_CE_MSK 0x1
+#define IPU_RUN_SFT 0x1
+#define IPU_RUN_MSK 0x1
+#define HRSZ_EN_SFT 0x2
+#define HRSZ_EN_MSK 0x1
+#define VRSZ_EN_SFT 0x3
+#define VRSZ_EN_MSK 0x1
+#define CSC_EN_SFT 0x4
+#define CSC_EN_MSK 0x1
+#define FM_IRQ_EN_SFT 0x5
+#define FM_IRQ_EN_MSK 0x1
+#define IPU_RST_SFT 0x6
+#define IPU_RST_MSK 0x1
+#define H_SCALE_SFT 0x8
+#define H_SCALE_MSK 0x1
+#define V_SCALE_SFT 0x9
+#define V_SCALE_MSK 0x1
+#define PKG_SEL_SFT 0xA
+#define PKG_SEL_MSK 0x1
+#define LCDC_SEL_SFT 0xB
+#define LCDC_SEL_MSK 0x1
+#define SPAGE_MAP_SFT 0xC
+#define SPAGE_MAP_MSK 0x1
+#define DPAGE_SEL_SFT 0xD
+#define DPAGE_SEL_MSK 0x1
+#define DISP_SEL_SFT 0xE
+#define DISP_SEL_MSK 0x1
+#define FIELD_CONF_EN_SFT 15
+#define FIELD_CONF_EN_MSK 1
+#define FIELD_SEL_SFT 16
+#define FIELD_SEL_MSK 1
+#define DFIX_SEL_SFT 17
+#define DFIX_SEL_MSK 1
+
+/* REG_STATUS: IPU Status Register */
+#define OUT_END_SFT 0x0
+#define OUT_END_MSK 0x1
+#define FMT_ERR_SFT 0x1
+#define FMT_ERR_MSK 0x1
+#define SIZE_ERR_SFT 0x2
+#define SIZE_ERR_MSK 0x1
+
+/* D_FMT: Data Format Register */
+#define IN_FMT_SFT 0x0
+#define IN_FMT_MSK 0x3
+#define IN_OFT_SFT 0x2
+#define IN_OFT_MSK 0x3
+#define YUV_PKG_OUT_SFT 0x10
+#define YUV_PKG_OUT_MSK 0x7
+#define OUT_FMT_SFT 0x13
+#define OUT_FMT_MSK 0x3
+#define RGB_OUT_OFT_SFT 0x15
+#define RGB_OUT_OFT_MSK 0x7
+#define RGB888_FMT_SFT 0x18
+#define RGB888_FMT_MSK 0x1
+
+/* IN_FM_GS: Input Geometric Size Register */
+#define IN_FM_H_SFT 0x0
+#define IN_FM_H_MSK 0xFFF
+#define IN_FM_W_SFT 0x10
+#define IN_FM_W_MSK 0xFFF
+
+/* Y_STRIDE: Input Y Data Line Stride Register */
+#define Y_S_SFT 0x0
+#define Y_S_MSK 0x3FFF
+
+/* UV_STRIDE: Input UV Data Line Stride Register */
+#define V_S_SFT 0x0
+#define V_S_MSK 0x1FFF
+#define U_S_SFT 0x10
+#define U_S_MSK 0x1FFF
+
+/* OUT_GS: Output Geometric Size Register */
+#define OUT_FM_H_SFT 0x0
+#define OUT_FM_H_MSK 0x1FFF
+#define OUT_FM_W_SFT 0x10
+#define OUT_FM_W_MSK 0x7FFF
+
+/* OUT_STRIDE: Output Data Line Stride Register */
+#define OUT_S_SFT 0x0
+#define OUT_S_MSK 0xFFFF
+
+/* RSZ_COEF_INDEX: Resize Coefficients Table Index Register */
+#define VE_IDX_SFT 0x0
+#define VE_IDX_MSK 0x1F
+#define HE_IDX_SFT 0x10
+#define HE_IDX_MSK 0x1F
+
+/* CSC_CX_COEF: CSC CX Coefficient Register */
+#define CX_COEF_SFT 0x0
+#define CX_COEF_MSK 0xFFF
+
+/* HRSZ_LUT_BASE, VRSZ_LUT_BASE: Resize Coefficients Look Up Table Register group */
+#define LUT_LEN 20
+
+#define OUT_N_SFT 0x0
+#define OUT_N_MSK 0x1
+#define IN_N_SFT 0x1
+#define IN_N_MSK 0x1
+#define W_COEF_SFT 0x2
+#define W_COEF_MSK 0x3FF
+
+/* CSC_OFSET_PARA: CSC Offset Parameter Register */
+#define CHROM_OF_SFT 0x10
+#define CHROM_OF_MSK 0xFF
+#define LUMA_OF_SFT 0x00
+#define LUMA_OF_MSK 0xFF
+
+
+#endif /* __JZ4750D_REGS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750d/serial.h b/arch/mips/include/asm/mach-jz4750d/serial.h
new file mode 100644
index 00000000000..d23c586a98a
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750d/serial.h
@@ -0,0 +1,30 @@
+/*
+ * linux/include/asm-mips/mach-jz4750d/serial.h
+ *
+ * Ingenic's JZ4750D common include.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_BOARD_SERIAL_H__
+#define __ASM_BOARD_SERIAL_H__
+
+#ifndef CONFIG_SERIAL_MANY_PORTS
+#undef RS_TABLE_SIZE
+#define RS_TABLE_SIZE 1
+#endif
+
+#define JZ_BASE_BAUD (12000000/16)
+
+#define JZ_SERIAL_PORT_DEFNS \
+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \
+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \
+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM },
+
+#endif /* __ASM_BORAD_SERIAL_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750d/war.h b/arch/mips/include/asm/mach-jz4750d/war.h
new file mode 100644
index 00000000000..3a5bc17e28f
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750d/war.h
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H
+#define __ASM_MIPS_MACH_JZ4740_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR 0
+#define R4600_V1_HIT_CACHEOP_WAR 0
+#define R4600_V2_HIT_CACHEOP_WAR 0
+#define R5432_CP0_INTERRUPT_WAR 0
+#define BCM1250_M3_WAR 0
+#define SIBYTE_1956_WAR 0
+#define MIPS4K_ICACHE_REFILL_WAR 0
+#define MIPS_CACHE_SYNC_WAR 0
+#define TX49XX_ICACHE_INDEX_INV_WAR 0
+#define RM9000_CDEX_SMP_WAR 0
+#define ICACHE_REFILLS_WORKAROUND_WAR 0
+#define R10000_LLSC_WAR 0
+#define MIPS34K_MISSED_ITLB_WAR 0
+
+#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */
diff --git a/arch/mips/include/asm/mach-jz4750l/board-f4750l.h b/arch/mips/include/asm/mach-jz4750l/board-f4750l.h
new file mode 100644
index 00000000000..1eafc978ed3
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750l/board-f4750l.h
@@ -0,0 +1,127 @@
+/*
+ * linux/include/asm-mips/mach-jz4750l/board-f4750l.h
+ *
+ * JZ4750L-based F4750L board ver 1.x definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750L_F4750L_H__
+#define __ASM_JZ4750L_F4750L_H__
+
+#define CONFIG_FPGA /* F4750L is an FPGA board */
+
+/*======================================================================
+ * Frequencies of on-board oscillators
+ */
+//#define JZ_EXTAL 48000000 /* Main extal freq: 12 MHz */
+#define JZ_EXTAL 70000000
+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
+#define CFG_DIV 1 /* hclk=pclk=mclk=CFG_EXTAL/CFG_DIV, just for FPGA board */
+
+
+/*======================================================================
+ * GPIO
+ */
+#define GPIO_SD0_VCC_EN_N (32*2+10) /* GPC10 */
+#define GPIO_SD0_CD_N (32*2+11) /* GPC11 */
+#define GPIO_SD0_WP (32*2+12) /* GPC12 */
+//#define GPIO_SD1_VCC_EN_N (32*2+13) /* GPC13 */
+#define GPIO_SD1_VCC_EN_N (32*4+4) /* GPE4 */
+#define GPIO_SD1_CD_N (32*2+14) /* GPC14 */
+#define GPIO_USB_DETE 102 /* GPD6 */
+#define GPIO_DC_DETE_N 103 /* GPD7 */
+#define GPIO_CHARG_STAT_N 111 /* GPD15 */
+#define GPIO_DISP_OFF_N 121 /* GPD25, LCD_REV */
+//#define GPIO_LED_EN 124 /* GPD28 */
+
+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
+
+/*======================================================================
+ * LCD backlight
+ */
+#define GPIO_LCD_PWM (32*2+14) /* GPE14 PWM4 */
+
+#define LCD_PWM_CHN 4 /* pwm channel */
+#define LCD_PWM_FULL 101
+
+/* 100 level: 0,1,...,100 */
+#define __lcd_set_backlight_level(n) \
+do { \
+ __gpio_as_output(GPIO_LCD_PWM); \
+ __gpio_set_pin(GPIO_LCD_PWM); \
+} while (0)
+
+#define __lcd_close_backlight() \
+do { \
+ __gpio_as_output(GPIO_LCD_PWM); \
+ __gpio_clear_pin(GPIO_LCD_PWM); \
+} while (0)
+
+/*======================================================================
+ * MMC/SD
+ */
+
+#define MSC0_WP_PIN GPIO_SD0_WP
+#define MSC0_HOTPLUG_PIN GPIO_SD0_CD_N
+#define MSC0_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD0_CD_N)
+
+#define MSC1_WP_PIN GPIO_SD1_WP
+#define MSC1_HOTPLUG_PIN GPIO_SD1_CD_N
+#define MSC1_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD1_CD_N)
+
+#define __msc0_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD0_VCC_EN_N); \
+ __gpio_as_input(GPIO_SD0_CD_N); \
+} while (0)
+
+#define __msc0_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD0_VCC_EN_N); \
+} while (0)
+
+#define __msc0_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD0_VCC_EN_N); \
+} while (0)
+
+#define __msc0_card_detected(s) \
+({ \
+ int detected = 1; \
+ if (__gpio_get_pin(GPIO_SD0_CD_N)) \
+ detected = 0; \
+ detected; \
+})
+
+#define __msc1_init_io() \
+do { \
+ __gpio_as_output(GPIO_SD1_VCC_EN_N); \
+ /* __gpio_as_input(GPIO_SD1_CD_N);*/ \
+} while (0)
+
+#define __msc1_enable_power() \
+do { \
+ __gpio_clear_pin(GPIO_SD1_VCC_EN_N); \
+} while (0)
+
+#define __msc1_disable_power() \
+do { \
+ __gpio_set_pin(GPIO_SD1_VCC_EN_N); \
+} while (0)
+
+#define __msc1_card_detected(s) \
+({ \
+ int detected = 0; \
+ if (__gpio_get_pin(GPIO_SD1_CD_N)) \
+ detected = 1; \
+ detected; \
+})
+
+#endif /* __ASM_JZ4750l_F4750L_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750l/clock.h b/arch/mips/include/asm/mach-jz4750l/clock.h
new file mode 100644
index 00000000000..5706bc3c232
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750l/clock.h
@@ -0,0 +1,231 @@
+/*
+ * linux/include/asm-mips/mach-jz4750l/clock.h
+ *
+ * JZ4750L clocks definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750L_CLOCK_H__
+#define __ASM_JZ4750L_CLOCK_H__
+
+#ifndef JZ_EXTAL
+#define JZ_EXTAL 12000000 /* 3.6864 MHz */
+#endif
+#ifndef JZ_EXTAL2
+#define JZ_EXTAL2 32768 /* 32.768 KHz */
+#endif
+
+/*
+ * JZ4750L clocks structure
+ */
+typedef struct {
+ unsigned int cclk; /* CPU clock */
+ unsigned int hclk; /* System bus clock */
+ unsigned int pclk; /* Peripheral bus clock */
+ unsigned int mclk; /* Flash/SRAM/SDRAM clock */
+ unsigned int h1clk; /* AHB1 clock */
+ unsigned int pixclk; /* LCD pixel clock */
+ unsigned int i2sclk; /* AIC module clock */
+ unsigned int usbclk; /* USB module clock */
+ unsigned int mscclk; /* MSC module clock */
+ unsigned int extalclk; /* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */
+ unsigned int rtcclk; /* RTC clock for CPM,INTC,RTC,TCU,WDT */
+} jz_clocks_t;
+
+extern jz_clocks_t jz_clocks;
+
+
+
+/* PLL output frequency */
+static __inline__ unsigned int __cpm_get_pllout(void)
+{
+#if defined(CONFIG_FPGA)
+ return JZ_EXTAL/CFG_DIV;
+#else
+ unsigned long m, n, no, pllout;
+ unsigned long cppcr = REG_CPM_CPPCR;
+ unsigned long od[4] = {1, 2, 2, 4};
+ if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) {
+ m = __cpm_get_pllm() + 2;
+ n = __cpm_get_plln() + 2;
+ no = od[__cpm_get_pllod()];
+ pllout = ((JZ_EXTAL) / (n * no)) * m;
+ } else
+ pllout = JZ_EXTAL;
+ return pllout;
+#endif
+}
+
+/* PLL output frequency for MSC/I2S/LCD/USB */
+static __inline__ unsigned int __cpm_get_pllout2(void)
+{
+#if defined(CONFIG_FPGA)
+ return JZ_EXTAL/CFG_DIV;
+#else
+ if (REG_CPM_CPCCR & CPM_CPCCR_PCS)
+ return __cpm_get_pllout();
+ else
+ return __cpm_get_pllout()/2;
+#endif
+}
+
+/* CPU core clock */
+static __inline__ unsigned int __cpm_get_cclk(void)
+{
+
+#if defined(CONFIG_FGPA)
+ return JZ_EXTAL;
+#else
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ return __cpm_get_pllout() / div[__cpm_get_cdiv()];
+#endif
+}
+
+/* AHB system bus clock */
+static __inline__ unsigned int __cpm_get_hclk(void)
+{
+#if defined(CONFIG_FPGA)
+ return JZ_EXTAL/CFG_DIV;
+#else
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_hdiv()];
+#endif
+
+}
+
+/* Memory bus clock */
+static __inline__ unsigned int __cpm_get_mclk(void)
+{
+#if defined(CONFIG_FPGA)
+ return JZ_EXTAL/CFG_DIV;
+#else
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_mdiv()];
+#endif
+}
+
+/* APB peripheral bus clock */
+static __inline__ unsigned int __cpm_get_pclk(void)
+{
+#if defined(CONFIG_FPGA)
+ return JZ_EXTAL/CFG_DIV;
+#else
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ return __cpm_get_pllout() / div[__cpm_get_pdiv()];
+#endif
+}
+
+/* AHB1 module clock */
+static __inline__ unsigned int __cpm_get_h1clk(void)
+{
+ return __cpm_get_pllout2() / (__cpm_get_h1div() + 1);
+}
+
+/* LCD pixel clock */
+static __inline__ unsigned int __cpm_get_pixclk(void)
+{
+ return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1);
+}
+
+/* I2S clock */
+static __inline__ unsigned int __cpm_get_i2sclk(void)
+{
+ if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) {
+ return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1);
+ }
+ else {
+ return JZ_EXTAL;
+ }
+}
+
+/* USB clock */
+static __inline__ unsigned int __cpm_get_usbclk(void)
+{
+ if (REG_CPM_CPCCR & CPM_CPCCR_UCS) {
+ return __cpm_get_pllout2() / (__cpm_get_udiv() + 1);
+ }
+ else {
+ return JZ_EXTAL;
+ }
+}
+
+/*
+ * MSC clock
+ * @n: the index of MMC/SD controller
+ */
+static __inline__ unsigned int __cpm_get_mscclk(int n)
+{
+ return __cpm_get_pllout2() / (__cpm_get_mscdiv(n) + 1);
+}
+
+/* EXTAL clock */
+static __inline__ unsigned int __cpm_get_extalclk0(void)
+{
+ return JZ_EXTAL;
+}
+
+/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */
+static __inline__ unsigned int __cpm_get_extalclk(void)
+{
+#if defined(CONFIG_FPGA)
+ return __cpm_get_pllout();
+#else
+ if (REG_CPM_CPCCR & CPM_CPCCR_ECS)
+ return __cpm_get_extalclk0()/2;
+ else
+ return __cpm_get_extalclk0();
+#endif
+
+}
+
+/* RTC clock for CPM,INTC,RTC,TCU,WDT */
+static __inline__ unsigned int __cpm_get_rtcclk(void)
+{
+ return JZ_EXTAL2;
+}
+
+/*
+ * Output 24MHz for SD and 16MHz for MMC.
+ * @n: the index of MMC/SD controller
+ */
+static inline void __cpm_select_msc_clk(int n, int sd)
+{
+ unsigned int pllout2 = __cpm_get_pllout2();
+ unsigned int div = 0;
+
+ if (sd) {
+ div = pllout2 / 24000000;
+ }
+ else {
+ div = pllout2 / 16000000;
+ }
+
+ REG_CPM_MSCCDR(n) = div - 1;
+ REG_CPM_CPCCR |= CPM_CPCCR_CE;
+}
+
+/*
+ * Output 48MHz for high speed card.
+ */
+static inline void __cpm_select_msc_clk_high(int n, int sd)
+{
+ unsigned int pllout2 = __cpm_get_pllout2();
+ unsigned int div = 0;
+
+ div = pllout2 / 48000000;
+
+ REG_CPM_MSCCDR(n) = div - 1;
+ REG_CPM_CPCCR |= CPM_CPCCR_CE;
+}
+
+#endif /* __ASM_JZ4750L_CLOCK_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750l/dma.h b/arch/mips/include/asm/mach-jz4750l/dma.h
new file mode 100644
index 00000000000..c83b7fa99fb
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750l/dma.h
@@ -0,0 +1,307 @@
+/*
+ * linux/include/asm-mips/mach-jz4750l/dma.h
+ *
+ * JZ4750L DMA definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750L_DMA_H__
+#define __ASM_JZ4750L_DMA_H__
+
+#include <linux/interrupt.h>
+#include <asm/io.h> /* need byte IO */
+#include <linux/spinlock.h> /* And spinlocks */
+#include <linux/delay.h>
+#include <asm/system.h>
+
+/*
+ * Descriptor structure for JZ4750L DMA engine
+ * Note: this structure must always be aligned to a 16-bytes boundary.
+ */
+
+/* old descriptor 4-word */
+typedef struct {
+ volatile u32 dcmd; /* DCMD value for the current transfer */
+ volatile u32 dsadr; /* DSAR value for the current transfer */
+ volatile u32 dtadr; /* DTAR value for the current transfer */
+ volatile u32 ddadr; /* Points to the next descriptor + transfer count */
+} jz_dma_desc;
+
+/* new descriptor 8-word */
+typedef struct {
+ volatile u32 dcmd; /* DCMD value for the current transfer */
+ volatile u32 dsadr; /* DSAR value for the current transfer */
+ volatile u32 dtadr; /* DTAR value for the current transfer */
+ volatile u32 ddadr; /* Points to the next descriptor + transfer count */
+ volatile u32 dstrd; /* DMA source and target stride address */
+ volatile u32 dreqt; /* DMA request type for current transfer */
+ volatile u32 reserved0; /* Reserved */
+ volatile u32 reserved1; /* Reserved */
+} jz_dma_desc_8word;
+
+/* DMA Device ID's follow */
+enum {
+ DMA_ID_EXT = 0, /* External request with DREQn */
+ DMA_ID_NAND, /* NAND DMA request */
+ DMA_ID_BCH_ENC, /* BCH Encoding DMA request */
+ DMA_ID_BCH_DEC, /* BCH Decoding DMA request */
+ DMA_ID_AUTO, /* Auto-request */
+// DMA_ID_TSSI_RX, /* TSSI receive fifo full request */
+ DMA_ID_UART3_TX, /* UART3 transmit-fifo-empty request */
+ DMA_ID_UART3_RX, /* UART3 receve-fifo-full request */
+ DMA_ID_UART2_TX, /* UART2 transmit-fifo-empty request */
+ DMA_ID_UART2_RX, /* UART2 receve-fifo-full request */
+ DMA_ID_UART1_TX, /* UART1 transmit-fifo-empty request */
+ DMA_ID_UART1_RX, /* UART1 receve-fifo-full request */
+ DMA_ID_UART0_TX, /* UART0 transmit-fifo-empty request */
+ DMA_ID_UART0_RX, /* UART0 receve-fifo-full request */
+ DMA_ID_SSI0_TX, /* SSI0 transmit-fifo-full request */
+ DMA_ID_SSI0_RX, /* SSI0 receive-fifo-empty request */
+ DMA_ID_AIC_TX, /* AIC transmit-fifo-full request */
+ DMA_ID_AIC_RX, /* AIC receive-fifo-empty request */
+ DMA_ID_MSC0_TX, /* MSC0 transmit-fifo-full request */
+ DMA_ID_MSC0_RX, /* MSC0 receive-fifo-empty request */
+ DMA_ID_TCU_OVERFLOW, /* TCU channel n overflow interrupt */
+ DMA_ID_SADC, /* SADC transfer request */
+ DMA_ID_MSC1_TX, /* MSC1 transmit-fifo-full request */
+ DMA_ID_MSC1_RX, /* MSC1 receive-fifo-empty request */
+ DMA_ID_SSI1_TX, /* SSI1 transmit-fifo-full request */
+ DMA_ID_SSI1_RX, /* SSI1 receive-fifo-empty request */
+ DMA_ID_PCM_TX, /* PM transmit-fifo-full request */
+ DMA_ID_PCM_RX, /* PM receive-fifo-empty request */
+ DMA_ID_RAW_SET,
+ DMA_ID_MAX
+};
+
+/* DMA modes, simulated by sw */
+#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */
+#define DMA_AUTOINIT 0x2
+#define DMA_MODE_MASK 0x3
+
+struct jz_dma_chan {
+ int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */
+ unsigned int io; /* DMA channel number */
+ const char *dev_str; /* string describes the DMA channel */
+ int irq; /* DMA irq number */
+ void *irq_dev; /* DMA private device structure */
+ unsigned int fifo_addr; /* physical fifo address of the requested device */
+ unsigned int cntl; /* DMA controll */
+ unsigned int mode; /* DMA configuration */
+ unsigned int source; /* DMA request source */
+};
+
+extern struct jz_dma_chan jz_dma_table[];
+
+
+#define DMA_8BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_8BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_16BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_32BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_32_32BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
+#define DMA_AIC_32_16BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_32_16BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BIT_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BIT_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BYTE_RX_CMD \
+ DMAC_DCMD_DAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BYTE_TX_CMD \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+#define DMA_AIC_16BYTE_TX_CMD_UC \
+ DMAC_DCMD_SAI | \
+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \
+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
+
+extern int jz_request_dma(int dev_id,
+ const char *dev_str,
+ irqreturn_t (*irqhandler)(int, void *),
+ unsigned long irqflags,
+ void *irq_dev_id);
+extern void jz_free_dma(unsigned int dmanr);
+
+extern int jz_dma_read_proc(char *buf, char **start, off_t fpos,
+ int length, int *eof, void *data);
+extern void dump_jz_dma_channel(unsigned int dmanr);
+
+extern void enable_dma(unsigned int dmanr);
+extern void disable_dma(unsigned int dmanr);
+extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr);
+extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt);
+extern void set_dma_mode(unsigned int dmanr, unsigned int mode);
+extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
+extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
+extern void jz_set_dma_src_width(int dmanr, int nbit);
+extern void jz_set_dma_dest_width(int dmanr, int nbit);
+extern void jz_set_dma_block_size(int dmanr, int nbyte);
+extern unsigned int get_dma_residue(unsigned int dmanr);
+
+extern spinlock_t dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dma_spin_lock, flags);
+ return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+ spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ */
+#define clear_dma_ff(channel)
+
+static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr)
+{
+ if (dmanr > MAX_DMA_NUM
+ || jz_dma_table[dmanr].dev_id < 0)
+ return NULL;
+ return &jz_dma_table[dmanr];
+}
+
+static __inline__ int dma_halted(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 1;
+ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0;
+}
+
+static __inline__ unsigned int get_dma_mode(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+ return chan->mode;
+}
+
+static __inline__ void clear_dma_done(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+}
+
+static __inline__ void clear_dma_halt(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT);
+ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT);
+}
+
+static __inline__ void clear_dma_flag(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR);
+}
+
+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
+{
+}
+
+static __inline__ unsigned int get_dma_done_status(unsigned int dmanr)
+{
+ unsigned long dccsr;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+ dccsr = REG_DMAC_DCCSR(chan->io);
+ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+}
+
+static __inline__ int get_dma_done_irq(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return -1;
+ return chan->irq;
+}
+
+#endif /* __ASM_JZ4750L_DMA_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750l/jz4750l.h b/arch/mips/include/asm/mach-jz4750l/jz4750l.h
new file mode 100644
index 00000000000..86d9ae2fbc2
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750l/jz4750l.h
@@ -0,0 +1,42 @@
+/*
+ * linux/include/asm-mips/mach-jz4750l/jz4750l.h
+ *
+ * JZ4750 common definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750_H__
+#define __ASM_JZ4750_H__
+
+#include <asm/mach-jz4750l/regs.h>
+#include <asm/mach-jz4750l/ops.h>
+#include <asm/mach-jz4750l/dma.h>
+#include <asm/mach-jz4750l/misc.h>
+
+/*------------------------------------------------------------------
+ * Platform definitions
+ */
+#define JZ_SOC_NAME "JZ4750L"
+
+#ifdef CONFIG_JZ4750L_F4750L
+#include <asm/mach-jz4750l/board-f4750l.h>
+#endif
+
+/* Add other platform definition here ... */
+
+
+/*------------------------------------------------------------------
+ * Follows are related to platform definitions
+ */
+
+#include <asm/mach-jz4750l/clock.h>
+#include <asm/mach-jz4750l/serial.h>
+
+#endif /* __ASM_JZ4750_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750l/misc.h b/arch/mips/include/asm/mach-jz4750l/misc.h
new file mode 100644
index 00000000000..8e985dcebf8
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750l/misc.h
@@ -0,0 +1,44 @@
+/*
+ * linux/include/asm-mips/mach-jz4750l/misc.h
+ *
+ * Ingenic's JZ4750L common include.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_JZ4750L_MISC_H__
+#define __ASM_JZ4750L_MISC_H__
+
+/*==========================================================
+ * I2C
+ *===========================================================*/
+
+#define I2C_EEPROM_DEV 0xA /* b'1010 */
+#define I2C_RTC_DEV 0xD /* b'1101 */
+#define DIMM0_SPD_ADDR 0
+#define DIMM1_SPD_ADDR 1
+#define DIMM2_SPD_ADDR 2
+#define DIMM3_SPD_ADDR 3
+#define JZ_HCI_ADDR 7
+
+#define DIMM_SPD_LEN 128
+#define JZ_HCI_LEN 512 /* 4K bits E2PROM */
+#define I2C_RTC_LEN 16
+#define HCI_MAC_OFFSET 64
+
+extern void i2c_open(void);
+extern void i2c_close(void);
+extern void i2c_setclk(unsigned int i2cclk);
+
+extern int i2c_read(unsigned char device, unsigned char *buf,
+ unsigned char address, int count);
+extern int i2c_write(unsigned char device, unsigned char *buf,
+ unsigned char address, int count);
+
+#endif /* __ASM_JZ4750L_MISC_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750l/ops.h b/arch/mips/include/asm/mach-jz4750l/ops.h
new file mode 100644
index 00000000000..1a1ff115e65
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750l/ops.h
@@ -0,0 +1,3400 @@
+/*
+ * linux/include/asm-mips/mach-jz4750l/ops.h
+ *
+ * JZ4750L register definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#ifndef __JZ4750L_OPS_H__
+#define __JZ4750L_OPS_H__
+
+/*
+ * Definition of Module Operations
+ */
+
+/***************************************************************************
+ * EMC
+ ***************************************************************************/
+#define is_share_mode() (1)
+
+/***************************************************************************
+ * GPIO
+ ***************************************************************************/
+
+//------------------------------------------------------
+// GPIO Pins Description
+//
+// PORT 0:
+//
+// PIN/BIT N FUNC0 FUNC1 NOTE
+// 0 D0 -
+// 1 D1 -
+// 2 D2 -
+// 3 D3 -
+// 4 D4 -
+// 5 D5 -
+// 6 D6 -
+// 7 D7 -
+// 8 D8 -
+// 9 D9 -
+// 10 D10 -
+// 11 D11 -
+// 12 D12 -
+// 13 D13 -
+// 14 D14 -
+// 15 D15 -
+// 16 D16 -
+// 17 D17 -
+// 18 D18 -
+// 19 D19 -
+// 20 D20 -
+// 21 D21 -
+// 22 D22 -
+// 23 D23 -
+// 24 D24 -
+// 25 D25 -
+// 26 D26 -
+// 27 D27 -
+// 28 D28 -
+// 29 D29 -
+// 30 D30 -
+// 31 D31 -
+//
+//------------------------------------------------------
+// PORT 1:
+//
+// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE
+// 0 A0 - -
+// 1 A1 - -
+// 2 A2 - -
+// 3 A3 - -
+// 4 A4 - -
+// 5 A5 - -
+// 6 A6 - -
+// 7 A7 - -
+// 8 A8 - -
+// 9 A9 - -
+// 10 A10 - -
+// 11 A11 - -
+// 12 A12 - -
+// 13 A13 - -
+// 14 A14 - -
+// 15 A15/CLE CL(unshare) MSC0_CLK
+// 16 DCS0# - -
+// 17 RAS# - -
+// 18 CAS# - -
+// 19 SDWE#/BUFD# - -
+// 20 WE0# - -
+// 21 WE1# - -
+// 22 WE2# - -
+// 23 WE3# - -
+// 24 CKO - - Note1
+// 25 CKE - -
+// 26 SSI_CLK MSC1_CLK -
+// 27 SSI_DT MSC1_D1 -
+// 28 SSI_DR MSC1_D0 -
+// 29 SSI_CE0# MSC1_CMD -
+// 30 SSI_GPC MSC1_D2 -
+// 31 SSI_CE1# MSC1_D3 -
+//
+// Note1: BIT24: it is CKO when chip is reset
+//
+//------------------------------------------------------
+// PORT 2:
+//
+// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE
+// 0 SD0 A20 -
+// 1 SD1 A21 -
+// 2 SD2 A22 -
+// 3 SD3 A23 -
+// 4 SD4 A24 -
+// 5 SD5 A25 -
+// 6 SD6 - -
+// 7 SD7 - -
+// 8 SD8 TSDI0 -
+// 9 SD9 TSDI1 -
+// 10 SD10 TSDI2 -
+// 11 SD11 TSDI3 -
+// 12 SD12 TSDI4 -
+// 13 SD13 TSDI5 -
+// 14 SD14 TSDI6 -
+// 15 SD15 TSDI7 -
+// 16 A16/ALE AL(unshare) MSC0_CMD
+// 17 A17 MSC0_D3 -
+// 18 A18 DREQ -
+// 19 A19 DACK -
+// 20 WAIT# - - Note2
+// 21 CS1# - -
+// 22 CS2# - -
+// 23 CS3# - -
+// 24 CS4# - -
+// 25 RD# - -
+// 26 WR# - -
+// 27 FRB# - - Note3
+// 28 FRE# MSC0_D0 -
+// 29 FWE# MSC0_D1 -
+// 30 - - - Note4
+// 31 - - - Note5
+//
+// Note2: BIT20: it is WIAT# pin when chip is reset
+//
+// Note3: BIT27: when NAND is used, it should connect to NANF FRB#.
+//
+// Note4: BIT30: it is BOOT_SEL0 which would be set as input without pulling when chip is reset.
+//
+// Note5: BIT31: it is BOOT_SEL1 which would be set as input without pulling when chip is reset.
+//
+//------------------------------------------------------
+// PORT 3:
+//
+// PIN/BIT N FUNC0 FUNC1 NOTE
+// 0 LCD_B2 -
+// 1 LCD_B3 -
+// 2 LCD_B4 -
+// 3 LCD_B5 -
+// 4 LCD_B6 -
+// 5 LCD_B7 -
+// 6 LCD_G2 -
+// 7 LCD_G3 -
+// 8 LCD_G4 -
+// 9 LCD_G5 -
+// 10 LCD_G6 -
+// 11 LCD_G7 -
+// 12 LCD_R2 -
+// 13 LCD_R3 -
+// 14 LCD_R4 -
+// 15 LCD_R5 -
+// 16 LCD_R6 -
+// 17 LCD_R7 -
+// 18 LCD_PCLK -
+// 19 LCD_HSYNC -
+// 20 LCD_VSYNC -
+// 21 LCD_DE -
+// 22 LCD_CLS LCD_R1
+// 23 LCD_SPL LCD_G0
+// 24 LCD_PS LCD_G1
+// 25 LCD_REV LCD_B1
+// 26 LCD_B0 -
+// 27 LCD_R0 -
+// 28 UART0_RXD TSCLK
+// 29 UART0_TXD TSSTR
+// 30 UART0_CTS TSFRM
+// 31 UART0_RTS TSFAIL
+//
+//------------------------------------------------------
+// PORT 4:
+//
+// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE
+// 0 CIM_D0 TSDI0 -
+// 1 CIM_D1 TSDI1 -
+// 2 CIM_D2 TSDI2 -
+// 3 CIM_D3 TSDI3 -
+// 4 CIM_D4 TSDI4 -
+// 5 CIM_D5 TSDI5 -
+// 6 CIM_D6 TSDI6 -
+// 7 CIM_D7 TSDI7 -
+// 8 CIM_MCLK TSFAIL -
+// 9 CIM_PCLK TSCLK -
+// 10 CIM_VSYNC TSSTR -
+// 11 CIM_HSYNC TSFRM -
+// 12 I2C_SDA - -
+// 13 I2C_SCK - -
+// 18 SDATO - -
+// 19 SDATI - -
+// 20 PWM0 - -
+// 22 PWM2 SYNC -
+// 23 PWM3 UART1_RxD BCLK
+// 24 PWM4 - -
+// 25 PWM5 UART1_TxD SCLK_RSTN
+// 28 DCS1# - -
+// 29 - - - Note6
+// 30 WKUP - - Note7
+// 31 - - - Note8
+//
+// Note6: BIT29: it is BOOT_SEL2 which would be set as input without pulling when chip is reset.
+// Note7: BIT30: it is only used as input and interrupt, and with no pull-up and pull-down
+// Note8: BIT31: it is used to select the function of UART or JTAG set by PESEL[31]
+// PESEL[31] = 0, select JTAG function
+// PESEL[31] = 1, select UART function
+//
+//------------------------------------------------------
+// PORT 5:
+//
+// PIN/BIT N FUNC0 FUNC1 NOTE
+// 10 SSI_CLK -
+// 11 SSI_DT PWM1
+// 12 SSI_DR -
+// 13 SSI_CE0# -
+// 14 SSI_GPC -
+// 15 SSI_CE2# -
+//
+//////////////////////////////////////////////////////////
+
+/*----------------------------------------------------------------
+ * p is the port number (0,1,2,3,4,5)
+ * o is the pin offset (0-31) inside the port
+ * n is the absolute number of a pin (0-127), regardless of the port
+ */
+
+//-------------------------------------------
+// Function Pins Mode
+
+#define __gpio_as_func0(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFUNS(p) = (1 << o); \
+ REG_GPIO_PXTRGC(p) = (1 << o); \
+ REG_GPIO_PXSELC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_func1(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFUNS(p) = (1 << o); \
+ REG_GPIO_PXTRGC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_func2(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFUNS(p) = (1 << o); \
+ REG_GPIO_PXTRGS(p) = (1 << o); \
+ REG_GPIO_PXSELC(p) = (1 << o); \
+} while (0)
+
+
+/*
+ * D0 ~ D15, A0 ~ A14, DCS0#, RAS#, CAS#,
+ * RDWE#, WE0#, WE1#, CKO#, CKE#
+ */
+#define __gpio_as_sdram_16bit() \
+do { \
+ REG_GPIO_PXFUNS(0) = 0x0000ffff; \
+ REG_GPIO_PXSELC(0) = 0x0000ffff; \
+ REG_GPIO_PXPES(0) = 0x0000ffff; \
+ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \
+ REG_GPIO_PXSELC(1) = 0x03ff7fff; \
+ REG_GPIO_PXPES(1) = 0x03ff7fff; \
+} while (0)
+
+/*
+ * D0 ~ D7, CS1#, CLE, ALE, FRE#, FWE#, FRB#, RDWE#/BUFD#
+ * @n: chip select number(1 ~ 4)
+ */
+#define __gpio_as_nand_8bit(n) \
+do { \
+ /* 32/16-bit data bus */ \
+ REG_GPIO_PXFUNS(0) = 0x000000ff; /* D0~D7 */ \
+ REG_GPIO_PXSELC(0) = 0x000000ff; \
+ REG_GPIO_PXPES(0) = 0x000000ff; \
+ REG_GPIO_PXFUNS(2) = 0x00000300; /* CLE(A15), ALE(A16) */ \
+ REG_GPIO_PXSELC(2) = 0x00000300; \
+ REG_GPIO_PXPES(2) = 0x0000300; \
+ \
+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \
+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \
+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \
+ \
+ REG_GPIO_PXFUNS(1) = 0x00080000; /* RDWE#/BUFD# */ \
+ REG_GPIO_PXSELC(1) = 0x00080000; \
+ REG_GPIO_PXPES(1) = 0x00080000; \
+ REG_GPIO_PXFUNS(2) = 0x30000000; /* FRE#, FWE# */ \
+ REG_GPIO_PXSELC(2) = 0x30000000; \
+ REG_GPIO_PXPES(2) = 0x30000000; \
+ REG_GPIO_PXFUNC(2) = 0x08000000; /* FRB#(input) */ \
+ REG_GPIO_PXSELC(2) = 0x08000000; \
+ REG_GPIO_PXDIRC(2) = 0x08000000; \
+ REG_GPIO_PXPES(2) = 0x08000000; \
+} while (0)
+
+/*
+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D7
+ * @n: chip select number(1 ~ 4)
+ */
+#define __gpio_as_nor_8bit(n) \
+do { \
+ /* 32/16-bit data bus */ \
+ REG_GPIO_PXFUNS(0) = 0x000000ff; \
+ REG_GPIO_PXSELC(0) = 0x000000ff; \
+ REG_GPIO_PXPES(0) = 0x000000ff; \
+ \
+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \
+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \
+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \
+ \
+ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \
+ REG_GPIO_PXSELC(1) = 0x0000ffff; \
+ REG_GPIO_PXPES(1) = 0x0000ffff; \
+ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \
+ REG_GPIO_PXSELC(2) = 0x06110007; \
+ REG_GPIO_PXPES(2) = 0x06110007; \
+ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \
+ REG_GPIO_PXSELS(2) = 0x000e0000; \
+ REG_GPIO_PXPES(2) = 0x000e0000; \
+} while (0)
+
+/*
+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D15
+ * @n: chip select number(1 ~ 4)
+ */
+#define __gpio_as_nor_16bit(n) \
+do { \
+ /* 32/16-bit data normal order */ \
+ REG_GPIO_PXFUNS(0) = 0x0000ffff; \
+ REG_GPIO_PXSELC(0) = 0x0000ffff; \
+ REG_GPIO_PXPES(0) = 0x0000ffff; \
+ \
+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \
+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \
+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \
+ \
+ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \
+ REG_GPIO_PXSELC(1) = 0x0000ffff; \
+ REG_GPIO_PXPES(1) = 0x0000ffff; \
+ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \
+ REG_GPIO_PXSELC(2) = 0x06110007; \
+ REG_GPIO_PXPES(2) = 0x06110007; \
+ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \
+ REG_GPIO_PXSELS(2) = 0x000e0000; \
+ REG_GPIO_PXPES(2) = 0x000e0000; \
+} while (0)
+
+/*
+ * UART0_TxD, UART0_RxD
+ */
+#define __gpio_as_uart0() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x00003000; \
+ REG_GPIO_PXTRGC(2) = 0x00003000; \
+ REG_GPIO_PXSELS(2) = 0x00003000; \
+ REG_GPIO_PXPES(2) = 0x00003000; \
+} while (0)
+
+/*
+ * UART0_TxD, UART0_RxD, UART0_CTS, UART0_RTS
+ */
+#define __gpio_as_uart0_ctsrts() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0xf0000000; \
+ REG_GPIO_PXSELC(3) = 0xf0000000; \
+ REG_GPIO_PXPES(3) = 0xf0000000; \
+} while (0)
+
+/*
+ * UART1_TxD, UART1_RxD
+ */
+#define __gpio_as_uart1() \
+do { \
+ REG_GPIO_PXTRGC(4) = 0x02800000; \
+ REG_GPIO_PXFUNS(4) = 0x02800000; \
+ REG_GPIO_PXSELS(4) = 0x02800000; \
+ REG_GPIO_PXPES(4) = 0x02800000; \
+} while (0)
+
+/*
+ * TSCLK, TSSTR, TSFRM, TSFAIL, TSDI0~7
+ */
+#define __gpio_as_tssi() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x0000ff00; \
+ REG_GPIO_PXSELS(2) = 0x0000ff00; \
+ REG_GPIO_PXPES(2) = 0x0000ff00; \
+ REG_GPIO_PXFUNS(3) = 0xf0000000; \
+ REG_GPIO_PXSELS(3) = 0xf0000000; \
+ REG_GPIO_PXPES(3) = 0xf0000000; \
+} while (0)
+
+/*
+ * LCD_D0~LCD_D7, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_8bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x003c00ff; \
+ REG_GPIO_PXTRGC(3) = 0x003c00ff; \
+ REG_GPIO_PXSELC(3) = 0x003c00ff; \
+ REG_GPIO_PXPES(3) = 0x003c00ff; \
+} while (0)
+
+/*
+ * LCD_D0~LCD_D15, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_16bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x003cffff; \
+ REG_GPIO_PXTRGC(3) = 0x003cffff; \
+ REG_GPIO_PXSELC(3) = 0x003cffff; \
+ REG_GPIO_PXPES(3) = 0x003cffff; \
+} while (0)
+
+/*
+ * LCD_R2~LCD_R7, LCD_G2~LCD_G7, LCD_B2~LCD_B7,
+ * LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_18bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x003fffff; \
+ REG_GPIO_PXTRGC(3) = 0x003fffff; \
+ REG_GPIO_PXSELC(3) = 0x003fffff; \
+ REG_GPIO_PXPES(3) = 0x003fffff; \
+} while (0)
+
+/*
+ * LCD_D0~LCD_D17, LCD_D_R1, LCD_D_G0, LCD_D_G1, LCD_D_B1,
+ * LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE
+ */
+#define __gpio_as_lcd_24bit() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x003fffff; \
+ REG_GPIO_PXTRGC(3) = 0x003fffff; \
+ REG_GPIO_PXSELC(3) = 0x003fffff; \
+ REG_GPIO_PXPES(3) = 0x003fffff; \
+ REG_GPIO_PXFUNS(3) = 0x03c00000; \
+ REG_GPIO_PXTRGC(3) = 0x03c00000; \
+ REG_GPIO_PXSELS(3) = 0x03c00000; \
+ REG_GPIO_PXPES(3) = 0x03c00000; \
+} while (0)
+
+/*
+ * LCD_CLS, LCD_SPL, LCD_PS, LCD_REV
+ */
+#define __gpio_as_lcd_special() \
+do { \
+ REG_GPIO_PXFUNS(3) = 0x03C00000; \
+ REG_GPIO_PXTRGC(3) = 0x03C00000; \
+ REG_GPIO_PXSELC(3) = 0x03C00000; \
+ REG_GPIO_PXPES(3) = 0x03C00000; \
+} while (0)
+
+/*
+ * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC
+ */
+#define __gpio_as_cim() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x00000ff; \
+ REG_GPIO_PXTRGS(2) = 0x00000ff; \
+ REG_GPIO_PXSELC(2) = 0x00000ff; \
+ REG_GPIO_PXPES(2) = 0x00000ff; \
+ REG_GPIO_PXFUNS(3) = 0x03c00000; \
+ REG_GPIO_PXTRGS(3) = 0x03c00000; \
+ REG_GPIO_PXSELC(3) = 0x03c00000; \
+ REG_GPIO_PXPES(3) = 0x03c00000; \
+} while (0)
+
+
+/*
+ * SDATO, SDATI, BCLK, SYNC, SCLK_RSTN(gpio sepc) or
+ * SDATA_OUT, SDATA_IN, BIT_CLK, SYNC, SCLK_RESET(aic spec)
+ */
+#define __gpio_as_aic() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x16c00000; \
+ REG_GPIO_PXTRGC(4) = 0x02c00000; \
+ REG_GPIO_PXTRGS(4) = 0x14000000; \
+ REG_GPIO_PXSELC(4) = 0x14c00000; \
+ REG_GPIO_PXSELS(4) = 0x02000000; \
+ REG_GPIO_PXPES(4) = 0x16c00000; \
+} while (0)
+
+/*
+ * MSC0_CMD, MSC0_CLK, MSC0_D0 ~ MSC0_D3
+ */
+#define __gpio_as_msc0_4bit() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x38400300; \
+ REG_GPIO_PXTRGC(2) = 0x38400300; \
+ REG_GPIO_PXSELS(2) = 0x30400300; \
+ REG_GPIO_PXSELC(2) = 0x08000000; \
+ REG_GPIO_PXPES(2) = 0x38400300; \
+} while (0)
+
+
+/*
+ * MSC1_CMD, MSC1_CLK, MSC1_D0 ~ MSC1_D3
+ */
+#define __gpio_as_msc1_4bit() \
+do { \
+ REG_GPIO_PXFUNS(1) = 0xfc000000; \
+ REG_GPIO_PXTRGC(1) = 0xfc000000; \
+ REG_GPIO_PXSELS(1) = 0xfc000000; \
+ REG_GPIO_PXPES(1) = 0xfc000000; \
+} while (0)
+
+#define __gpio_as_msc __gpio_as_msc0_4bit /* default as msc0 4bit */
+#define __gpio_as_msc0 __gpio_as_msc0_4bit /* msc0 default as 4bit */
+#define __gpio_as_msc1 __gpio_as_msc1_4bit /* msc1 only support 4bit */
+
+/*
+ * SSI_CE0, SSI_CE1, SSI_GPC, SSI_CLK, SSI_DT, SSI_DR
+ */
+#define __gpio_as_ssi() \
+do { \
+ REG_GPIO_PXFUNS(1) = 0xfc000000; \
+ REG_GPIO_PXTRGC(1) = 0xfc000000; \
+ REG_GPIO_PXSELC(1) = 0xfc000000; \
+ REG_GPIO_PXPES(1) = 0xfc000000; \
+} while (0)
+
+/*
+ * SSI_CE0, SSI_CE2, SSI_GPC, SSI_CLK, SSI_DT, SSI1_DR
+ */
+#define __gpio_as_ssi_1() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x0000fc00; \
+ REG_GPIO_PXTRGC(5) = 0x0000fc00; \
+ REG_GPIO_PXSELC(5) = 0x0000fc00; \
+ REG_GPIO_PXPES(5) = 0x0000fc00; \
+} while (0)
+
+/*
+ * I2C_SCK, I2C_SDA
+ */
+#define __gpio_as_i2c() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x00000c00; \
+ REG_GPIO_PXTRGC(2) = 0x00000c00; \
+ REG_GPIO_PXSELS(2) = 0x00000c00; \
+ REG_GPIO_PXPES(2) = 0x00000c00; \
+} while (0)
+
+/*
+ * PWM0
+ */
+#define __gpio_as_pwm0() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00100000; \
+ REG_GPIO_PXSELC(4) = 0x00100000; \
+ REG_GPIO_PXPES(4) = 0x00100000; \
+} while (0)
+
+/*
+ * PWM1
+ */
+#define __gpio_as_pwm1() \
+do { \
+ REG_GPIO_PXFUNS(5) = 0x00000800; \
+ REG_GPIO_PXSELC(5) = 0x00000800; \
+ REG_GPIO_PXPES(5) = 0x00000800; \
+} while (0)
+
+/*
+ * PWM2
+ */
+#define __gpio_as_pwm2() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00400000; \
+ REG_GPIO_PXSELC(4) = 0x00400000; \
+ REG_GPIO_PXPES(4) = 0x00400000; \
+} while (0)
+
+/*
+ * PWM3
+ */
+#define __gpio_as_pwm3() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x00800000; \
+ REG_GPIO_PXSELC(4) = 0x00800000; \
+ REG_GPIO_PXPES(4) = 0x00800000; \
+} while (0)
+
+/*
+ * PWM4
+ */
+#define __gpio_as_pwm4() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x01000000; \
+ REG_GPIO_PXSELC(4) = 0x01000000; \
+ REG_GPIO_PXPES(4) = 0x01000000; \
+} while (0)
+
+/*
+ * PWM5
+ */
+#define __gpio_as_pwm5() \
+do { \
+ REG_GPIO_PXFUNS(4) = 0x02000000; \
+ REG_GPIO_PXSELC(4) = 0x02000000; \
+ REG_GPIO_PXPES(4) = 0x02000000; \
+} while (0)
+
+/*
+ * n = 0 ~ 5
+ */
+#define __gpio_as_pwm(n) __gpio_as_pwm##n()
+
+/*
+ * DREQ
+ */
+#define __gpio_as_dreq() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x00040000; \
+ REG_GPIO_PXSELS(2) = 0x00040000; \
+ REG_GPIO_PXPES(2) = 0x00040000; \
+} while (0)
+
+/*
+ * DACK
+ */
+#define __gpio_as_dack() \
+do { \
+ REG_GPIO_PXFUNS(2) = 0x00080000; \
+ REG_GPIO_PXSELS(2) = 0x00080000; \
+ REG_GPIO_PXPES(2) = 0x00080000; \
+} while (0)
+
+/*
+ * GPIO or Interrupt Mode
+ */
+#define __gpio_get_port(p) (REG_GPIO_PXPIN(p))
+
+#define __gpio_port_as_output(p, o) \
+do { \
+ REG_GPIO_PXFUNC(p) = (1 << (o)); \
+ REG_GPIO_PXSELC(p) = (1 << (o)); \
+ REG_GPIO_PXDIRS(p) = (1 << (o)); \
+} while (0)
+
+#define __gpio_port_as_input(p, o) \
+do { \
+ REG_GPIO_PXFUNC(p) = (1 << (o)); \
+ REG_GPIO_PXSELC(p) = (1 << (o)); \
+ REG_GPIO_PXDIRC(p) = (1 << (o)); \
+} while (0)
+
+#define __gpio_as_output(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_as_output(p, o); \
+} while (0)
+
+#define __gpio_as_input(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ __gpio_port_as_input(p, o); \
+} while (0)
+
+#define __gpio_set_pin(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXDATS(p) = (1 << o); \
+} while (0)
+
+#define __gpio_clear_pin(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXDATC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_get_pin(n) \
+({ \
+ unsigned int p, o, v; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ if (__gpio_get_port(p) & (1 << o)) \
+ v = 1; \
+ else \
+ v = 0; \
+ v; \
+})
+
+#define __gpio_as_irq_high_level(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGC(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRS(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_irq_low_level(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGC(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRC(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_irq_rise_edge(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGS(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRS(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_as_irq_fall_edge(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+ REG_GPIO_PXTRGS(p) = (1 << o); \
+ REG_GPIO_PXFUNC(p) = (1 << o); \
+ REG_GPIO_PXSELS(p) = (1 << o); \
+ REG_GPIO_PXDIRC(p) = (1 << o); \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_mask_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMS(p) = (1 << o); \
+} while (0)
+
+#define __gpio_unmask_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXIMC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_ack_irq(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXFLGC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_get_irq() \
+({ \
+ unsigned int p, i, tmp, v = 0; \
+ for (p = 3; p >= 0; p--) { \
+ tmp = REG_GPIO_PXFLG(p); \
+ for (i = 0; i < 32; i++) \
+ if (tmp & (1 << i)) \
+ v = (32*p + i); \
+ } \
+ v; \
+})
+
+#define __gpio_group_irq(n) \
+({ \
+ register int tmp, i; \
+ tmp = REG_GPIO_PXFLG((n)); \
+ for (i=31;i>=0;i--) \
+ if (tmp & (1 << i)) \
+ break; \
+ i; \
+})
+
+#define __gpio_enable_pull(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXPEC(p) = (1 << o); \
+} while (0)
+
+#define __gpio_disable_pull(n) \
+do { \
+ unsigned int p, o; \
+ p = (n) / 32; \
+ o = (n) % 32; \
+ REG_GPIO_PXPES(p) = (1 << o); \
+} while (0)
+
+
+/***************************************************************************
+ * CPM
+ ***************************************************************************/
+#define __cpm_get_pllm() \
+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLM_MASK) >> CPM_CPPCR_PLLM_BIT)
+#define __cpm_get_plln() \
+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLN_MASK) >> CPM_CPPCR_PLLN_BIT)
+#define __cpm_get_pllod() \
+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLOD_MASK) >> CPM_CPPCR_PLLOD_BIT)
+
+#define __cpm_get_cdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_CDIV_MASK) >> CPM_CPCCR_CDIV_BIT)
+#define __cpm_get_hdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_HDIV_MASK) >> CPM_CPCCR_HDIV_BIT)
+#define __cpm_get_pdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_PDIV_MASK) >> CPM_CPCCR_PDIV_BIT)
+#define __cpm_get_mdiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT)
+#define __cpm_get_h1div() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_H1DIV_MASK) >> CPM_CPCCR_H1DIV_BIT)
+#define __cpm_get_udiv() \
+ ((REG_CPM_CPCCR & CPM_CPCCR_UDIV_MASK) >> CPM_CPCCR_UDIV_BIT)
+#define __cpm_get_i2sdiv() \
+ ((REG_CPM_I2SCDR & CPM_I2SCDR_I2SDIV_MASK) >> CPM_I2SCDR_I2SDIV_BIT)
+#define __cpm_get_pixdiv() \
+ ((REG_CPM_LPCDR & CPM_LPCDR_PIXDIV_MASK) >> CPM_LPCDR_PIXDIV_BIT)
+#define __cpm_get_mscdiv(n) \
+ ((REG_CPM_MSCCDR(n) & CPM_MSCCDR_MSCDIV_MASK) >> CPM_MSCCDR_MSCDIV_BIT)
+#define __cpm_get_uhcdiv() \
+ ((REG_CPM_UHCCDR & CPM_UHCCDR_UHCDIV_MASK) >> CPM_UHCCDR_UHCDIV_BIT)
+#define __cpm_get_ssidiv() \
+ ((REG_CPM_SSICCDR & CPM_SSICDR_SSICDIV_MASK) >> CPM_SSICDR_SSIDIV_BIT)
+#define __cpm_get_pcmdiv(v) \
+ ((REG_CPM_PCMCDR & CPM_PCMCDR_PCMCD_MASK) >> CPM_PCMCDR_PCMCD_BIT)
+
+#define __cpm_set_cdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_CDIV_MASK) | ((v) << (CPM_CPCCR_CDIV_BIT)))
+#define __cpm_set_hdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_HDIV_MASK) | ((v) << (CPM_CPCCR_HDIV_BIT)))
+#define __cpm_set_pdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_PDIV_MASK) | ((v) << (CPM_CPCCR_PDIV_BIT)))
+#define __cpm_set_mdiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_MDIV_MASK) | ((v) << (CPM_CPCCR_MDIV_BIT)))
+#define __cpm_set_h1div(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_H1DIV_MASK) | ((v) << (CPM_CPCCR_H1DIV_BIT)))
+#define __cpm_set_udiv(v) \
+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_UDIV_MASK) | ((v) << (CPM_CPCCR_UDIV_BIT)))
+#define __cpm_set_i2sdiv(v) \
+ (REG_CPM_I2SCDR = (REG_CPM_I2SCDR & ~CPM_I2SCDR_I2SDIV_MASK) | ((v) << (CPM_I2SCDR_I2SDIV_BIT)))
+#define __cpm_set_pixdiv(v) \
+ (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT)))
+#define __cpm_set_mscdiv(n, v) \
+ (REG_CPM_MSCCDR(n) = (REG_CPM_MSCCDR(n) & ~CPM_MSCCDR_MSCDIV_MASK) | ((v) << (CPM_MSCCDR_MSCDIV_BIT)))
+#define __cpm_set_uhcdiv(v) \
+ (REG_CPM_UHCCDR = (REG_CPM_UHCCDR & ~CPM_UHCCDR_UHCDIV_MASK) | ((v) << (CPM_UHCCDR_UHCDIV_BIT)))
+#define __cpm_set_ssidiv(v) \
+ (REG_CPM_SSICDR = (REG_CPM_SSICDR & ~CPM_SSICDR_SSIDIV_MASK) | ((v) << (CPM_SSICDR_SSIDIV_BIT)))
+#define __cpm_set_pcmdiv(v) \
+ (REG_CPM_PCMCDR = (REG_CPM_PCMCDR & ~CPM_PCMCDR_PCMCD_MASK) | ((v) << (CPM_PCMCDR_PCMCD_BIT)))
+
+#define __cpm_select_pcmclk_pll() (REG_CPM_PCMCDR |= CPM_PCMCDR_PCMS)
+#define __cpm_select_pcmclk_exclk() (REG_CPM_PCMCDR &= ~CPM_PCMCDR_PCMS)
+#define __cpm_select_tveclk_exclk() (REG_CPM_LPCDR |= CPM_CPCCR_LSCS)
+#define __cpm_select_tveclk_pll() (REG_CPM_LPCDR &= ~CPM_LPCDR_LSCS)
+#define __cpm_select_pixclk_lcd() (REG_CPM_LPCDR &= ~CPM_LPCDR_LTCS)
+#define __cpm_select_pixclk_tve() (REG_CPM_LPCDR |= CPM_LPCDR_LTCS)
+#define __cpm_select_i2sclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_I2CS)
+#define __cpm_select_i2sclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_I2CS)
+#define __cpm_select_usbclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_UCS)
+#define __cpm_select_usbclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_UCS)
+
+#define __cpm_enable_cko()
+#define __cpm_exclk_direct() (REG_CPM_CPCCR &= ~CPM_CPCCR_ECS)
+#define __cpm_exclk_div2() (REG_CPM_CPCCR |= CPM_CPCCR_ECS)
+#define __cpm_enable_pll_change() (REG_CPM_CPCCR |= CPM_CPCCR_CE)
+#define __cpm_pllout_direct() (REG_CPM_CPCCR |= CPM_CPCCR_PCS)
+#define __cpm_pllout_div2() (REG_CPM_CPCCR &= ~CPM_CPCCR_PCS)
+#define __cpm_pll_enable() (REG_CPM_CPPCR |= CPM_CPPCR_PLLEN)
+
+#define __cpm_pll_is_off() (REG_CPM_CPPSR & CPM_CPPSR_PLLOFF)
+#define __cpm_pll_is_on() (REG_CPM_CPPSR & CPM_CPPSR_PLLON)
+#define __cpm_pll_bypass() (REG_CPM_CPPSR |= CPM_CPPSR_PLLBP)
+
+#define __cpm_get_cclk_doze_duty() \
+ ((REG_CPM_LCR & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT)
+#define __cpm_set_cclk_doze_duty(v) \
+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_DOZE_DUTY_MASK) | ((v) << (CPM_LCR_DOZE_DUTY_BIT)))
+
+#define __cpm_doze_mode() (REG_CPM_LCR |= CPM_LCR_DOZE_ON)
+#define __cpm_idle_mode() \
+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_IDLE)
+#define __cpm_sleep_mode() \
+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_SLEEP)
+
+#define __cpm_stop_all() (REG_CPM_CLKGR = 0x1fffffff)
+#define __cpm_stop_cimram() (REG_CPM_CLKGR |= CPM_CLKGR_CIMRAM)
+#define __cpm_stop_idct() (REG_CPM_CLKGR |= CPM_CLKGR_IDCT)
+#define __cpm_stop_db() (REG_CPM_CLKGR |= CPM_CLKGR_DB)
+#define __cpm_stop_me() (REG_CPM_CLKGR |= CPM_CLKGR_ME)
+#define __cpm_stop_mc() (REG_CPM_CLKGR |= CPM_CLKGR_MC)
+#define __cpm_stop_tve() (REG_CPM_CLKGR |= CPM_CLKGR_TVE)
+#define __cpm_stop_tssi() (REG_CPM_CLKGR |= CPM_CLKGR_TSSI)
+#define __cpm_stop_owi() (REG_CPM_CLKGR |= CPM_CLKGR_OWI)
+#define __cpm_stop_pcm() (REG_CPM_CLKGR |= CPM_CLKGR_PCM)
+#define __cpm_stop_uart3() (REG_CPM_CLKGR |= CPM_CLKGR_UART3)
+#define __cpm_stop_uart2() (REG_CPM_CLKGR |= CPM_CLKGR_UART2)
+#define __cpm_stop_uart1() (REG_CPM_CLKGR |= CPM_CLKGR_UART1)
+#define __cpm_stop_uhc() (REG_CPM_CLKGR |= CPM_CLKGR_UHC)
+#define __cpm_stop_ipu() (REG_CPM_CLKGR |= CPM_CLKGR_IPU)
+#define __cpm_stop_dmac() (REG_CPM_CLKGR |= CPM_CLKGR_DMAC)
+#define __cpm_stop_udc() (REG_CPM_CLKGR |= CPM_CLKGR_UDC)
+#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD)
+#define __cpm_stop_cim() (REG_CPM_CLKGR |= CPM_CLKGR_CIM)
+#define __cpm_stop_sadc() (REG_CPM_CLKGR |= CPM_CLKGR_SADC)
+#define __cpm_stop_msc(n) (REG_CPM_CLKGR |= CPM_CLKGR_MSC##n)
+#define __cpm_stop_aic1() (REG_CPM_CLKGR |= CPM_CLKGR_AIC1)
+#define __cpm_stop_aic2() (REG_CPM_CLKGR |= CPM_CLKGR_AIC2)
+#define __cpm_stop_ssi(n) (REG_CPM_CLKGR |= CPM_CLKGR_SSI##n)
+#define __cpm_stop_i2c() (REG_CPM_CLKGR |= CPM_CLKGR_I2C)
+#define __cpm_stop_rtc() (REG_CPM_CLKGR |= CPM_CLKGR_RTC)
+#define __cpm_stop_tcu() (REG_CPM_CLKGR |= CPM_CLKGR_TCU)
+#define __cpm_stop_uart0() (REG_CPM_CLKGR |= CPM_CLKGR_UART0)
+
+#define __cpm_start_all() (REG_CPM_CLKGR = 0x0)
+#define __cpm_start_cimram() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIMRAM)
+#define __cpm_start_idct() (REG_CPM_CLKGR &= ~CPM_CLKGR_IDCT)
+#define __cpm_start_db() (REG_CPM_CLKGR &= ~CPM_CLKGR_DB)
+#define __cpm_start_me() (REG_CPM_CLKGR &= ~CPM_CLKGR_ME)
+#define __cpm_start_mc() (REG_CPM_CLKGR &= ~CPM_CLKGR_MC)
+#define __cpm_start_tve() (REG_CPM_CLKGR &= ~CPM_CLKGR_TVE)
+#define __cpm_start_tssi() (REG_CPM_CLKGR &= ~CPM_CLKGR_TSSI)
+#define __cpm_start_owi() (REG_CPM_CLKGR &= ~CPM_CLKGR_OWI)
+#define __cpm_start_pcm() (REG_CPM_CLKGR &= ~CPM_CLKGR_PCM)
+#define __cpm_start_uart3() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART3)
+#define __cpm_start_uart2() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART2)
+#define __cpm_start_uart1() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART1)
+#define __cpm_start_uhc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UHC)
+#define __cpm_start_ipu() (REG_CPM_CLKGR &= ~CPM_CLKGR_IPU)
+#define __cpm_start_dmac() (REG_CPM_CLKGR &= ~CPM_CLKGR_DMAC)
+#define __cpm_start_udc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UDC)
+#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD)
+#define __cpm_start_cim() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIM)
+#define __cpm_start_sadc() (REG_CPM_CLKGR &= ~CPM_CLKGR_SADC)
+#define __cpm_start_msc(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_MSC##n)
+#define __cpm_start_aic1() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC1)
+#define __cpm_start_aic2() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC2)
+#define __cpm_start_ssi(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_SSI##n)
+#define __cpm_start_i2c() (REG_CPM_CLKGR &= ~CPM_CLKGR_I2C)
+#define __cpm_start_rtc() (REG_CPM_CLKGR &= ~CPM_CLKGR_RTC)
+#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU)
+#define __cpm_start_uart0() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART0)
+
+#define __cpm_get_o1st() \
+ ((REG_CPM_OPCR & CPM_OPCR_O1ST_MASK) >> CPM_OPCR_O1ST_BIT)
+#define __cpm_set_o1st(v) \
+ (REG_CPM_OPCR = (REG_CPM_OPCR & ~CPM_OPCR_O1ST_MASK) | ((v) << (CPM_OPCR_O1ST_BIT)))
+#define __cpm_enable_uhcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UHCPHY_DISABLE)
+#define __cpm_suspend_uhcphy() (REG_CPM_OPCR |= CPM_OPCR_UHCPHY_DISABLE)
+#define __cpm_enable_udcphy() (REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE)
+#define __cpm_suspend_udcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE)
+#define __cpm_enable_osc_in_sleep() (REG_CPM_OPCR |= CPM_OPCR_OSC_ENABLE)
+#define __cpm_disable_osc_in_sleep() (REG_CPM_OPCR &= ~CPM_OPCR_OSC_ENABLE)
+#define __cpm_select_rtcclk_rtc() (REG_CPM_OPCR |= CPM_OPCR_ERCS)
+#define __cpm_select_rtcclk_exclk() (REG_CPM_OPCR &= ~CPM_OPCR_ERCS)
+
+
+/***************************************************************************
+ * TCU
+ ***************************************************************************/
+// where 'n' is the TCU channel
+#define __tcu_select_extalclk(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_EXT_EN)
+#define __tcu_select_rtcclk(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_RTC_EN)
+#define __tcu_select_pclk(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_PCK_EN)
+#define __tcu_disable_pclk(n) \
+ REG_TCU_TCSR(n) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PCK_EN);
+#define __tcu_select_clk_div1(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1)
+#define __tcu_select_clk_div4(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE4)
+#define __tcu_select_clk_div16(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE16)
+#define __tcu_select_clk_div64(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE64)
+#define __tcu_select_clk_div256(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE256)
+#define __tcu_select_clk_div1024(n) \
+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1024)
+
+#define __tcu_enable_pwm_output(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_EN)
+#define __tcu_disable_pwm_output(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_EN)
+
+#define __tcu_init_pwm_output_high(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_INITL_HIGH)
+#define __tcu_init_pwm_output_low(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_INITL_HIGH)
+
+#define __tcu_set_pwm_output_shutdown_graceful(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_SD)
+#define __tcu_set_pwm_output_shutdown_abrupt(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_SD)
+
+#define __tcu_clear_counter_to_zero(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_CNT_CLRZ)
+
+#define __tcu_ost_enabled() (REG_TCU_TER & TCU_TER_OSTEN)
+#define __tcu_enable_ost() (REG_TCU_TESR = TCU_TESR_OSTST)
+#define __tcu_disable_ost() (REG_TCU_TECR = TCU_TECR_OSTCL)
+
+#define __tcu_counter_enabled(n) (REG_TCU_TER & (1 << (n)))
+#define __tcu_start_counter(n) (REG_TCU_TESR |= (1 << (n)))
+#define __tcu_stop_counter(n) (REG_TCU_TECR |= (1 << (n)))
+
+#define __tcu_half_match_flag(n) (REG_TCU_TFR & (1 << ((n) + 16)))
+#define __tcu_full_match_flag(n) (REG_TCU_TFR & (1 << (n)))
+#define __tcu_set_half_match_flag(n) (REG_TCU_TFSR = (1 << ((n) + 16)))
+#define __tcu_set_full_match_flag(n) (REG_TCU_TFSR = (1 << (n)))
+#define __tcu_clear_half_match_flag(n) (REG_TCU_TFCR = (1 << ((n) + 16)))
+#define __tcu_clear_full_match_flag(n) (REG_TCU_TFCR = (1 << (n)))
+#define __tcu_mask_half_match_irq(n) (REG_TCU_TMSR = (1 << ((n) + 16)))
+#define __tcu_mask_full_match_irq(n) (REG_TCU_TMSR = (1 << (n)))
+#define __tcu_unmask_half_match_irq(n) (REG_TCU_TMCR = (1 << ((n) + 16)))
+#define __tcu_unmask_full_match_irq(n) (REG_TCU_TMCR = (1 << (n)))
+
+#define __tcu_ost_match_flag() (REG_TCU_TFR & TCU_TFR_OSTFLAG)
+#define __tcu_set_ost_match_flag() (REG_TCU_TFSR = TCU_TFSR_OSTFST)
+#define __tcu_clear_ost_match_flag() (REG_TCU_TFCR = TCU_TFCR_OSTFCL)
+#define __tcu_ost_match_irq_masked() (REG_TCU_TMR & TCU_TMR_OSTMASK)
+#define __tcu_mask_ost_match_irq() (REG_TCU_TMSR = TCU_TMSR_OSTMST)
+#define __tcu_unmask_ost_match_irq() (REG_TCU_TMCR = TCU_TMCR_OSTMCL)
+
+#define __tcu_wdt_clock_stopped() (REG_TCU_TSR & TCU_TSSR_WDTSC)
+#define __tcu_ost_clock_stopped() (REG_TCU_TSR & TCU_TSR_OST)
+#define __tcu_timer_clock_stopped(n) (REG_TCU_TSR & (1 << (n)))
+
+#define __tcu_start_wdt_clock() (REG_TCU_TSCR = TCU_TSSR_WDTSC)
+#define __tcu_start_ost_clock() (REG_TCU_TSCR = TCU_TSCR_OSTSC)
+#define __tcu_start_timer_clock(n) (REG_TCU_TSCR = (1 << (n)))
+
+#define __tcu_stop_wdt_clock() (REG_TCU_TSSR = TCU_TSSR_WDTSC)
+#define __tcu_stop_ost_clock() (REG_TCU_TSSR = TCU_TSSR_OSTSS)
+#define __tcu_stop_timer_clock(n) (REG_TCU_TSSR = (1 << (n)))
+
+#define __tcu_get_count(n) (REG_TCU_TCNT((n)))
+#define __tcu_set_count(n,v) (REG_TCU_TCNT((n)) = (v))
+#define __tcu_set_full_data(n,v) (REG_TCU_TDFR((n)) = (v))
+#define __tcu_set_half_data(n,v) (REG_TCU_TDHR((n)) = (v))
+
+/* TCU2, counter 1, 2*/
+#define __tcu_read_real_value(n) (REG_TCU_TSTR & (1 << ((n) + 16)))
+#define __tcu_read_false_value(n) (REG_TCU_TSTR & (1 << ((n) + 16)))
+#define __tcu_counter_busy(n) (REG_TCU_TSTR & (1 << (n)))
+#define __tcu_counter_ready(n) (REG_TCU_TSTR & (1 << (n)))
+
+#define __tcu_set_read_real_value(n) (REG_TCU_TSTSR = (1 << ((n) + 16)))
+#define __tcu_set_read_false_value(n) (REG_TCU_TSTCR = (1 << ((n) + 16)))
+#define __tcu_set_counter_busy(n) (REG_TCU_TSTSR = (1 << (n)))
+#define __tcu_set_counter_ready(n) (REG_TCU_TSTCR = (1 << (n)))
+
+/* ost counter */
+#define __ostcu_set_pwm_output_shutdown_graceful() (REG_TCU_OSTCSR &= ~TCU_TCSR_PWM_SD)
+#define __ostcu_set_ost_output_shutdown_abrupt() (REG_TCU_OSTCSR |= TCU_TCSR_PWM_SD)
+#define __ostcu_select_clk_div1() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1)
+#define __ostcu_select_clk_div4() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE4)
+#define __ostcu_select_clk_div16() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE16)
+#define __ostcu_select_clk_div64() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE64)
+#define __ostcu_select_clk_div256() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE256)
+#define __ostcu_select_clk_div1024() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1024)
+#define __ostcu_select_rtcclk() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_RTC_EN)
+#define __ostcu_select_extalclk() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_EXT_EN)
+#define __ostcu_select_pclk() \
+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_PCK_EN)
+
+
+/***************************************************************************
+ * WDT
+ ***************************************************************************/
+#define __wdt_start() ( REG_WDT_TCER |= WDT_TCER_TCEN )
+#define __wdt_stop() ( REG_WDT_TCER &= ~WDT_TCER_TCEN )
+#define __wdt_set_count(v) ( REG_WDT_TCNT = (v) )
+#define __wdt_set_data(v) ( REG_WDT_TDR = (v) )
+
+#define __wdt_select_extalclk() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_EXT_EN)
+#define __wdt_select_rtcclk() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_RTC_EN)
+#define __wdt_select_pclk() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_PCK_EN)
+
+#define __wdt_select_clk_div1() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1)
+#define __wdt_select_clk_div4() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE4)
+#define __wdt_select_clk_div16() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE16)
+#define __wdt_select_clk_div64() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE64)
+#define __wdt_select_clk_div256() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE256)
+#define __wdt_select_clk_div1024() \
+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1024)
+
+
+/***************************************************************************
+ * UART
+ ***************************************************************************/
+
+#define __uart_enable(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE )
+#define __uart_disable(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE )
+
+#define __uart_enable_transmit_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE )
+#define __uart_disable_transmit_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE )
+
+#define __uart_enable_receive_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE )
+#define __uart_disable_receive_irq(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) )
+
+#define __uart_enable_loopback(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP )
+#define __uart_disable_loopback(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP )
+
+#define __uart_set_8n1(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 )
+
+#define __uart_set_baud(n, devclk, baud) \
+ do { \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \
+ } while (0)
+
+#define __uart_parity_error(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 )
+
+#define __uart_clear_errors(n) \
+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) )
+
+#define __uart_transmit_fifo_empty(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 )
+
+#define __uart_transmit_end(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 )
+
+#define __uart_transmit_char(n, ch) \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch)
+
+#define __uart_receive_fifo_full(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 )
+
+#define __uart_receive_ready(n) \
+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 )
+
+#define __uart_receive_char(n) \
+ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR)
+
+#define __uart_disable_irda() \
+ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) )
+#define __uart_enable_irda() \
+ /* Tx high pulse as 0, Rx low pulse as 0 */ \
+ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS )
+
+
+/***************************************************************************
+ * DMAC
+ ***************************************************************************/
+
+/* m is the DMA controller index (0, 1), n is the DMA channel index (0 - 11) */
+
+#define __dmac_enable_module(m) \
+ ( REG_DMAC_DMACR(m) |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_012345 )
+#define __dmac_disable_module(m) \
+ ( REG_DMAC_DMACR(m) &= ~DMAC_DMACR_DMAE )
+
+/* p=0,1,2,3 */
+#define __dmac_set_priority(m,p) \
+do { \
+ REG_DMAC_DMACR(m) &= ~DMAC_DMACR_PR_MASK; \
+ REG_DMAC_DMACR(m) |= ((p) << DMAC_DMACR_PR_BIT); \
+} while (0)
+
+#define __dmac_test_halt_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_HLT )
+#define __dmac_test_addr_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_AR )
+
+#define __dmac_channel_enable_clk(n) \
+ REG_DMAC_DMACKE((n)/HALF_DMA_NUM) |= 1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM);
+
+#define __dmac_enable_descriptor(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES )
+#define __dmac_disable_descriptor(n) \
+ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES )
+
+#define __dmac_enable_channel(n) \
+do { \
+ REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN; \
+} while (0)
+#define __dmac_disable_channel(n) \
+do { \
+ REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN; \
+} while (0)
+#define __dmac_channel_enabled(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN )
+
+#define __dmac_channel_enable_irq(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE )
+#define __dmac_channel_disable_irq(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE )
+
+#define __dmac_channel_transmit_halt_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT )
+#define __dmac_channel_transmit_end_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT )
+#define __dmac_channel_address_error_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR )
+#define __dmac_channel_count_terminated_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT )
+#define __dmac_channel_descriptor_invalid_detected(n) \
+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV )
+
+#define __dmac_channel_clear_transmit_halt(n) \
+ do { \
+ /* clear both channel halt error and globle halt error */ \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT; \
+ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_HLT; \
+ } while (0)
+#define __dmac_channel_clear_transmit_end(n) \
+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT )
+#define __dmac_channel_clear_address_error(n) \
+ do { \
+ REG_DMAC_DDA(n) = 0; /* clear descriptor address register */ \
+ REG_DMAC_DSAR(n) = 0; /* clear source address register */ \
+ REG_DMAC_DTAR(n) = 0; /* clear target address register */ \
+ /* clear both channel addr error and globle address error */ \
+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR; \
+ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_AR; \
+ } while (0)
+#define __dmac_channel_clear_count_terminated(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT )
+#define __dmac_channel_clear_descriptor_invalid(n) \
+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV )
+
+#define __dmac_channel_set_transfer_unit_32bit(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_16bit(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_8bit(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_16byte(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \
+} while (0)
+
+#define __dmac_channel_set_transfer_unit_32byte(n) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \
+} while (0)
+
+/* w=8,16,32 */
+#define __dmac_channel_set_dest_port_width(n,w) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \
+} while (0)
+
+/* w=8,16,32 */
+#define __dmac_channel_set_src_port_width(n,w) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \
+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \
+} while (0)
+
+/* v=0-15 */
+#define __dmac_channel_set_rdil(n,v) \
+do { \
+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \
+ REG_DMAC_DCMD((n) |= ((v) << DMAC_DCMD_RDIL_BIT); \
+} while (0)
+
+#define __dmac_channel_dest_addr_fixed(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI )
+#define __dmac_channel_dest_addr_increment(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI )
+
+#define __dmac_channel_src_addr_fixed(n) \
+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI )
+#define __dmac_channel_src_addr_increment(n) \
+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI )
+
+#define __dmac_channel_set_doorbell(n) \
+ ( REG_DMAC_DMADBSR((n)/HALF_DMA_NUM) = (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) )
+
+#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) & (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) )
+#define __dmac_channel_ack_irq(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) &= ~(1 <<((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) )
+
+static __inline__ int __dmac_get_irq(void)
+{
+ int i;
+ for (i = 0; i < MAX_DMA_NUM; i++)
+ if (__dmac_channel_irq_detected(i))
+ return i;
+ return -1;
+}
+
+
+/***************************************************************************
+ * AIC (AC'97 & I2S Controller)
+ ***************************************************************************/
+
+#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB )
+#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB )
+
+#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL )
+#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL )
+
+#define __aic_play_zero() ( REG_AIC_FR &= ~AIC_FR_LSMP )
+#define __aic_play_lastsample() ( REG_AIC_FR |= AIC_FR_LSMP )
+
+#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD )
+#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) )
+#define __aic_reset_status() ( REG_AIC_FR & AIC_FR_RST )
+
+#define __aic_reset() \
+do { \
+ REG_AIC_FR |= AIC_FR_RST; \
+} while(0)
+
+
+#define __aic_set_transmit_trigger(n) \
+do { \
+ REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \
+ REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \
+} while(0)
+
+#define __aic_set_receive_trigger(n) \
+do { \
+ REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \
+ REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \
+} while(0)
+
+#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC )
+#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC )
+#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL )
+#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL )
+#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF )
+#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF )
+
+#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH )
+#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH )
+
+#define __aic_enable_transmit_intr() \
+ ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) )
+#define __aic_disable_transmit_intr() \
+ ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) )
+#define __aic_enable_receive_intr() \
+ ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) )
+#define __aic_disable_receive_intr() \
+ ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) )
+
+#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS )
+#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS )
+#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS )
+#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS )
+
+#define __aic_enable_mono2stereo() ( REG_AIC_CR |= AIC_CR_M2S )
+#define __aic_disable_mono2stereo() ( REG_AIC_CR &= ~AIC_CR_M2S )
+#define __aic_enable_byteswap() ( REG_AIC_CR |= AIC_CR_ENDSW )
+#define __aic_disable_byteswap() ( REG_AIC_CR &= ~AIC_CR_ENDSW )
+#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU )
+#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU )
+
+#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3
+#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4
+#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6
+#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7
+#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8
+#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9
+
+#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3
+#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4
+#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6
+#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7
+#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8
+#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9
+
+#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK )
+#define __ac97_set_xs_mono() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \
+} while(0)
+#define __ac97_set_xs_stereo() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \
+} while(0)
+
+/* In fact, only stereo is support now. */
+#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK )
+#define __ac97_set_rs_mono() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \
+} while(0)
+#define __ac97_set_rs_stereo() \
+do { \
+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \
+ REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \
+} while(0)
+
+#define __ac97_warm_reset_codec() \
+ do { \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SA; \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SS; \
+ udelay(2); \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \
+ } while (0)
+
+#define __ac97_cold_reset_codec() \
+ do { \
+ REG_AIC_ACCR2 |= AIC_ACCR2_SR; \
+ udelay(2); \
+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \
+ } while (0)
+
+/* n=8,16,18,20 */
+#define __ac97_set_iass(n) \
+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT )
+#define __ac97_set_oass(n) \
+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT )
+
+#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL )
+#define __i2s_select_msbjustified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL )
+
+/* n=8,16,18,20,24 */
+/*#define __i2s_set_sample_size(n) \
+ ( REG_AIC_I2SCR |= (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )*/
+
+#define __i2s_set_oss_sample_size(n) \
+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT )
+#define __i2s_set_iss_sample_size(n) \
+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT )
+
+#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK )
+#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK )
+
+#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS )
+#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS )
+#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR )
+#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR )
+
+#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) )
+
+#define __aic_get_transmit_resident() \
+ ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT )
+#define __aic_get_receive_count() \
+ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT )
+
+#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT )
+#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR )
+#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO )
+#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM )
+#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY )
+#define __ac97_slot_error_detected() ( REG_AIC_ACSR & AIC_ACSR_SLTERR )
+#define __ac97_clear_slot_error() ( REG_AIC_ACSR &= ~AIC_ACSR_SLTERR )
+
+#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY )
+
+#define CODEC_READ_CMD (1 << 19)
+#define CODEC_WRITE_CMD (0 << 19)
+#define CODEC_REG_INDEX_BIT 12
+#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */
+#define CODEC_REG_DATA_BIT 4
+#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */
+
+#define __ac97_out_rcmd_addr(reg) \
+do { \
+ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \
+} while (0)
+
+#define __ac97_out_wcmd_addr(reg) \
+do { \
+ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \
+} while (0)
+
+#define __ac97_out_data(value) \
+do { \
+ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \
+} while (0)
+
+#define __ac97_in_data() \
+ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT )
+
+#define __ac97_in_status_addr() \
+ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT )
+
+#define __i2s_set_sample_rate(i2sclk, sync) \
+ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) )
+
+#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) )
+#define __aic_read_rfifo() ( REG_AIC_DR )
+
+#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC )
+#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC )
+
+//
+// Define next ops for AC97 compatible
+//
+
+#define AC97_ACSR AIC_ACSR
+
+#define __ac97_enable() __aic_enable(); __aic_select_ac97()
+#define __ac97_disable() __aic_disable()
+#define __ac97_reset() __aic_reset()
+
+#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n)
+#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n)
+
+#define __ac97_enable_record() __aic_enable_record()
+#define __ac97_disable_record() __aic_disable_record()
+#define __ac97_enable_replay() __aic_enable_replay()
+#define __ac97_disable_replay() __aic_disable_replay()
+#define __ac97_enable_loopback() __aic_enable_loopback()
+#define __ac97_disable_loopback() __aic_disable_loopback()
+
+#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma()
+#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma()
+#define __ac97_enable_receive_dma() __aic_enable_receive_dma()
+#define __ac97_disable_receive_dma() __aic_disable_receive_dma()
+
+#define __ac97_transmit_request() __aic_transmit_request()
+#define __ac97_receive_request() __aic_receive_request()
+#define __ac97_transmit_underrun() __aic_transmit_underrun()
+#define __ac97_receive_overrun() __aic_receive_overrun()
+
+#define __ac97_clear_errors() __aic_clear_errors()
+
+#define __ac97_get_transmit_resident() __aic_get_transmit_resident()
+#define __ac97_get_receive_count() __aic_get_receive_count()
+
+#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr()
+#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr()
+#define __ac97_enable_receive_intr() __aic_enable_receive_intr()
+#define __ac97_disable_receive_intr() __aic_disable_receive_intr()
+
+#define __ac97_write_tfifo(v) __aic_write_tfifo(v)
+#define __ac97_read_rfifo() __aic_read_rfifo()
+
+//
+// Define next ops for I2S compatible
+//
+
+#define I2S_ACSR AIC_I2SSR
+
+#define __i2s_enable() __aic_enable(); __aic_select_i2s()
+#define __i2s_disable() __aic_disable()
+#define __i2s_reset() __aic_reset()
+
+#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n)
+#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n)
+
+#define __i2s_enable_record() __aic_enable_record()
+#define __i2s_disable_record() __aic_disable_record()
+#define __i2s_enable_replay() __aic_enable_replay()
+#define __i2s_disable_replay() __aic_disable_replay()
+#define __i2s_enable_loopback() __aic_enable_loopback()
+#define __i2s_disable_loopback() __aic_disable_loopback()
+
+#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma()
+#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma()
+#define __i2s_enable_receive_dma() __aic_enable_receive_dma()
+#define __i2s_disable_receive_dma() __aic_disable_receive_dma()
+
+#define __i2s_transmit_request() __aic_transmit_request()
+#define __i2s_receive_request() __aic_receive_request()
+#define __i2s_transmit_underrun() __aic_transmit_underrun()
+#define __i2s_receive_overrun() __aic_receive_overrun()
+
+#define __i2s_clear_errors() __aic_clear_errors()
+
+#define __i2s_get_transmit_resident() __aic_get_transmit_resident()
+#define __i2s_get_receive_count() __aic_get_receive_count()
+
+#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr()
+#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr()
+#define __i2s_enable_receive_intr() __aic_enable_receive_intr()
+#define __i2s_disable_receive_intr() __aic_disable_receive_intr()
+
+#define __i2s_write_tfifo(v) __aic_write_tfifo(v)
+#define __i2s_read_rfifo() __aic_read_rfifo()
+
+#define __i2s_reset_codec() \
+ do { \
+ } while (0)
+
+/*************************************************************************
+ * PCM Controller operation
+ *************************************************************************/
+
+#define __pcm_enable() ( REG_PCM_CTL |= PCM_CTL_PCMEN )
+#define __pcm_disable() ( REG_PCM_CTL &= ~PCM_CTL_PCMEN )
+
+#define __pcm_clk_enable() ( REG_PCM_CTL |= PCM_CTL_CLKEN )
+#define __pcm_clk_disable() ( REG_PCM_CTL &= ~PCM_CTL_CLKEN )
+
+#define __pcm_reset() ( REG_PCM_CTL |= PCM_CTL_RST )
+#define __pcm_flush_fifo() ( REG_PCM_CTL |= PCM_CTL_FLUSH )
+
+#define __pcm_enable_record() ( REG_PCM_CTL |= PCM_CTL_EREC )
+#define __pcm_disable_record() ( REG_PCM_CTL &= ~PCM_CTL_EREC )
+#define __pcm_enable_playback() ( REG_PCM_CTL |= PCM_CTL_ERPL )
+#define __pcm_disable_playback() ( REG_PCM_CTL &= ~PCM_CTL_ERPL )
+
+#define __pcm_enable_rxfifo() __pcm_enable_record()
+#define __pcm_disable_rxfifo() __pcm_disable_record()
+#define __pcm_enable_txfifo() __pcm_enable_playback()
+#define __pcm_disable_txfifo() __pcm_disable_playback()
+
+#define __pcm_last_sample() ( REG_PCM_CTL |= PCM_CTL_LSMP )
+#define __pcm_zero_sample() ( REG_PCM_CTL &= ~PCM_CTL_LSMP )
+
+#define __pcm_enable_transmit_dma() ( REG_PCM_CTL |= PCM_CTL_ETDMA )
+#define __pcm_disable_transmit_dma() ( REG_PCM_CTL &= ~PCM_CTL_ETDMA )
+#define __pcm_enable_receive_dma() ( REG_PCM_CTL |= PCM_CTL_ERDMA )
+#define __pcm_disable_receive_dma() ( REG_PCM_CTL &= ~PCM_CTL_ERDMA )
+
+#define __pcm_as_master() ( REG_PCM_CFG &= PCM_CFG_MODE )
+#define __pcm_as_slave() ( REG_PCM_CFG |= ~PCM_CFG_MODE )
+
+#define __pcm_set_transmit_trigger(n) \
+do { \
+ REG_PCM_CFG &= ~PCM_CFG_TFTH_MASK; \
+ REG_PCM_CFG |= ((n) << PCM_CFG_TFTH_BIT); \
+} while(0)
+
+#define __pcm_set_receive_trigger(n) \
+do { \
+ REG_PCM_CFG &= ~PCM_CFG_RFTH_MASK; \
+ REG_PCM_CFG |= ((n) << PCM_CFG_RFTH_BIT); \
+} while(0)
+
+#define __pcm_omsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_OMSBPOS )
+#define __pcm_omsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_OMSBPOS )
+
+#define __pcm_imsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_IMSBPOS )
+#define __pcm_imsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_IMSBPOS )
+
+/* set input sample size 8 or 16*/
+#define __pcm_set_iss(n) \
+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_ISS_MASK) | PCM_CFG_ISS_##n )
+/* set output sample size 8 or 16*/
+#define __pcm_set_oss(n) \
+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_OSS_MASK) | PCM_CFG_OSS_##n )
+
+#define __pcm_set_valid_slot(n) \
+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_SLOT_MASK) | PCM_CFG_SLOT_##n )
+
+#define __pcm_write_data(v) ( REG_PCM_DP = (v) )
+#define __pcm_read_data() ( REG_PCM_DP )
+
+#define __pcm_enable_tfs_intr() ( REG_PCM_INTC |= PCM_INTC_ETFS )
+#define __pcm_disable_tfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETFS )
+
+#define __pcm_enable_tur_intr() ( REG_PCM_INTC |= PCM_INTC_ETUR )
+#define __pcm_disable_tur_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETUR )
+
+#define __pcm_enable_rfs_intr() ( REG_PCM_INTC |= PCM_INTC_ERFS )
+#define __pcm_disable_rfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ERFS )
+
+#define __pcm_enable_ror_intr() ( REG_PCM_INTC |= PCM_INTC_EROR )
+#define __pcm_disable_ror_intr() ( REG_PCM_INTC &= ~PCM_INTC_EROR )
+
+#define __pcm_ints_valid_tx() \
+( ((REG_PCM_INTS & PCM_INTS_TFL_MASK) >> PCM_INTS_TFL_BIT) )
+#define __pcm_ints_valid_rx() \
+( ((REG_PCM_INTS & PCM_INTS_RFL_MASK) >> PCM_INTS_RFL_BIT) )
+
+#define __pcm_set_clk_div(n) \
+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_CLKDIV_MASK) | ((n) << PCM_DIV_CLKDIV_BIT) )
+
+/* sysclk(cpm_pcm_sysclk) Hz is created by cpm logic, and pcmclk Hz is the pcm in/out clock wanted */
+#define __pcm_set_clk_rate(sysclk, pcmclk) \
+__pcm_set_clk_div(((sysclk) / (pcmclk) - 1))
+
+#define __pcm_set_sync_div(n) \
+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNDIV_MASK) | ((n) << PCM_DIV_SYNDIV_BIT) )
+
+/* pcmclk is source clock Hz, and sync is the frame sync clock Hz wanted */
+#define __pcm_set_sync_rate(pcmclk, sync) \
+__pcm_set_sync_div(((pcmclk) / (8 * (sync)) - 1))
+
+ /* set sync length in pcmclk n = 0 ... 63 */
+#define __pcm_set_sync_len(n) \
+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNL_MASK) | (n << PCM_DIV_SYNL_BIT) )
+
+
+/***************************************************************************
+ * ICDC
+ ***************************************************************************/
+#define __i2s_internal_codec() __aic_internal_codec()
+#define __i2s_external_codec() __aic_external_codec()
+
+#define __icdc_clk_ready() ( REG_ICDC_CKCFG & ICDC_CKCFG_CKRDY )
+#define __icdc_sel_adc() ( REG_ICDC_CKCFG |= ICDC_CKCFG_SELAD )
+#define __icdc_sel_dac() ( REG_ICDC_CKCFG &= ~ICDC_CKCFG_SELAD )
+
+#define __icdc_set_rgwr() ( REG_ICDC_RGADW |= ICDC_RGADW_RGWR )
+#define __icdc_clear_rgwr() ( REG_ICDC_RGADW &= ~ICDC_RGADW_RGWR )
+#define __icdc_rgwr_ready() ( REG_ICDC_RGADW & ICDC_RGADW_RGWR )
+
+#define __icdc_set_addr(n) \
+do { \
+ REG_ICDC_RGADW &= ~ICDC_RGADW_RGADDR_MASK; \
+ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGADDR_BIT; \
+} while(0)
+
+#define __icdc_set_cmd(n) \
+do { \
+ REG_ICDC_RGADW &= ~ICDC_RGADW_RGDIN_MASK; \
+ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGDIN_BIT; \
+} while(0)
+
+#define __icdc_irq_pending() ( REG_ICDC_RGDATA & ICDC_RGDATA_IRQ )
+#define __icdc_get_value() ( REG_ICDC_RGDATA & ICDC_RGDATA_RGDOUT_MASK )
+
+/***************************************************************************
+ * INTC
+ ***************************************************************************/
+#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) )
+#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) )
+#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) /* A dummy ack, as the Pending Register is Read Only. Should we remove __intc_ack_irq() */
+
+
+/***************************************************************************
+ * I2C
+ ***************************************************************************/
+
+#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE )
+#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE )
+
+#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA )
+#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO )
+#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC )
+#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC )
+
+#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF )
+#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF )
+#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF )
+
+#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) )
+#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY )
+#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND )
+
+#define __i2c_set_clk(dev_clk, i2c_clk) \
+ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 )
+
+#define __i2c_read() ( REG_I2C_DR )
+#define __i2c_write(val) ( REG_I2C_DR = (val) )
+
+
+/***************************************************************************
+ * MSC
+ ***************************************************************************/
+/* n = 0, 1 (MSC0, MSC1) */
+
+#define __msc_start_op(n) \
+ ( REG_MSC_STRPCL(n) = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START )
+
+#define __msc_set_resto(n, to) ( REG_MSC_RESTO(n) = to )
+#define __msc_set_rdto(n, to) ( REG_MSC_RDTO(n) = to )
+#define __msc_set_cmd(n, cmd) ( REG_MSC_CMD(n) = cmd )
+#define __msc_set_arg(n, arg) ( REG_MSC_ARG(n) = arg )
+#define __msc_set_nob(n, nob) ( REG_MSC_NOB(n) = nob )
+#define __msc_get_nob(n) ( REG_MSC_NOB(n) )
+#define __msc_set_blklen(n, len) ( REG_MSC_BLKLEN(n) = len )
+#define __msc_set_cmdat(n, cmdat) ( REG_MSC_CMDAT(n) = cmdat )
+#define __msc_set_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_IO_ABORT )
+#define __msc_clear_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_IO_ABORT )
+
+#define __msc_set_cmdat_bus_width1(n) \
+do { \
+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \
+ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_1BIT; \
+} while(0)
+
+#define __msc_set_cmdat_bus_width4(n) \
+do { \
+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \
+ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_4BIT; \
+} while(0)
+
+#define __msc_set_cmdat_dma_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DMA_EN )
+#define __msc_set_cmdat_init(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_INIT )
+#define __msc_set_cmdat_busy(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_BUSY )
+#define __msc_set_cmdat_stream(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_STREAM_BLOCK )
+#define __msc_set_cmdat_block(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_STREAM_BLOCK )
+#define __msc_set_cmdat_read(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_WRITE_READ )
+#define __msc_set_cmdat_write(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_WRITE_READ )
+#define __msc_set_cmdat_data_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DATA_EN )
+
+/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */
+#define __msc_set_cmdat_res_format(n, r) \
+do { \
+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \
+ REG_MSC_CMDAT(n) |= (r); \
+} while(0)
+
+#define __msc_clear_cmdat(n) \
+ REG_MSC_CMDAT(n) &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \
+ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \
+ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK )
+
+#define __msc_get_imask(n) ( REG_MSC_IMASK(n) )
+#define __msc_mask_all_intrs(n) ( REG_MSC_IMASK(n) = 0xff )
+#define __msc_unmask_all_intrs(n) ( REG_MSC_IMASK(n) = 0x00 )
+#define __msc_mask_rd(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_RXFIFO_RD_REQ )
+#define __msc_unmask_rd(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_RXFIFO_RD_REQ )
+#define __msc_mask_wr(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_TXFIFO_WR_REQ )
+#define __msc_unmask_wr(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_TXFIFO_WR_REQ )
+#define __msc_mask_endcmdres(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_END_CMD_RES )
+#define __msc_unmask_endcmdres(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_END_CMD_RES )
+#define __msc_mask_datatrandone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_DATA_TRAN_DONE )
+#define __msc_unmask_datatrandone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_DATA_TRAN_DONE )
+#define __msc_mask_prgdone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_PRG_DONE )
+#define __msc_unmask_prgdone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_PRG_DONE )
+
+/* m=0,1,2,3,4,5,6,7 */
+#define __msc_set_clkrt(n, m) \
+do { \
+ REG_MSC_CLKRT(n) = m; \
+} while(0)
+
+#define __msc_get_ireg(n) ( REG_MSC_IREG(n) )
+#define __msc_ireg_rd(n) ( REG_MSC_IREG(n) & MSC_IREG_RXFIFO_RD_REQ )
+#define __msc_ireg_wr(n) ( REG_MSC_IREG(n) & MSC_IREG_TXFIFO_WR_REQ )
+#define __msc_ireg_end_cmd_res(n) ( REG_MSC_IREG(n) & MSC_IREG_END_CMD_RES )
+#define __msc_ireg_data_tran_done(n) ( REG_MSC_IREG(n) & MSC_IREG_DATA_TRAN_DONE )
+#define __msc_ireg_prg_done(n) ( REG_MSC_IREG(n) & MSC_IREG_PRG_DONE )
+#define __msc_ireg_clear_end_cmd_res(n) ( REG_MSC_IREG(n) = MSC_IREG_END_CMD_RES )
+#define __msc_ireg_clear_data_tran_done(n) ( REG_MSC_IREG(n) = MSC_IREG_DATA_TRAN_DONE )
+#define __msc_ireg_clear_prg_done(n) ( REG_MSC_IREG(n) = MSC_IREG_PRG_DONE )
+
+#define __msc_get_stat(n) ( REG_MSC_STAT(n) )
+#define __msc_stat_not_end_cmd_res(n) ( (REG_MSC_STAT(n) & MSC_STAT_END_CMD_RES) == 0)
+#define __msc_stat_crc_err(n) \
+ ( REG_MSC_STAT(n) & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) )
+#define __msc_stat_res_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_RES_ERR )
+#define __msc_stat_rd_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_READ_ERROR )
+#define __msc_stat_wr_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_WRITE_ERROR_YES )
+#define __msc_stat_resto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_RES )
+#define __msc_stat_rdto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_READ )
+
+#define __msc_rd_resfifo(n) ( REG_MSC_RES(n) )
+#define __msc_rd_rxfifo(n) ( REG_MSC_RXFIFO(n) )
+#define __msc_wr_txfifo(n, v) ( REG_MSC_TXFIFO(n) = v )
+
+#define __msc_reset(n) \
+do { \
+ REG_MSC_STRPCL(n) = MSC_STRPCL_RESET; \
+ while (REG_MSC_STAT(n) & MSC_STAT_IS_RESETTING); \
+} while (0)
+
+#define __msc_start_clk(n) \
+do { \
+ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_START; \
+} while (0)
+
+#define __msc_stop_clk(n) \
+do { \
+ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_STOP; \
+} while (0)
+
+#define MMC_CLK 19169200
+#define SD_CLK 24576000
+
+/* msc_clk should little than pclk and little than clk retrieve from card */
+#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \
+do { \
+ unsigned int rate, pclk, i; \
+ pclk = dev_clk; \
+ rate = type?SD_CLK:MMC_CLK; \
+ if (msc_clk && msc_clk < pclk) \
+ pclk = msc_clk; \
+ i = 0; \
+ while (pclk < rate) \
+ { \
+ i ++; \
+ rate >>= 1; \
+ } \
+ lv = i; \
+} while(0)
+
+/* divide rate to little than or equal to 400kHz */
+#define __msc_calc_slow_clk_divisor(type, lv) \
+do { \
+ unsigned int rate, i; \
+ rate = (type?SD_CLK:MMC_CLK)/1000/400; \
+ i = 0; \
+ while (rate > 0) \
+ { \
+ rate >>= 1; \
+ i ++; \
+ } \
+ lv = i; \
+} while(0)
+
+
+/***************************************************************************
+ * SSI (Synchronous Serial Interface)
+ ***************************************************************************/
+/* n = 0, 1 (SSI0, SSI1) */
+#define __ssi_enable(n) ( REG_SSI_CR0(n) |= SSI_CR0_SSIE )
+#define __ssi_disable(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_SSIE )
+#define __ssi_select_ce(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_FSEL )
+
+#define __ssi_normal_mode(n) ( REG_SSI_ITR(n) &= ~SSI_ITR_IVLTM_MASK )
+
+#define __ssi_select_ce2(n) \
+do { \
+ REG_SSI_CR0(n) |= SSI_CR0_FSEL; \
+ REG_SSI_CR1(n) &= ~SSI_CR1_MULTS; \
+} while (0)
+
+#define __ssi_select_gpc(n) \
+do { \
+ REG_SSI_CR0(n) &= ~SSI_CR0_FSEL; \
+ REG_SSI_CR1(n) |= SSI_CR1_MULTS; \
+} while (0)
+
+#define __ssi_underrun_auto_clear(n) \
+do { \
+ REG_SSI_CR0(n) |= SSI_CR0_EACLRUN; \
+} while (0)
+
+#define __ssi_underrun_clear_manually(n) \
+do { \
+ REG_SSI_CR0(n) &= ~SSI_CR0_EACLRUN; \
+} while (0)
+
+#define __ssi_enable_tx_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_TIE | SSI_CR0_TEIE )
+
+#define __ssi_disable_tx_intr(n) \
+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) )
+
+#define __ssi_enable_rx_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_RIE | SSI_CR0_REIE )
+
+#define __ssi_disable_rx_intr(n) \
+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RIE | SSI_CR0_REIE) )
+
+#define __ssi_enable_txfifo_half_empty_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_TIE )
+#define __ssi_disable_txfifo_half_empty_intr(n) \
+ ( REG_SSI_CR0(n) &= ~SSI_CR0_TIE )
+#define __ssi_enable_tx_error_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_TEIE )
+#define __ssi_disable_tx_error_intr(n) \
+ ( REG_SSI_CR0(n) &= ~SSI_CR0_TEIE )
+#define __ssi_enable_rxfifo_half_full_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_RIE )
+#define __ssi_disable_rxfifo_half_full_intr(n) \
+ ( REG_SSI_CR0(n) &= ~SSI_CR0_RIE )
+#define __ssi_enable_rx_error_intr(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_REIE )
+#define __ssi_disable_rx_error_intr(n) \
+ ( REG_SSI_CR0(n) &= ~SSI_CR0_REIE )
+
+#define __ssi_enable_loopback(n) ( REG_SSI_CR0(n) |= SSI_CR0_LOOP )
+#define __ssi_disable_loopback(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_LOOP )
+
+#define __ssi_enable_receive(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_DISREV )
+#define __ssi_disable_receive(n) ( REG_SSI_CR0(n) |= SSI_CR0_DISREV )
+
+#define __ssi_finish_receive(n) \
+ ( REG_SSI_CR0(n) |= (SSI_CR0_RFINE | SSI_CR0_RFINC) )
+
+#define __ssi_disable_recvfinish(n) \
+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) )
+
+#define __ssi_flush_txfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH )
+#define __ssi_flush_rxfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_RFLUSH )
+
+#define __ssi_flush_fifo(n) \
+ ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH )
+
+#define __ssi_finish_transmit(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_UNFIN )
+#define __ssi_wait_transmit(n) ( REG_SSI_CR1(n) |= SSI_CR1_UNFIN )
+#define __ssi_use_busy_wait_mode(n) __ssi_wait_transmit(n)
+#define __ssi_unset_busy_wait_mode(n) __ssi_finish_transmit(n)
+
+#define __ssi_spi_format(n) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \
+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SPI; \
+ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \
+ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \
+ } while (0)
+
+/* TI's SSP format, must clear SSI_CR1.UNFIN */
+#define __ssi_ssp_format(n) \
+ do { \
+ REG_SSI_CR1(n) &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \
+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SSP; \
+ } while (0)
+
+/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */
+#define __ssi_microwire_format(n) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \
+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_MW1; \
+ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \
+ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \
+ REG_SSI_CR0(n) &= ~SSI_CR0_RFINE; \
+ } while (0)
+
+/* CE# level (FRMHL), CE# in interval time (ITFRM),
+ clock phase and polarity (PHA POL),
+ interval time (SSIITR), interval characters/frame (SSIICR) */
+
+/* frmhl,endian,mcom,flen,pha,pol MASK */
+#define SSICR1_MISC_MASK \
+ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \
+ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL )
+
+#define __ssi_spi_set_misc(n,frmhl,endian,flen,mcom,pha,pol) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSICR1_MISC_MASK; \
+ REG_SSI_CR1(n) |= ((frmhl) << 30) | ((endian) << 25) | \
+ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \
+ ((pha) << 1) | (pol); \
+ } while(0)
+
+/* Transfer with MSB or LSB first */
+#define __ssi_set_msb(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_LFST )
+#define __ssi_set_lsb(n) ( REG_SSI_CR1(n) |= SSI_CR1_LFST )
+
+#define __ssi_set_frame_length(n, m) \
+ REG_SSI_CR1(n) = (REG_SSI_CR1(n) & ~SSI_CR1_FLEN_MASK) | (((m) - 2) << 4)
+
+/* m = 1 - 16 */
+#define __ssi_set_microwire_command_length(n,m) \
+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##m##BIT) )
+
+/* Set the clock phase for SPI */
+#define __ssi_set_spi_clock_phase(n, m) \
+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_PHA) | (((m)&0x1)<< 1)))
+
+/* Set the clock polarity for SPI */
+#define __ssi_set_spi_clock_polarity(n, p) \
+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_POL) | ((p)&0x1)) )
+
+/* SSI tx trigger, m = i x 8 */
+#define __ssi_set_tx_trigger(n, m) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSI_CR1_TTRG_MASK; \
+ REG_SSI_CR1(n) |= ((m)/8)<<SSI_CR1_TTRG_BIT; \
+ } while (0)
+
+/* SSI rx trigger, m = i x 8 */
+#define __ssi_set_rx_trigger(n, m) \
+ do { \
+ REG_SSI_CR1(n) &= ~SSI_CR1_RTRG_MASK; \
+ REG_SSI_CR1(n) |= ((m)/8)<<SSI_CR1_RTRG_BIT; \
+ } while (0)
+
+#define __ssi_get_txfifo_count(n) \
+ ( (REG_SSI_SR(n) & SSI_SR_TFIFONUM_MASK) >> SSI_SR_TFIFONUM_BIT )
+
+#define __ssi_get_rxfifo_count(n) \
+ ( (REG_SSI_SR(n) & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT )
+
+#define __ssi_transfer_end(n) ( REG_SSI_SR(n) & SSI_SR_END )
+#define __ssi_is_busy(n) ( REG_SSI_SR(n) & SSI_SR_BUSY )
+
+#define __ssi_txfifo_full(n) ( REG_SSI_SR(n) & SSI_SR_TFF )
+#define __ssi_rxfifo_empty(n) ( REG_SSI_SR(n) & SSI_SR_RFE )
+#define __ssi_rxfifo_half_full(n) ( REG_SSI_SR(n) & SSI_SR_RFHF )
+#define __ssi_txfifo_half_empty(n) ( REG_SSI_SR(n) & SSI_SR_TFHE )
+#define __ssi_underrun(n) ( REG_SSI_SR(n) & SSI_SR_UNDR )
+#define __ssi_overrun(n) ( REG_SSI_SR(n) & SSI_SR_OVER )
+#define __ssi_clear_underrun(n) ( REG_SSI_SR(n) = ~SSI_SR_UNDR )
+#define __ssi_clear_overrun(n) ( REG_SSI_SR(n) = ~SSI_SR_OVER )
+#define __ssi_clear_errors(n) ( REG_SSI_SR(n) &= ~(SSI_SR_UNDR | SSI_SR_OVER) )
+
+#define __ssi_set_clk(n, dev_clk, ssi_clk) \
+ ( REG_SSI_GR(n) = (dev_clk) / (2*(ssi_clk)) - 1 )
+
+#define __ssi_receive_data(n) REG_SSI_DR(n)
+#define __ssi_transmit_data(n, v) (REG_SSI_DR(n) = (v))
+
+
+/***************************************************************************
+ * CIM
+ ***************************************************************************/
+
+#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA )
+#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA )
+
+/* n = 0, 1, 2, 3 */
+#define __cim_set_input_data_stream_order(n) \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_ORDER_MASK; \
+ REG_CIM_CFG |= ((n)<<CIM_CFG_ORDER_BIT)&CIM_CFG_ORDER_MASK; \
+ } while (0)
+
+#define __cim_input_data_format_select_RGB() \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_DF_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DF_RGB; \
+ } while (0)
+
+#define __cim_input_data_format_select_YUV444() \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_DF_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DF_YUV444; \
+ } while (0)
+
+#define __cim_input_data_format_select_YUV422() \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_DF_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DF_YUV422; \
+ } while (0)
+
+#define __cim_input_data_format_select_ITU656() \
+ do { \
+ REG_CIM_CFG &= CIM_CFG_DF_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DF_ITU656; \
+ } while (0)
+
+#define __cim_input_data_inverse() ( REG_CIM_CFG |= CIM_CFG_INV_DAT )
+#define __cim_input_data_normal() ( REG_CIM_CFG &= ~CIM_CFG_INV_DAT )
+
+#define __cim_vsync_active_low() ( REG_CIM_CFG |= CIM_CFG_VSP )
+#define __cim_vsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_VSP )
+
+#define __cim_hsync_active_low() ( REG_CIM_CFG |= CIM_CFG_HSP )
+#define __cim_hsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_HSP )
+
+#define __cim_sample_data_at_pclk_falling_edge() \
+ ( REG_CIM_CFG |= CIM_CFG_PCP )
+#define __cim_sample_data_at_pclk_rising_edge() \
+ ( REG_CIM_CFG &= ~CIM_CFG_PCP )
+
+#define __cim_enable_dummy_zero() ( REG_CIM_CFG |= CIM_CFG_DUMMY_ZERO )
+#define __cim_disable_dummy_zero() ( REG_CIM_CFG &= ~CIM_CFG_DUMMY_ZERO )
+
+#define __cim_select_external_vsync() ( REG_CIM_CFG |= CIM_CFG_EXT_VSYNC )
+#define __cim_select_internal_vsync() ( REG_CIM_CFG &= ~CIM_CFG_EXT_VSYNC )
+
+/* n=0-7 */
+#define __cim_set_data_packing_mode(n) \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_PACK_MASK; \
+ REG_CIM_CFG |= (CIM_CFG_PACK_##n); \
+} while (0)
+
+#define __cim_enable_bypass_func() (REG_CIM_CFG |= CIM_CFG_BYPASS)
+#define __cim_disable_bypass_func() (REG_CIM_CFG &= ~CIM_CFG_BYPASS_MASK)
+
+#define __cim_enable_ccir656_progressive_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_CPM; \
+} while (0)
+
+#define __cim_enable_ccir656_interlace_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_CIM; \
+} while (0)
+
+#define __cim_enable_gated_clock_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_GCM; \
+} while (0)
+
+#define __cim_enable_nongated_clock_mode() \
+do { \
+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \
+ REG_CIM_CFG |= CIM_CFG_DSM_NGCM; \
+} while (0)
+
+/* sclk:system bus clock
+ * mclk: CIM master clock
+ */
+#define __cim_set_master_clk(sclk, mclk) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_MCLKDIV_MASK; \
+ REG_CIM_CTRL |= (((sclk)/(mclk) - 1) << CIM_CTRL_MCLKDIV_BIT); \
+} while (0)
+/* n=1-16 */
+#define __cim_set_frame_rate(n) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_FRC_MASK; \
+ REG_CIM_CTRL |= CIM_CTRL_FRC_##n; \
+} while (0)
+
+#define __cim_enable_size_func() \
+ ( REG_CIM_CTRL |= CIM_CTRL_SIZEEN )
+#define __cim_disable_size_func() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_SIZEEN_MASK )
+
+#define __cim_enable_vdd_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_VDDM )
+#define __cim_disable_vdd_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_VDDM )
+
+#define __cim_enable_sof_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_SOFM )
+#define __cim_disable_sof_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_SOFM )
+
+#define __cim_enable_eof_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_EOFM )
+#define __cim_disable_eof_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EOFM )
+
+#define __cim_enable_eeof_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_EEOFM )
+#define __cim_disable_eeof_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EEOFM )
+
+#define __cim_enable_stop_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_STOPM )
+#define __cim_disable_stop_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_STOPM )
+
+#define __cim_enable_trig_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_TRIGM )
+#define __cim_disable_trig_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIGM )
+
+#define __cim_enable_rxfifo_overflow_intr() \
+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_OFM )
+#define __cim_disable_rxfifo_overflow_intr() \
+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_OFM )
+
+/* n=4,8,12,16,20,24,28,32 */
+#define __cim_set_rxfifo_trigger(n) \
+do { \
+ REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \
+ REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \
+} while (0)
+#define __cim_enable_fast_mode() ( REG_CIM_CTRL |= CIM_CTRL_FAST_MODE )
+#define __cim_disable_fast_mode() ( REG_CIM_CTRL &= ~CIM_CTRL_FAST_MODE )
+#define __cim_use_normal_mode() __cim_disable_fast_mode()
+#define __cim_enable_dma() ( REG_CIM_CTRL |= CIM_CTRL_DMA_EN )
+#define __cim_disable_dma() ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EN )
+#define __cim_reset_rxfifo() ( REG_CIM_CTRL |= CIM_CTRL_RXF_RST )
+#define __cim_unreset_rxfifo() ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_RST )
+
+#define __cim_clear_state() ( REG_CIM_STATE = 0 )
+
+#define __cim_disable_done() ( REG_CIM_STATE & CIM_STATE_VDD )
+#define __cim_rxfifo_empty() ( REG_CIM_STATE & CIM_STATE_RXF_EMPTY )
+#define __cim_rxfifo_reach_trigger() ( REG_CIM_STATE & CIM_STATE_RXF_TRIG )
+#define __cim_rxfifo_overflow() ( REG_CIM_STATE & CIM_STATE_RXF_OF )
+#define __cim_clear_rxfifo_overflow() ( REG_CIM_STATE &= ~CIM_STATE_RXF_OF )
+#define __cim_dma_stop() ( REG_CIM_STATE & CIM_STATE_DMA_STOP )
+#define __cim_dma_eof() ( REG_CIM_STATE & CIM_STATE_DMA_EOF )
+#define __cim_dma_sof() ( REG_CIM_STATE & CIM_STATE_DMA_SOF )
+
+#define __cim_get_iid() ( REG_CIM_IID )
+#define __cim_get_fid() ( REG_CIM_FID )
+#define __cim_get_image_data() ( REG_CIM_RXFIFO )
+#define __cim_get_dma_cmd() ( REG_CIM_CMD )
+
+#define __cim_set_da(a) ( REG_CIM_DA = (a) )
+
+#define __cim_set_line(a) ( REG_CIM_SIZE = (REG_CIM_SIZE&(~CIM_SIZE_LPF_MASK))|((a)<<CIM_SIZE_LPF_BIT) )
+#define __cim_set_pixel(a) ( REG_CIM_SIZE = (REG_CIM_SIZE&(~CIM_SIZE_PPL_MASK))|((a)<<CIM_SIZE_PPL_BIT) )
+#define __cim_get_line() ((REG_CIM_SIZE&CIM_SIZE_LPF_MASK)>>CIM_SIZE_LPF_BIT)
+#define __cim_get_pixel() ((REG_CIM_SIZE&CIM_SIZE_PPL_MASK)>>CIM_SIZE_PPL_BIT)
+
+#define __cim_set_v_offset(a) ( REG_CIM_OFFSET = (REG_CIM_OFFSET&(~CIM_OFFSET_V_MASK)) | ((a)<<CIM_OFFSET_V_BIT) )
+#define __cim_set_h_offset(a) ( REG_CIM_OFFSET = (REG_CIM_OFFSET&(~CIM_OFFSET_H_MASK)) | ((a)<<CIM_OFFSET_H_BIT) )
+#define __cim_get_v_offset() ((REG_CIM_OFFSET&CIM_OFFSET_V_MASK)>>CIM_OFFSET_V_BIT)
+#define __cim_get_h_offset() ((REG_CIM_OFFSET&CIM_OFFSET_H_MASK)>>CIM_OFFSET_H_BIT)
+
+/*************************************************************************
+ * SLCD (Smart LCD Controller)
+ *************************************************************************/
+#define __slcd_set_data_18bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_18BIT )
+#define __slcd_set_data_16bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_16BIT )
+#define __slcd_set_data_8bit_x3() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x3 )
+#define __slcd_set_data_8bit_x2() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x2 )
+#define __slcd_set_data_8bit_x1() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x1 )
+#define __slcd_set_data_24bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_24BIT )
+#define __slcd_set_data_9bit_x2() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_9BIT_x2 )
+
+#define __slcd_set_cmd_16bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_16BIT )
+#define __slcd_set_cmd_8bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_8BIT )
+#define __slcd_set_cmd_18bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_18BIT )
+#define __slcd_set_cmd_24bit() \
+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_24BIT )
+
+#define __slcd_set_cs_high() ( REG_SLCD_CFG |= SLCD_CFG_CS_ACTIVE_HIGH )
+#define __slcd_set_cs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_CS_ACTIVE_HIGH )
+
+#define __slcd_set_rs_high() ( REG_SLCD_CFG |= SLCD_CFG_RS_CMD_HIGH )
+#define __slcd_set_rs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_RS_CMD_HIGH )
+
+#define __slcd_set_clk_falling() ( REG_SLCD_CFG &= ~SLCD_CFG_CLK_ACTIVE_RISING )
+#define __slcd_set_clk_rising() ( REG_SLCD_CFG |= SLCD_CFG_CLK_ACTIVE_RISING )
+
+#define __slcd_set_parallel_type() ( REG_SLCD_CFG &= ~SLCD_CFG_TYPE_SERIAL )
+#define __slcd_set_serial_type() ( REG_SLCD_CFG |= SLCD_CFG_TYPE_SERIAL )
+
+/* SLCD Control Register */
+#define __slcd_enable_dma() ( REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN )
+#define __slcd_disable_dma() ( REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN )
+
+/* SLCD Status Register */
+#define __slcd_is_busy() ( REG_SLCD_STATE & SLCD_STATE_BUSY )
+
+/* SLCD Data Register */
+#define __slcd_set_cmd_rs() ( REG_SLCD_DATA |= SLCD_DATA_RS_COMMAND)
+#define __slcd_set_data_rs() ( REG_SLCD_DATA &= ~SLCD_DATA_RS_COMMAND)
+
+
+/***************************************************************************
+ * LCD
+ ***************************************************************************/
+
+/***************************************************************************
+ * LCD
+ ***************************************************************************/
+#define __lcd_as_smart_lcd() ( REG_LCD_CFG |= ( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD))
+#define __lcd_as_general_lcd() ( REG_LCD_CFG &= ~( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD))
+
+#define __lcd_enable_tvepeh() ( REG_LCD_CFG |= LCD_CFG_TVEPEH )
+#define __lcd_disable_tvepeh() ( REG_LCD_CFG &= ~LCD_CFG_TVEPEH )
+
+#define __lcd_enable_fuhold() ( REG_LCD_CFG |= LCD_CFG_FUHOLD )
+#define __lcd_disable_fuhold() ( REG_LCD_CFG &= ~LCD_CFG_FUHOLD )
+
+#define __lcd_des_8word() ( REG_LCD_CFG |= LCD_CFG_NEWDES )
+#define __lcd_des_4word() ( REG_LCD_CFG &= ~LCD_CFG_NEWDES )
+
+#define __lcd_enable_bypass_pal() ( REG_LCD_CFG |= LCD_CFG_PALBP )
+#define __lcd_disable_bypass_pal() ( REG_LCD_CFG &= ~LCD_CFG_PALBP )
+
+#define __lcd_set_lcdpnl_term() ( REG_LCD_CFG |= LCD_CFG_TVEN )
+#define __lcd_set_tv_term() ( REG_LCD_CFG &= ~LCD_CFG_TVEN )
+
+#define __lcd_enable_auto_recover() ( REG_LCD_CFG |= LCD_CFG_RECOVER )
+#define __lcd_disable_auto_recover() ( REG_LCD_CFG &= ~LCD_CFG_RECOVER )
+
+#define __lcd_enable_dither() ( REG_LCD_CFG |= LCD_CFG_DITHER )
+#define __lcd_disable_dither() ( REG_LCD_CFG &= ~LCD_CFG_DITHER )
+
+#define __lcd_disable_ps_mode() ( REG_LCD_CFG |= LCD_CFG_PSM )
+#define __lcd_enable_ps_mode() ( REG_LCD_CFG &= ~LCD_CFG_PSM )
+
+#define __lcd_disable_cls_mode() ( REG_LCD_CFG |= LCD_CFG_CLSM )
+#define __lcd_enable_cls_mode() ( REG_LCD_CFG &= ~LCD_CFG_CLSM )
+
+#define __lcd_disable_spl_mode() ( REG_LCD_CFG |= LCD_CFG_SPLM )
+#define __lcd_enable_spl_mode() ( REG_LCD_CFG &= ~LCD_CFG_SPLM )
+
+#define __lcd_disable_rev_mode() ( REG_LCD_CFG |= LCD_CFG_REVM )
+#define __lcd_enable_rev_mode() ( REG_LCD_CFG &= ~LCD_CFG_REVM )
+
+#define __lcd_disable_hsync_mode() ( REG_LCD_CFG |= LCD_CFG_HSYNM )
+#define __lcd_enable_hsync_mode() ( REG_LCD_CFG &= ~LCD_CFG_HSYNM )
+
+#define __lcd_disable_pclk_mode() ( REG_LCD_CFG |= LCD_CFG_PCLKM )
+#define __lcd_enable_pclk_mode() ( REG_LCD_CFG &= ~LCD_CFG_PCLKM )
+
+#define __lcd_normal_outdata() ( REG_LCD_CFG &= ~LCD_CFG_INVDAT )
+#define __lcd_inverse_outdata() ( REG_LCD_CFG |= LCD_CFG_INVDAT )
+
+#define __lcd_sync_input() ( REG_LCD_CFG |= LCD_CFG_SYNDIR_IN )
+#define __lcd_sync_output() ( REG_LCD_CFG &= ~LCD_CFG_SYNDIR_IN )
+
+#define __lcd_hsync_active_high() ( REG_LCD_CFG &= ~LCD_CFG_HSP )
+#define __lcd_hsync_active_low() ( REG_LCD_CFG |= LCD_CFG_HSP )
+
+#define __lcd_pclk_rising() ( REG_LCD_CFG &= ~LCD_CFG_PCP )
+#define __lcd_pclk_falling() ( REG_LCD_CFG |= LCD_CFG_PCP )
+
+#define __lcd_de_active_high() ( REG_LCD_CFG &= ~LCD_CFG_DEP )
+#define __lcd_de_active_low() ( REG_LCD_CFG |= LCD_CFG_DEP )
+
+#define __lcd_vsync_rising() ( REG_LCD_CFG &= ~LCD_CFG_VSP )
+#define __lcd_vsync_falling() ( REG_LCD_CFG |= LCD_CFG_VSP )
+
+#define __lcd_set_16_tftpnl() \
+ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_16BIT )
+
+#define __lcd_set_18_tftpnl() \
+ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_18BIT )
+
+#define __lcd_set_24_tftpnl() ( REG_LCD_CFG |= LCD_CFG_MODE_TFT_24BIT )
+
+/*
+ * n=1,2,4,8 for single mono-STN
+ * n=4,8 for dual mono-STN
+ */
+#define __lcd_set_panel_datawidth(n) \
+do { \
+ REG_LCD_CFG &= ~LCD_CFG_PDW_MASK; \
+ REG_LCD_CFG |= LCD_CFG_PDW_n##; \
+} while (0)
+
+/* m = LCD_CFG_MODE_GENERUIC_TFT_xxx */
+#define __lcd_set_panel_mode(m) \
+do { \
+ REG_LCD_CFG &= ~LCD_CFG_MODE_MASK; \
+ REG_LCD_CFG |= (m); \
+} while(0)
+
+/* n=4,8,16 */
+#define __lcd_set_burst_length(n) \
+do { \
+ REG_LCD_CTRL &= ~LCD_CTRL_BST_MASK; \
+ REG_LCD_CTRL |= LCD_CTRL_BST_n##; \
+} while (0)
+
+#define __lcd_select_rgb565() ( REG_LCD_CTRL &= ~LCD_CTRL_RGB555 )
+#define __lcd_select_rgb555() ( REG_LCD_CTRL |= LCD_CTRL_RGB555 )
+
+#define __lcd_set_ofup() ( REG_LCD_CTRL |= LCD_CTRL_OFUP )
+#define __lcd_clr_ofup() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUP )
+
+/* n=2,4,16 */
+#define __lcd_set_stn_frc(n) \
+do { \
+ REG_LCD_CTRL &= ~LCD_CTRL_FRC_MASK; \
+ REG_LCD_CTRL |= LCD_CTRL_FRC_n##; \
+} while (0)
+
+#define __lcd_enable_eof_intr() ( REG_LCD_CTRL |= LCD_CTRL_EOFM )
+#define __lcd_disable_eof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_EOFM )
+
+#define __lcd_enable_sof_intr() ( REG_LCD_CTRL |= LCD_CTRL_SOFM )
+#define __lcd_disable_sof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_SOFM )
+
+#define __lcd_enable_ofu_intr() ( REG_LCD_CTRL |= LCD_CTRL_OFUM )
+#define __lcd_disable_ofu_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUM )
+
+#define __lcd_enable_ifu0_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM0 )
+#define __lcd_disable_ifu0_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM0 )
+
+#define __lcd_enable_ifu1_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM1 )
+#define __lcd_disable_ifu1_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM1 )
+
+#define __lcd_enable_ldd_intr() ( REG_LCD_CTRL |= LCD_CTRL_LDDM )
+#define __lcd_disable_ldd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_LDDM )
+
+#define __lcd_enable_qd_intr() ( REG_LCD_CTRL |= LCD_CTRL_QDM )
+#define __lcd_disable_qd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_QDM )
+
+#define __lcd_reverse_byte_endian() ( REG_LCD_CTRL |= LCD_CTRL_BEDN )
+#define __lcd_normal_byte_endian() ( REG_LCD_CTRL &= ~LCD_CTRL_BEDN )
+
+#define __lcd_pixel_endian_little() ( REG_LCD_CTRL |= LCD_CTRL_PEDN )
+#define __lcd_pixel_endian_big() ( REG_LCD_CTRL &= ~LCD_CTRL_PEDN )
+
+#define __lcd_set_dis() ( REG_LCD_CTRL |= LCD_CTRL_DIS )
+#define __lcd_clr_dis() ( REG_LCD_CTRL &= ~LCD_CTRL_DIS )
+
+#define __lcd_set_ena() ( REG_LCD_CTRL |= LCD_CTRL_ENA )
+#define __lcd_clr_ena() ( REG_LCD_CTRL &= ~LCD_CTRL_ENA )
+
+/* n=1,2,4,8,16 */
+#define __lcd_set_bpp(n) \
+ ( REG_LCD_CTRL = (REG_LCD_CTRL & ~LCD_CTRL_BPP_MASK) | LCD_CTRL_BPP_##n )
+
+/* LCD status register indication */
+
+#define __lcd_quick_disable_done() ( REG_LCD_STATE & LCD_STATE_QD )
+#define __lcd_disable_done() ( REG_LCD_STATE & LCD_STATE_LDD )
+#define __lcd_infifo0_underrun() ( REG_LCD_STATE & LCD_STATE_IFU0 )
+#define __lcd_infifo1_underrun() ( REG_LCD_STATE & LCD_STATE_IFU1 )
+#define __lcd_outfifo_underrun() ( REG_LCD_STATE & LCD_STATE_OFU )
+#define __lcd_start_of_frame() ( REG_LCD_STATE & LCD_STATE_SOF )
+#define __lcd_end_of_frame() ( REG_LCD_STATE & LCD_STATE_EOF )
+
+#define __lcd_clr_outfifounderrun() ( REG_LCD_STATE &= ~LCD_STATE_OFU )
+#define __lcd_clr_sof() ( REG_LCD_STATE &= ~LCD_STATE_SOF )
+#define __lcd_clr_eof() ( REG_LCD_STATE &= ~LCD_STATE_EOF )
+
+/* OSD functions */
+#define __lcd_enable_osd() (REG_LCD_OSDC |= LCD_OSDC_OSDEN)
+#define __lcd_enable_f0() (REG_LCD_OSDC |= LCD_OSDC_F0EN)
+#define __lcd_enable_f1() (REG_LCD_OSDC |= LCD_OSDC_F1EN)
+#define __lcd_enable_alpha() (REG_LCD_OSDC |= LCD_OSDC_ALPHAEN)
+#define __lcd_enable_alphamd() (REG_LCD_OSDC |= LCD_OSDC_ALPHAMD)
+
+#define __lcd_disable_osd() (REG_LCD_OSDC &= ~LCD_OSDC_OSDEN)
+#define __lcd_disable_f0() (REG_LCD_OSDC &= ~LCD_OSDC_F0EN)
+#define __lcd_disable_f1() (REG_LCD_OSDC &= ~LCD_OSDC_F1EN)
+#define __lcd_disable_alpha() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAEN)
+#define __lcd_disable_alphamd() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAMD)
+
+/* OSD Controll Register */
+#define __lcd_fg1_use_ipu() (REG_LCD_OSDCTRL |= LCD_OSDCTRL_IPU)
+#define __lcd_fg1_use_dma_chan1() (REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_IPU)
+#define __lcd_fg1_unuse_ipu() __lcd_fg1_use_dma_chan1()
+#define __lcd_osd_rgb555_mode() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_RGB555 )
+#define __lcd_osd_rgb565_mode() ( REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_RGB555 )
+#define __lcd_osd_change_size() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES )
+#define __lcd_osd_bpp_15_16() \
+ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_15_16 )
+#define __lcd_osd_bpp_18_24() \
+ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_18_24 )
+
+/* OSD State Register */
+#define __lcd_start_of_fg1() ( REG_LCD_STATE & LCD_OSDS_SOF1 )
+#define __lcd_end_of_fg1() ( REG_LCD_STATE & LCD_OSDS_EOF1 )
+#define __lcd_start_of_fg0() ( REG_LCD_STATE & LCD_OSDS_SOF0 )
+#define __lcd_end_of_fg0() ( REG_LCD_STATE & LCD_OSDS_EOF0 )
+#define __lcd_change_is_rdy() ( REG_LCD_STATE & LCD_OSDS_READY )
+
+/* Foreground Color Key Register 0,1(foreground 0, foreground 1) */
+#define __lcd_enable_colorkey0() (REG_LCD_KEY0 |= LCD_KEY_KEYEN)
+#define __lcd_enable_colorkey1() (REG_LCD_KEY1 |= LCD_KEY_KEYEN)
+#define __lcd_enable_colorkey0_md() (REG_LCD_KEY0 |= LCD_KEY_KEYMD)
+#define __lcd_enable_colorkey1_md() (REG_LCD_KEY1 |= LCD_KEY_KEYMD)
+#define __lcd_set_colorkey0(key) (REG_LCD_KEY0 = (REG_LCD_KEY0&~0xFFFFFF)|(key))
+#define __lcd_set_colorkey1(key) (REG_LCD_KEY1 = (REG_LCD_KEY1&~0xFFFFFF)|(key))
+
+#define __lcd_disable_colorkey0() (REG_LCD_KEY0 &= ~LCD_KEY_KEYEN)
+#define __lcd_disable_colorkey1() (REG_LCD_KEY1 &= ~LCD_KEY_KEYEN)
+#define __lcd_disable_colorkey0_md() (REG_LCD_KEY0 &= ~LCD_KEY_KEYMD)
+#define __lcd_disable_colorkey1_md() (REG_LCD_KEY1 &= ~LCD_KEY_KEYMD)
+
+/* IPU Restart Register */
+#define __lcd_enable_ipu_restart() (REG_LCD_IPUR |= LCD_IPUR_IPUREN)
+#define __lcd_disable_ipu_restart() (REG_LCD_IPUR &= ~LCD_IPUR_IPUREN)
+#define __lcd_set_ipu_restart_triger(n) (REG_LCD_IPUR = (REG_LCD_IPUR&(~0xFFFFFF))|(n))
+
+/* RGB Control Register */
+#define __lcd_enable_rgb_dummy() (REG_LCD_RGBC |= LCD_RGBC_RGBDM)
+#define __lcd_disable_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_RGBDM)
+
+#define __lcd_dummy_rgb() (REG_LCD_RGBC |= LCD_RGBC_DMM)
+#define __lcd_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_DMM)
+
+#define __lcd_rgb2ycc() (REG_LCD_RGBC |= LCD_RGBC_YCC)
+#define __lcd_notrgb2ycc() (REG_LCD_RGBC &= ~LCD_RGBC_YCC)
+
+#define __lcd_odd_mode_rgb() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RGB )
+#define __lcd_odd_mode_rbg() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RBG )
+#define __lcd_odd_mode_grb() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GRB)
+
+#define __lcd_odd_mode_gbr() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GBR)
+#define __lcd_odd_mode_brg() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BRG)
+#define __lcd_odd_mode_bgr() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BGR)
+
+#define __lcd_even_mode_rgb() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RGB )
+#define __lcd_even_mode_rbg() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RBG )
+#define __lcd_even_mode_grb() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GRB)
+
+#define __lcd_even_mode_gbr() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GBR)
+#define __lcd_even_mode_brg() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BRG)
+#define __lcd_even_mode_bgr() \
+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BGR)
+
+/* Vertical Synchronize Register */
+#define __lcd_vsync_get_vps() \
+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPS_MASK) >> LCD_VSYNC_VPS_BIT )
+
+#define __lcd_vsync_get_vpe() \
+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT )
+#define __lcd_vsync_set_vpe(n) \
+do { \
+ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \
+ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \
+} while (0)
+
+#define __lcd_hsync_get_hps() \
+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT )
+#define __lcd_hsync_set_hps(n) \
+do { \
+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \
+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \
+} while (0)
+
+#define __lcd_hsync_get_hpe() \
+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT )
+#define __lcd_hsync_set_hpe(n) \
+do { \
+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \
+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \
+} while (0)
+
+#define __lcd_vat_get_ht() \
+ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT )
+#define __lcd_vat_set_ht(n) \
+do { \
+ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \
+ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \
+} while (0)
+
+#define __lcd_vat_get_vt() \
+ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT )
+#define __lcd_vat_set_vt(n) \
+do { \
+ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \
+ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \
+} while (0)
+
+#define __lcd_dah_get_hds() \
+ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT )
+#define __lcd_dah_set_hds(n) \
+do { \
+ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \
+ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \
+} while (0)
+
+#define __lcd_dah_get_hde() \
+ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT )
+#define __lcd_dah_set_hde(n) \
+do { \
+ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \
+ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \
+} while (0)
+
+#define __lcd_dav_get_vds() \
+ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT )
+#define __lcd_dav_set_vds(n) \
+do { \
+ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \
+ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \
+} while (0)
+
+#define __lcd_dav_get_vde() \
+ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT )
+#define __lcd_dav_set_vde(n) \
+do { \
+ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \
+ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \
+} while (0)
+
+/* DMA Command Register */
+#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT )
+#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT )
+#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT )
+#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT )
+
+#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT )
+#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT )
+#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT )
+#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT )
+
+#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL )
+#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL )
+
+#define __lcd_cmd0_get_len() \
+ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT )
+#define __lcd_cmd1_get_len() \
+ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT )
+
+/*************************************************************************
+ * TVE (TV Encoder Controller) ops
+ *************************************************************************/
+/* TV Encoder Control register ops */
+#define __tve_soft_reset() (REG_TVE_CTRL |= TVE_CTRL_SWRST)
+
+#define __tve_output_colorbar() (REG_TVE_CTRL |= TVE_CTRL_CLBAR)
+#define __tve_output_video() (REG_TVE_CTRL &= ~TVE_CTRL_CLBAR)
+
+#define __tve_input_cr_first() (REG_TVE_CTRL |= TVE_CTRL_CR1ST)
+#define __tve_input_cb_first() (REG_TVE_CTRL &= ~TVE_CTRL_CR1ST)
+
+#define __tve_set_0_as_black() (REG_TVE_CTRL |= TVE_CTRL_ZBLACK)
+#define __tve_set_16_as_black() (REG_TVE_CTRL &= ~TVE_CTRL_ZBLACK)
+
+#define __tve_ena_invert_top_bottom() (REG_TVE_CTRL |= TVE_CTRL_FINV)
+#define __tve_dis_invert_top_bottom() (REG_TVE_CTRL &= ~TVE_CTRL_FINV)
+
+#define __tve_set_pal_mode() (REG_TVE_CTRL |= TVE_CTRL_PAL)
+#define __tve_set_ntsc_mode() (REG_TVE_CTRL &= ~TVE_CTRL_PAL)
+
+#define __tve_set_pal_dura() (REG_TVE_CTRL |= TVE_CTRL_SYNCT)
+#define __tve_set_ntsc_dura() (REG_TVE_CTRL &= ~TVE_CTRL_SYNCT)
+
+/* n = 0 ~ 3 */
+#define __tve_set_c_bandwidth(n) \
+do {\
+ REG_TVE_CTRL &= ~TVE_CTRL_CBW_MASK;\
+ REG_TVE_CTRL |= (n) << TVE_CTRL_CBW_BIT; \
+}while(0)
+
+/* n = 0 ~ 3 */
+#define __tve_set_c_gain(n) \
+do {\
+ REG_TVE_CTRL &= ~TVE_CTRL_CGAIN_MASK;\
+ (REG_TVE_CTRL |= (n) << TVE_CTRL_CGAIN_BIT; \
+}while(0)
+
+/* n = 0 ~ 7 */
+#define __tve_set_yc_delay(n) \
+do { \
+ REG_TVE_CTRL &= ~TVE_CTRL_YCDLY_MASK \
+ REG_TVE_CTRL |= ((n) << TVE_CTRL_YCDLY_BIT); \
+} while(0)
+
+#define __tve_disable_all_dacs() (REG_TVE_CTRL |= TVE_CTRL_DAPD)
+#define __tve_disable_dac1() (REG_TVE_CTRL |= TVE_CTRL_DAPD1)
+#define __tve_enable_dac1() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD1)
+#define __tve_disable_dac2() (REG_TVE_CTRL |= TVE_CTRL_DAPD2)
+#define __tve_enable_dac2() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD2)
+#define __tve_disable_dac3() (REG_TVE_CTRL |= TVE_CTRL_DAPD3)
+#define __tve_enable_dac3() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD3)
+
+#define __tve_enable_svideo_fmt() (REG_TVE_CTRL |= TVE_CTRL_ECVBS)
+#define __tve_enable_cvbs_fmt() (REG_TVE_CTRL &= ~TVE_CTRL_ECVBS)
+
+/* TV Encoder Frame Configure register ops */
+/* n = 0 ~ 255 */
+#define __tve_set_first_video_line(n) \
+do {\
+ REG_TVE_FRCFG &= ~TVE_FRCFG_L1ST_MASK;\
+ REG_TVE_FRCFG |= (n) << TVE_FRCFG_L1ST_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_line_num_per_frm(n) \
+do {\
+ REG_TVE_FRCFG &= ~TVE_FRCFG_NLINE_MASK;\
+ REG_TVE_CFG |= (n) << TVE_FRCFG_NLINE_BIT;\
+} while(0)
+#define __tve_get_video_line_num()\
+ (((REG_TVE_FRCFG & TVE_FRCFG_NLINE_MASK) >> TVE_FRCFG_NLINE_BIT) - 1 - 2 * ((REG_TVE_FRCFG & TVE_FRCFG_L1ST_MASK) >> TVE_FRCFG_L1ST_BIT))
+
+/* TV Encoder Signal Level Configure register ops */
+/* n = 0 ~ 1023 */
+#define __tve_set_white_level(n) \
+do {\
+ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_WHITEL_MASK;\
+ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_WHITEL_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_black_level(n) \
+do {\
+ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_BLACKL_MASK;\
+ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_BLACKL_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_blank_level(n) \
+do {\
+ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_BLANKL_MASK;\
+ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_BLANKL_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_vbi_blank_level(n) \
+do {\
+ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_VBLANKL_MASK;\
+ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_VBLANKL_BIT;\
+} while(0)
+/* n = 0 ~ 1023 */
+#define __tve_set_sync_level(n) \
+do {\
+ REG_TVE_SLCFG3 &= ~TVE_SLCFG3_SYNCL_MASK;\
+ REG_TVE_SLCFG3 |= (n) << TVE_SLCFG3_SYNCL_BIT;\
+} while(0)
+
+/* TV Encoder Signal Level Configure register ops */
+/* n = 0 ~ 31 */
+#define __tve_set_front_porch(n) \
+do {\
+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_FRONTP_MASK;\
+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_FRONTP_BIT; \
+} while(0)
+/* n = 0 ~ 127 */
+#define __tve_set_hsync_width(n) \
+do {\
+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_HSYNCW_MASK;\
+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_HSYNCW_BIT; \
+} while(0)
+/* n = 0 ~ 127 */
+#define __tve_set_back_porch(n) \
+do {\
+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_BACKP_MASK;\
+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_BACKP_BIT; \
+} while(0)
+/* n = 0 ~ 2047 */
+#define __tve_set_active_linec(n) \
+do {\
+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_ACTLIN_MASK;\
+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_ACTLIN_BIT; \
+} while(0)
+/* n = 0 ~ 31 */
+#define __tve_set_breezy_way(n) \
+do {\
+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_PREBW_MASK;\
+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_PREBW_BIT; \
+} while(0)
+
+/* n = 0 ~ 127 */
+#define __tve_set_burst_width(n) \
+do {\
+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_BURSTW_MASK;\
+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_BURSTW_BIT; \
+} while(0)
+
+/* TV Encoder Chrominance filter and Modulation register ops */
+/* n = 0 ~ (2^32-1) */
+#define __tve_set_c_sub_carrier_freq(n) REG_TVE_CFREQ = (n)
+/* n = 0 ~ 255 */
+#define __tve_set_c_sub_carrier_init_phase(n) \
+do { \
+ REG_TVE_CPHASE &= ~TVE_CPHASE_INITPH_MASK; \
+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_INITPH_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_c_sub_carrier_act_phase(n) \
+do { \
+ REG_TVE_CPHASE &= ~TVE_CPHASE_ACTPH_MASK; \
+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_ACTPH_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_c_phase_rst_period(n) \
+do { \
+ REG_TVE_CPHASE &= ~TVE_CPHASE_CCRSTP_MASK; \
+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_CCRSTP_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_cb_burst_amp(n) \
+do { \
+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBBA_MASK; \
+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBBA_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_cr_burst_amp(n) \
+do { \
+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRBA_MASK; \
+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRBA_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_cb_gain_amp(n) \
+do { \
+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBGAIN_MASK; \
+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBGAIN_BIT; \
+} while(0)
+/* n = 0 ~ 255 */
+#define __tve_set_cr_gain_amp(n) \
+do { \
+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRGAIN_MASK; \
+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRGAIN_BIT; \
+} while(0)
+
+/* TV Encoder Wide Screen Signal Control register ops */
+/* n = 0 ~ 7 */
+#define __tve_set_notch_freq(n) \
+do { \
+ REG_TVE_WSSCR &= ~TVE_WSSCR_NCHFREQ_MASK; \
+ REG_TVE_WSSCR |= (n) << TVE_WSSCR_NCHFREQ_BIT; \
+} while(0)
+/* n = 0 ~ 7 */
+#define __tve_set_notch_width() (REG_TVE_WSSCR |= TVE_WSSCR_NCHW_BIT)
+#define __tve_clear_notch_width() (REG_TVE_WSSCR &= ~TVE_WSSCR_NCHW_BIT)
+#define __tve_enable_notch() (REG_TVE_WSSCR |= TVE_WSSCR_ENCH_BIT)
+#define __tve_disable_notch() (REG_TVE_WSSCR &= ~TVE_WSSCR_ENCH_BIT)
+/* n = 0 ~ 7 */
+#define __tve_set_wss_edge(n) \
+do { \
+ REG_TVE_WSSCR &= ~TVE_WSSCR_WSSEDGE_MASK; \
+ REG_TVE_WSSCR |= (n) << TVE_WSSCR_WSSEDGE_BIT; \
+} while(0)
+#define __tve_set_wss_clkbyp() (REG_TVE_WSSCR |= TVE_WSSCR_WSSCKBP_BIT)
+#define __tve_set_wss_type() (REG_TVE_WSSCR |= TVE_WSSCR_WSSTP_BIT)
+#define __tve_enable_wssf1() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS1_BIT)
+#define __tve_enable_wssf0() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS0_BIT)
+
+/* TV Encoder Wide Screen Signal Configure register 1, 2 and 3 ops */
+/* n = 0 ~ 1023 */
+#define __tve_set_wss_level(n) \
+do { \
+ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSL_MASK; \
+ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSL_BIT; \
+} while(0)
+/* n = 0 ~ 4095 */
+#define __tve_set_wss_freq(n) \
+do { \
+ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSFREQ_MASK; \
+ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSFREQ_BIT; \
+} while(0)
+/* n = 0, 1; l = 0 ~ 255 */
+#define __tve_set_wss_line(n,v) \
+do { \
+ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \
+ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \
+} while(0)
+/* n = 0, 1; d = 0 ~ (2^20-1) */
+#define __tve_set_wss_data(n, v) \
+do { \
+ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \
+ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \
+} while(0)
+
+/***************************************************************************
+ * RTC ops
+ ***************************************************************************/
+
+#define __rtc_write_ready() ( (REG_RTC_RCR & RTC_RCR_WRDY) >> RTC_RCR_WRDY_BIT )
+#define __rtc_enabled() ( REG_RTC_RCR |= RTC_RCR_RTCE )
+#define __rtc_disabled() ( REG_RTC_RCR &= ~RTC_RCR_RTCE )
+#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE )
+#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE )
+#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE )
+#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE )
+#define __rtc_enable_1Hz_irq() ( REG_RTC_RCR |= RTC_RCR_1HZIE )
+#define __rtc_disable_1Hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_1HZIE )
+
+#define __rtc_get_1Hz_flag() ( (REG_RTC_RCR >> RTC_RCR_1HZ_BIT) & 0x1 )
+#define __rtc_clear_1Hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_1HZ )
+#define __rtc_get_alarm_flag() ( (REG_RTC_RCR >> RTC_RCR_AF_BIT) & 0x1 )
+#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF )
+
+#define __rtc_get_second() ( REG_RTC_RSR )
+#define __rtc_set_second(v) ( REG_RTC_RSR = v )
+
+#define __rtc_get_alarm_second() ( REG_RTC_RSAR )
+#define __rtc_set_alarm_second(v) ( REG_RTC_RSAR = v )
+
+#define __rtc_RGR_is_locked() ( (REG_RTC_RGR >> RTC_RGR_LOCK) )
+#define __rtc_lock_RGR() ( REG_RTC_RGR |= RTC_RGR_LOCK )
+#define __rtc_unlock_RGR() ( REG_RTC_RGR &= ~RTC_RGR_LOCK )
+#define __rtc_get_adjc_val() ( (REG_RTC_RGR & RTC_RGR_ADJC_MASK) >> RTC_RGR_ADJC_BIT )
+#define __rtc_set_adjc_val(v) \
+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_ADJC_MASK) | (v << RTC_RGR_ADJC_BIT) ))
+#define __rtc_get_nc1Hz_val() ( (REG_RTC_RGR & RTC_RGR_NC1HZ_MASK) >> RTC_RGR_NC1HZ_BIT )
+#define __rtc_set_nc1Hz_val(v) \
+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_NC1HZ_MASK) | (v << RTC_RGR_NC1HZ_BIT) ))
+
+#define __rtc_power_down() ( REG_RTC_HCR |= RTC_HCR_PD )
+
+#define __rtc_get_hwfcr_val() ( REG_RTC_HWFCR & RTC_HWFCR_MASK )
+#define __rtc_set_hwfcr_val(v) ( REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK )
+#define __rtc_get_hrcr_val() ( REG_RTC_HRCR & RTC_HRCR_MASK )
+#define __rtc_set_hrcr_val(v) ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK )
+
+#define __rtc_enable_alarm_wakeup() ( REG_RTC_HWCR |= RTC_HWCR_EALM )
+#define __rtc_disable_alarm_wakeup() ( REG_RTC_HWCR &= ~RTC_HWCR_EALM )
+
+#define __rtc_status_hib_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_HR) & 0x1 )
+#define __rtc_status_ppr_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_PPR) & 0x1 )
+#define __rtc_status_wakeup_pin_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_PIN) & 0x1 )
+#define __rtc_status_alarm_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_ALM) & 0x1 )
+#define __rtc_clear_hib_stat_all() ( REG_RTC_HWRSR = 0 )
+
+#define __rtc_get_scratch_pattern() (REG_RTC_HSPR)
+#define __rtc_set_scratch_pattern(n) (REG_RTC_HSPR = n )
+
+/*************************************************************************
+ * BCH
+ *************************************************************************/
+#define __ecc_encoding_4bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \
+ REG_BCH_CRC = BCH_CR_BSEL8; \
+} while(0)
+#define __ecc_decoding_4bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BCHE; \
+ REG_BCH_CRC = BCH_CR_ENCE | BCH_CR_BSEL8; \
+} while(0)
+#define __ecc_encoding_8bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \
+} while(0)
+#define __ecc_decoding_8bit() \
+do { \
+ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \
+ REG_BCH_CRC = BCH_CR_ENCE; \
+} while(0)
+#define __ecc_dma_enable() ( REG_BCH_CRS = BCH_CR_DMAE )
+#define __ecc_dma_disable() ( REG_BCH_CRC = BCH_CR_DMAE )
+#define __ecc_disable() ( REG_BCH_CRC = BCH_CR_BCHE )
+#define __ecc_encode_sync() while (!(REG_BCH_INTS & BCH_INTS_ENCF))
+#define __ecc_decode_sync() while (!(REG_BCH_INTS & BCH_INTS_DECF))
+#define __ecc_cnt_dec(n) \
+do { \
+ REG_BCH_CNT &= ~(BCH_CNT_DEC_MASK << BCH_CNT_DEC_BIT); \
+ REG_BCH_CNT = (n) << BCH_CNT_DEC_BIT; \
+} while(0)
+#define __ecc_cnt_enc(n) \
+do { \
+ REG_BCH_CNT &= ~(BCH_CNT_ENC_MASK << BCH_CNT_ENC_BIT); \
+ REG_BCH_CNT = (n) << BCH_CNT_ENC_BIT; \
+} while(0)
+
+/***************************************************************************
+ * OWI (one-wire bus) ops
+ ***************************************************************************/
+
+/* OW control register ops */
+#define __owi_enable_all_interrupts() ( REG_OWI_CTL = (OWI_CTL_EBYTE | OWI_CTL_EBIT | OWI_CTL_ERST) )
+#define __owi_disable_all_interrupts() ( REG_OWI_CTL = 0 )
+
+#define __owi_enable_byte_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBYTE )
+#define __owi_disable_byte_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBYTE )
+#define __owi_enable_bit_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBIT )
+#define __owi_disable_bit_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBIT )
+#define __owi_enable_rst_interrupt() ( REG_OWI_CTL |= OWI_CTL_ERST )
+#define __owi_disable_rst_interrupt() ( REG_OWI_CTL &=~OWI_CTL_ERST )
+
+/* OW configure register ops */
+#define __owi_select_regular_mode() ( REG_OWI_CFG &= ~OWI_CFG_MODE )
+#define __owi_select_overdrive_mode() ( REG_OWI_CFG |= OWI_CFG_MODE )
+
+#define __owi_set_rddata() ( REG_OWI_CFG |= OWI_CFG_RDDATA )
+#define __owi_clr_rddata() ( REG_OWI_CFG &= ~OWI_CFG_RDDATA )
+#define __owi_get_rddata() ( REG_OWI_CFG & OWI_CFG_RDDATA )
+
+#define __owi_set_wrdata() ( REG_OWI_CFG |= OWI_CFG_WRDATA )
+#define __owi_clr_wrdata() ( REG_OWI_CFG &= ~OWI_CFG_WRDATA )
+#define __owi_get_wrdata() ( REG_OWI_CFG & OWI_CFG_WRDATA )
+
+#define __owi_get_rdst() ( REG_OWI_CFG & OWI_CFG_RDST )
+
+#define __owi_set_wr1rd() ( REG_OWI_CFG |= OWI_CFG_WR1RD )
+#define __owi_clr_wr1rd() ( REG_OWI_CFG &= ~OWI_CFG_WR1RD )
+#define __owi_get_wr1rd() ( REG_OWI_CFG & OWI_CFG_WR1RD )
+
+#define __owi_set_wr0() ( REG_OWI_CFG |= OWI_CFG_WR0 )
+#define __owi_clr_wr0() ( REG_OWI_CFG &= ~OWI_CFG_WR0 )
+#define __owi_get_wr0() ( REG_OWI_CFG & OWI_CFG_WR0 )
+
+#define __owi_set_rst() ( REG_OWI_CFG |= OWI_CFG_RST )
+#define __owi_clr_rst() ( REG_OWI_CFG &= ~OWI_CFG_RST )
+#define __owi_get_rst() ( REG_OWI_CFG & OWI_CFG_RST )
+
+#define __owi_enable_ow_ops() ( REG_OWI_CFG |= OWI_CFG_ENA )
+#define __owi_disable_ow_ops() ( REG_OWI_CFG &= ~OWI_CFG_ENA )
+#define __owi_get_enable() ( REG_OWI_CFG & OWI_CFG_ENA )
+
+#define __owi_wait_ops_rdy() \
+ do { \
+ while(__owi_get_enable()); \
+ udelay(1); \
+ } while(0);
+
+/* OW status register ops */
+#define __owi_clr_sts() ( REG_OWI_STS = 0 )
+#define __owi_get_sts_pst() ( REG_OWI_STS & OWI_STS_PST )
+#define __owi_get_sts_byte_rdy() ( REG_OWI_STS & OWI_STS_BYTE_RDY )
+#define __owi_get_sts_bit_rdy() ( REG_OWI_STS & OWI_STS_BIT_RDY )
+#define __owi_get_sts_pst_rdy() ( REG_OWI_STS & OWI_STS_PST_RDY )
+
+/*************************************************************************
+ * TSSI MPEG 2-TS slave interface operation
+ *************************************************************************/
+#define __tssi_enable() ( REG_TSSI_ENA |= TSSI_ENA_ENA )
+#define __tssi_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_ENA )
+#define __tssi_soft_reset() ( REG_TSSI_ENA |= TSSI_ENA_SFT_RST )
+#define __tssi_dma_enable() ( REG_TSSI_ENA |= TSSI_ENA_DMA_EN )
+#define __tssi_dma_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_DMA_EN )
+#define __tssi_filter_enable() ( REG_TSSI_ENA |= TSSI_ENA_PID_EN )
+#define __tssi_filter_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_PID_EN )
+
+/* n = 4, 8, 16 */
+#define __tssi_set_tigger_num(n) \
+ do { \
+ REG_TSSI_CFG &= ~TSSI_CFG_TRIG_MASK; \
+ REG_TSSI_CFG |= TSSI_CFG_TRIG_##n; \
+ } while (0)
+
+#define __tssi_set_wd_1() ( REG_TSSI_CFG |= TSSI_CFG_END_WD )
+#define __tssi_set_wd_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_WD )
+
+#define __tssi_set_bt_1() ( REG_TSSI_CFG |= TSSI_CFG_END_BD )
+#define __tssi_set_bt_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_BD )
+
+#define __tssi_set_data_pola_high() ( REG_TSSI_CFG |= TSSI_CFG_TSDI_H )
+#define __tssi_set_data_pola_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSDI_H )
+
+#define __tssi_set_data_use_data0() ( REG_TSSI_CFG |= TSSI_CFG_USE_0 )
+#define __tssi_set_data_use_data7() ( REG_TSSI_CFG &= ~TSSI_CFG_USE_0 )
+
+#define __tssi_select_clk_fast() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_CH )
+#define __tssi_select_clk_slow() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_CH )
+
+#define __tssi_select_serail_mode() ( REG_TSSI_CFG &= ~TSSI_CFG_PARAL )
+#define __tssi_select_paral_mode() ( REG_TSSI_CFG |= TSSI_CFG_PARAL )
+
+#define __tssi_select_clk_nega_edge() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_P )
+#define __tssi_select_clk_posi_edge() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_P )
+
+#define __tssi_select_frm_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFRM_H )
+#define __tssi_select_frm_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFRM_H )
+
+#define __tssi_select_str_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSSTR_H )
+#define __tssi_select_str_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSSTR_H )
+
+#define __tssi_select_fail_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFAIL_H )
+#define __tssi_select_fail_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFAIL_H )
+
+#define __tssi_enable_ovrn_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_OVRNM )
+#define __tssi_disable_ovrn_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_OVRNM )
+
+#define __tssi_enable_trig_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_TRIGM )
+#define __tssi_disable_trig_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_TRIGM )
+
+#define __tssi_state_is_overrun() ( REG_TSSI_STAT & TSSI_STAT_OVRN )
+#define __tssi_state_trigger_meet() ( REG_TSSI_STAT & TSSI_STAT_TRIG )
+#define __tssi_clear_state() ( REG_TSSI_STAT = 0 ) /* write 0??? */
+#define __tssi_state_clear_overrun() ( REG_TSSI_STAT = TSSI_STAT_OVRN )
+
+#define __tssi_enable_filte_pid0() ( REG_TSSI_PEN |= TSSI_PEN_PID0 )
+#define __tssi_disable_filte_pid0() ( REG_TSSI_PEN &= ~TSSI_PEN_PID0 )
+
+/* m = 0, ..., 15 */
+#define __tssi_enable_pid_filter(m) \
+ do { \
+ int n = (m); \
+ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \
+ if ( n >= TSSI_PID_MAX ) n += 8; \
+ REG_TSSI_PEN |= ( 1 << n ); \
+ } \
+ } while (0)
+
+/* m = 0, ..., 15 */
+#define __tssi_disable_pid_filter(m) \
+ do { \
+ int n = (m); \
+ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \
+ if ( n >= TSSI_PID_MAX ) n += 8; \
+ REG_TSSI_PEN &= ~( 1 << n ); \
+ } \
+ } while (0)
+
+/* n = 0, ..., 7 */
+#define __tssi_set_pid0(n, pid0) \
+ do { \
+ REG_TSSI_PID(n) &= ~TSSI_PID_PID0_MASK; \
+ REG_TSSI_PID(n) |= ((pid0)<<TSSI_PID_PID0_BIT)&TSSI_PID_PID0_MASK; \
+ }while (0)
+/* n = 0, ..., 7 */
+#define __tssi_set_pid1(n, pid1) \
+ do { \
+ REG_TSSI_PID(n) &= ~TSSI_PID_PID1_MASK; \
+ REG_TSSI_PID(n) |= ((pid1)<<TSSI_PID_PID1_BIT)&TSSI_PID_PID1_MASK; \
+ }while (0)
+
+/* n = 0, ..., 15 */
+#define __tssi_set_pid(n, pid) \
+ do { \
+ if ( n>=0 && n < TSSI_PID_MAX*2) { \
+ if ( n < TSSI_PID_MAX ) \
+ __tssi_set_pid0(n, pid); \
+ else \
+ __tssi_set_pid1(n-TSSI_PID_MAX, pid); \
+ } \
+ }while (0)
+
+
+#if 0
+/*************************************************************************
+ * IPU (Image Processing Unit)
+ *************************************************************************/
+#define u32 volatile unsigned long
+
+#define write_reg(reg, val) \
+do { \
+ *(u32 *)(reg) = (val); \
+} while(0)
+
+#define read_reg(reg, off) (*(u32 *)((reg)+(off)))
+
+
+#define set_ipu_fmt(rgb_888_out_fmt, rgb_out_oft, out_fmt, yuv_pkg_out, in_oft, in_fmt ) \
+({ write_reg( (IPU_V_BASE + REG_D_FMT), ((in_fmt) & IN_FMT_MSK)<<IN_FMT_SFT \
+| ((in_oft) & IN_OFT_MSK)<< IN_OFT_SFT \
+| ((out_fmt) & OUT_FMT_MSK)<<OUT_FMT_SFT \
+| ((yuv_pkg_out) & YUV_PKG_OUT_MSK ) << YUV_PKG_OUT_SFT \
+| ((rgb_888_out_fmt) & RGB888_FMT_MSK ) << RGB888_FMT_SFT \
+| ((rgb_out_oft) & RGB_OUT_OFT_MSK ) << RGB_OUT_OFT_SFT); \
+})
+#define set_y_addr(y_addr) \
+({ write_reg( (IPU_V_BASE + REG_Y_ADDR), y_addr); \
+})
+#define set_u_addr(u_addr) \
+({ write_reg( (IPU_V_BASE + REG_U_ADDR), u_addr); \
+})
+
+#define set_v_addr(v_addr) \
+({ write_reg( (IPU_V_BASE + REG_V_ADDR), v_addr); \
+})
+
+#define set_y_phy_t_addr(y_phy_t_addr) \
+({ write_reg( (IPU_V_BASE + REG_Y_PHY_T_ADDR), y_phy_t_addr); \
+})
+
+#define set_u_phy_t_addr(u_phy_t_addr) \
+({ write_reg( (IPU_V_BASE + REG_U_PHY_T_ADDR), u_phy_t_addr); \
+})
+
+#define set_v_phy_t_addr(v_phy_t_addr) \
+({ write_reg( (IPU_V_BASE + REG_V_PHY_T_ADDR), v_phy_t_addr); \
+})
+
+#define set_out_phy_t_addr(out_phy_t_addr) \
+({ write_reg( (IPU_V_BASE + REG_OUT_PHY_T_ADDR), out_phy_t_addr); \
+})
+
+#define set_inframe_gsize(width, height, y_stride, u_stride, v_stride) \
+({ write_reg( (IPU_V_BASE + REG_IN_FM_GS), ((width) & IN_FM_W_MSK)<<IN_FM_W_SFT \
+| ((height) & IN_FM_H_MSK)<<IN_FM_H_SFT); \
+ write_reg( (IPU_V_BASE + REG_Y_STRIDE), ((y_stride) & Y_S_MSK)<<Y_S_SFT); \
+ write_reg( (IPU_V_BASE + REG_UV_STRIDE), ((u_stride) & U_S_MSK)<<U_S_SFT \
+| ((v_stride) & V_S_MSK)<<V_S_SFT); \
+})
+#define set_out_addr(out_addr) \
+({ write_reg( (IPU_V_BASE + REG_OUT_ADDR), out_addr); \
+})
+#define set_outframe_gsize(width, height, o_stride) \
+({ write_reg( (IPU_V_BASE + REG_OUT_GS), ((width) & OUT_FM_W_MSK)<<OUT_FM_W_SFT \
+| ((height) & OUT_FM_H_MSK)<<OUT_FM_H_SFT); \
+ write_reg( (IPU_V_BASE + REG_OUT_STRIDE), ((o_stride) & OUT_S_MSK)<<OUT_S_SFT); \
+})
+#define set_rsz_lut_end(h_end, v_end) \
+({ write_reg( (IPU_V_BASE + REG_RSZ_COEF_INDEX), ((h_end) & HE_IDX_MSK)<<HE_IDX_SFT \
+| ((v_end) & VE_IDX_MSK)<<VE_IDX_SFT); \
+})
+#define set_csc_c0(c0_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_CO_COEF), ((c0_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_csc_c1(c1_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_C1_COEF), ((c1_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_csc_c2(c2_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_C2_COEF), ((c2_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_csc_c3(c3_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_C3_COEF), ((c3_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_csc_c4(c4_coeff) \
+({ write_reg( (IPU_V_BASE + REG_CSC_C4_COEF), ((c4_coeff) & CX_COEF_MSK)<<CX_COEF_SFT); \
+})
+#define set_hrsz_lut_coef(coef, in_n, out_n) \
+({ write_reg( (IPU_V_BASE + HRSZ_LUT_BASE ), ((coef) & W_COEF_MSK)<<W_COEF_SFT \
+| ((in_n) & IN_N_MSK)<<IN_N_SFT | ((out_n) & OUT_N_MSK)<<OUT_N_SFT); \
+})
+#define set_vrsz_lut_coef(coef, in_n, out_n) \
+({ write_reg( (IPU_V_BASE + VRSZ_LUT_BASE), ((coef) & W_COEF_MSK)<<W_COEF_SFT \
+| ((in_n) & IN_N_MSK)<<IN_N_SFT | ((out_n) & OUT_N_MSK)<<OUT_N_SFT); \
+})
+
+#define set_primary_ctrl(vrsz_en, hrsz_en,csc_en, irq_en) \
+({ write_reg( (IPU_V_BASE + REG_CTRL), ((irq_en) & FM_IRQ_EN_MSK)<<FM_IRQ_EN_SFT \
+| ((vrsz_en) & VRSZ_EN_MSK)<<VRSZ_EN_SFT \
+| ((hrsz_en) & HRSZ_EN_MSK)<<HRSZ_EN_SFT \
+| ((csc_en) & CSC_EN_MSK)<<CSC_EN_SFT \
+| (read_reg(IPU_V_BASE, REG_CTRL)) \
+& ~(CSC_EN_MSK<<CSC_EN_SFT | FM_IRQ_EN_MSK<<FM_IRQ_EN_SFT | VRSZ_EN_MSK<<VRSZ_EN_SFT | HRSZ_EN_MSK<<HRSZ_EN_SFT ) ); \
+})
+
+#define set_source_ctrl(pkg_sel, spage_sel) \
+({ write_reg( (IPU_V_BASE + REG_CTRL), ((pkg_sel) & PKG_SEL_MSK )<< PKG_SEL_SFT \
+| ((spage_sel) & SPAGE_MAP_MSK )<< SPAGE_MAP_SFT \
+| (read_reg(IPU_V_BASE, REG_CTRL)) \
+& ~(SPAGE_MAP_MSK << SPAGE_MAP_SFT | PKG_SEL_MSK << PKG_SEL_SFT ) ) ; \
+})
+
+#define set_out_ctrl(lcdc_sel, dpage_sel, disp_sel) \
+({ write_reg( (IPU_V_BASE + REG_CTRL), ((lcdc_sel) & LCDC_SEL_MSK )<< LCDC_SEL_SFT \
+| ((dpage_sel) & DPAGE_SEL_MSK )<< DPAGE_SEL_SFT \
+| ((disp_sel) & DISP_SEL_MSK )<< DISP_SEL_SFT \
+| (read_reg(IPU_V_BASE, REG_CTRL)) \
+& ~(LCDC_SEL_MSK<< LCDC_SEL_SFT | DPAGE_SEL_MSK << DPAGE_SEL_SFT | DISP_SEL_MSK << DISP_SEL_SFT ) ); \
+})
+
+#define set_scale_ctrl(v_scal, h_scal) \
+({ write_reg( (IPU_V_BASE + REG_CTRL), ((v_scal) & V_SCALE_MSK)<<V_SCALE_SFT \
+| ((h_scal) & H_SCALE_MSK)<<H_SCALE_SFT \
+| (read_reg(IPU_V_BASE, REG_CTRL)) & ~(V_SCALE_MSK<<V_SCALE_SFT | H_SCALE_MSK<<H_SCALE_SFT ) ); \
+})
+
+
+#define set_csc_ofset_para(chrom_oft, luma_oft) \
+({ write_reg( (IPU_V_BASE + REG_CSC_OFSET_PARA ), ((chrom_oft) & CHROM_OF_MSK ) << CHROM_OF_SFT \
+| ((luma_oft) & LUMA_OF_MSK ) << LUMA_OF_SFT ) ; \
+})
+
+#define sw_reset_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) \
+| IPU_RST_MSK<<IPU_RST_SFT); \
+})
+#define enable_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) | 0x1); \
+})
+#define disable_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) & ~0x1); \
+})
+#define run_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) | 0x2); \
+})
+#define stop_ipu() \
+({ write_reg( (IPU_V_BASE + REG_CTRL), (read_reg(IPU_V_BASE, REG_CTRL)) & ~0x2); \
+})
+
+#define polling_end_flag() \
+({ (read_reg(IPU_V_BASE, REG_STATUS)) & 0x01; \
+})
+
+#define start_vlut_coef_write() \
+({ write_reg( (IPU_V_BASE + VRSZ_LUT_BASE), ( 0x1<<12 ) ); \
+})
+
+#define start_hlut_coef_write() \
+({ write_reg( (IPU_V_BASE + HRSZ_LUT_BASE), ( 0x01<<12 ) ); \
+})
+
+#define clear_end_flag() \
+({ write_reg( (IPU_V_BASE + REG_STATUS), 0); \
+})
+#endif /* #if 0 */
+
+
+#endif /* __JZ4750L_OPS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750l/regs.h b/arch/mips/include/asm/mach-jz4750l/regs.h
new file mode 100644
index 00000000000..6a3ba98bdce
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750l/regs.h
@@ -0,0 +1,3390 @@
+/*
+ * linux/include/asm-mips/mach-jz4750l/regs.h
+ *
+ * JZ4750L register definition.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __JZ4750L_REGS_H__
+#define __JZ4750L_REGS_H__
+
+#if defined(__ASSEMBLY__) || defined(__LANGUAGE_ASSEMBLY)
+#define REG8(addr) (addr)
+#define REG16(addr) (addr)
+#define REG32(addr) (addr)
+#else
+#define REG8(addr) *((volatile unsigned char *)(addr))
+#define REG16(addr) *((volatile unsigned short *)(addr))
+#define REG32(addr) *((volatile unsigned int *)(addr))
+#endif
+
+/*
+ * Define the module base addresses
+ */
+#define CPM_BASE 0xB0000000
+#define INTC_BASE 0xB0001000
+#define TCU_BASE 0xB0002000
+#define WDT_BASE 0xB0002000
+#define RTC_BASE 0xB0003000
+#define GPIO_BASE 0xB0010000
+#define AIC_BASE 0xB0020000
+#define ICDC_BASE 0xB0020000
+#define MSC_BASE 0xB0021000
+#define UART0_BASE 0xB0030000
+#define UART1_BASE 0xB0031000
+#define UART2_BASE 0xB0032000
+#define UART3_BASE 0xB0033000
+#define I2C_BASE 0xB0042000
+#define SSI_BASE 0xB0043000
+#define SADC_BASE 0xB0070000
+#define PCM_BASE 0xB0071000
+#define EMC_BASE 0xB3010000
+#define DMAC_BASE 0xB3020000
+#define UHC_BASE 0xB3030000
+#define UDC_BASE 0xB3040000
+#define LCD_BASE 0xB3050000
+#define SLCD_BASE 0xB3050000
+#define TVE_BASE 0xB3050100
+#define CIM_BASE 0xB3060000
+#define IPU_BASE 0xB3080000
+#define ME_BASE 0xB3090000
+#define MC_BASE 0xB30A0000
+#define BCH_BASE 0xB30D0000
+#define ETH_BASE 0xB3100000
+#define TCSM_BASE 0xF4000000
+#define OWI_BASE 0XB0072000
+#define OTP_BASE 0xB3012000
+#define TSSI_BASE 0xB0073000
+
+/*************************************************************************
+ * INTC (Interrupt Controller)
+ *************************************************************************/
+#define INTC_ISR (INTC_BASE + 0x00)
+#define INTC_IMR (INTC_BASE + 0x04)
+#define INTC_IMSR (INTC_BASE + 0x08)
+#define INTC_IMCR (INTC_BASE + 0x0c)
+#define INTC_IPR (INTC_BASE + 0x10)
+#define INTC_ISSR (INTC_BASE + 0x18) /* Interrupt Controller Source Set Register */
+#define INTC_ISCR (INTC_BASE + 0x1c) /* Interrupt Controller Source Clear Register */
+
+#define REG_INTC_ISR REG32(INTC_ISR)
+#define REG_INTC_IMR REG32(INTC_IMR)
+#define REG_INTC_IMSR REG32(INTC_IMSR)
+#define REG_INTC_IMCR REG32(INTC_IMCR)
+#define REG_INTC_IPR REG32(INTC_IPR)
+#define REG_INTC_ISSR REG32(INTC_ISSR)
+#define REG_INTC_ISCR REG32(INTC_ISCR)
+
+// 1st-level interrupts
+#define IRQ_ETH 0
+#define IRQ_SFT 4
+#define IRQ_I2C 5
+#define IRQ_RTC 6
+#define IRQ_UART2 7
+#define IRQ_UART1 8
+#define IRQ_UART0 9
+#define IRQ_AIC 10
+#define IRQ_GPIO5 11
+#define IRQ_GPIO4 12
+#define IRQ_GPIO3 13
+#define IRQ_GPIO2 14
+#define IRQ_GPIO1 15
+#define IRQ_GPIO0 16
+#define IRQ_BCH 17
+#define IRQ_SADC 18
+#define IRQ_CIM 19
+#define IRQ_TSSI 20
+#define IRQ_TCU2 21
+#define IRQ_TCU1 22
+#define IRQ_TCU0 23
+#define IRQ_MSC1 24
+#define IRQ_MSC0 25
+#define IRQ_SSI 26
+#define IRQ_UDC 27
+#define IRQ_DMAC1 28
+#define IRQ_DMAC0 29
+#define IRQ_IPU 30
+#define IRQ_LCD 31
+
+// 2nd-level interrupts
+#define IRQ_DMA_0 32 /* 32 to 43 for DMAC0's 0-5 and DMAC1's 0-5 */
+#define IRQ_GPIO_0 48 /* 48 to 240 for GPIO pin 0 to 192 */
+
+#define NUM_DMA MAX_DMA_NUM /* 12 */
+#define NUM_GPIO MAX_GPIO_NUM /* GPIO NUM: 192, Jz4750L real num GPIO 178 */
+
+
+/*************************************************************************
+ * RTC
+ *************************************************************************/
+#define RTC_RCR (RTC_BASE + 0x00) /* RTC Control Register */
+#define RTC_RSR (RTC_BASE + 0x04) /* RTC Second Register */
+#define RTC_RSAR (RTC_BASE + 0x08) /* RTC Second Alarm Register */
+#define RTC_RGR (RTC_BASE + 0x0c) /* RTC Regulator Register */
+
+#define RTC_HCR (RTC_BASE + 0x20) /* Hibernate Control Register */
+#define RTC_HWFCR (RTC_BASE + 0x24) /* Hibernate Wakeup Filter Counter Reg */
+#define RTC_HRCR (RTC_BASE + 0x28) /* Hibernate Reset Counter Register */
+#define RTC_HWCR (RTC_BASE + 0x2c) /* Hibernate Wakeup Control Register */
+#define RTC_HWRSR (RTC_BASE + 0x30) /* Hibernate Wakeup Status Register */
+#define RTC_HSPR (RTC_BASE + 0x34) /* Hibernate Scratch Pattern Register */
+
+#define REG_RTC_RCR REG32(RTC_RCR)
+#define REG_RTC_RSR REG32(RTC_RSR)
+#define REG_RTC_RSAR REG32(RTC_RSAR)
+#define REG_RTC_RGR REG32(RTC_RGR)
+#define REG_RTC_HCR REG32(RTC_HCR)
+#define REG_RTC_HWFCR REG32(RTC_HWFCR)
+#define REG_RTC_HRCR REG32(RTC_HRCR)
+#define REG_RTC_HWCR REG32(RTC_HWCR)
+#define REG_RTC_HWRSR REG32(RTC_HWRSR)
+#define REG_RTC_HSPR REG32(RTC_HSPR)
+
+/* RTC Control Register */
+#define RTC_RCR_WRDY_BIT 7
+#define RTC_RCR_WRDY (1 << 7) /* Write Ready Flag */
+#define RTC_RCR_1HZ_BIT 6
+#define RTC_RCR_1HZ (1 << RTC_RCR_1HZ_BIT) /* 1Hz Flag */
+#define RTC_RCR_1HZIE (1 << 5) /* 1Hz Interrupt Enable */
+#define RTC_RCR_AF_BIT 4
+#define RTC_RCR_AF (1 << RTC_RCR_AF_BIT) /* Alarm Flag */
+#define RTC_RCR_AIE (1 << 3) /* Alarm Interrupt Enable */
+#define RTC_RCR_AE (1 << 2) /* Alarm Enable */
+#define RTC_RCR_RTCE (1 << 0) /* RTC Enable */
+
+/* RTC Regulator Register */
+#define RTC_RGR_LOCK (1 << 31) /* Lock Bit */
+#define RTC_RGR_ADJC_BIT 16
+#define RTC_RGR_ADJC_MASK (0x3ff << RTC_RGR_ADJC_BIT)
+#define RTC_RGR_NC1HZ_BIT 0
+#define RTC_RGR_NC1HZ_MASK (0xffff << RTC_RGR_NC1HZ_BIT)
+
+/* Hibernate Control Register */
+#define RTC_HCR_PD (1 << 0) /* Power Down */
+
+/* Hibernate Wakeup Filter Counter Register */
+#define RTC_HWFCR_BIT 5
+#define RTC_HWFCR_MASK (0x7ff << RTC_HWFCR_BIT)
+
+/* Hibernate Reset Counter Register */
+#define RTC_HRCR_BIT 5
+#define RTC_HRCR_MASK (0x7f << RTC_HRCR_BIT)
+
+/* Hibernate Wakeup Control Register */
+#define RTC_HWCR_EALM (1 << 0) /* RTC alarm wakeup enable */
+
+/* Hibernate Wakeup Status Register */
+#define RTC_HWRSR_HR (1 << 5) /* Hibernate reset */
+#define RTC_HWRSR_PPR (1 << 4) /* PPR reset */
+#define RTC_HWRSR_PIN (1 << 1) /* Wakeup pin status bit */
+#define RTC_HWRSR_ALM (1 << 0) /* RTC alarm status bit */
+
+
+/*************************************************************************
+ * CPM (Clock reset and Power control Management)
+ *************************************************************************/
+#define CPM_CPCCR (CPM_BASE+0x00)
+#define CPM_CPPCR (CPM_BASE+0x10)
+#define CPM_CPPSR (CPM_BASE+0x14) /* PLL Switch and Status Register */
+#define CPM_I2SCDR (CPM_BASE+0x60)
+#define CPM_LPCDR (CPM_BASE+0x64)
+#define CPM_MSCCDR(n) (CPM_BASE+0x68) /* MSC0(n=0) or MSC1(n=1) device clock divider Register */
+#define CPM_UHCCDR (CPM_BASE+0x6C)
+#define CPM_SSICDR (CPM_BASE+0x74)
+#define CPM_PCMCDR (CPM_BASE+0x7C) /* PCM device clock divider Register */
+
+#define CPM_LCR (CPM_BASE+0x04)
+#define CPM_CLKGR (CPM_BASE+0x20)
+#define CPM_OPCR (CPM_BASE+0x24) /* Oscillator and Power Control Register */
+
+#define CPM_RSR (CPM_BASE+0x08)
+
+#define REG_CPM_CPCCR REG32(CPM_CPCCR)
+#define REG_CPM_CPPCR REG32(CPM_CPPCR)
+#define REG_CPM_CPPSR REG32(CPM_CPPSR)
+#define REG_CPM_I2SCDR REG32(CPM_I2SCDR)
+#define REG_CPM_LPCDR REG32(CPM_LPCDR)
+#define REG_CPM_MSCCDR(n) REG32(CPM_MSCCDR(n))
+#define REG_CPM_UHCCDR REG32(CPM_UHCCDR)
+#define REG_CPM_SSICDR REG32(CPM_SSICDR)
+#define REG_CPM_PCMCDR REG32(CPM_PCMCDR)
+
+#define REG_CPM_LCR REG32(CPM_LCR)
+#define REG_CPM_CLKGR REG32(CPM_CLKGR)
+#define REG_CPM_OPCR REG32(CPM_OPCR)
+
+#define REG_CPM_RSR REG32(CPM_RSR)
+
+/* Clock Control Register */
+#define CPM_CPCCR_I2CS (1 << 31)
+#define CPM_CPCCR_ECS (1 << 30) /* Select the between EXCLK and EXCLK/2 output */
+#define CPM_CPCCR_UCS (1 << 29)
+#define CPM_CPCCR_UDIV_BIT 23
+#define CPM_CPCCR_UDIV_MASK (0x3f << CPM_CPCCR_UDIV_BIT)
+#define CPM_CPCCR_CE (1 << 22)
+#define CPM_CPCCR_PCS (1 << 21)
+#define CPM_CPCCR_H1DIV_BIT 16
+#define CPM_CPCCR_H1DIV_MASK (0x1f << CPM_CPCCR_H1DIV_BIT)
+#define CPM_CPCCR_MDIV_BIT 12
+#define CPM_CPCCR_MDIV_MASK (0x0f << CPM_CPCCR_MDIV_BIT)
+#define CPM_CPCCR_PDIV_BIT 8
+#define CPM_CPCCR_PDIV_MASK (0x0f << CPM_CPCCR_PDIV_BIT)
+#define CPM_CPCCR_HDIV_BIT 4
+#define CPM_CPCCR_HDIV_MASK (0x0f << CPM_CPCCR_HDIV_BIT)
+#define CPM_CPCCR_CDIV_BIT 0
+#define CPM_CPCCR_CDIV_MASK (0x0f << CPM_CPCCR_CDIV_BIT)
+
+/* PLL Switch and Status Register */
+#define CPM_CPPSR_PLLOFF (1<<31)
+#define CPM_CPPSR_PLLBP (1<<30)
+#define CPM_CPPSR_PLLON (1<<29)
+#define CPM_CPPSR_PS (1<<28) /* Indicate whether the PLL parameters' change has finished */
+#define CPM_CPPSR_FS (1<<27) /* Indicate whether the main clock's change has finished */
+#define CPM_CPPSR_CS (1<<26) /* Indicate whether the clock switch has finished */
+#define CPM_CPPSR_PM (1<<1) /* Clock switch mode */
+#define CPM_CPPSR_FM (1<<0) /* Clock frequency change mode */
+
+/* I2S Clock Divider Register */
+#define CPM_I2SCDR_I2SDIV_BIT 0
+#define CPM_I2SCDR_I2SDIV_MASK (0x1ff << CPM_I2SCDR_I2SDIV_BIT)
+
+/* LCD Pixel Clock Divider Register */
+#define CPM_LPCDR_PIXDIV_BIT 0
+#define CPM_LPCDR_PIXDIV_MASK (0x7ff << CPM_LPCDR_PIXDIV_BIT)
+
+/* MSC Clock Divider Register */
+#define CPM_MSCCDR_MSCDIV_BIT 0
+#define CPM_MSCCDR_MSCDIV_MASK (0x1f << CPM_MSCCDR_MSCDIV_BIT)
+
+/* SSI Clock Divider Register */
+#define CPM_SSICDR_SSIDIV_BIT 0
+#define CPM_SSICDR_SSIDIV_MASK (0xf << CPM_SSICDR_SSIDIV_BIT)
+
+/* PCM device clock divider Register */
+#define CPM_PCMCDR_PCMS 31 /* PCM source clock Selection */
+#define CPM_PCMCDR_PCMCD_BIT 0
+#define CPM_PCMCDR_PCMCD_MASK (0x1ff << CPM_PCMCDR_PCMCD_BIT)
+
+/* PLL Control Register */
+#define CPM_CPPCR_PLLM_BIT 23
+#define CPM_CPPCR_PLLM_MASK (0x1ff << CPM_CPPCR_PLLM_BIT)
+#define CPM_CPPCR_PLLN_BIT 18
+#define CPM_CPPCR_PLLN_MASK (0x1f << CPM_CPPCR_PLLN_BIT)
+#define CPM_CPPCR_PLLOD_BIT 16
+#define CPM_CPPCR_PLLOD_MASK (0x03 << CPM_CPPCR_PLLOD_BIT)
+#define CPM_CPPCR_PLLS (1 << 10) /* obsolete, replaced by CPM_CPPSR_PLLON */
+#define CPM_CPPCR_PLLBP (1 << 9)
+#define CPM_CPPCR_PLLEN (1 << 8)
+#define CPM_CPPCR_PLLST_BIT 0
+#define CPM_CPPCR_PLLST_MASK (0xff << CPM_CPPCR_PLLST_BIT)
+
+/* Low Power Control Register */
+#define CPM_LCR_DOZE_DUTY_BIT 3
+#define CPM_LCR_DOZE_DUTY_MASK (0x1f << CPM_LCR_DOZE_DUTY_BIT)
+#define CPM_LCR_DOZE_ON (1 << 2)
+#define CPM_LCR_LPM_BIT 0
+#define CPM_LCR_LPM_MASK (0x3 << CPM_LCR_LPM_BIT)
+ #define CPM_LCR_LPM_IDLE (0x0 << CPM_LCR_LPM_BIT)
+ #define CPM_LCR_LPM_SLEEP (0x1 << CPM_LCR_LPM_BIT)
+
+/* Clock Gate Register */
+#define CPM_CLKGR_AUX_CPU (1 << 24)
+#define CPM_CLKGR_AHB1 (1 << 23)
+#define CPM_CLKGR_IDCT (1 << 22)
+#define CPM_CLKGR_DB (1 << 21)
+#define CPM_CLKGR_ME (1 << 20)
+#define CPM_CLKGR_MC (1 << 19)
+#define CPM_CLKGR_TVE (1 << 18)
+#define CPM_CLKGR_TSSI (1 << 17)
+#define CPM_CLKGR_MSC1 (1 << 16)
+#define CPM_CLKGR_UART2 (1 << 15)
+#define CPM_CLKGR_UART1 (1 << 14)
+#define CPM_CLKGR_IPU (1 << 13)
+#define CPM_CLKGR_DMAC (1 << 12)
+#define CPM_CLKGR_BCH (1 << 11)
+#define CPM_CLKGR_UDC (1 << 10)
+#define CPM_CLKGR_LCD (1 << 9)
+#define CPM_CLKGR_CIM (1 << 8)
+#define CPM_CLKGR_SADC (1 << 7)
+#define CPM_CLKGR_MSC0 (1 << 6)
+#define CPM_CLKGR_AIC (1 << 5)
+#define CPM_CLKGR_SSI (1 << 4)
+#define CPM_CLKGR_I2C (1 << 3)
+#define CPM_CLKGR_RTC (1 << 2)
+#define CPM_CLKGR_TCU (1 << 1)
+#define CPM_CLKGR_UART0 (1 << 0)
+
+/* Oscillator and Power Control Register */
+#define CPM_OPCR_O1ST_BIT 8
+#define CPM_OPCR_O1ST_MASK (0xff << CPM_SCR_O1ST_BIT)
+#define CPM_OPCR_UHCPHY_DISABLE (1 << 7)
+#define CPM_OPCR_UDCPHY_ENABLE (1 << 6)
+#define CPM_OPCR_OSC_ENABLE (1 << 4)
+#define CPM_OPCR_ERCS (1 << 2) /* EXCLK/512 clock and RTCLK clock selection */
+#define CPM_OPCR_MOSE (1 << 1) /* Main Oscillator Enable */
+#define CPM_OPCR_MCS (1 << 0) /* Main clock source select register */
+
+/* Reset Status Register */
+#define CPM_RSR_HR (1 << 2)
+#define CPM_RSR_WR (1 << 1)
+#define CPM_RSR_PR (1 << 0)
+
+
+/*************************************************************************
+ * TCU (Timer Counter Unit)
+ *************************************************************************/
+#define TCU_TSTR (TCU_BASE + 0xF0) /* Timer Status Register,Only Used In Tcu2 Mode */
+#define TCU_TSTSR (TCU_BASE + 0xF4) /* Timer Status Set Register */
+#define TCU_TSTCR (TCU_BASE + 0xF8) /* Timer Status Clear Register */
+#define TCU_TSR (TCU_BASE + 0x1C) /* Timer Stop Register */
+#define TCU_TSSR (TCU_BASE + 0x2C) /* Timer Stop Set Register */
+#define TCU_TSCR (TCU_BASE + 0x3C) /* Timer Stop Clear Register */
+#define TCU_TER (TCU_BASE + 0x10) /* Timer Counter Enable Register */
+#define TCU_TESR (TCU_BASE + 0x14) /* Timer Counter Enable Set Register */
+#define TCU_TECR (TCU_BASE + 0x18) /* Timer Counter Enable Clear Register */
+#define TCU_TFR (TCU_BASE + 0x20) /* Timer Flag Register */
+#define TCU_TFSR (TCU_BASE + 0x24) /* Timer Flag Set Register */
+#define TCU_TFCR (TCU_BASE + 0x28) /* Timer Flag Clear Register */
+#define TCU_TMR (TCU_BASE + 0x30) /* Timer Mask Register */
+#define TCU_TMSR (TCU_BASE + 0x34) /* Timer Mask Set Register */
+#define TCU_TMCR (TCU_BASE + 0x38) /* Timer Mask Clear Register */
+
+#define TCU_TDFR0 (TCU_BASE + 0x40) /* Timer Data Full Register */
+#define TCU_TDHR0 (TCU_BASE + 0x44) /* Timer Data Half Register */
+#define TCU_TCNT0 (TCU_BASE + 0x48) /* Timer Counter Register */
+#define TCU_TCSR0 (TCU_BASE + 0x4C) /* Timer Control Register */
+#define TCU_TDFR1 (TCU_BASE + 0x50)
+#define TCU_TDHR1 (TCU_BASE + 0x54)
+#define TCU_TCNT1 (TCU_BASE + 0x58)
+#define TCU_TCSR1 (TCU_BASE + 0x5C)
+#define TCU_TDFR2 (TCU_BASE + 0x60)
+#define TCU_TDHR2 (TCU_BASE + 0x64)
+#define TCU_TCNT2 (TCU_BASE + 0x68)
+#define TCU_TCSR2 (TCU_BASE + 0x6C)
+#define TCU_TDFR3 (TCU_BASE + 0x70)
+#define TCU_TDHR3 (TCU_BASE + 0x74)
+#define TCU_TCNT3 (TCU_BASE + 0x78)
+#define TCU_TCSR3 (TCU_BASE + 0x7C)
+#define TCU_TDFR4 (TCU_BASE + 0x80)
+#define TCU_TDHR4 (TCU_BASE + 0x84)
+#define TCU_TCNT4 (TCU_BASE + 0x88)
+#define TCU_TCSR4 (TCU_BASE + 0x8C)
+#define TCU_TDFR5 (TCU_BASE + 0x90)
+#define TCU_TDHR5 (TCU_BASE + 0x94)
+#define TCU_TCNT5 (TCU_BASE + 0x98)
+#define TCU_TCSR5 (TCU_BASE + 0x9C)
+
+#define REG_TCU_TSTR REG32(TCU_TSTR)
+#define REG_TCU_TSTSR REG32(TCU_TSTSR)
+#define REG_TCU_TSTCR REG32(TCU_TSTCR)
+#define REG_TCU_TSR REG32(TCU_TSR)
+#define REG_TCU_TSSR REG32(TCU_TSSR)
+#define REG_TCU_TSCR REG32(TCU_TSCR)
+#define REG_TCU_TER REG16(TCU_TER)
+#define REG_TCU_TESR REG32(TCU_TESR)
+#define REG_TCU_TECR REG32(TCU_TECR)
+#define REG_TCU_TFR REG32(TCU_TFR)
+#define REG_TCU_TFSR REG32(TCU_TFSR)
+#define REG_TCU_TFCR REG32(TCU_TFCR)
+#define REG_TCU_TMR REG32(TCU_TMR)
+#define REG_TCU_TMSR REG32(TCU_TMSR)
+#define REG_TCU_TMCR REG32(TCU_TMCR)
+#define REG_TCU_TDFR0 REG16(TCU_TDFR0)
+#define REG_TCU_TDHR0 REG16(TCU_TDHR0)
+#define REG_TCU_TCNT0 REG16(TCU_TCNT0)
+#define REG_TCU_TCSR0 REG16(TCU_TCSR0)
+#define REG_TCU_TDFR1 REG16(TCU_TDFR1)
+#define REG_TCU_TDHR1 REG16(TCU_TDHR1)
+#define REG_TCU_TCNT1 REG16(TCU_TCNT1)
+#define REG_TCU_TCSR1 REG16(TCU_TCSR1)
+#define REG_TCU_TDFR2 REG16(TCU_TDFR2)
+#define REG_TCU_TDHR2 REG16(TCU_TDHR2)
+#define REG_TCU_TCNT2 REG16(TCU_TCNT2)
+#define REG_TCU_TCSR2 REG16(TCU_TCSR2)
+#define REG_TCU_TDFR3 REG16(TCU_TDFR3)
+#define REG_TCU_TDHR3 REG16(TCU_TDHR3)
+#define REG_TCU_TCNT3 REG16(TCU_TCNT3)
+#define REG_TCU_TCSR3 REG16(TCU_TCSR3)
+#define REG_TCU_TDFR4 REG16(TCU_TDFR4)
+#define REG_TCU_TDHR4 REG16(TCU_TDHR4)
+#define REG_TCU_TCNT4 REG16(TCU_TCNT4)
+#define REG_TCU_TCSR4 REG16(TCU_TCSR4)
+
+// n = 0,1,2,3,4,5
+#define TCU_TDFR(n) (TCU_BASE + (0x40 + (n)*0x10)) /* Timer Data Full Reg */
+#define TCU_TDHR(n) (TCU_BASE + (0x44 + (n)*0x10)) /* Timer Data Half Reg */
+#define TCU_TCNT(n) (TCU_BASE + (0x48 + (n)*0x10)) /* Timer Counter Reg */
+#define TCU_TCSR(n) (TCU_BASE + (0x4C + (n)*0x10)) /* Timer Control Reg */
+#define TCU_OSTDR (TCU_BASE + 0xe0) /* Operating System Timer Data Reg */
+#define TCU_OSTCNT (TCU_BASE + 0xe8) /* Operating System Timer Counter Reg */
+#define TCU_OSTCSR (TCU_BASE + 0xeC) /* Operating System Timer Control Reg */
+
+#define REG_TCU_TDFR(n) REG16(TCU_TDFR((n)))
+#define REG_TCU_TDHR(n) REG16(TCU_TDHR((n)))
+#define REG_TCU_TCNT(n) REG16(TCU_TCNT((n)))
+#define REG_TCU_TCSR(n) REG16(TCU_TCSR((n)))
+#define REG_TCU_OSTDR REG32(TCU_OSTDR)
+#define REG_TCU_OSTCNT REG32(TCU_OSTCNT)
+#define REG_TCU_OSTCSR REG32(TCU_OSTCSR)
+
+// Register definitions
+#define TCU_TSTR_REAL2 (1 << 18) /* only used in TCU2 mode */
+#define TCU_TSTR_REAL1 (1 << 17) /* only used in TCU2 mode */
+#define TCU_TSTR_BUSY2 (1 << 2) /* only used in TCU2 mode */
+#define TCU_TSTR_BUSY1 (1 << 1) /* only used in TCU2 mode */
+
+#define TCU_TSTSR_REAL2 (1 << 18)
+#define TCU_TSTSR_REAL1 (1 << 17)
+#define TCU_TSTSR_BUSY2 (1 << 2)
+#define TCU_TSTSR_BUSY1 (1 << 1)
+
+#define TCU_TSTCR_REAL2 (1 << 18)
+#define TCU_TSTCR_REAL1 (1 << 17)
+#define TCU_TSTCR_BUSY2 (1 << 2)
+#define TCU_TSTCR_BUSY1 (1 << 1)
+
+#define TCU_TSR_WDTS (1 << 16) /*the clock supplies to wdt is stopped */
+#define TCU_TSR_OSTS (1 << 15) /*the clock supplies to osts is stopped */
+#define TCU_TSR_STOP5 (1 << 5) /*the clock supplies to timer5 is stopped */
+#define TCU_TSR_STOP4 (1 << 4) /*the clock supplies to timer4 is stopped */
+#define TCU_TSR_STOP3 (1 << 3) /*the clock supplies to timer3 is stopped */
+#define TCU_TSR_STOP2 (1 << 2) /*the clock supplies to timer2 is stopped */
+#define TCU_TSR_STOP1 (1 << 1) /*the clock supplies to timer1 is stopped */
+#define TCU_TSR_STOP0 (1 << 0) /*the clock supplies to timer0 is stopped */
+
+#define TCU_TSSR_WDTSS (1 << 16)
+#define TCU_TSSR_OSTSS (1 << 15)
+#define TCU_TSSR_STPS5 (1 << 5)
+#define TCU_TSSR_STPS4 (1 << 4)
+#define TCU_TSSR_STPS3 (1 << 3)
+#define TCU_TSSR_STPS2 (1 << 2)
+#define TCU_TSSR_STPS1 (1 << 1)
+#define TCU_TSSR_STPS0 (1 << 0)
+
+#define TCU_TSCR_WDTSC (1 << 16)
+#define TCU_TSCR_OSTSC (1 << 15)
+#define TCU_TSCR_STPC5 (1 << 5)
+#define TCU_TSCR_STPC4 (1 << 4)
+#define TCU_TSCR_STPC3 (1 << 3)
+#define TCU_TSCR_STPC2 (1 << 2)
+#define TCU_TSCR_STPC1 (1 << 1)
+#define TCU_TSCR_STPC0 (1 << 0)
+
+#define TCU_TER_OSTEN (1 << 15) /* enable the counter in ost */
+#define TCU_TER_TCEN5 (1 << 5) /* enable the counter in timer5 */
+#define TCU_TER_TCEN4 (1 << 4)
+#define TCU_TER_TCEN3 (1 << 3)
+#define TCU_TER_TCEN2 (1 << 2)
+#define TCU_TER_TCEN1 (1 << 1)
+#define TCU_TER_TCEN0 (1 << 0)
+
+#define TCU_TESR_OSTST (1 << 15)
+#define TCU_TESR_TCST5 (1 << 5)
+#define TCU_TESR_TCST4 (1 << 4)
+#define TCU_TESR_TCST3 (1 << 3)
+#define TCU_TESR_TCST2 (1 << 2)
+#define TCU_TESR_TCST1 (1 << 1)
+#define TCU_TESR_TCST0 (1 << 0)
+
+#define TCU_TECR_OSTCL (1 << 15)
+#define TCU_TECR_TCCL5 (1 << 5)
+#define TCU_TECR_TCCL4 (1 << 4)
+#define TCU_TECR_TCCL3 (1 << 3)
+#define TCU_TECR_TCCL2 (1 << 2)
+#define TCU_TECR_TCCL1 (1 << 1)
+#define TCU_TECR_TCCL0 (1 << 0)
+
+#define TCU_TFR_HFLAG5 (1 << 21) /* half comparison match flag */
+#define TCU_TFR_HFLAG4 (1 << 20)
+#define TCU_TFR_HFLAG3 (1 << 19)
+#define TCU_TFR_HFLAG2 (1 << 18)
+#define TCU_TFR_HFLAG1 (1 << 17)
+#define TCU_TFR_HFLAG0 (1 << 16)
+#define TCU_TFR_OSTFLAG (1 << 15) /* ost comparison match flag */
+#define TCU_TFR_FFLAG5 (1 << 5) /* full comparison match flag */
+#define TCU_TFR_FFLAG4 (1 << 4)
+#define TCU_TFR_FFLAG3 (1 << 3)
+#define TCU_TFR_FFLAG2 (1 << 2)
+#define TCU_TFR_FFLAG1 (1 << 1)
+#define TCU_TFR_FFLAG0 (1 << 0)
+
+#define TCU_TFSR_HFST5 (1 << 21)
+#define TCU_TFSR_HFST4 (1 << 20)
+#define TCU_TFSR_HFST3 (1 << 19)
+#define TCU_TFSR_HFST2 (1 << 18)
+#define TCU_TFSR_HFST1 (1 << 17)
+#define TCU_TFSR_HFST0 (1 << 16)
+#define TCU_TFSR_OSTFST (1 << 15)
+#define TCU_TFSR_FFST5 (1 << 5)
+#define TCU_TFSR_FFST4 (1 << 4)
+#define TCU_TFSR_FFST3 (1 << 3)
+#define TCU_TFSR_FFST2 (1 << 2)
+#define TCU_TFSR_FFST1 (1 << 1)
+#define TCU_TFSR_FFST0 (1 << 0)
+
+#define TCU_TFCR_HFCL5 (1 << 21)
+#define TCU_TFCR_HFCL4 (1 << 20)
+#define TCU_TFCR_HFCL3 (1 << 19)
+#define TCU_TFCR_HFCL2 (1 << 18)
+#define TCU_TFCR_HFCL1 (1 << 17)
+#define TCU_TFCR_HFCL0 (1 << 16)
+#define TCU_TFCR_OSTFCL (1 << 15)
+#define TCU_TFCR_FFCL5 (1 << 5)
+#define TCU_TFCR_FFCL4 (1 << 4)
+#define TCU_TFCR_FFCL3 (1 << 3)
+#define TCU_TFCR_FFCL2 (1 << 2)
+#define TCU_TFCR_FFCL1 (1 << 1)
+#define TCU_TFCR_FFCL0 (1 << 0)
+
+#define TCU_TMR_HMASK5 (1 << 21) /* half comparison match interrupt mask */
+#define TCU_TMR_HMASK4 (1 << 20)
+#define TCU_TMR_HMASK3 (1 << 19)
+#define TCU_TMR_HMASK2 (1 << 18)
+#define TCU_TMR_HMASK1 (1 << 17)
+#define TCU_TMR_HMASK0 (1 << 16)
+#define TCU_TMR_OSTMASK (1 << 15) /* ost comparison match interrupt mask */
+#define TCU_TMR_FMASK5 (1 << 5) /* full comparison match interrupt mask */
+#define TCU_TMR_FMASK4 (1 << 4)
+#define TCU_TMR_FMASK3 (1 << 3)
+#define TCU_TMR_FMASK2 (1 << 2)
+#define TCU_TMR_FMASK1 (1 << 1)
+#define TCU_TMR_FMASK0 (1 << 0)
+
+#define TCU_TMSR_HMST5 (1 << 21)
+#define TCU_TMSR_HMST4 (1 << 20)
+#define TCU_TMSR_HMST3 (1 << 19)
+#define TCU_TMSR_HMST2 (1 << 18)
+#define TCU_TMSR_HMST1 (1 << 17)
+#define TCU_TMSR_HMST0 (1 << 16)
+#define TCU_TMSR_OSTMST (1 << 15)
+#define TCU_TMSR_FMST5 (1 << 5)
+#define TCU_TMSR_FMST4 (1 << 4)
+#define TCU_TMSR_FMST3 (1 << 3)
+#define TCU_TMSR_FMST2 (1 << 2)
+#define TCU_TMSR_FMST1 (1 << 1)
+#define TCU_TMSR_FMST0 (1 << 0)
+
+#define TCU_TMCR_HMCL5 (1 << 21)
+#define TCU_TMCR_HMCL4 (1 << 20)
+#define TCU_TMCR_HMCL3 (1 << 19)
+#define TCU_TMCR_HMCL2 (1 << 18)
+#define TCU_TMCR_HMCL1 (1 << 17)
+#define TCU_TMCR_HMCL0 (1 << 16)
+#define TCU_TMCR_OSTMCL (1 << 15)
+#define TCU_TMCR_FMCL5 (1 << 5)
+#define TCU_TMCR_FMCL4 (1 << 4)
+#define TCU_TMCR_FMCL3 (1 << 3)
+#define TCU_TMCR_FMCL2 (1 << 2)
+#define TCU_TMCR_FMCL1 (1 << 1)
+#define TCU_TMCR_FMCL0 (1 << 0)
+
+#define TCU_TCSR_CNT_CLRZ (1 << 10) /* clear counter to 0, only used in TCU2 mode */
+#define TCU_TCSR_PWM_SD (1 << 9) /* shut down the pwm output only used in TCU1 mode */
+#define TCU_TCSR_PWM_INITL_HIGH (1 << 8) /* selects an initial output level for pwm output */
+#define TCU_TCSR_PWM_EN (1 << 7) /* pwm pin output enable */
+#define TCU_TCSR_PRESCALE_BIT 3 /* select the tcnt count clock frequency*/
+#define TCU_TCSR_PRESCALE_MASK (0x7 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE1 (0x0 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE4 (0x1 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE16 (0x2 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE64 (0x3 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE256 (0x4 << TCU_TCSR_PRESCALE_BIT)
+ #define TCU_TCSR_PRESCALE1024 (0x5 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_EXT_EN (1 << 2) /* select extal as the timer clock input */
+#define TCU_TCSR_RTC_EN (1 << 1) /* select rtcclk as the timer clock input */
+#define TCU_TCSR_PCK_EN (1 << 0) /* select pclk as the timer clock input */
+
+#define TCU_TSTR_REAL2 (1 << 18) /* the value read from counter 2 is a real value */
+#define TCU_TSTR_REAL1 (1 << 17)
+#define TCU_TSTR_BUSY2 (1 << 2) /* the counter 2 is busy now */
+#define TCU_TSTR_BUSY1 (1 << 1)
+
+#define TCU_TSTSR_REALS2 (1 << 18)
+#define TCU_TSTSR_REALS1 (1 << 17)
+#define TCU_TSTSR_BUSYS2 (1 << 2)
+#define TCU_TSTSR_BUSYS1 (1 << 1)
+
+#define TCU_TSTCR_REALC2 (1 << 18)
+#define TCU_TSTCR_REALC1 (1 << 17)
+#define TCU_TSTCR_BUSYC2 (1 << 2)
+#define TCU_TSTCR_BUSYC1 (1 << 1)
+
+#define TCU_OSTCR_CNT_MD (1 << 15) /* when the value counter is equal to compare value,the counter is go on increasing till overflow,and then icrease from 0 */
+#define TCU_OSTCR_PWM_SD (1 << 9) /* shut down the pwm output, only used in TCU1 mode */
+#define TCU_OSTCSR_PRESCALE_BIT 3
+#define TCU_OSTCSR_PRESCALE_MASK (0x7 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE1 (0x0 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE4 (0x1 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE16 (0x2 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE64 (0x3 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE256 (0x4 << TCU_OSTCSR_PRESCALE_BIT)
+ #define TCU_OSTCSR_PRESCALE1024 (0x5 << TCU_OSTCSR_PRESCALE_BIT)
+#define TCU_OSTCSR_EXT_EN (1 << 2) /* select extal as the timer clock input */
+#define TCU_OSTCSR_RTC_EN (1 << 1) /* select rtcclk as the timer clock input */
+#define TCU_OSTCSR_PCK_EN (1 << 0) /* select pclk as the timer clock input */
+
+/*************************************************************************
+ * WDT (WatchDog Timer)
+ *************************************************************************/
+#define WDT_TDR (WDT_BASE + 0x00)
+#define WDT_TCER (WDT_BASE + 0x04)
+#define WDT_TCNT (WDT_BASE + 0x08)
+#define WDT_TCSR (WDT_BASE + 0x0C)
+
+#define REG_WDT_TDR REG16(WDT_TDR)
+#define REG_WDT_TCER REG8(WDT_TCER)
+#define REG_WDT_TCNT REG16(WDT_TCNT)
+#define REG_WDT_TCSR REG16(WDT_TCSR)
+
+// Register definition
+#define WDT_TCSR_PRESCALE_BIT 3
+#define WDT_TCSR_PRESCALE_MASK (0x7 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE1 (0x0 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE4 (0x1 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE16 (0x2 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE64 (0x3 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE256 (0x4 << WDT_TCSR_PRESCALE_BIT)
+ #define WDT_TCSR_PRESCALE1024 (0x5 << WDT_TCSR_PRESCALE_BIT)
+#define WDT_TCSR_EXT_EN (1 << 2)
+#define WDT_TCSR_RTC_EN (1 << 1)
+#define WDT_TCSR_PCK_EN (1 << 0)
+
+#define WDT_TCER_TCEN (1 << 0)
+
+
+/*************************************************************************
+ * DMAC (DMA Controller)
+ *************************************************************************/
+
+#define MAX_DMA_NUM 8 /* max 8 channels */
+#define HALF_DMA_NUM 4 /* the number of one dma controller's channels */
+
+/* m is the DMA controller index (0, 1), n is the DMA channel index (0 - 11) */
+
+#define DMAC_DSAR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x00 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA source address */
+#define DMAC_DTAR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x04 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA target address */
+#define DMAC_DTCR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x08 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA transfer count */
+#define DMAC_DRSR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x0c + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA request source */
+#define DMAC_DCCSR(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x10 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA control/status */
+#define DMAC_DCMD(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x14 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA command */
+#define DMAC_DDA(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0x18 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x20)) /* DMA descriptor address */
+#define DMAC_DSD(n) (DMAC_BASE + ((n)/HALF_DMA_NUM*0x100 + 0xc0 + ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM) * 0x04)) /* DMA Stride Address */
+
+#define DMAC_DMACR(m) (DMAC_BASE + 0x0300 + 0x100 * (m)) /* DMA control register */
+#define DMAC_DMAIPR(m) (DMAC_BASE + 0x0304 + 0x100 * (m)) /* DMA interrupt pending */
+#define DMAC_DMADBR(m) (DMAC_BASE + 0x0308 + 0x100 * (m)) /* DMA doorbell */
+#define DMAC_DMADBSR(m) (DMAC_BASE + 0x030C + 0x100 * (m)) /* DMA doorbell set */
+#define DMAC_DMACKE(m) (DMAC_BASE + 0x0310 + 0x100 * (m))
+
+#define REG_DMAC_DSAR(n) REG32(DMAC_DSAR((n)))
+#define REG_DMAC_DTAR(n) REG32(DMAC_DTAR((n)))
+#define REG_DMAC_DTCR(n) REG32(DMAC_DTCR((n)))
+#define REG_DMAC_DRSR(n) REG32(DMAC_DRSR((n)))
+#define REG_DMAC_DCCSR(n) REG32(DMAC_DCCSR((n)))
+#define REG_DMAC_DCMD(n) REG32(DMAC_DCMD((n)))
+#define REG_DMAC_DDA(n) REG32(DMAC_DDA((n)))
+#define REG_DMAC_DSD(n) REG32(DMAC_DSD(n))
+#define REG_DMAC_DMACR(m) REG32(DMAC_DMACR(m))
+#define REG_DMAC_DMAIPR(m) REG32(DMAC_DMAIPR(m))
+#define REG_DMAC_DMADBR(m) REG32(DMAC_DMADBR(m))
+#define REG_DMAC_DMADBSR(m) REG32(DMAC_DMADBSR(m))
+#define REG_DMAC_DMACKE(m) REG32(DMAC_DMACKE(m))
+
+// DMA request source register
+#define DMAC_DRSR_RS_BIT 0
+#define DMAC_DRSR_RS_MASK (0x3f << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_EXT (0 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_NAND (1 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_BCH_ENC (2 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_BCH_DEC (3 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_TSSIIN (9 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART3OUT (14 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART3IN (15 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART2OUT (16 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART2IN (17 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART1OUT (18 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART1IN (19 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSI0OUT (22 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSI0IN (23 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSC0OUT (26 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSC0IN (27 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_TCU (28 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SADC (29 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSC1OUT (30 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_MSC1IN (31 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSI1OUT (32 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_SSI1IN (33 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_PMOUT (34 << DMAC_DRSR_RS_BIT)
+ #define DMAC_DRSR_RS_PMIN (35 << DMAC_DRSR_RS_BIT)
+
+// DMA channel control/status register
+#define DMAC_DCCSR_NDES (1 << 31) /* descriptor (0) or not (1) ? */
+#define DMAC_DCCSR_DES8 (1 << 30) /* Descriptor 8 Word */
+#define DMAC_DCCSR_DES4 (0 << 30) /* Descriptor 4 Word */
+#define DMAC_DCCSR_CDOA_BIT 16 /* copy of DMA offset address */
+#define DMAC_DCCSR_CDOA_MASK (0xff << DMAC_DCCSR_CDOA_BIT)
+#define DMAC_DCCSR_BERR (1 << 7) /* BCH error within this transfer, Only for channel 0 */
+#define DMAC_DCCSR_INV (1 << 6) /* descriptor invalid */
+#define DMAC_DCCSR_AR (1 << 4) /* address error */
+#define DMAC_DCCSR_TT (1 << 3) /* transfer terminated */
+#define DMAC_DCCSR_HLT (1 << 2) /* DMA halted */
+#define DMAC_DCCSR_CT (1 << 1) /* count terminated */
+#define DMAC_DCCSR_EN (1 << 0) /* channel enable bit */
+
+// DMA channel command register
+#define DMAC_DCMD_EACKS_LOW (1 << 31) /* External DACK Output Level Select, active low */
+#define DMAC_DCMD_EACKS_HIGH (0 << 31) /* External DACK Output Level Select, active high */
+#define DMAC_DCMD_EACKM_WRITE (1 << 30) /* External DACK Output Mode Select, output in write cycle */
+#define DMAC_DCMD_EACKM_READ (0 << 30) /* External DACK Output Mode Select, output in read cycle */
+#define DMAC_DCMD_ERDM_BIT 28 /* External DREQ Detection Mode Select */
+#define DMAC_DCMD_ERDM_MASK (0x03 << DMAC_DCMD_ERDM_BIT)
+ #define DMAC_DCMD_ERDM_LOW (0 << DMAC_DCMD_ERDM_BIT)
+ #define DMAC_DCMD_ERDM_FALL (1 << DMAC_DCMD_ERDM_BIT)
+ #define DMAC_DCMD_ERDM_HIGH (2 << DMAC_DCMD_ERDM_BIT)
+ #define DMAC_DCMD_ERDM_RISE (3 << DMAC_DCMD_ERDM_BIT)
+#define DMAC_DCMD_BLAST (1 << 25) /* BCH last */
+#define DMAC_DCMD_SAI (1 << 23) /* source address increment */
+#define DMAC_DCMD_DAI (1 << 22) /* dest address increment */
+#define DMAC_DCMD_RDIL_BIT 16 /* request detection interval length */
+#define DMAC_DCMD_RDIL_MASK (0x0f << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_IGN (0 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_2 (1 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_4 (2 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_8 (3 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_12 (4 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_16 (5 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_20 (6 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_24 (7 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_28 (8 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_32 (9 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_48 (10 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_60 (11 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_64 (12 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_124 (13 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_128 (14 << DMAC_DCMD_RDIL_BIT)
+ #define DMAC_DCMD_RDIL_200 (15 << DMAC_DCMD_RDIL_BIT)
+#define DMAC_DCMD_SWDH_BIT 14 /* source port width */
+#define DMAC_DCMD_SWDH_MASK (0x03 << DMAC_DCMD_SWDH_BIT)
+ #define DMAC_DCMD_SWDH_32 (0 << DMAC_DCMD_SWDH_BIT)
+ #define DMAC_DCMD_SWDH_8 (1 << DMAC_DCMD_SWDH_BIT)
+ #define DMAC_DCMD_SWDH_16 (2 << DMAC_DCMD_SWDH_BIT)
+#define DMAC_DCMD_DWDH_BIT 12 /* dest port width */
+#define DMAC_DCMD_DWDH_MASK (0x03 << DMAC_DCMD_DWDH_BIT)
+ #define DMAC_DCMD_DWDH_32 (0 << DMAC_DCMD_DWDH_BIT)
+ #define DMAC_DCMD_DWDH_8 (1 << DMAC_DCMD_DWDH_BIT)
+ #define DMAC_DCMD_DWDH_16 (2 << DMAC_DCMD_DWDH_BIT)
+#define DMAC_DCMD_DS_BIT 8 /* transfer data size of a data unit */
+#define DMAC_DCMD_DS_MASK (0x07 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_32BIT (0 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_8BIT (1 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_16BIT (2 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_16BYTE (3 << DMAC_DCMD_DS_BIT)
+ #define DMAC_DCMD_DS_32BYTE (4 << DMAC_DCMD_DS_BIT)
+#define DMAC_DCMD_STDE (1 << 5) /* Stride Disable/Enable */
+#define DMAC_DCMD_DES_V (1 << 4) /* descriptor valid flag */
+#define DMAC_DCMD_DES_VM (1 << 3) /* descriptor valid mask: 1:support V-bit */
+#define DMAC_DCMD_DES_VIE (1 << 2) /* DMA valid error interrupt enable */
+#define DMAC_DCMD_TIE (1 << 1) /* DMA transfer interrupt enable */
+#define DMAC_DCMD_LINK (1 << 0) /* descriptor link enable */
+
+// DMA descriptor address register
+#define DMAC_DDA_BASE_BIT 12 /* descriptor base address */
+#define DMAC_DDA_BASE_MASK (0x0fffff << DMAC_DDA_BASE_BIT)
+#define DMAC_DDA_OFFSET_BIT 4 /* descriptor offset address */
+#define DMAC_DDA_OFFSET_MASK (0x0ff << DMAC_DDA_OFFSET_BIT)
+
+// DMA stride address register
+#define DMAC_DSD_TSD_BIT 16 /* target stride address */
+#define DMAC_DSD_TSD_MASK (0xffff << DMAC_DSD_TSD_BIT)
+#define DMAC_DSD_SSD_BIT 0 /* source stride address */
+#define DMAC_DSD_SSD_MASK (0xffff << DMAC_DSD_SSD_BIT)
+
+// DMA control register
+#define DMAC_DMACR_FMSC (1 << 31) /* MSC Fast DMA mode */
+#define DMAC_DMACR_FSSI (1 << 30) /* SSI Fast DMA mode */
+#define DMAC_DMACR_FTSSI (1 << 29) /* TSSI Fast DMA mode */
+#define DMAC_DMACR_FUART (1 << 28) /* UART Fast DMA mode */
+#define DMAC_DMACR_FAIC (1 << 27) /* AIC Fast DMA mode */
+#define DMAC_DMACR_PR_BIT 8 /* channel priority mode */
+#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_012345 (0 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_120345 (1 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_230145 (2 << DMAC_DMACR_PR_BIT)
+ #define DMAC_DMACR_PR_340125 (3 << DMAC_DMACR_PR_BIT)
+#define DMAC_DMACR_HLT (1 << 3) /* DMA halt flag */
+#define DMAC_DMACR_AR (1 << 2) /* address error flag */
+#define DMAC_DMACR_DMAE (1 << 0) /* DMA enable bit */
+
+// DMA doorbell register
+#define DMAC_DMADBR_DB5 (1 << 5) /* doorbell for channel 5 */
+#define DMAC_DMADBR_DB4 (1 << 4) /* doorbell for channel 4 */
+#define DMAC_DMADBR_DB3 (1 << 3) /* doorbell for channel 3 */
+#define DMAC_DMADBR_DB2 (1 << 2) /* doorbell for channel 2 */
+#define DMAC_DMADBR_DB1 (1 << 1) /* doorbell for channel 1 */
+#define DMAC_DMADBR_DB0 (1 << 0) /* doorbell for channel 0 */
+
+// DMA doorbell set register
+#define DMAC_DMADBSR_DBS5 (1 << 5) /* enable doorbell for channel 5 */
+#define DMAC_DMADBSR_DBS4 (1 << 4) /* enable doorbell for channel 4 */
+#define DMAC_DMADBSR_DBS3 (1 << 3) /* enable doorbell for channel 3 */
+#define DMAC_DMADBSR_DBS2 (1 << 2) /* enable doorbell for channel 2 */
+#define DMAC_DMADBSR_DBS1 (1 << 1) /* enable doorbell for channel 1 */
+#define DMAC_DMADBSR_DBS0 (1 << 0) /* enable doorbell for channel 0 */
+
+// DMA interrupt pending register
+#define DMAC_DMAIPR_CIRQ5 (1 << 5) /* irq pending status for channel 5 */
+#define DMAC_DMAIPR_CIRQ4 (1 << 4) /* irq pending status for channel 4 */
+#define DMAC_DMAIPR_CIRQ3 (1 << 3) /* irq pending status for channel 3 */
+#define DMAC_DMAIPR_CIRQ2 (1 << 2) /* irq pending status for channel 2 */
+#define DMAC_DMAIPR_CIRQ1 (1 << 1) /* irq pending status for channel 1 */
+#define DMAC_DMAIPR_CIRQ0 (1 << 0) /* irq pending status for channel 0 */
+
+
+/*************************************************************************
+ * GPIO (General-Purpose I/O Ports)
+ *************************************************************************/
+#define MAX_GPIO_NUM 192
+#define GPIO_WAKEUP (32 * 4 + 30)
+
+//n = 0,1,2,3,4,5 (PORTA, PORTB, PORTC, PORTD, PORTE, PORTF)
+#define GPIO_PXPIN(n) (GPIO_BASE + (0x00 + (n)*0x100)) /* PIN Level Register */
+#define GPIO_PXDAT(n) (GPIO_BASE + (0x10 + (n)*0x100)) /* Port Data Register */
+#define GPIO_PXDATS(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Data Set Register */
+#define GPIO_PXDATC(n) (GPIO_BASE + (0x18 + (n)*0x100)) /* Port Data Clear Register */
+#define GPIO_PXIM(n) (GPIO_BASE + (0x20 + (n)*0x100)) /* Interrupt Mask Register */
+#define GPIO_PXIMS(n) (GPIO_BASE + (0x24 + (n)*0x100)) /* Interrupt Mask Set Reg */
+#define GPIO_PXIMC(n) (GPIO_BASE + (0x28 + (n)*0x100)) /* Interrupt Mask Clear Reg */
+#define GPIO_PXPE(n) (GPIO_BASE + (0x30 + (n)*0x100)) /* Pull Enable Register */
+#define GPIO_PXPES(n) (GPIO_BASE + (0x34 + (n)*0x100)) /* Pull Enable Set Reg. */
+#define GPIO_PXPEC(n) (GPIO_BASE + (0x38 + (n)*0x100)) /* Pull Enable Clear Reg. */
+#define GPIO_PXFUN(n) (GPIO_BASE + (0x40 + (n)*0x100)) /* Function Register */
+#define GPIO_PXFUNS(n) (GPIO_BASE + (0x44 + (n)*0x100)) /* Function Set Register */
+#define GPIO_PXFUNC(n) (GPIO_BASE + (0x48 + (n)*0x100)) /* Function Clear Register */
+#define GPIO_PXSEL(n) (GPIO_BASE + (0x50 + (n)*0x100)) /* Select Register */
+#define GPIO_PXSELS(n) (GPIO_BASE + (0x54 + (n)*0x100)) /* Select Set Register */
+#define GPIO_PXSELC(n) (GPIO_BASE + (0x58 + (n)*0x100)) /* Select Clear Register */
+#define GPIO_PXDIR(n) (GPIO_BASE + (0x60 + (n)*0x100)) /* Direction Register */
+#define GPIO_PXDIRS(n) (GPIO_BASE + (0x64 + (n)*0x100)) /* Direction Set Register */
+#define GPIO_PXDIRC(n) (GPIO_BASE + (0x68 + (n)*0x100)) /* Direction Clear Register */
+#define GPIO_PXTRG(n) (GPIO_BASE + (0x70 + (n)*0x100)) /* Trigger Register */
+#define GPIO_PXTRGS(n) (GPIO_BASE + (0x74 + (n)*0x100)) /* Trigger Set Register */
+#define GPIO_PXTRGC(n) (GPIO_BASE + (0x78 + (n)*0x100)) /* Trigger Set Register */
+#define GPIO_PXFLG(n) (GPIO_BASE + (0x80 + (n)*0x100)) /* Port Flag Register */
+#define GPIO_PXFLGC(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Flag Clear Register */
+
+#define REG_GPIO_PXPIN(n) REG32(GPIO_PXPIN((n))) /* PIN level */
+#define REG_GPIO_PXDAT(n) REG32(GPIO_PXDAT((n))) /* 1: interrupt pending */
+#define REG_GPIO_PXDATS(n) REG32(GPIO_PXDATS((n)))
+#define REG_GPIO_PXDATC(n) REG32(GPIO_PXDATC((n)))
+#define REG_GPIO_PXIM(n) REG32(GPIO_PXIM((n))) /* 1: mask pin interrupt */
+#define REG_GPIO_PXIMS(n) REG32(GPIO_PXIMS((n)))
+#define REG_GPIO_PXIMC(n) REG32(GPIO_PXIMC((n)))
+#define REG_GPIO_PXPE(n) REG32(GPIO_PXPE((n))) /* 1: disable pull up/down */
+#define REG_GPIO_PXPES(n) REG32(GPIO_PXPES((n)))
+#define REG_GPIO_PXPEC(n) REG32(GPIO_PXPEC((n)))
+#define REG_GPIO_PXFUN(n) REG32(GPIO_PXFUN((n))) /* 0:GPIO or intr, 1:FUNC */
+#define REG_GPIO_PXFUNS(n) REG32(GPIO_PXFUNS((n)))
+#define REG_GPIO_PXFUNC(n) REG32(GPIO_PXFUNC((n)))
+#define REG_GPIO_PXSEL(n) REG32(GPIO_PXSEL((n))) /* 0:GPIO/Fun0,1:intr/fun1*/
+#define REG_GPIO_PXSELS(n) REG32(GPIO_PXSELS((n)))
+#define REG_GPIO_PXSELC(n) REG32(GPIO_PXSELC((n)))
+#define REG_GPIO_PXDIR(n) REG32(GPIO_PXDIR((n))) /* 0:input/low-level-trig/falling-edge-trig, 1:output/high-level-trig/rising-edge-trig */
+#define REG_GPIO_PXDIRS(n) REG32(GPIO_PXDIRS((n)))
+#define REG_GPIO_PXDIRC(n) REG32(GPIO_PXDIRC((n)))
+#define REG_GPIO_PXTRG(n) REG32(GPIO_PXTRG((n))) /* 0:level-trigger, 1:edge-trigger */
+#define REG_GPIO_PXTRGS(n) REG32(GPIO_PXTRGS((n)))
+#define REG_GPIO_PXTRGC(n) REG32(GPIO_PXTRGC((n)))
+#define REG_GPIO_PXFLG(n) REG32(GPIO_PXFLG((n))) /* interrupt flag */
+#define REG_GPIO_PXFLGC(n) REG32(GPIO_PXFLGC((n))) /* interrupt flag */
+
+
+/*************************************************************************
+ * UART
+ *************************************************************************/
+
+#define IRDA_BASE UART0_BASE
+#define UART_BASE UART0_BASE
+#define UART_OFF 0x1000
+
+/* Register Offset */
+#define OFF_RDR (0x00) /* R 8b H'xx */
+#define OFF_TDR (0x00) /* W 8b H'xx */
+#define OFF_DLLR (0x00) /* RW 8b H'00 */
+#define OFF_DLHR (0x04) /* RW 8b H'00 */
+#define OFF_IER (0x04) /* RW 8b H'00 */
+#define OFF_ISR (0x08) /* R 8b H'01 */
+#define OFF_FCR (0x08) /* W 8b H'00 */
+#define OFF_LCR (0x0C) /* RW 8b H'00 */
+#define OFF_MCR (0x10) /* RW 8b H'00 */
+#define OFF_LSR (0x14) /* R 8b H'00 */
+#define OFF_MSR (0x18) /* R 8b H'00 */
+#define OFF_SPR (0x1C) /* RW 8b H'00 */
+#define OFF_SIRCR (0x20) /* RW 8b H'00, UART0 */
+#define OFF_UMR (0x24) /* RW 8b H'00, UART M Register */
+#define OFF_UACR (0x28) /* RW 8b H'00, UART Add Cycle Register */
+
+/* Register Address */
+#define UART0_RDR (UART0_BASE + OFF_RDR)
+#define UART0_TDR (UART0_BASE + OFF_TDR)
+#define UART0_DLLR (UART0_BASE + OFF_DLLR)
+#define UART0_DLHR (UART0_BASE + OFF_DLHR)
+#define UART0_IER (UART0_BASE + OFF_IER)
+#define UART0_ISR (UART0_BASE + OFF_ISR)
+#define UART0_FCR (UART0_BASE + OFF_FCR)
+#define UART0_LCR (UART0_BASE + OFF_LCR)
+#define UART0_MCR (UART0_BASE + OFF_MCR)
+#define UART0_LSR (UART0_BASE + OFF_LSR)
+#define UART0_MSR (UART0_BASE + OFF_MSR)
+#define UART0_SPR (UART0_BASE + OFF_SPR)
+#define UART0_SIRCR (UART0_BASE + OFF_SIRCR)
+#define UART0_UMR (UART0_BASE + OFF_UMR)
+#define UART0_UACR (UART0_BASE + OFF_UACR)
+
+#define UART1_RDR (UART1_BASE + OFF_RDR)
+#define UART1_TDR (UART1_BASE + OFF_TDR)
+#define UART1_DLLR (UART1_BASE + OFF_DLLR)
+#define UART1_DLHR (UART1_BASE + OFF_DLHR)
+#define UART1_IER (UART1_BASE + OFF_IER)
+#define UART1_ISR (UART1_BASE + OFF_ISR)
+#define UART1_FCR (UART1_BASE + OFF_FCR)
+#define UART1_LCR (UART1_BASE + OFF_LCR)
+#define UART1_MCR (UART1_BASE + OFF_MCR)
+#define UART1_LSR (UART1_BASE + OFF_LSR)
+#define UART1_MSR (UART1_BASE + OFF_MSR)
+#define UART1_SPR (UART1_BASE + OFF_SPR)
+#define UART1_SIRCR (UART1_BASE + OFF_SIRCR)
+
+#define UART2_RDR (UART2_BASE + OFF_RDR)
+#define UART2_TDR (UART2_BASE + OFF_TDR)
+#define UART2_DLLR (UART2_BASE + OFF_DLLR)
+#define UART2_DLHR (UART2_BASE + OFF_DLHR)
+#define UART2_IER (UART2_BASE + OFF_IER)
+#define UART2_ISR (UART2_BASE + OFF_ISR)
+#define UART2_FCR (UART2_BASE + OFF_FCR)
+#define UART2_LCR (UART2_BASE + OFF_LCR)
+#define UART2_MCR (UART2_BASE + OFF_MCR)
+#define UART2_LSR (UART2_BASE + OFF_LSR)
+#define UART2_MSR (UART2_BASE + OFF_MSR)
+#define UART2_SPR (UART2_BASE + OFF_SPR)
+#define UART2_SIRCR (UART2_BASE + OFF_SIRCR)
+
+#define UART3_RDR (UART3_BASE + OFF_RDR)
+#define UART3_TDR (UART3_BASE + OFF_TDR)
+#define UART3_DLLR (UART3_BASE + OFF_DLLR)
+#define UART3_DLHR (UART3_BASE + OFF_DLHR)
+#define UART3_IER (UART3_BASE + OFF_IER)
+#define UART3_ISR (UART3_BASE + OFF_ISR)
+#define UART3_FCR (UART3_BASE + OFF_FCR)
+#define UART3_LCR (UART3_BASE + OFF_LCR)
+#define UART3_MCR (UART3_BASE + OFF_MCR)
+#define UART3_LSR (UART3_BASE + OFF_LSR)
+#define UART3_MSR (UART3_BASE + OFF_MSR)
+#define UART3_SPR (UART3_BASE + OFF_SPR)
+#define UART3_SIRCR (UART3_BASE + OFF_SIRCR)
+
+
+/*
+ * Define macros for UARTIER
+ * UART Interrupt Enable Register
+ */
+#define UARTIER_RIE (1 << 0) /* 0: receive fifo full interrupt disable */
+#define UARTIER_TIE (1 << 1) /* 0: transmit fifo empty interrupt disable */
+#define UARTIER_RLIE (1 << 2) /* 0: receive line status interrupt disable */
+#define UARTIER_MIE (1 << 3) /* 0: modem status interrupt disable */
+#define UARTIER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */
+
+/*
+ * Define macros for UARTISR
+ * UART Interrupt Status Register
+ */
+#define UARTISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */
+#define UARTISR_IID (7 << 1) /* Source of Interrupt */
+#define UARTISR_IID_MSI (0 << 1) /* Modem status interrupt */
+#define UARTISR_IID_THRI (1 << 1) /* Transmitter holding register empty */
+#define UARTISR_IID_RDI (2 << 1) /* Receiver data interrupt */
+#define UARTISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */
+#define UARTISR_IID_RTO (6 << 1) /* Receive timeout */
+#define UARTISR_FFMS (3 << 6) /* FIFO mode select, set when UARTFCR.FE is set to 1 */
+#define UARTISR_FFMS_NO_FIFO (0 << 6)
+#define UARTISR_FFMS_FIFO_MODE (3 << 6)
+
+/*
+ * Define macros for UARTFCR
+ * UART FIFO Control Register
+ */
+#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */
+#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */
+#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */
+#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */
+#define UARTFCR_UUE (1 << 4) /* 0: disable UART */
+#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */
+#define UARTFCR_RTRG_1 (0 << 6)
+#define UARTFCR_RTRG_4 (1 << 6)
+#define UARTFCR_RTRG_8 (2 << 6)
+#define UARTFCR_RTRG_15 (3 << 6)
+
+/*
+ * Define macros for UARTLCR
+ * UART Line Control Register
+ */
+#define UARTLCR_WLEN (3 << 0) /* word length */
+#define UARTLCR_WLEN_5 (0 << 0)
+#define UARTLCR_WLEN_6 (1 << 0)
+#define UARTLCR_WLEN_7 (2 << 0)
+#define UARTLCR_WLEN_8 (3 << 0)
+#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8
+ 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */
+#define UARTLCR_STOP1 (0 << 2)
+#define UARTLCR_STOP2 (1 << 2)
+#define UARTLCR_PE (1 << 3) /* 0: parity disable */
+#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */
+#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */
+#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */
+#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */
+
+/*
+ * Define macros for UARTLSR
+ * UART Line Status Register
+ */
+#define UARTLSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */
+#define UARTLSR_ORER (1 << 1) /* 0: no overrun error */
+#define UARTLSR_PER (1 << 2) /* 0: no parity error */
+#define UARTLSR_FER (1 << 3) /* 0; no framing error */
+#define UARTLSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */
+#define UARTLSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */
+#define UARTLSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */
+#define UARTLSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */
+
+/*
+ * Define macros for UARTMCR
+ * UART Modem Control Register
+ */
+#define UARTMCR_RTS (1 << 1) /* 0: RTS_ output high, 1: RTS_ output low */
+#define UARTMCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */
+#define UARTMCR_MCE (1 << 7) /* 0: modem function is disable */
+
+/*
+ * Define macros for UARTMSR
+ * UART Modem Status Register
+ */
+#define UARTMSR_CCTS (1 << 0) /* 1: a change on CTS_ pin */
+#define UARTMSR_CTS (1 << 4) /* 0: CTS_ pin is high */
+
+/*
+ * Define macros for SIRCR
+ * Slow IrDA Control Register
+ */
+#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: SIR mode */
+#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: SIR mode */
+#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length
+ 1: 0 pulse width is 1.6us for 115.2Kbps */
+#define SIRCR_TDPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */
+#define SIRCR_RDPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */
+
+
+/*************************************************************************
+ * AIC (AC97/I2S Controller)
+ *************************************************************************/
+#define AIC_FR (AIC_BASE + 0x000)
+#define AIC_CR (AIC_BASE + 0x004)
+#define AIC_ACCR1 (AIC_BASE + 0x008)
+#define AIC_ACCR2 (AIC_BASE + 0x00C)
+#define AIC_I2SCR (AIC_BASE + 0x010)
+#define AIC_SR (AIC_BASE + 0x014)
+#define AIC_ACSR (AIC_BASE + 0x018)
+#define AIC_I2SSR (AIC_BASE + 0x01C)
+#define AIC_ACCAR (AIC_BASE + 0x020)
+#define AIC_ACCDR (AIC_BASE + 0x024)
+#define AIC_ACSAR (AIC_BASE + 0x028)
+#define AIC_ACSDR (AIC_BASE + 0x02C)
+#define AIC_I2SDIV (AIC_BASE + 0x030)
+#define AIC_DR (AIC_BASE + 0x034)
+
+#define REG_AIC_FR REG32(AIC_FR)
+#define REG_AIC_CR REG32(AIC_CR)
+#define REG_AIC_ACCR1 REG32(AIC_ACCR1)
+#define REG_AIC_ACCR2 REG32(AIC_ACCR2)
+#define REG_AIC_I2SCR REG32(AIC_I2SCR)
+#define REG_AIC_SR REG32(AIC_SR)
+#define REG_AIC_ACSR REG32(AIC_ACSR)
+#define REG_AIC_I2SSR REG32(AIC_I2SSR)
+#define REG_AIC_ACCAR REG32(AIC_ACCAR)
+#define REG_AIC_ACCDR REG32(AIC_ACCDR)
+#define REG_AIC_ACSAR REG32(AIC_ACSAR)
+#define REG_AIC_ACSDR REG32(AIC_ACSDR)
+#define REG_AIC_I2SDIV REG32(AIC_I2SDIV)
+#define REG_AIC_DR REG32(AIC_DR)
+
+/* AIC Controller Configuration Register (AIC_FR) */
+
+#define AIC_FR_RFTH_BIT 12 /* Receive FIFO Threshold */
+#define AIC_FR_RFTH_MASK (0xf << AIC_FR_RFTH_BIT)
+#define AIC_FR_TFTH_BIT 8 /* Transmit FIFO Threshold */
+#define AIC_FR_TFTH_MASK (0xf << AIC_FR_TFTH_BIT)
+#define AIC_FR_LSMP (1 << 6) /* Play Zero sample or last sample */
+#define AIC_FR_ICDC (1 << 5) /* External(0) or Internal CODEC(1) */
+#define AIC_FR_AUSEL (1 << 4) /* AC97(0) or I2S/MSB-justified(1) */
+#define AIC_FR_RST (1 << 3) /* AIC registers reset */
+#define AIC_FR_BCKD (1 << 2) /* I2S BIT_CLK direction, 0:input,1:output */
+#define AIC_FR_SYNCD (1 << 1) /* I2S SYNC direction, 0:input,1:output */
+#define AIC_FR_ENB (1 << 0) /* AIC enable bit */
+
+/* AIC Controller Common Control Register (AIC_CR) */
+
+#define AIC_CR_OSS_BIT 19 /* Output Sample Size from memory (AIC V2 only) */
+#define AIC_CR_OSS_MASK (0x7 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_8BIT (0x0 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_16BIT (0x1 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_18BIT (0x2 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_20BIT (0x3 << AIC_CR_OSS_BIT)
+ #define AIC_CR_OSS_24BIT (0x4 << AIC_CR_OSS_BIT)
+#define AIC_CR_ISS_BIT 16 /* Input Sample Size from memory (AIC V2 only) */
+#define AIC_CR_ISS_MASK (0x7 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_8BIT (0x0 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_16BIT (0x1 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_18BIT (0x2 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_20BIT (0x3 << AIC_CR_ISS_BIT)
+ #define AIC_CR_ISS_24BIT (0x4 << AIC_CR_ISS_BIT)
+#define AIC_CR_RDMS (1 << 15) /* Receive DMA enable */
+#define AIC_CR_TDMS (1 << 14) /* Transmit DMA enable */
+#define AIC_CR_M2S (1 << 11) /* Mono to Stereo enable */
+#define AIC_CR_ENDSW (1 << 10) /* Endian switch enable */
+#define AIC_CR_AVSTSU (1 << 9) /* Signed <-> Unsigned toggle enable */
+#define AIC_CR_FLUSH (1 << 8) /* Flush FIFO */
+#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */
+#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */
+#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */
+#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */
+#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */
+#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */
+#define AIC_CR_EREC (1 << 0) /* Enable Record Function */
+
+/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */
+
+#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */
+#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT)
+ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */
+ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */
+ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */
+ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */
+ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */
+ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */
+ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */
+ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */
+ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */
+ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */
+#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */
+#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT)
+ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */
+ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */
+ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */
+ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */
+ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */
+ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */
+ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */
+ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */
+ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */
+ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */
+
+/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */
+
+#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */
+#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */
+#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */
+#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */
+#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT)
+ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */
+ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */
+ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */
+ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */
+#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */
+#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT)
+ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */
+ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */
+ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */
+ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */
+#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */
+#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */
+#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */
+#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */
+
+/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */
+
+#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */
+#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */
+#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT)
+ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */
+ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */
+ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */
+ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */
+ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */
+#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */
+
+/* AIC Controller FIFO Status Register (AIC_SR) */
+
+#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */
+#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT)
+#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */
+#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT)
+#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */
+#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */
+#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */
+#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */
+
+/* AIC Controller AC-link Status Register (AIC_ACSR) */
+
+#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */
+#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */
+#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */
+#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */
+#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */
+#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */
+
+/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */
+
+#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */
+
+/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */
+
+#define AIC_ACCAR_CAR_BIT 0
+#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT)
+
+/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */
+
+#define AIC_ACCDR_CDR_BIT 0
+#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT)
+
+/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */
+
+#define AIC_ACSAR_SAR_BIT 0
+#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT)
+
+/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */
+
+#define AIC_ACSDR_SDR_BIT 0
+#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT)
+
+/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */
+
+#define AIC_I2SDIV_DIV_BIT 0
+#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT)
+ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */
+ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */
+ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */
+ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */
+ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */
+ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */
+
+
+/*************************************************************************
+ * ICDC (Internal CODEC)
+ *************************************************************************/
+
+#define ICDC_CKCFG (ICDC_BASE + 0x00a0) /* Clock Configure Register */
+#define ICDC_RGADW (ICDC_BASE + 0x00a4) /* internal register access control */
+#define ICDC_RGDATA (ICDC_BASE + 0x00a8) /* internal register data output */
+
+#define REG_ICDC_CKCFG REG32(ICDC_CKCFG)
+#define REG_ICDC_RGADW REG32(ICDC_RGADW)
+#define REG_ICDC_RGDATA REG32(ICDC_RGDATA)
+
+/* ICDC Clock Configure Register */
+#define ICDC_CKCFG_CKRDY (1 << 1)
+#define ICDC_CKCFG_SELAD (1 << 0)
+
+/* ICDC internal register access control Register */
+#define ICDC_RGADW_RGWR (1 << 16)
+#define ICDC_RGADW_RGADDR_BIT 8
+#define ICDC_RGADW_RGADDR_MASK (0x7f << ICDC_RGADW_RGADDR_BIT)
+#define ICDC_RGADW_RGDIN_BIT 0
+#define ICDC_RGADW_RGDIN_MASK (0xff << ICDC_RGADW_RGDIN_BIT)
+
+/* ICDC internal register data output Register */
+#define ICDC_RGDATA_IRQ (1 << 8)
+#define ICDC_RGDATA_RGDOUT_BIT 0
+#define ICDC_RGDATA_RGDOUT_MASK (0xff << ICDC_RGDATA_RGDOUT_BIT)
+
+/*************************************************************************
+ * PCM Controller
+ *************************************************************************/
+
+#define PCM_CTL (PCM_BASE + 0x000)
+#define PCM_CFG (PCM_BASE + 0x004)
+#define PCM_DP (PCM_BASE + 0x008)
+#define PCM_INTC (PCM_BASE + 0x00c)
+#define PCM_INTS (PCM_BASE + 0x010)
+#define PCM_DIV (PCM_BASE + 0x014)
+
+#define REG_PCM_CTL REG32(PCM_CTL)
+#define REG_PCM_CFG REG32(PCM_CFG)
+#define REG_PCM_DP REG32(PCM_DP)
+#define REG_PCM_INTC REG32(PCM_INTC)
+#define REG_PCM_INTS REG32(PCM_INTS)
+#define REG_PCM_DIV REG32(PCM_DIV)
+
+/* PCM Controller control Register (PCM_CTL) */
+
+#define PCM_CTL_ERDMA (1 << 9) /* Enable Receive DMA */
+#define PCM_CTL_ETDMA (1 << 8) /* Enable Transmit DMA */
+#define PCM_CTL_LSMP (1 << 7) /* Play Zero sample or last sample */
+#define PCM_CTL_ERPL (1 << 6) /* Enable Playing Back Function */
+#define PCM_CTL_EREC (1 << 5) /* Enable Recording Function */
+#define PCM_CTL_FLUSH (1 << 4) /* FIFO flush */
+#define PCM_CTL_RST (1 << 3) /* Reset PCM */
+#define PCM_CTL_CLKEN (1 << 1) /* Enable the clock division logic */
+#define PCM_CTL_PCMEN (1 << 0) /* Enable PCM module */
+
+/* PCM Controller configure Register (PCM_CFG) */
+
+#define PCM_CFG_SLOT_BIT 13
+#define PCM_CFG_SLOT_MASK (0x3 << PCM_CFG_SLOT_BIT)
+ #define PCM_CFG_SLOT_0 (0 << PCM_CFG_SLOT_BIT) /* Slot is 0 */
+ #define PCM_CFG_SLOT_1 (1 << PCM_CFG_SLOT_BIT) /* Slot is 1 */
+ #define PCM_CFG_SLOT_2 (2 << PCM_CFG_SLOT_BIT) /* Slot is 2 */
+ #define PCM_CFG_SLOT_3 (3 << PCM_CFG_SLOT_BIT) /* Slot is 3 */
+#define PCM_CFG_ISS_BIT 12
+#define PCM_CFG_ISS_MASK (0x1 << PCM_CFG_ISS_BIT)
+ #define PCM_CFG_ISS_8 (0 << PCM_CFG_ISS_BIT)
+ #define PCM_CFG_ISS_16 (1 << PCM_CFG_ISS_BIT)
+#define PCM_CFG_OSS_BIT 11
+#define PCM_CFG_OSS_MASK (0x1 << PCM_CFG_OSS_BIT)
+ #define PCM_CFG_OSS_8 (0 << PCM_CFG_OSS_BIT)
+ #define PCM_CFG_OSS_16 (1 << PCM_CFG_OSS_BIT)
+#define PCM_CFG_IMSBPOS (1 << 10)
+#define PCM_CFG_OMSBPOS (1 << 9)
+#define PCM_CFG_RFTH_BIT 5 /* Receive FIFO Threshold */
+#define PCM_CFG_RFTH_MASK (0xf << PCM_CFG_RFTH_BIT)
+#define PCM_CFG_TFTH_BIT 1 /* Transmit FIFO Threshold */
+#define PCM_CFG_TFTH_MASK (0xf << PCM_CFG_TFTH_BIT)
+#define PCM_CFG_MODE (0x0 << 0)
+
+/* PCM Controller interrupt control Register (PCM_INTC) */
+
+#define PCM_INTC_ETFS (1 << 3)
+#define PCM_INTC_ETUR (1 << 2)
+#define PCM_INTC_ERFS (1 << 1)
+#define PCM_INTC_EROR (1 << 0)
+
+/* PCM Controller interrupt status Register (PCM_INTS) */
+
+#define PCM_INTS_RSTS (1 << 14) /* Reset or flush has not complete */
+#define PCM_INTS_TFL_BIT 9
+#define PCM_INTS_TFL_MASK (0x1f << PCM_INTS_TFL_BIT)
+#define PCM_INTS_TFS (1 << 8) /* Tranmit FIFO Service Request */
+#define PCM_INTS_TUR (1 << 7) /* Transmit FIFO Under Run */
+#define PCM_INTS_RFL_BIT 2
+#define PCM_INTS_RFL_MASK (0x1f << PCM_INTS_RFL_BIT)
+#define PCM_INTS_RFS (1 << 1) /* Receive FIFO Service Request */
+#define PCM_INTS_ROR (1 << 0) /* Receive FIFO Over Run */
+
+/* PCM Controller clock division Register (PCM_DIV) */
+#define PCM_DIV_SYNL_BIT 11
+#define PCM_DIV_SYNL_MASK (0x3f << PCM_DIV_SYNL_BIT)
+#define PCM_DIV_SYNDIV_BIT 6
+#define PCM_DIV_SYNDIV_MASK (0x1f << PCM_DIV_SYNDIV_BIT)
+#define PCM_DIV_CLKDIV_BIT 0
+#define PCM_DIV_CLKDIV_MASK (0x3f << PCM_DIV_CLKDIV_BIT)
+
+
+/*************************************************************************
+ * I2C
+ *************************************************************************/
+#define I2C_DR (I2C_BASE + 0x000)
+#define I2C_CR (I2C_BASE + 0x004)
+#define I2C_SR (I2C_BASE + 0x008)
+#define I2C_GR (I2C_BASE + 0x00C)
+
+#define REG_I2C_DR REG8(I2C_DR)
+#define REG_I2C_CR REG8(I2C_CR)
+#define REG_I2C_SR REG8(I2C_SR)
+#define REG_I2C_GR REG16(I2C_GR)
+
+/* I2C Control Register (I2C_CR) */
+
+#define I2C_CR_IEN (1 << 4)
+#define I2C_CR_STA (1 << 3)
+#define I2C_CR_STO (1 << 2)
+#define I2C_CR_AC (1 << 1)
+#define I2C_CR_I2CE (1 << 0)
+
+/* I2C Status Register (I2C_SR) */
+
+#define I2C_SR_STX (1 << 4)
+#define I2C_SR_BUSY (1 << 3)
+#define I2C_SR_TEND (1 << 2)
+#define I2C_SR_DRF (1 << 1)
+#define I2C_SR_ACKF (1 << 0)
+
+
+/*************************************************************************
+ * SSI (Synchronous Serial Interface)
+ *************************************************************************/
+/* n = 0, 1 (SSI0, SSI1) */
+#define SSI_DR(n) (SSI_BASE + 0x000 + (n)*0x2000)
+#define SSI_CR0(n) (SSI_BASE + 0x004 + (n)*0x2000)
+#define SSI_CR1(n) (SSI_BASE + 0x008 + (n)*0x2000)
+#define SSI_SR(n) (SSI_BASE + 0x00C + (n)*0x2000)
+#define SSI_ITR(n) (SSI_BASE + 0x010 + (n)*0x2000)
+#define SSI_ICR(n) (SSI_BASE + 0x014 + (n)*0x2000)
+#define SSI_GR(n) (SSI_BASE + 0x018 + (n)*0x2000)
+
+#define REG_SSI_DR(n) REG32(SSI_DR(n))
+#define REG_SSI_CR0(n) REG16(SSI_CR0(n))
+#define REG_SSI_CR1(n) REG32(SSI_CR1(n))
+#define REG_SSI_SR(n) REG32(SSI_SR(n))
+#define REG_SSI_ITR(n) REG16(SSI_ITR(n))
+#define REG_SSI_ICR(n) REG8(SSI_ICR(n))
+#define REG_SSI_GR(n) REG16(SSI_GR(n))
+
+/* SSI Data Register (SSI_DR) */
+
+#define SSI_DR_GPC_BIT 0
+#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT)
+
+#define SSI_MAX_FIFO_ENTRIES 128 /* 128 txfifo and 128 rxfifo */
+
+/* SSI Control Register 0 (SSI_CR0) */
+
+#define SSI_CR0_SSIE (1 << 15)
+#define SSI_CR0_TIE (1 << 14)
+#define SSI_CR0_RIE (1 << 13)
+#define SSI_CR0_TEIE (1 << 12)
+#define SSI_CR0_REIE (1 << 11)
+#define SSI_CR0_LOOP (1 << 10)
+#define SSI_CR0_RFINE (1 << 9)
+#define SSI_CR0_RFINC (1 << 8)
+#define SSI_CR0_EACLRUN (1 << 7) /* hardware auto clear underrun when TxFifo no empty */
+#define SSI_CR0_FSEL (1 << 6)
+#define SSI_CR0_TFLUSH (1 << 2)
+#define SSI_CR0_RFLUSH (1 << 1)
+#define SSI_CR0_DISREV (1 << 0)
+
+/* SSI Control Register 1 (SSI_CR1) */
+
+#define SSI_CR1_FRMHL_BIT 30
+#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT)
+ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */
+ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */
+ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */
+ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */
+#define SSI_CR1_TFVCK_BIT 28
+#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT)
+ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT)
+#define SSI_CR1_TCKFI_BIT 26
+#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT)
+ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT)
+#define SSI_CR1_LFST (1 << 25)
+#define SSI_CR1_ITFRM (1 << 24)
+#define SSI_CR1_UNFIN (1 << 23)
+#define SSI_CR1_MULTS (1 << 22)
+#define SSI_CR1_FMAT_BIT 20
+#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT)
+ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */
+ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */
+ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */
+ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */
+#define SSI_CR1_TTRG_BIT 16 /* SSI1 TX trigger */
+#define SSI_CR1_TTRG_MASK (0xf << SSI_CR1_TTRG_BIT)
+#define SSI_CR1_MCOM_BIT 12
+#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT)
+ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */
+ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */
+ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */
+ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */
+ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */
+ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */
+ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */
+ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */
+ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */
+ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */
+ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */
+ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */
+ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */
+ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */
+ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */
+ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */
+#define SSI_CR1_RTRG_BIT 8 /* SSI RX trigger */
+#define SSI_CR1_RTRG_MASK (0xf << SSI_CR1_RTRG_BIT)
+#define SSI_CR1_FLEN_BIT 4
+#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT)
+ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT)
+#define SSI_CR1_PHA (1 << 1)
+#define SSI_CR1_POL (1 << 0)
+
+/* SSI Status Register (SSI_SR) */
+
+#define SSI_SR_TFIFONUM_BIT 16
+#define SSI_SR_TFIFONUM_MASK (0xff << SSI_SR_TFIFONUM_BIT)
+#define SSI_SR_RFIFONUM_BIT 8
+#define SSI_SR_RFIFONUM_MASK (0xff << SSI_SR_RFIFONUM_BIT)
+#define SSI_SR_END (1 << 7)
+#define SSI_SR_BUSY (1 << 6)
+#define SSI_SR_TFF (1 << 5)
+#define SSI_SR_RFE (1 << 4)
+#define SSI_SR_TFHE (1 << 3)
+#define SSI_SR_RFHF (1 << 2)
+#define SSI_SR_UNDR (1 << 1)
+#define SSI_SR_OVER (1 << 0)
+
+/* SSI Interval Time Control Register (SSI_ITR) */
+
+#define SSI_ITR_CNTCLK (1 << 15)
+#define SSI_ITR_IVLTM_BIT 0
+#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT)
+
+
+/*************************************************************************
+ * MSC
+ ************************************************************************/
+/* n = 0, 1 (MSC0, MSC1) */
+#define MSC_STRPCL(n) (MSC_BASE + (n)*0x1000 + 0x000)
+#define MSC_STAT(n) (MSC_BASE + (n)*0x1000 + 0x004)
+#define MSC_CLKRT(n) (MSC_BASE + (n)*0x1000 + 0x008)
+#define MSC_CMDAT(n) (MSC_BASE + (n)*0x1000 + 0x00C)
+#define MSC_RESTO(n) (MSC_BASE + (n)*0x1000 + 0x010)
+#define MSC_RDTO(n) (MSC_BASE + (n)*0x1000 + 0x014)
+#define MSC_BLKLEN(n) (MSC_BASE + (n)*0x1000 + 0x018)
+#define MSC_NOB(n) (MSC_BASE + (n)*0x1000 + 0x01C)
+#define MSC_SNOB(n) (MSC_BASE + (n)*0x1000 + 0x020)
+#define MSC_IMASK(n) (MSC_BASE + (n)*0x1000 + 0x024)
+#define MSC_IREG(n) (MSC_BASE + (n)*0x1000 + 0x028)
+#define MSC_CMD(n) (MSC_BASE + (n)*0x1000 + 0x02C)
+#define MSC_ARG(n) (MSC_BASE + (n)*0x1000 + 0x030)
+#define MSC_RES(n) (MSC_BASE + (n)*0x1000 + 0x034)
+#define MSC_RXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x038)
+#define MSC_TXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x03C)
+#define MSC_LPM(n) (MSC_BASE + (n)*0x1000 + 0x040)
+
+#define REG_MSC_STRPCL(n) REG16(MSC_STRPCL(n))
+#define REG_MSC_STAT(n) REG32(MSC_STAT(n))
+#define REG_MSC_CLKRT(n) REG16(MSC_CLKRT(n))
+#define REG_MSC_CMDAT(n) REG32(MSC_CMDAT(n))
+#define REG_MSC_RESTO(n) REG16(MSC_RESTO(n))
+#define REG_MSC_RDTO(n) REG16(MSC_RDTO(n))
+#define REG_MSC_BLKLEN(n) REG16(MSC_BLKLEN(n))
+#define REG_MSC_NOB(n) REG16(MSC_NOB(n))
+#define REG_MSC_SNOB(n) REG16(MSC_SNOB(n))
+#define REG_MSC_IMASK(n) REG32(MSC_IMASK(n))
+#define REG_MSC_IREG(n) REG16(MSC_IREG(n))
+#define REG_MSC_CMD(n) REG8(MSC_CMD(n))
+#define REG_MSC_ARG(n) REG32(MSC_ARG(n))
+#define REG_MSC_RES(n) REG16(MSC_RES(n))
+#define REG_MSC_RXFIFO(n) REG32(MSC_RXFIFO(n))
+#define REG_MSC_TXFIFO(n) REG32(MSC_TXFIFO(n))
+#define REG_MSC_LPM(n) REG32(MSC_LPM(n))
+
+/* MSC Clock and Control Register (MSC_STRPCL) */
+#define MSC_STRPCL_SEND_CCSD (1 << 15) /*send command completion signal disable to ceata */
+#define MSC_STRPCL_SEND_AS_CCSD (1 << 14) /*send internally generated stop after sending ccsd */
+#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7)
+#define MSC_STRPCL_EXIT_TRANSFER (1 << 6)
+#define MSC_STRPCL_START_READWAIT (1 << 5)
+#define MSC_STRPCL_STOP_READWAIT (1 << 4)
+#define MSC_STRPCL_RESET (1 << 3)
+#define MSC_STRPCL_START_OP (1 << 2)
+#define MSC_STRPCL_CLOCK_CONTROL_BIT 0
+#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT)
+ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */
+ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */
+
+/* MSC Status Register (MSC_STAT) */
+#define MSC_STAT_AUTO_CMD_DONE (1 << 31) /*12 is internally generated by controller has finished */
+#define MSC_STAT_IS_RESETTING (1 << 15)
+#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14)
+#define MSC_STAT_PRG_DONE (1 << 13)
+#define MSC_STAT_DATA_TRAN_DONE (1 << 12)
+#define MSC_STAT_END_CMD_RES (1 << 11)
+#define MSC_STAT_DATA_FIFO_AFULL (1 << 10)
+#define MSC_STAT_IS_READWAIT (1 << 9)
+#define MSC_STAT_CLK_EN (1 << 8)
+#define MSC_STAT_DATA_FIFO_FULL (1 << 7)
+#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6)
+#define MSC_STAT_CRC_RES_ERR (1 << 5)
+#define MSC_STAT_CRC_READ_ERROR (1 << 4)
+#define MSC_STAT_CRC_WRITE_ERROR_BIT 2
+#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT)
+ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */
+ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */
+ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */
+#define MSC_STAT_TIME_OUT_RES (1 << 1)
+#define MSC_STAT_TIME_OUT_READ (1 << 0)
+
+/* MSC Bus Clock Control Register (MSC_CLKRT) */
+#define MSC_CLKRT_CLK_RATE_BIT 0
+#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT)
+ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */
+ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */
+
+/* MSC Command Sequence Control Register (MSC_CMDAT) */
+#define MSC_CMDAT_CCS_EXPECTED (1 << 31) /* interrupts are enabled in ce-ata */
+#define MSC_CMDAT_READ_CEATA (1 << 30)
+#define MSC_CMDAT_SDIO_PRDT (1 << 17) /* exact 2 cycle */
+#define MSC_CMDAT_SEND_AS_STOP (1 << 16)
+#define MSC_CMDAT_RTRG_BIT 14
+ #define MSC_CMDAT_RTRG_EQUALT_8 (0x0 << MSC_CMDAT_RTRG_BIT)
+ #define MSC_CMDAT_RTRG_EQUALT_16 (0x1 << MSC_CMDAT_RTRG_BIT) /* reset value */
+ #define MSC_CMDAT_RTRG_EQUALT_24 (0x2 << MSC_CMDAT_RTRG_BIT)
+
+#define MSC_CMDAT_TTRG_BIT 12
+ #define MSC_CMDAT_TTRG_LESS_8 (0x0 << MSC_CMDAT_TTRG_BIT)
+ #define MSC_CMDAT_TTRG_LESS_16 (0x1 << MSC_CMDAT_TTRG_BIT) /*reset value */
+ #define MSC_CMDAT_TTRG_LESS_24 (0x2 << MSC_CMDAT_TTRG_BIT)
+#define MSC_CMDAT_STOP_ABORT (1 << 11)
+#define MSC_CMDAT_BUS_WIDTH_BIT 9
+#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT)
+ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */
+ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */
+ #define MSC_CMDAT_BUS_WIDTH_8BIT (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) /* 8-bit data bus */
+#define MSC_CMDAT_DMA_EN (1 << 8)
+#define MSC_CMDAT_INIT (1 << 7)
+#define MSC_CMDAT_BUSY (1 << 6)
+#define MSC_CMDAT_STREAM_BLOCK (1 << 5)
+#define MSC_CMDAT_WRITE (1 << 4)
+#define MSC_CMDAT_READ (0 << 4)
+#define MSC_CMDAT_DATA_EN (1 << 3)
+#define MSC_CMDAT_RESPONSE_BIT 0
+#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT)
+ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */
+ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */
+ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */
+ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */
+ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */
+ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */
+ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */
+
+#define CMDAT_DMA_EN (1 << 8)
+#define CMDAT_INIT (1 << 7)
+#define CMDAT_BUSY (1 << 6)
+#define CMDAT_STREAM (1 << 5)
+#define CMDAT_WRITE (1 << 4)
+#define CMDAT_DATA_EN (1 << 3)
+
+/* MSC Interrupts Mask Register (MSC_IMASK) */
+#define MSC_IMASK_AUTO_CMD_DONE (1 << 8)
+#define MSC_IMASK_SDIO (1 << 7)
+#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6)
+#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5)
+#define MSC_IMASK_END_CMD_RES (1 << 2)
+#define MSC_IMASK_PRG_DONE (1 << 1)
+#define MSC_IMASK_DATA_TRAN_DONE (1 << 0)
+
+/* MSC Interrupts Status Register (MSC_IREG) */
+#define MSC_IREG_AUTO_CMD_DONE (1 << 8)
+#define MSC_IREG_SDIO (1 << 7)
+#define MSC_IREG_TXFIFO_WR_REQ (1 << 6)
+#define MSC_IREG_RXFIFO_RD_REQ (1 << 5)
+#define MSC_IREG_END_CMD_RES (1 << 2)
+#define MSC_IREG_PRG_DONE (1 << 1)
+#define MSC_IREG_DATA_TRAN_DONE (1 << 0)
+
+/* MSC Low Power Mode Register (MSC_LPM) */
+#define MSC_SET_LPM (1 << 0)
+
+/*************************************************************************
+ * EMC (External Memory Controller)
+ *************************************************************************/
+#define EMC_BCR (EMC_BASE + 0x00) /* Bus Control Register */
+#define EMC_SMCR0 (EMC_BASE + 0x10) /* Static Memory Control Register 0 */
+#define EMC_SMCR1 (EMC_BASE + 0x14) /* Static Memory Control Register 1 */
+#define EMC_SMCR2 (EMC_BASE + 0x18) /* Static Memory Control Register 2 */
+#define EMC_SMCR3 (EMC_BASE + 0x1c) /* Static Memory Control Register 3 */
+#define EMC_SMCR4 (EMC_BASE + 0x20) /* Static Memory Control Register 4 */
+#define EMC_SACR0 (EMC_BASE + 0x30) /* Static Memory Bank 0 Addr Config Reg */
+#define EMC_SACR1 (EMC_BASE + 0x34) /* Static Memory Bank 1 Addr Config Reg */
+#define EMC_SACR2 (EMC_BASE + 0x38) /* Static Memory Bank 2 Addr Config Reg */
+#define EMC_SACR3 (EMC_BASE + 0x3c) /* Static Memory Bank 3 Addr Config Reg */
+#define EMC_SACR4 (EMC_BASE + 0x40) /* Static Memory Bank 4 Addr Config Reg */
+
+#define EMC_NFCSR (EMC_BASE + 0x050) /* NAND Flash Control/Status Register */
+
+#define EMC_DMCR (EMC_BASE + 0x80) /* DRAM Control Register */
+#define EMC_RTCSR (EMC_BASE + 0x84) /* Refresh Time Control/Status Register */
+#define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */
+#define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */
+#define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */
+#define EMC_DMAR1 (EMC_BASE + 0x94) /* SDRAM Bank 1 Addr Config Register */
+#define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */
+
+#define REG_EMC_BCR REG32(EMC_BCR)
+#define REG_EMC_SMCR0 REG32(EMC_SMCR0)
+#define REG_EMC_SMCR1 REG32(EMC_SMCR1)
+#define REG_EMC_SMCR2 REG32(EMC_SMCR2)
+#define REG_EMC_SMCR3 REG32(EMC_SMCR3)
+#define REG_EMC_SMCR4 REG32(EMC_SMCR4)
+#define REG_EMC_SACR0 REG32(EMC_SACR0)
+#define REG_EMC_SACR1 REG32(EMC_SACR1)
+#define REG_EMC_SACR2 REG32(EMC_SACR2)
+#define REG_EMC_SACR3 REG32(EMC_SACR3)
+#define REG_EMC_SACR4 REG32(EMC_SACR4)
+
+#define REG_EMC_NFCSR REG32(EMC_NFCSR)
+
+#define REG_EMC_DMCR REG32(EMC_DMCR)
+#define REG_EMC_RTCSR REG16(EMC_RTCSR)
+#define REG_EMC_RTCNT REG16(EMC_RTCNT)
+#define REG_EMC_RTCOR REG16(EMC_RTCOR)
+#define REG_EMC_DMAR0 REG32(EMC_DMAR0)
+#define REG_EMC_DMAR1 REG32(EMC_DMAR1)
+
+/* Bus Control Register */
+#define EMC_BCR_BT_SEL_BIT 30
+#define EMC_BCR_BT_SEL_MASK (0x3 << EMC_BCR_BT_SEL_BIT)
+#define EMC_BCR_PK_SEL (1 << 24)
+#define EMC_BCR_BSR_MASK (1 << 2) /* Nand and SDRAM Bus Share Select: 0, share; 1, unshare */
+ #define EMC_BCR_BSR_SHARE (0 << 2)
+ #define EMC_BCR_BSR_UNSHARE (1 << 2)
+#define EMC_BCR_BRE (1 << 1)
+#define EMC_BCR_ENDIAN (1 << 0)
+
+/* Static Memory Control Register */
+#define EMC_SMCR_STRV_BIT 24
+#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT)
+#define EMC_SMCR_TAW_BIT 20
+#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT)
+#define EMC_SMCR_TBP_BIT 16
+#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT)
+#define EMC_SMCR_TAH_BIT 12
+#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT)
+#define EMC_SMCR_TAS_BIT 8
+#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT)
+#define EMC_SMCR_BW_BIT 6
+#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT)
+ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT)
+#define EMC_SMCR_BCM (1 << 3)
+#define EMC_SMCR_BL_BIT 1
+#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT)
+ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT)
+#define EMC_SMCR_SMT (1 << 0)
+
+/* Static Memory Bank Addr Config Reg */
+#define EMC_SACR_BASE_BIT 8
+#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT)
+#define EMC_SACR_MASK_BIT 0
+#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT)
+
+/* NAND Flash Control/Status Register */
+#define EMC_NFCSR_NFCE4 (1 << 7) /* NAND Flash Enable */
+#define EMC_NFCSR_NFE4 (1 << 6) /* NAND Flash FCE# Assertion Enable */
+#define EMC_NFCSR_NFCE3 (1 << 5)
+#define EMC_NFCSR_NFE3 (1 << 4)
+#define EMC_NFCSR_NFCE2 (1 << 3)
+#define EMC_NFCSR_NFE2 (1 << 2)
+#define EMC_NFCSR_NFCE1 (1 << 1)
+#define EMC_NFCSR_NFE1 (1 << 0)
+
+/* DRAM Control Register */
+#define EMC_DMCR_BW_BIT 31
+#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT)
+#define EMC_DMCR_CA_BIT 26
+#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT)
+ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT)
+#define EMC_DMCR_RMODE (1 << 25)
+#define EMC_DMCR_RFSH (1 << 24)
+#define EMC_DMCR_MRSET (1 << 23)
+#define EMC_DMCR_RA_BIT 20
+#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT)
+ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT)
+#define EMC_DMCR_BA_BIT 19
+#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT)
+#define EMC_DMCR_PDM (1 << 18)
+#define EMC_DMCR_EPIN (1 << 17)
+#define EMC_DMCR_MBSEL (1 << 16)
+#define EMC_DMCR_TRAS_BIT 13
+#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT)
+#define EMC_DMCR_RCD_BIT 11
+#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT)
+#define EMC_DMCR_TPC_BIT 8
+#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT)
+#define EMC_DMCR_TRWL_BIT 5
+#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT)
+#define EMC_DMCR_TRC_BIT 2
+#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT)
+#define EMC_DMCR_TCL_BIT 0
+#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT)
+
+/* Refresh Time Control/Status Register */
+#define EMC_RTCSR_SFR (1 << 8) /* self refresh flag */
+#define EMC_RTCSR_CMF (1 << 7)
+#define EMC_RTCSR_CKS_BIT 0
+#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT)
+ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT)
+
+/* SDRAM Bank Address Configuration Register */
+#define EMC_DMAR_BASE_BIT 8
+#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT)
+#define EMC_DMAR_MASK_BIT 0
+#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT)
+
+/* Mode Register of SDRAM bank 0 */
+#define EMC_SDMR_BM (1 << 9) /* Write Burst Mode */
+#define EMC_SDMR_OM_BIT 7 /* Operating Mode */
+#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT)
+ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT)
+#define EMC_SDMR_CAS_BIT 4 /* CAS Latency */
+#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT)
+ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT)
+#define EMC_SDMR_BT_BIT 3 /* Burst Type */
+#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT)
+ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) /* Sequential */
+ #define EMC_SDMR_BT_INT (1 << EMC_SDMR_BT_BIT) /* Interleave */
+#define EMC_SDMR_BL_BIT 0 /* Burst Length */
+#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT)
+ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT)
+
+#define EMC_SDMR_CAS2_16BIT \
+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2)
+#define EMC_SDMR_CAS2_32BIT \
+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4)
+#define EMC_SDMR_CAS3_16BIT \
+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2)
+#define EMC_SDMR_CAS3_32BIT \
+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4)
+
+
+/*************************************************************************
+ * CIM
+ *************************************************************************/
+#define CIM_CFG (CIM_BASE + 0x0000)
+#define CIM_CTRL (CIM_BASE + 0x0004)
+#define CIM_STATE (CIM_BASE + 0x0008)
+#define CIM_IID (CIM_BASE + 0x000C)
+#define CIM_RXFIFO (CIM_BASE + 0x0010)
+#define CIM_DA (CIM_BASE + 0x0020)
+#define CIM_FA (CIM_BASE + 0x0024)
+#define CIM_FID (CIM_BASE + 0x0028)
+#define CIM_CMD (CIM_BASE + 0x002C)
+#define CIM_SIZE (CIM_BASE + 0x0030)
+#define CIM_OFFSET (CIM_BASE + 0x0034)
+#define CIM_RAM_ADDR (CIM_BASE + 0x1000)
+
+#define REG_CIM_CFG REG32(CIM_CFG)
+#define REG_CIM_CTRL REG32(CIM_CTRL)
+#define REG_CIM_STATE REG32(CIM_STATE)
+#define REG_CIM_IID REG32(CIM_IID)
+#define REG_CIM_RXFIFO REG32(CIM_RXFIFO)
+#define REG_CIM_DA REG32(CIM_DA)
+#define REG_CIM_FA REG32(CIM_FA)
+#define REG_CIM_FID REG32(CIM_FID)
+#define REG_CIM_CMD REG32(CIM_CMD)
+#define REG_CIM_SIZE REG32(CIM_SIZE)
+#define REG_CIM_OFFSET REG32(CIM_OFFSET)
+
+#define CIM_CFG_ORDER_BIT 18
+#define CIM_CFG_ORDER_MASK (0x3 << CIM_CFG_ORDER_BIT)
+ #define CIM_CFG_ORDER_0 (0x0 << CIM_CFG_ORDER_BIT) /* Y0CbY1Cr; YCbCr */
+ #define CIM_CFG_ORDER_1 (0x1 << CIM_CFG_ORDER_BIT) /* Y0CrY1Cb; YCrCb */
+ #define CIM_CFG_ORDER_2 (0x2 << CIM_CFG_ORDER_BIT) /* CbY0CrY1; CbCrY */
+ #define CIM_CFG_ORDER_3 (0x3 << CIM_CFG_ORDER_BIT) /* CrY0CbY1; CrCbY */
+#define CIM_CFG_DF_BIT 16
+#define CIM_CFG_DF_MASK (0x3 << CIM_CFG_DF_BIT)
+ #define CIM_CFG_DF_YUV444 (0x1 << CIM_CFG_DF_BIT) /* YCbCr444 */
+ #define CIM_CFG_DF_YUV422 (0x2 << CIM_CFG_DF_BIT) /* YCbCr422 */
+ #define CIM_CFG_DF_ITU656 (0x3 << CIM_CFG_DF_BIT) /* ITU656 YCbCr422 */
+#define CIM_CFG_INV_DAT (1 << 15)
+#define CIM_CFG_VSP (1 << 14) /* VSYNC Polarity:0-rising edge active,1-falling edge active */
+#define CIM_CFG_HSP (1 << 13) /* HSYNC Polarity:0-rising edge active,1-falling edge active */
+#define CIM_CFG_PCP (1 << 12) /* PCLK working edge: 0-rising, 1-falling */
+#define CIM_CFG_DMA_BURST_TYPE_BIT 10
+#define CIM_CFG_DMA_BURST_TYPE_MASK (0x3 << CIM_CFG_DMA_BURST_TYPE_BIT)
+ #define CIM_CFG_DMA_BURST_INCR4 (0 << CIM_CFG_DMA_BURST_TYPE_BIT)
+ #define CIM_CFG_DMA_BURST_INCR8 (1 << CIM_CFG_DMA_BURST_TYPE_BIT) /* Suggested */
+ #define CIM_CFG_DMA_BURST_INCR16 (2 << CIM_CFG_DMA_BURST_TYPE_BIT) /* Suggested High speed AHB*/
+#define CIM_CFG_DUMMY_ZERO (1 << 9)
+#define CIM_CFG_EXT_VSYNC (1 << 8) /* Only for ITU656 Progressive mode */
+#define CIM_CFG_PACK_BIT 4
+#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT)
+ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) /* 11 22 33 44 0xY0CbY1Cr */
+ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) /* 22 33 44 11 0xCbY1CrY0 */
+ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) /* 33 44 11 22 0xY1CrY0Cb */
+ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) /* 44 11 22 33 0xCrY0CbY1 */
+ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) /* 44 33 22 11 0xCrY1CbY0 */
+ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) /* 33 22 11 44 0xY1CbY0Cr */
+ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) /* 22 11 44 33 0xCbY0CrY1 */
+ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) /* 11 44 33 22 0xY0CrY1Cb */
+#define CIM_CFG_BYPASS_BIT 2
+#define CIM_CFG_BYPASS_MASK (1 << CIM_CFG_BYPASS_BIT)
+ #define CIM_CFG_BYPASS (1 << CIM_CFG_BYPASS_BIT)
+#define CIM_CFG_DSM_BIT 0
+#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT)
+ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */
+ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */
+ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */
+
+/* CIM Control Register (CIM_CTRL) */
+#define CIM_CTRL_EEOF_LINE_BIT 20
+#define CIM_CTRL_EEOF_LINE_MASK (0xfff << CIM_CTRL_EEOF_LINE_BIT)
+#define CIM_CTRL_FRC_BIT 16
+#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT)
+ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */
+ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */
+ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */
+ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */
+ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */
+ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */
+ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */
+ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */
+ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */
+ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */
+ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */
+ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */
+ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */
+ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */
+ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */
+ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */
+
+#define CIM_CTRL_DMA_EEOF (1 << 15) /* Enable EEOF interrupt */
+#define CIM_CTRL_WIN_EN (1 << 14)
+#define CIM_CTRL_VDDM (1 << 13) /* VDD interrupt enable */
+#define CIM_CTRL_DMA_SOFM (1 << 12)
+#define CIM_CTRL_DMA_EOFM (1 << 11)
+#define CIM_CTRL_DMA_STOPM (1 << 10)
+#define CIM_CTRL_RXF_TRIGM (1 << 9)
+#define CIM_CTRL_RXF_OFM (1 << 8)
+#define CIM_CTRL_DMA_SYNC (1 << 7) /*when change DA, do frame sync */
+#define CIM_CTRL_RXF_TRIG_BIT 3
+#define CIM_CTRL_RXF_TRIG_MASK (0xf << CIM_CTRL_RXF_TRIG_BIT) /* trigger value = (n+1)*burst_type */
+
+#define CIM_CTRL_DMA_EN (1 << 2) /* Enable DMA */
+#define CIM_CTRL_RXF_RST (1 << 1) /* RxFIFO reset */
+#define CIM_CTRL_ENA (1 << 0) /* Enable CIM */
+
+/* CIM State Register (CIM_STATE) */
+#define CIM_STATE_DMA_EEOF (1 << 7) /* DMA Line EEOf irq */
+#define CIM_STATE_DMA_SOF (1 << 6) /* DMA start irq */
+#define CIM_STATE_DMA_EOF (1 << 5) /* DMA end irq */
+#define CIM_STATE_DMA_STOP (1 << 4) /* DMA stop irq */
+#define CIM_STATE_RXF_OF (1 << 3) /* RXFIFO over flow irq */
+#define CIM_STATE_RXF_TRIG (1 << 2) /* RXFIFO triger meet irq */
+#define CIM_STATE_RXF_EMPTY (1 << 1) /* RXFIFO empty irq */
+#define CIM_STATE_VDD (1 << 0) /* CIM disabled irq */
+
+/* CIM DMA Command Register (CIM_CMD) */
+
+#define CIM_CMD_SOFINT (1 << 31) /* enable DMA start irq */
+#define CIM_CMD_EOFINT (1 << 30) /* enable DMA end irq */
+#define CIM_CMD_EEOFINT (1 << 29) /* enable DMA EEOF irq */
+#define CIM_CMD_STOP (1 << 28) /* enable DMA stop irq */
+#define CIM_CMD_OFRCV (1 << 27) /* enable recovery when TXFiFo overflow */
+#define CIM_CMD_LEN_BIT 0
+#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT)
+
+/* CIM Window-Image Size Register (CIM_SIZE) */
+#define CIM_SIZE_LPF_BIT 16 /* Lines per freame for csc output image */
+#define CIM_SIZE_LPF_MASK (0x1fff << CIM_SIZE_LPF_BIT)
+#define CIM_SIZE_PPL_BIT 0 /* Pixels per line for csc output image, should be an even number */
+#define CIM_SIZE_PPL_MASK (0x1fff << CIM_SIZE_PPL_BIT)
+
+/* CIM Image Offset Register (CIM_OFFSET) */
+#define CIM_OFFSET_V_BIT 16 /* Vertical offset */
+#define CIM_OFFSET_V_MASK (0xfff << CIM_OFFSET_V_BIT)
+#define CIM_OFFSET_H_BIT 0 /* Horizontal offset, should be an enen number */
+#define CIM_OFFSET_H_MASK (0xfff << CIM_OFFSET_H_BIT) /*OFFSET_H should be even number*/
+
+/*************************************************************************
+ * SADC (Smart A/D Controller)
+ *************************************************************************/
+
+#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */
+#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */
+#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */
+#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/
+#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */
+#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */
+#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */
+#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC PBAT Data Register */
+#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC SADCIN Data Register */
+#define SADC_ADCLK (SADC_BASE + 0x28) /* ADC Clock Divide Register */
+
+#define REG_SADC_ENA REG8(SADC_ENA)
+#define REG_SADC_CFG REG32(SADC_CFG)
+#define REG_SADC_CTRL REG8(SADC_CTRL)
+#define REG_SADC_STATE REG8(SADC_STATE)
+#define REG_SADC_SAMETIME REG16(SADC_SAMETIME)
+#define REG_SADC_WAITTIME REG16(SADC_WAITTIME)
+#define REG_SADC_TSDAT REG32(SADC_TSDAT)
+#define REG_SADC_BATDAT REG16(SADC_BATDAT)
+#define REG_SADC_SADDAT REG16(SADC_SADDAT)
+#define REG_SADC_ADCLK REG32(SADC_ADCLK)
+
+/* ADC Enable Register */
+#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */
+#define SADC_ENA_ENTR_SLP (1 << 6) /* Touch Screen Enable */
+#define SADC_ENA_EXIT_SLP (1 << 5) /* Touch Screen Enable */
+#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */
+#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */
+#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */
+
+/* ADC Configure Register */
+#define SADC_CFG_EXIN (1 << 30)
+#define SADC_CFG_CLKOUT_NUM_BIT 16
+#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT)
+#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */
+#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */
+#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT)
+ #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT)
+ #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT)
+ #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT)
+#define SADC_CFG_SNUM_BIT 10 /* Sample Number */
+#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT)
+ #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT)
+#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */
+#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT)
+#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */
+#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */
+#define SADC_CFG_CMD_BIT 0 /* ADC Command */
+#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT)
+ #define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */
+ #define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */
+ #define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */
+ #define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */
+ #define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */
+ #define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */
+ #define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */
+ #define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */
+ #define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */
+ #define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */
+ #define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */
+ #define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */
+ #define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */
+
+/* ADC Control Register */
+#define SADC_CTRL_SLPENDM (1 << 5) /* sleep Interrupt Mask */
+#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */
+#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */
+#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */
+#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */
+#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */
+
+/* ADC Status Register */
+#define SADC_STATE_SLEEPND (1 << 5) /* Pen Down Interrupt Flag */
+#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */
+#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */
+#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */
+#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */
+#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */
+
+/* ADC Touch Screen Data Register */
+#define SADC_TSDAT_DATA0_BIT 0
+#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT)
+#define SADC_TSDAT_TYPE0 (1 << 15)
+#define SADC_TSDAT_DATA1_BIT 16
+#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT)
+#define SADC_TSDAT_TYPE1 (1 << 31)
+
+/* ADC Clock Divide Register */
+#define SADC_ADCLK_CLKDIV_10_BIT 16
+#define SADC_ADCLK_CLKDIV_10_MASK (0x7f << SADC_ADCLK_CLKDIV_10_BIT)
+#define SADC_ADCLK_CLKDIV_BIT 0
+#define SADC_ADCLK_CLKDIV_MASK (0x3f << SADC_ADCLK_CLKDIV_BIT)
+
+/*************************************************************************
+ * SLCD (Smart LCD Controller)
+ *************************************************************************/
+
+#define SLCD_CFG (SLCD_BASE + 0xA0) /* SLCD Configure Register */
+#define SLCD_CTRL (SLCD_BASE + 0xA4) /* SLCD Control Register */
+#define SLCD_STATE (SLCD_BASE + 0xA8) /* SLCD Status Register */
+#define SLCD_DATA (SLCD_BASE + 0xAC) /* SLCD Data Register */
+
+#define REG_SLCD_CFG REG32(SLCD_CFG)
+#define REG_SLCD_CTRL REG8(SLCD_CTRL)
+#define REG_SLCD_STATE REG8(SLCD_STATE)
+#define REG_SLCD_DATA REG32(SLCD_DATA)
+
+/* SLCD Configure Register */
+#define SLCD_CFG_DWIDTH_BIT 10
+#define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_18BIT (0 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_16BIT (1 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_8BIT_x3 (2 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_8BIT_x2 (3 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_8BIT_x1 (4 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_24BIT (5 << SLCD_CFG_DWIDTH_BIT)
+ #define SLCD_CFG_DWIDTH_9BIT_x2 (7 << SLCD_CFG_DWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_BIT (8)
+#define SLCD_CFG_CWIDTH_MASK (0x7 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_16BIT (0 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_8BIT (1 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_18BIT (2 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CWIDTH_24BIT (3 << SLCD_CFG_CWIDTH_BIT)
+#define SLCD_CFG_CS_ACTIVE_LOW (0 << 4)
+#define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4)
+#define SLCD_CFG_RS_CMD_LOW (0 << 3)
+#define SLCD_CFG_RS_CMD_HIGH (1 << 3)
+#define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1)
+#define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1)
+#define SLCD_CFG_TYPE_PARALLEL (0 << 0)
+#define SLCD_CFG_TYPE_SERIAL (1 << 0)
+
+/* SLCD Control Register */
+#define SLCD_CTRL_DMA_MODE (1 << 2)
+#define SLCD_CTRL_DMA_START (1 << 1)
+#define SLCD_CTRL_DMA_EN (1 << 0)
+
+/* SLCD Status Register */
+#define SLCD_STATE_BUSY (1 << 0)
+
+/* SLCD Data Register */
+#define SLCD_DATA_RS_DATA (0 << 31)
+#define SLCD_DATA_RS_COMMAND (1 << 31)
+
+/*************************************************************************
+ * LCD (LCD Controller)
+ *************************************************************************/
+#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */
+#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */
+#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */
+
+#define LCD_OSDC (LCD_BASE + 0x100) /* LCD OSD Configure Register */
+#define LCD_OSDCTRL (LCD_BASE + 0x104) /* LCD OSD Control Register */
+#define LCD_OSDS (LCD_BASE + 0x108) /* LCD OSD Status Register */
+#define LCD_BGC (LCD_BASE + 0x10C) /* LCD Background Color Register */
+#define LCD_KEY0 (LCD_BASE + 0x110) /* LCD Foreground Color Key Register 0 */
+#define LCD_KEY1 (LCD_BASE + 0x114) /* LCD Foreground Color Key Register 1 */
+#define LCD_ALPHA (LCD_BASE + 0x118) /* LCD ALPHA Register */
+#define LCD_IPUR (LCD_BASE + 0x11C) /* LCD IPU Restart Register */
+
+#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */
+#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */
+#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */
+
+#define LCD_XYP0 (LCD_BASE + 0x120) /* Foreground 0 XY Position Register */
+#define LCD_XYP1 (LCD_BASE + 0x124) /* Foreground 1 XY Position Register */
+#define LCD_SIZE0 (LCD_BASE + 0x128) /* Foreground 0 Size Register */
+#define LCD_SIZE1 (LCD_BASE + 0x12C) /* Foreground 1 Size Register */
+#define LCD_RGBC (LCD_BASE + 0x90) /* RGB Controll Register */
+
+#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */
+#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */
+#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */
+#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */
+#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */
+#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */
+#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */
+#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */
+#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */
+#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */
+#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */
+#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */
+#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */
+#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */
+#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */
+
+#define LCD_OFFS0 (LCD_BASE + 0x60) /* DMA Offsize Register 0 */
+#define LCD_PW0 (LCD_BASE + 0x64) /* DMA Page Width Register 0 */
+#define LCD_CNUM0 (LCD_BASE + 0x68) /* DMA Command Counter Register 0 */
+#define LCD_DESSIZE0 (LCD_BASE + 0x6C) /* Foreground Size in Descriptor 0 Register*/
+#define LCD_OFFS1 (LCD_BASE + 0x70) /* DMA Offsize Register 1 */
+#define LCD_PW1 (LCD_BASE + 0x74) /* DMA Page Width Register 1 */
+#define LCD_CNUM1 (LCD_BASE + 0x78) /* DMA Command Counter Register 1 */
+#define LCD_DESSIZE1 (LCD_BASE + 0x7C) /* Foreground Size in Descriptor 1 Register*/
+
+#define REG_LCD_CFG REG32(LCD_CFG)
+#define REG_LCD_CTRL REG32(LCD_CTRL)
+#define REG_LCD_STATE REG32(LCD_STATE)
+
+#define REG_LCD_OSDC REG16(LCD_OSDC)
+#define REG_LCD_OSDCTRL REG16(LCD_OSDCTRL)
+#define REG_LCD_OSDS REG16(LCD_OSDS)
+#define REG_LCD_BGC REG32(LCD_BGC)
+#define REG_LCD_KEY0 REG32(LCD_KEY0)
+#define REG_LCD_KEY1 REG32(LCD_KEY1)
+#define REG_LCD_ALPHA REG8(LCD_ALPHA)
+#define REG_LCD_IPUR REG32(LCD_IPUR)
+
+#define REG_LCD_VAT REG32(LCD_VAT)
+#define REG_LCD_DAH REG32(LCD_DAH)
+#define REG_LCD_DAV REG32(LCD_DAV)
+
+#define REG_LCD_XYP0 REG32(LCD_XYP0)
+#define REG_LCD_XYP1 REG32(LCD_XYP1)
+#define REG_LCD_SIZE0 REG32(LCD_SIZE0)
+#define REG_LCD_SIZE1 REG32(LCD_SIZE1)
+#define REG_LCD_RGBC REG16(LCD_RGBC)
+
+#define REG_LCD_VSYNC REG32(LCD_VSYNC)
+#define REG_LCD_HSYNC REG32(LCD_HSYNC)
+#define REG_LCD_PS REG32(LCD_PS)
+#define REG_LCD_CLS REG32(LCD_CLS)
+#define REG_LCD_SPL REG32(LCD_SPL)
+#define REG_LCD_REV REG32(LCD_REV)
+#define REG_LCD_IID REG32(LCD_IID)
+#define REG_LCD_DA0 REG32(LCD_DA0)
+#define REG_LCD_SA0 REG32(LCD_SA0)
+#define REG_LCD_FID0 REG32(LCD_FID0)
+#define REG_LCD_CMD0 REG32(LCD_CMD0)
+#define REG_LCD_DA1 REG32(LCD_DA1)
+#define REG_LCD_SA1 REG32(LCD_SA1)
+#define REG_LCD_FID1 REG32(LCD_FID1)
+#define REG_LCD_CMD1 REG32(LCD_CMD1)
+
+#define REG_LCD_OFFS0 REG32(LCD_OFFS0)
+#define REG_LCD_PW0 REG32(LCD_PW0)
+#define REG_LCD_CNUM0 REG32(LCD_CNUM0)
+#define REG_LCD_DESSIZE0 REG32(LCD_DESSIZE0)
+#define REG_LCD_OFFS1 REG32(LCD_OFFS1)
+#define REG_LCD_PW1 REG32(LCD_PW1)
+#define REG_LCD_CNUM1 REG32(LCD_CNUM1)
+#define REG_LCD_DESSIZE1 REG32(LCD_DESSIZE1)
+
+/* LCD Configure Register */
+#define LCD_CFG_LCDPIN_BIT 31 /* LCD pins selection */
+#define LCD_CFG_LCDPIN_MASK (0x1 << LCD_CFG_LCDPIN_BIT)
+ #define LCD_CFG_LCDPIN_LCD (0x0 << LCD_CFG_LCDPIN_BIT)
+ #define LCD_CFG_LCDPIN_SLCD (0x1 << LCD_CFG_LCDPIN_BIT)
+#define LCD_CFG_TVEPEH (1 << 30) /* TVE PAL enable extra halfline signal */
+#define LCD_CFG_FUHOLD (1 << 29) /* hold pixel clock when outFIFO underrun */
+#define LCD_CFG_NEWDES (1 << 28) /* use new descripter. old: 4words, new:8words */
+#define LCD_CFG_PALBP (1 << 27) /* bypass data format and alpha blending */
+#define LCD_CFG_TVEN (1 << 26) /* indicate the terminal is lcd or tv */
+#define LCD_CFG_RECOVER (1 << 25) /* Auto recover when output fifo underrun */
+#define LCD_CFG_DITHER (1 << 24) /* Dither function */
+#define LCD_CFG_PSM (1 << 23) /* PS signal mode */
+#define LCD_CFG_CLSM (1 << 22) /* CLS signal mode */
+#define LCD_CFG_SPLM (1 << 21) /* SPL signal mode */
+#define LCD_CFG_REVM (1 << 20) /* REV signal mode */
+#define LCD_CFG_HSYNM (1 << 19) /* HSYNC signal mode */
+#define LCD_CFG_PCLKM (1 << 18) /* PCLK signal mode */
+#define LCD_CFG_INVDAT (1 << 17) /* Inverse output data */
+#define LCD_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */
+#define LCD_CFG_PSP (1 << 15) /* PS pin reset state */
+#define LCD_CFG_CLSP (1 << 14) /* CLS pin reset state */
+#define LCD_CFG_SPLP (1 << 13) /* SPL pin reset state */
+#define LCD_CFG_REVP (1 << 12) /* REV pin reset state */
+#define LCD_CFG_HSP (1 << 11) /* HSYNC polarity:0-active high,1-active low */
+#define LCD_CFG_PCP (1 << 10) /* PCLK polarity:0-rising,1-falling */
+#define LCD_CFG_DEP (1 << 9) /* DE polarity:0-active high,1-active low */
+#define LCD_CFG_VSP (1 << 8) /* VSYNC polarity:0-rising,1-falling */
+#define LCD_CFG_MODE_TFT_18BIT (1 << 7) /* 18bit TFT */
+#define LCD_CFG_MODE_TFT_16BIT (0 << 7) /* 16bit TFT */
+#define LCD_CFG_MODE_TFT_24BIT (1 << 6) /* 24bit TFT */
+#define LCD_CFG_PDW_BIT 4 /* STN pins utilization */
+#define LCD_CFG_PDW_MASK (0x3 << LCD_DEV_PDW_BIT)
+#define LCD_CFG_PDW_1 (0 << LCD_CFG_PDW_BIT) /* LCD_D[0] */
+ #define LCD_CFG_PDW_2 (1 << LCD_CFG_PDW_BIT) /* LCD_D[0:1] */
+ #define LCD_CFG_PDW_4 (2 << LCD_CFG_PDW_BIT) /* LCD_D[0:3]/LCD_D[8:11] */
+ #define LCD_CFG_PDW_8 (3 << LCD_CFG_PDW_BIT) /* LCD_D[0:7]/LCD_D[8:15] */
+#define LCD_CFG_MODE_BIT 0 /* Display Device Mode Select */
+#define LCD_CFG_MODE_MASK (0x0f << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_CFG_MODE_BIT) /* 16,18 bit TFT */
+ #define LCD_CFG_MODE_SPECIAL_TFT_1 (1 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SPECIAL_TFT_2 (2 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SPECIAL_TFT_3 (3 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SERIAL_TFT (12 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_LCM (13 << LCD_CFG_MODE_BIT)
+ #define LCD_CFG_MODE_SLCD LCD_CFG_MODE_LCM
+
+/* LCD Control Register */
+#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */
+#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT)
+ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */
+ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */
+ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */
+ #define LCD_CTRL_BST_32 (3 << LCD_CTRL_BST_BIT) /* 32-word */
+#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode(foreground 0 in OSD mode) */
+#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode(foreground 0 in OSD mode) */
+#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */
+#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */
+#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT)
+ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */
+ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */
+ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */
+#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */
+#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT)
+#define LCD_CTRL_VGA (1 << 15) /* VGA interface enable */
+#define LCD_CTRL_DACTE (1 << 14) /* DAC loop back test */
+#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */
+#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */
+#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */
+#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */
+#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */
+#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */
+#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */
+#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */
+#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */
+#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */
+#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */
+#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */
+#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT)
+ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */
+ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */
+ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */
+ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */
+ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */
+ #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */
+ #define LCD_CTRL_BPP_CMPS_24 (6 << LCD_CTRL_BPP_BIT) /* 24 compress bpp */
+
+/* LCD Status Register */
+#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */
+#define LCD_STATE_EOF (1 << 5) /* EOF Flag */
+#define LCD_STATE_SOF (1 << 4) /* SOF Flag */
+#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */
+#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */
+#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */
+#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */
+
+/* OSD Configure Register */
+#define LCD_OSDC_SOFM1 (1 << 15) /* Start of frame interrupt mask for foreground 1 */
+#define LCD_OSDC_EOFM1 (1 << 14) /* End of frame interrupt mask for foreground 1 */
+#define LCD_OSDC_SOFM0 (1 << 11) /* Start of frame interrupt mask for foreground 0 */
+#define LCD_OSDC_EOFM0 (1 << 10) /* End of frame interrupt mask for foreground 0 */
+#define LCD_OSDC_F1EN (1 << 4) /* enable foreground 1 */
+#define LCD_OSDC_F0EN (1 << 3) /* enable foreground 0 */
+#define LCD_OSDC_ALPHAEN (1 << 2) /* enable alpha blending */
+#define LCD_OSDC_ALPHAMD (1 << 1) /* alpha blending mode */
+#define LCD_OSDC_OSDEN (1 << 0) /* OSD mode enable */
+
+/* OSD Controll Register */
+#define LCD_OSDCTRL_IPU (1 << 15) /* input data from IPU */
+#define LCD_OSDCTRL_RGB565 (0 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */
+#define LCD_OSDCTRL_RGB555 (1 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */
+#define LCD_OSDCTRL_CHANGES (1 << 3) /* Change size flag */
+#define LCD_OSDCTRL_OSDBPP_BIT 0 /* Bits Per Pixel of OSD Channel 1 */
+#define LCD_OSDCTRL_OSDBPP_MASK (0x7<<LCD_OSDCTRL_OSDBPP_BIT) /* Bits Per Pixel of OSD Channel 1's MASK */
+ #define LCD_OSDCTRL_OSDBPP_16 (4 << LCD_OSDCTRL_OSDBPP_BIT) /* RGB 15,16 bit*/
+ #define LCD_OSDCTRL_OSDBPP_15_16 (4 << LCD_OSDCTRL_OSDBPP_BIT) /* RGB 15,16 bit*/
+ #define LCD_OSDCTRL_OSDBPP_18_24 (5 << LCD_OSDCTRL_OSDBPP_BIT) /* RGB 18,24 bit*/
+ #define LCD_OSDCTRL_OSDBPP_CMPS_24 (6 << LCD_OSDCTRL_OSDBPP_BIT) /* RGB 18,24 bit*/
+
+/* OSD State Register */
+#define LCD_OSDS_SOF1 (1 << 15) /* Start of frame flag for foreground 1 */
+#define LCD_OSDS_EOF1 (1 << 14) /* End of frame flag for foreground 1 */
+#define LCD_OSDS_SOF0 (1 << 11) /* Start of frame flag for foreground 0 */
+#define LCD_OSDS_EOF0 (1 << 10) /* End of frame flag for foreground 0 */
+#define LCD_OSDS_READY (1 << 0) /* Read for accept the change */
+
+/* Background Color Register */
+#define LCD_BGC_RED_OFFSET (1 << 16) /* Red color offset */
+#define LCD_BGC_RED_MASK (0xFF<<LCD_BGC_RED_OFFSET)
+#define LCD_BGC_GREEN_OFFSET (1 << 8) /* Green color offset */
+#define LCD_BGC_GREEN_MASK (0xFF<<LCD_BGC_GREEN_OFFSET)
+#define LCD_BGC_BLUE_OFFSET (1 << 0) /* Blue color offset */
+#define LCD_BGC_BLUE_MASK (0xFF<<LCD_BGC_BLUE_OFFSET)
+
+/* Foreground Color Key Register 0,1(foreground 0, foreground 1) */
+#define LCD_KEY_KEYEN (1 << 31) /* enable color key */
+#define LCD_KEY_KEYMD (1 << 30) /* color key mode */
+#define LCD_KEY_RED_OFFSET 16 /* Red color offset */
+#define LCD_KEY_RED_MASK (0xFF<<LCD_KEY_RED_OFFSET)
+#define LCD_KEY_GREEN_OFFSET 8 /* Green color offset */
+#define LCD_KEY_GREEN_MASK (0xFF<<LCD_KEY_GREEN_OFFSET)
+#define LCD_KEY_BLUE_OFFSET 0 /* Blue color offset */
+#define LCD_KEY_BLUE_MASK (0xFF<<LCD_KEY_BLUE_OFFSET)
+#define LCD_KEY_MASK (LCD_KEY_RED_MASK|LCD_KEY_GREEN_MASK|LCD_KEY_BLUE_MASK)
+
+/* IPU Restart Register */
+#define LCD_IPUR_IPUREN (1 << 31) /* IPU restart function enable*/
+#define LCD_IPUR_IPURMASK (0xFFFFFF) /* IPU restart value mask*/
+
+/* RGB Control Register */
+#define LCD_RGBC_RGBDM (1 << 15) /* enable RGB Dummy data */
+#define LCD_RGBC_DMM (1 << 14) /* RGB Dummy mode */
+#define LCD_RGBC_YCC (1 << 8) /* RGB to YCC */
+#define LCD_RGBC_ODDRGB_BIT 4 /* odd line serial RGB data arrangement */
+#define LCD_RGBC_ODDRGB_MASK (0x7<<LCD_RGBC_ODDRGB_BIT)
+ #define LCD_RGBC_ODD_RGB 0
+ #define LCD_RGBC_ODD_RBG 1
+ #define LCD_RGBC_ODD_GRB 2
+ #define LCD_RGBC_ODD_GBR 3
+ #define LCD_RGBC_ODD_BRG 4
+ #define LCD_RGBC_ODD_BGR 5
+#define LCD_RGBC_EVENRGB_BIT 0 /* even line serial RGB data arrangement */
+#define LCD_RGBC_EVENRGB_MASK (0x7<<LCD_RGBC_EVENRGB_BIT)
+ #define LCD_RGBC_EVEN_RGB 0
+ #define LCD_RGBC_EVEN_RBG 1
+ #define LCD_RGBC_EVEN_GRB 2
+ #define LCD_RGBC_EVEN_GBR 3
+ #define LCD_RGBC_EVEN_BRG 4
+ #define LCD_RGBC_EVEN_BGR 5
+
+/* Vertical Synchronize Register */
+#define LCD_VSYNC_VPS_BIT 16 /* VSYNC pulse start in line clock, fixed to 0 */
+#define LCD_VSYNC_VPS_MASK (0xffff << LCD_VSYNC_VPS_BIT)
+#define LCD_VSYNC_VPE_BIT 0 /* VSYNC pulse end in line clock */
+#define LCD_VSYNC_VPE_MASK (0xffff << LCD_VSYNC_VPS_BIT)
+
+/* Horizontal Synchronize Register */
+#define LCD_HSYNC_HPS_BIT 16 /* HSYNC pulse start position in dot clock */
+#define LCD_HSYNC_HPS_MASK (0xffff << LCD_HSYNC_HPS_BIT)
+#define LCD_HSYNC_HPE_BIT 0 /* HSYNC pulse end position in dot clock */
+#define LCD_HSYNC_HPE_MASK (0xffff << LCD_HSYNC_HPE_BIT)
+
+/* Virtual Area Setting Register */
+#define LCD_VAT_HT_BIT 16 /* Horizontal Total size in dot clock */
+#define LCD_VAT_HT_MASK (0xffff << LCD_VAT_HT_BIT)
+#define LCD_VAT_VT_BIT 0 /* Vertical Total size in dot clock */
+#define LCD_VAT_VT_MASK (0xffff << LCD_VAT_VT_BIT)
+
+/* Display Area Horizontal Start/End Point Register */
+#define LCD_DAH_HDS_BIT 16 /* Horizontal display area start in dot clock */
+#define LCD_DAH_HDS_MASK (0xffff << LCD_DAH_HDS_BIT)
+#define LCD_DAH_HDE_BIT 0 /* Horizontal display area end in dot clock */
+#define LCD_DAH_HDE_MASK (0xffff << LCD_DAH_HDE_BIT)
+
+/* Display Area Vertical Start/End Point Register */
+#define LCD_DAV_VDS_BIT 16 /* Vertical display area start in line clock */
+#define LCD_DAV_VDS_MASK (0xffff << LCD_DAV_VDS_BIT)
+#define LCD_DAV_VDE_BIT 0 /* Vertical display area end in line clock */
+#define LCD_DAV_VDE_MASK (0xffff << LCD_DAV_VDE_BIT)
+
+/* Foreground XY Position Register */
+#define LCD_XYP_YPOS_BIT 16 /* Y position bit of foreground 0 or 1 */
+#define LCD_XYP_YPOS_MASK (0xffff << LCD_XYP_YPOS_BIT)
+#define LCD_XYP_XPOS_BIT 0 /* X position bit of foreground 0 or 1 */
+#define LCD_XYP_XPOS_MASK (0xffff << LCD_XYP_XPOS_BIT)
+
+/* PS Signal Setting */
+#define LCD_PS_PSS_BIT 16 /* PS signal start position in dot clock */
+#define LCD_PS_PSS_MASK (0xffff << LCD_PS_PSS_BIT)
+#define LCD_PS_PSE_BIT 0 /* PS signal end position in dot clock */
+#define LCD_PS_PSE_MASK (0xffff << LCD_PS_PSE_BIT)
+
+/* CLS Signal Setting */
+#define LCD_CLS_CLSS_BIT 16 /* CLS signal start position in dot clock */
+#define LCD_CLS_CLSS_MASK (0xffff << LCD_CLS_CLSS_BIT)
+#define LCD_CLS_CLSE_BIT 0 /* CLS signal end position in dot clock */
+#define LCD_CLS_CLSE_MASK (0xffff << LCD_CLS_CLSE_BIT)
+
+/* SPL Signal Setting */
+#define LCD_SPL_SPLS_BIT 16 /* SPL signal start position in dot clock */
+#define LCD_SPL_SPLS_MASK (0xffff << LCD_SPL_SPLS_BIT)
+#define LCD_SPL_SPLE_BIT 0 /* SPL signal end position in dot clock */
+#define LCD_SPL_SPLE_MASK (0xffff << LCD_SPL_SPLE_BIT)
+
+/* REV Signal Setting */
+#define LCD_REV_REVS_BIT 16 /* REV signal start position in dot clock */
+#define LCD_REV_REVS_MASK (0xffff << LCD_REV_REVS_BIT)
+
+/* DMA Command Register */
+#define LCD_CMD_SOFINT (1 << 31)
+#define LCD_CMD_EOFINT (1 << 30)
+#define LCD_CMD_CMD (1 << 29) /* indicate command in slcd mode */
+#define LCD_CMD_PAL (1 << 28)
+#define LCD_CMD_LEN_BIT 0
+#define LCD_CMD_LEN_MASK (0xffffff << LCD_CMD_LEN_BIT)
+
+/* DMA Offsize Register 0,1 */
+
+/* DMA Page Width Register 0,1 */
+
+/* DMA Command Counter Register 0,1 */
+
+/* Foreground 0,1 Size Register */
+#define LCD_DESSIZE_HEIGHT_BIT 16 /* height of foreground 1 */
+#define LCD_DESSIZE_HEIGHT_MASK (0xffff << LCD_DESSIZE_HEIGHT_BIT)
+#define LCD_DESSIZE_WIDTH_BIT 0 /* width of foreground 1 */
+#define LCD_DESSIZE_WIDTH_MASK (0xffff << LCD_DESSIZE_WIDTH_BIT)
+
+/*************************************************************************
+ * TVE (TV Encoder Controller)
+ *************************************************************************/
+#define TVE_CTRL (TVE_BASE + 0x40) /* TV Encoder Control register */
+#define TVE_FRCFG (TVE_BASE + 0x44) /* Frame configure register */
+#define TVE_SLCFG1 (TVE_BASE + 0x50) /* TV signal level configure register 1 */
+#define TVE_SLCFG2 (TVE_BASE + 0x54) /* TV signal level configure register 2*/
+#define TVE_SLCFG3 (TVE_BASE + 0x58) /* TV signal level configure register 3*/
+#define TVE_LTCFG1 (TVE_BASE + 0x60) /* Line timing configure register 1 */
+#define TVE_LTCFG2 (TVE_BASE + 0x64) /* Line timing configure register 2 */
+#define TVE_CFREQ (TVE_BASE + 0x70) /* Chrominance sub-carrier frequency configure register */
+#define TVE_CPHASE (TVE_BASE + 0x74) /* Chrominance sub-carrier phase configure register */
+#define TVE_CBCRCFG (TVE_BASE + 0x78) /* Chrominance filter configure register */
+#define TVE_WSSCR (TVE_BASE + 0x80) /* Wide screen signal control register */
+#define TVE_WSSCFG1 (TVE_BASE + 0x84) /* Wide screen signal configure register 1 */
+#define TVE_WSSCFG2 (TVE_BASE + 0x88) /* Wide screen signal configure register 2 */
+#define TVE_WSSCFG3 (TVE_BASE + 0x8c) /* Wide screen signal configure register 3 */
+
+#define REG_TVE_CTRL REG32(TVE_CTRL)
+#define REG_TVE_FRCFG REG32(TVE_FRCFG)
+#define REG_TVE_SLCFG1 REG32(TVE_SLCFG1)
+#define REG_TVE_SLCFG2 REG32(TVE_SLCFG2)
+#define REG_TVE_SLCFG3 REG32(TVE_SLCFG3)
+#define REG_TVE_LTCFG1 REG32(TVE_LTCFG1)
+#define REG_TVE_LTCFG2 REG32(TVE_LTCFG2)
+#define REG_TVE_CFREQ REG32(TVE_CFREQ)
+#define REG_TVE_CPHASE REG32(TVE_CPHASE)
+#define REG_TVE_CBCRCFG REG32(TVE_CBCRCFG)
+#define REG_TVE_WSSCR REG32(TVE_WSSCR)
+#define REG_TVE_WSSCFG1 REG32(TVE_WSSCFG1)
+#define REG_TVE_WSSCFG2 REG32(TVE_WSSCFG2)
+#define REG_TVE_WSSCFG3 REG32(TVE_WSSCFG3)
+
+/* TV Encoder Control register */
+#define TVE_CTRL_EYCBCR (1 << 25) /* YCbCr_enable */
+#define TVE_CTRL_ECVBS (1 << 24) /* cvbs_enable */
+#define TVE_CTRL_DAPD3 (1 << 23) /* DAC 3 power down */
+#define TVE_CTRL_DAPD2 (1 << 22) /* DAC 2 power down */
+#define TVE_CTRL_DAPD1 (1 << 21) /* DAC 1 power down */
+#define TVE_CTRL_DAPD (1 << 20) /* power down all DACs */
+#define TVE_CTRL_YCDLY_BIT 16
+#define TVE_CTRL_YCDLY_MASK (0x7 << TVE_CTRL_YCDLY_BIT)
+#define TVE_CTRL_CGAIN_BIT 14
+#define TVE_CTRL_CGAIN_MASK (0x3 << TVE_CTRL_CGAIN_BIT)
+ #define TVE_CTRL_CGAIN_FULL (0 << TVE_CTRL_CGAIN_BIT) /* gain = 1 */
+ #define TVE_CTRL_CGAIN_QUTR (1 << TVE_CTRL_CGAIN_BIT) /* gain = 1/4 */
+ #define TVE_CTRL_CGAIN_HALF (2 << TVE_CTRL_CGAIN_BIT) /* gain = 1/2 */
+ #define TVE_CTRL_CGAIN_THREE_QURT (3 << TVE_CTRL_CGAIN_BIT) /* gain = 3/4 */
+#define TVE_CTRL_CBW_BIT 12
+#define TVE_CTRL_CBW_MASK (0x3 << TVE_CTRL_CBW_BIT)
+ #define TVE_CTRL_CBW_NARROW (0 << TVE_CTRL_CBW_BIT) /* Narrow band */
+ #define TVE_CTRL_CBW_WIDE (1 << TVE_CTRL_CBW_BIT) /* Wide band */
+ #define TVE_CTRL_CBW_EXTRA (2 << TVE_CTRL_CBW_BIT) /* Extra wide band */
+ #define TVE_CTRL_CBW_ULTRA (3 << TVE_CTRL_CBW_BIT) /* Ultra wide band */
+#define TVE_CTRL_SYNCT (1 << 9)
+#define TVE_CTRL_PAL (1 << 8)
+#define TVE_CTRL_FINV (1 << 7) /* invert_top:1-invert top and bottom fields. */
+#define TVE_CTRL_ZBLACK (1 << 6) /* bypass_yclamp:1-Black of luminance (Y) input is 0.*/
+#define TVE_CTRL_CR1ST (1 << 5) /* uv_order:0-Cb before Cr,1-Cr before Cb */
+#define TVE_CTRL_CLBAR (1 << 4) /* Color bar mode:0-Output input video to TV,1-Output color bar to TV */
+#define TVE_CTRL_SWRST (1 << 0) /* Software reset:1-TVE is reset */
+
+/* Signal level configure register 1 */
+#define TVE_SLCFG1_BLACKL_BIT 0
+#define TVE_SLCFG1_BLACKL_MASK (0x3ff << TVE_SLCFG1_BLACKL_BIT)
+#define TVE_SLCFG1_WHITEL_BIT 16
+#define TVE_SLCFG1_WHITEL_MASK (0x3ff << TVE_SLCFG1_WHITEL_BIT)
+
+/* Signal level configure register 2 */
+#define TVE_SLCFG2_BLANKL_BIT 0
+#define TVE_SLCFG2_BLANKL_MASK (0x3ff << TVE_SLCFG2_BLANKL_BIT)
+#define TVE_SLCFG2_VBLANKL_BIT 16
+#define TVE_SLCFG2_VBLANKL_MASK (0x3ff << TVE_SLCFG2_VBLANKL_BIT)
+
+/* Signal level configure register 3 */
+#define TVE_SLCFG3_SYNCL_BIT 0
+#define TVE_SLCFG3_SYNCL_MASK (0xff << TVE_SLCFG3_SYNCL_BIT)
+
+/* Line timing configure register 1 */
+#define TVE_LTCFG1_BACKP_BIT 0
+#define TVE_LTCFG1_BACKP_MASK (0x7f << TVE_LTCFG1_BACKP_BIT)
+#define TVE_LTCFG1_HSYNCW_BIT 8
+#define TVE_LTCFG1_HSYNCW_MASK (0x7f << TVE_LTCFG1_HSYNCW_BIT)
+#define TVE_LTCFG1_FRONTP_BIT 16
+#define TVE_LTCFG1_FRONTP_MASK (0x1f << TVE_LTCFG1_FRONTP_BIT)
+
+/* Line timing configure register 2 */
+#define TVE_LTCFG2_BURSTW_BIT 0
+#define TVE_LTCFG2_BURSTW_MASK (0x3f << TVE_LTCFG2_BURSTW_BIT)
+#define TVE_LTCFG2_PREBW_BIT 8
+#define TVE_LTCFG2_PREBW_MASK (0x1f << TVE_LTCFG2_PREBW_BIT)
+#define TVE_LTCFG2_ACTLIN_BIT 16
+#define TVE_LTCFG2_ACTLIN_MASK (0x7ff << TVE_LTCFG2_ACTLIN_BIT)
+
+/* Chrominance sub-carrier phase configure register */
+#define TVE_CPHASE_CCRSTP_BIT 0
+#define TVE_CPHASE_CCRSTP_MASK (0x3 << TVE_CPHASE_CCRSTP_BIT)
+ #define TVE_CPHASE_CCRSTP_8 (0 << TVE_CPHASE_CCRSTP_BIT) /* Every 8 field */
+ #define TVE_CPHASE_CCRSTP_4 (1 << TVE_CPHASE_CCRSTP_BIT) /* Every 4 field */
+ #define TVE_CPHASE_CCRSTP_2 (2 << TVE_CPHASE_CCRSTP_BIT) /* Every 2 lines */
+ #define TVE_CPHASE_CCRSTP_0 (3 << TVE_CPHASE_CCRSTP_BIT) /* Never */
+#define TVE_CPHASE_ACTPH_BIT 16
+#define TVE_CPHASE_ACTPH_MASK (0xff << TVE_CPHASE_ACTPH_BIT)
+#define TVE_CPHASE_INITPH_BIT 24
+#define TVE_CPHASE_INITPH_MASK (0xff << TVE_CPHASE_INITPH_BIT)
+
+/* Chrominance filter configure register */
+#define TVE_CBCRCFG_CRGAIN_BIT 0
+#define TVE_CBCRCFG_CRGAIN_MASK (0xff << TVE_CBCRCFG_CRGAIN_BIT)
+#define TVE_CBCRCFG_CBGAIN_BIT 8
+#define TVE_CBCRCFG_CBGAIN_MASK (0xff << TVE_CBCRCFG_CBGAIN_BIT)
+#define TVE_CBCRCFG_CRBA_BIT 16
+#define TVE_CBCRCFG_CRBA_MASK (0xff << TVE_CBCRCFG_CRBA_BIT)
+#define TVE_CBCRCFG_CBBA_BIT 24
+#define TVE_CBCRCFG_CBBA_MASK (0xff << TVE_CBCRCFG_CBBA_BIT)
+
+/* Frame configure register */
+#define TVE_FRCFG_NLINE_BIT 0
+#define TVE_FRCFG_NLINE_MASK (0x3ff << TVE_FRCFG_NLINE_BIT)
+#define TVE_FRCFG_L1ST_BIT 16
+#define TVE_FRCFG_L1ST_MASK (0xff << TVE_FRCFG_L1ST_BIT)
+
+/* Wide screen signal control register */
+#define TVE_WSSCR_EWSS0_BIT 0
+#define TVE_WSSCR_EWSS1_BIT 1
+#define TVE_WSSCR_WSSTP_BIT 2
+#define TVE_WSSCR_WSSCKBP_BIT 3
+#define TVE_WSSCR_WSSEDGE_BIT 4
+#define TVE_WSSCR_WSSEDGE_MASK (0x7 << TVE_WSSCR_WSSEDGE_BIT)
+#define TVE_WSSCR_ENCH_BIT 8
+#define TVE_WSSCR_NCHW_BIT 9
+#define TVE_WSSCR_NCHFREQ_BIT 12
+#define TVE_WSSCR_NCHFREQ_MASK (0x7 << TVE_WSSCR_NCHFREQ_BIT)
+
+/*************************************************************************
+ * USB Device
+ *************************************************************************/
+#define USB_BASE UDC_BASE
+
+#define USB_REG_FADDR (USB_BASE + 0x00) /* Function Address 8-bit */
+#define USB_REG_POWER (USB_BASE + 0x01) /* Power Managemetn 8-bit */
+#define USB_REG_INTRIN (USB_BASE + 0x02) /* Interrupt IN 16-bit */
+#define USB_REG_INTROUT (USB_BASE + 0x04) /* Interrupt OUT 16-bit */
+#define USB_REG_INTRINE (USB_BASE + 0x06) /* Intr IN enable 16-bit */
+#define USB_REG_INTROUTE (USB_BASE + 0x08) /* Intr OUT enable 16-bit */
+#define USB_REG_INTRUSB (USB_BASE + 0x0a) /* Interrupt USB 8-bit */
+#define USB_REG_INTRUSBE (USB_BASE + 0x0b) /* Interrupt USB Enable 8-bit */
+#define USB_REG_FRAME (USB_BASE + 0x0c) /* Frame number 16-bit */
+#define USB_REG_INDEX (USB_BASE + 0x0e) /* Index register 8-bit */
+#define USB_REG_TESTMODE (USB_BASE + 0x0f) /* USB test mode 8-bit */
+
+#define USB_REG_CSR0 (USB_BASE + 0x12) /* EP0 CSR 8-bit */
+#define USB_REG_INMAXP (USB_BASE + 0x10) /* EP1-2 IN Max Pkt Size 16-bit */
+#define USB_REG_INCSR (USB_BASE + 0x12) /* EP1-2 IN CSR LSB 8/16bit */
+#define USB_REG_INCSRH (USB_BASE + 0x13) /* EP1-2 IN CSR MSB 8-bit */
+#define USB_REG_OUTMAXP (USB_BASE + 0x14) /* EP1 OUT Max Pkt Size 16-bit */
+#define USB_REG_OUTCSR (USB_BASE + 0x16) /* EP1 OUT CSR LSB 8/16bit */
+#define USB_REG_OUTCSRH (USB_BASE + 0x17) /* EP1 OUT CSR MSB 8-bit */
+#define USB_REG_OUTCOUNT (USB_BASE + 0x18) /* bytes in EP0/1 OUT FIFO 16-bit */
+
+#define USB_FIFO_EP0 (USB_BASE + 0x20)
+#define USB_FIFO_EP1 (USB_BASE + 0x24)
+#define USB_FIFO_EP2 (USB_BASE + 0x28)
+
+#define USB_REG_EPINFO (USB_BASE + 0x78) /* Endpoint information */
+#define USB_REG_RAMINFO (USB_BASE + 0x79) /* RAM information */
+
+#define USB_REG_INTR (USB_BASE + 0x200) /* DMA pending interrupts */
+#define USB_REG_CNTL1 (USB_BASE + 0x204) /* DMA channel 1 control */
+#define USB_REG_ADDR1 (USB_BASE + 0x208) /* DMA channel 1 AHB memory addr */
+#define USB_REG_COUNT1 (USB_BASE + 0x20c) /* DMA channel 1 byte count */
+#define USB_REG_CNTL2 (USB_BASE + 0x214) /* DMA channel 2 control */
+#define USB_REG_ADDR2 (USB_BASE + 0x218) /* DMA channel 2 AHB memory addr */
+#define USB_REG_COUNT2 (USB_BASE + 0x21c) /* DMA channel 2 byte count */
+
+
+/* Power register bit masks */
+#define USB_POWER_SUSPENDM 0x01
+#define USB_POWER_RESUME 0x04
+#define USB_POWER_HSMODE 0x10
+#define USB_POWER_HSENAB 0x20
+#define USB_POWER_SOFTCONN 0x40
+
+/* Interrupt register bit masks */
+#define USB_INTR_SUSPEND 0x01
+#define USB_INTR_RESUME 0x02
+#define USB_INTR_RESET 0x04
+
+#define USB_INTR_EP0 0x0001
+#define USB_INTR_INEP1 0x0002
+#define USB_INTR_INEP2 0x0004
+#define USB_INTR_OUTEP1 0x0002
+
+/* CSR0 bit masks */
+#define USB_CSR0_OUTPKTRDY 0x01
+#define USB_CSR0_INPKTRDY 0x02
+#define USB_CSR0_SENTSTALL 0x04
+#define USB_CSR0_DATAEND 0x08
+#define USB_CSR0_SETUPEND 0x10
+#define USB_CSR0_SENDSTALL 0x20
+#define USB_CSR0_SVDOUTPKTRDY 0x40
+#define USB_CSR0_SVDSETUPEND 0x80
+
+/* Endpoint CSR register bits */
+#define USB_INCSRH_AUTOSET 0x80
+#define USB_INCSRH_ISO 0x40
+#define USB_INCSRH_MODE 0x20
+#define USB_INCSRH_DMAREQENAB 0x10
+#define USB_INCSRH_DMAREQMODE 0x04
+#define USB_INCSR_CDT 0x40
+#define USB_INCSR_SENTSTALL 0x20
+#define USB_INCSR_SENDSTALL 0x10
+#define USB_INCSR_FF 0x08
+#define USB_INCSR_UNDERRUN 0x04
+#define USB_INCSR_FFNOTEMPT 0x02
+#define USB_INCSR_INPKTRDY 0x01
+#define USB_OUTCSRH_AUTOCLR 0x80
+#define USB_OUTCSRH_ISO 0x40
+#define USB_OUTCSRH_DMAREQENAB 0x20
+#define USB_OUTCSRH_DNYT 0x10
+#define USB_OUTCSRH_DMAREQMODE 0x08
+#define USB_OUTCSR_CDT 0x80
+#define USB_OUTCSR_SENTSTALL 0x40
+#define USB_OUTCSR_SENDSTALL 0x20
+#define USB_OUTCSR_FF 0x10
+#define USB_OUTCSR_DATAERR 0x08
+#define USB_OUTCSR_OVERRUN 0x04
+#define USB_OUTCSR_FFFULL 0x02
+#define USB_OUTCSR_OUTPKTRDY 0x01
+
+/* Testmode register bits */
+#define USB_TEST_SE0NAK 0x01
+#define USB_TEST_J 0x02
+#define USB_TEST_K 0x04
+#define USB_TEST_PACKET 0x08
+
+/* DMA control bits */
+#define USB_CNTL_ENA 0x01
+#define USB_CNTL_DIR_IN 0x02
+#define USB_CNTL_MODE_1 0x04
+#define USB_CNTL_INTR_EN 0x08
+#define USB_CNTL_EP(n) ((n) << 4)
+#define USB_CNTL_BURST_0 (0 << 9)
+#define USB_CNTL_BURST_4 (1 << 9)
+#define USB_CNTL_BURST_8 (2 << 9)
+#define USB_CNTL_BURST_16 (3 << 9)
+
+/*************************************************************************
+ * BCH
+ *************************************************************************/
+#define BCH_CR (BCH_BASE + 0x00) /* BCH Control register */
+#define BCH_CRS (BCH_BASE + 0x04) /* BCH Control Set register */
+#define BCH_CRC (BCH_BASE + 0x08) /* BCH Control Clear register */
+#define BCH_CNT (BCH_BASE + 0x0C) /* BCH ENC/DEC Count register */
+#define BCH_DR (BCH_BASE + 0x10) /* BCH data register */
+#define BCH_PAR0 (BCH_BASE + 0x14) /* BCH Parity 0 register */
+#define BCH_PAR1 (BCH_BASE + 0x18) /* BCH Parity 1 register */
+#define BCH_PAR2 (BCH_BASE + 0x1C) /* BCH Parity 2 register */
+#define BCH_PAR3 (BCH_BASE + 0x20) /* BCH Parity 3 register */
+#define BCH_INTS (BCH_BASE + 0x24) /* BCH Interrupt Status register */
+#define BCH_ERR0 (BCH_BASE + 0x28) /* BCH Error Report 0 register */
+#define BCH_ERR1 (BCH_BASE + 0x2C) /* BCH Error Report 1 register */
+#define BCH_ERR2 (BCH_BASE + 0x30) /* BCH Error Report 2 register */
+#define BCH_ERR3 (BCH_BASE + 0x34) /* BCH Error Report 3 register */
+#define BCH_INTE (BCH_BASE + 0x38) /* BCH Interrupt Enable register */
+#define BCH_INTES (BCH_BASE + 0x3C) /* BCH Interrupt Set register */
+#define BCH_INTEC (BCH_BASE + 0x40) /* BCH Interrupt Clear register */
+
+#define REG_BCH_CR REG32(BCH_CR)
+#define REG_BCH_CRS REG32(BCH_CRS)
+#define REG_BCH_CRC REG32(BCH_CRC)
+#define REG_BCH_CNT REG32(BCH_CNT)
+#define REG_BCH_DR REG8(BCH_DR)
+#define REG_BCH_PAR0 REG32(BCH_PAR0)
+#define REG_BCH_PAR1 REG32(BCH_PAR1)
+#define REG_BCH_PAR2 REG32(BCH_PAR2)
+#define REG_BCH_PAR3 REG32(BCH_PAR3)
+#define REG_BCH_INTS REG32(BCH_INTS)
+#define REG_BCH_ERR0 REG32(BCH_ERR0)
+#define REG_BCH_ERR1 REG32(BCH_ERR1)
+#define REG_BCH_ERR2 REG32(BCH_ERR2)
+#define REG_BCH_ERR3 REG32(BCH_ERR3)
+#define REG_BCH_INTE REG32(BCH_INTE)
+#define REG_BCH_INTEC REG32(BCH_INTEC)
+#define REG_BCH_INTES REG32(BCH_INTES)
+
+/* BCH Control Register*/
+#define BCH_CR_DMAE (1 << 4) /* BCH DMA Enable */
+#define BCH_CR_ENCE (1 << 3) /* BCH Encoding Select */
+#define BCH_CR_DECE (0 << 3) /* BCH Decoding Select */
+#define BCH_CR_BSEL8 (1 << 2) /* 8 Bit BCH Select */
+#define BCH_CR_BSEL4 (0 << 2) /* 4 Bit BCH Select */
+#define BCH_CR_BRST (1 << 1) /* BCH Reset */
+#define BCH_CR_BCHE (1 << 0) /* BCH Enable */
+
+/* BCH Interrupt Status Register */
+#define BCH_INTS_ERRC_BIT 28
+#define BCH_INTS_ERRC_MASK (0xf << BCH_INTS_ERRC_BIT)
+#define BCH_INTS_ALL0 (1 << 5)
+#define BCH_INTS_ALLf (1 << 4)
+#define BCH_INTS_DECF (1 << 3)
+#define BCH_INTS_ENCF (1 << 2)
+#define BCH_INTS_UNCOR (1 << 1)
+#define BCH_INTS_ERR (1 << 0)
+
+/* BCH ENC/DEC Count Register */
+#define BCH_CNT_DEC_BIT 16
+#define BCH_CNT_DEC_MASK (0x3ff << BCH_CNT_DEC_BIT)
+#define BCH_CNT_ENC_BIT 0
+#define BCH_CNT_ENC_MASK (0x3ff << BCH_CNT_ENC_BIT)
+
+/* BCH Error Report Register */
+#define BCH_ERR_INDEX_ODD_BIT 16
+#define BCH_ERR_INDEX_ODD_MASK (0x1fff << BCH_ERR_INDEX_ODD_BIT)
+#define BCH_ERR_INDEX_EVEN_BIT 0
+#define BCH_ERR_INDEX_EVEN_MASK (0x1fff << BCH_ERR_INDEX_EVEN_BIT)
+
+/*************************************************************************
+ * OWI (One-wire Bus Controller )
+ *************************************************************************/
+#define OWI_CFG (OWI_BASE + 0x00) /* OWI Configure Register */
+#define OWI_CTL (OWI_BASE + 0x04) /* OWI Control Register */
+#define OWI_STS (OWI_BASE + 0x08) /* OWI Status Register */
+#define OWI_DAT (OWI_BASE + 0x0c) /* OWI Data Register */
+#define OWI_DIV (OWI_BASE + 0x10) /* OWI Clock Divide Register */
+
+#define REG_OWI_CFG REG8(OWI_CFG)
+#define REG_OWI_CTL REG8(OWI_CTL)
+#define REG_OWI_STS REG8(OWI_STS)
+#define REG_OWI_DAT REG8(OWI_DAT)
+#define REG_OWI_DIV REG8(OWI_DIV)
+
+/* OWI Configure Register */
+#define OWI_CFG_MODE (1 << 7) /* 0: Regular speed mode 1: Overdrive speed mode */
+#define OWI_CFG_RDDATA (1 << 6) /* 1: receive data from one-wire bus and stored in OWDAT*/
+#define OWI_CFG_WRDATA (1 << 5) /* 1: transmit the data in OWDAT */
+#define OWI_CFG_RDST (1 << 4) /* 1: was sampled during a read */
+#define OWI_CFG_WR1RD (1 << 3) /* 1: generate write 1 sequence on line */
+#define OWI_CFG_WR0 (1 << 2) /* 1: generate write 0 sequence on line */
+#define OWI_CFG_RST (1 << 1) /* 1: generate reset pulse and sample slaves presence pulse*/
+#define OWI_CFG_ENA (1 << 0) /* 1: enable the OWI operation */
+
+/* OWI Control Register */
+#define OWI_CTL_EBYTE (1 << 2) /* enable byte write/read interrupt */
+#define OWI_CTL_EBIT (1 << 1) /* enable bit write/read interrupt */
+#define OWI_CTL_ERST (1 << 0) /* enable reset sequence finished interrupt */
+
+/* OWI Status Register */
+#define OWI_STS_PST (1 << 7) /* 1: one-wire bus has device on it */
+#define OWI_STS_BYTE_RDY (1 << 2) /* 1: have received or transmitted a data */
+#define OWI_STS_BIT_RDY (1 << 1) /* 1: have received or transmitted a bit */
+#define OWI_STS_PST_RDY (1 << 0) /* 1: have finished a reset pulse */
+
+/* OWI Clock Divide Register */
+#define OWI_DIV_CLKDIV_BIT 5
+
+
+/*************************************************************************
+ * MC (Motion Compensation)
+ *************************************************************************/
+#define MC_CTRL (MC_BASE + 0x00) /* MC Control Register */
+#define MC_STAT (MC_BASE + 0x04) /* MC Status Register */
+#define MC_REF_ADDR (MC_BASE + 0x08) /* MC Reference Block Address Register */
+#define MC_REF2_ADDR (MC_BASE + 0x0C) /* MC 2nd Reference Block Address Register */
+#define MC_CURR_ADDR (MC_BASE + 0x10) /* MC Current Block Address Register */
+#define MC_REF_STRD (MC_BASE + 0x14) /* MC Reference Frame Stride Register */
+#define MC_CURR_STRD (MC_BASE + 0x18) /* MC Current Frame Stride Register */
+#define MC_ITP_INFO (MC_BASE + 0x1C) /* MC Block Interpolation Information Register */
+#define MC_TAP_COEF1 (MC_BASE + 0x20) /* MC TAP Filter Coefficient 1 Register */
+#define MC_TAP_COEF2 (MC_BASE + 0x24) /* MC TAP Filter Coefficient 2 Register */
+
+#define REG_MC_CTRL REG32(MC_CTRL)
+#define REG_MC_STAT REG32(MC_STAT)
+#define REG_MC_REF_ADDR REG32(MC_REF_ADDR)
+#define REG_MC_REF2_ADDR REG32(MC_REF2_ADDR)
+#define REG_MC_CURR_ADDR REG32(MC_CURR_ADDR)
+#define REG_MC_REF_STRD REG32(MC_REF_STRD)
+#define REG_MC_CURR_STRD REG32(MC_CURR_STRD)
+#define REG_MC_ITP_INFO REG32(MC_ITP_INFO)
+#define REG_MC_TAP_COEF1 REG32(MC_TAP_COEF1)
+#define REG_MC_TAP_COEF2 REG32(MC_TAP_COEF2)
+
+/* MC Control Register */
+#define MC_CTRL_CACHECLR (1 << 2) /* MC Cache clear */
+#define MC_CTRL_RESET (1 << 1) /* MC Reset */
+#define MC_CTRL_ENABLE (1 << 0) /* MC enable */
+
+/* MC Status Register */
+#define MC_STAT_OUT_END (1 << 0) /* Output DMA termination flag */
+
+/* MC Reference Frame Stride Register, unit: byte */
+#define MC_REF_STRD_BIT 16
+#define MC_REF_STRD_MASK (0xfff << MC_REF_STRD_BIT)
+#define MC_REF_STRD2_BIT 0
+#define MC_REF_STRD2_MASK (0xfff << MC_REF_STRD2_BIT)
+
+/* MC Current Frame Stride Register, unit: byte */
+#define MC_CURR_STRD_BIT 0
+#define MC_CURR_STRD_MASK (0xfff << MC_CURR_STRD_BIT)
+
+/* MC Block Interpolation Information Register */
+#define MC_ITP_INFO_RND1_BIT 24 /* Rounding data during interpolation */
+#define MC_ITP_INFO_RND1_MASK (0xff << MC_ITP_INFO_RND1_BIT)
+#define MC_ITP_INFO_RND0_BIT 16 /* Rounding data during interpolation */
+#define MC_ITP_INFO_RND0_MASK (0xff << MC_ITP_INFO_RND0_BIT)
+#define MC_ITP_INFO_AVG (1 << 12) /* 0: output interpolated data directly; 1: doing average operation with 2nd source data after interpolating and output */
+#define MC_ITP_INFO_FMT_BIT 8 /* Indicate current interpolation's type */
+#define MC_ITP_INFO_RMT_MASK (0xf << MC_ITP_INFO_RMT_BIT)
+ #define MC_ITP_INFO_FMT_MPEG_HPEL (0x0 << MC_ITP_INFO_RMT_BIT) /* MPEG Half-pixel interpolation */
+ #define MC_ITP_INFO_FMT_MPEG_QPEL (0x1 << MC_ITP_INFO_RMT_BIT) /* MPEG 8-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_H264_QPEL (0x2 << MC_ITP_INFO_RMT_BIT) /* H264 6-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_H264_EPEL (0x3 << MC_ITP_INFO_RMT_BIT) /* H264 2-tap Eight-pixel interpolation */
+ #define MC_ITP_INFO_FMT_H264_WPDT (0x4 << MC_ITP_INFO_RMT_BIT) /* H264 Weighted-prediction */
+ #define MC_ITP_INFO_FMT_WMV2_QPEL (0x5 << MC_ITP_INFO_RMT_BIT) /* WMV2 4-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_VC1_QPEL (0x6 << MC_ITP_INFO_RMT_BIT) /* VC1 4-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_RV8_TPEL (0x7 << MC_ITP_INFO_RMT_BIT) /* RV8 4-tap Third-pixel interpolation */
+ #define MC_ITP_INFO_FMT_RV8_CHROM (0x8 << MC_ITP_INFO_RMT_BIT) /* RV8 2-tap Third-pixel interpolation */
+ #define MC_ITP_INFO_FMT_RV9_QPEL (0x9 << MC_ITP_INFO_RMT_BIT) /* RV9 6-tap Quarter-pixel interpolation */
+ #define MC_ITP_INFO_FMT_RV9_CHROM (0xa << MC_ITP_INFO_RMT_BIT) /* RV9 2-tap Quarter-pixel interpolation */
+#define MC_ITP_INFO_BLK_W_BIT 6 /* Indicate reference block's width, unit: pixel */
+#define MC_ITP_INFO_BLK_W_MASK (0x3 << MC_ITP_INFO_BLK_W_BIT)
+ #define MC_ITP_INFO_BLK_W_2 (0x0 << MC_ITP_INFO_BLK_W_BIT)
+ #define MC_ITP_INFO_BLK_W_4 (0x1 << MC_ITP_INFO_BLK_W_BIT)
+ #define MC_ITP_INFO_BLK_W_8 (0x2 << MC_ITP_INFO_BLK_W_BIT)
+ #define MC_ITP_INFO_BLK_W_16 (0x3 << MC_ITP_INFO_BLK_W_BIT)
+#define MC_ITP_INFO_BLK_H_BIT 4 /* Indicate reference block's height, unit: pixel */
+#define MC_ITP_INFO_BLK_H_MASK (0x3 << MC_ITP_INFO_BLK_H_BIT)
+ #define MC_ITP_INFO_BLK_H_2 (0x0 << MC_ITP_INFO_BLK_H_BIT)
+ #define MC_ITP_INFO_BLK_H_4 (0x1 << MC_ITP_INFO_BLK_H_BIT)
+ #define MC_ITP_INFO_BLK_H_8 (0x2 << MC_ITP_INFO_BLK_H_BIT)
+ #define MC_ITP_INFO_BLK_H_16 (0x3 << MC_ITP_INFO_BLK_H_BIT)
+#define MC_ITP_INFO_ITP_CASE_BIT 0 /* Indicate interpolation final destination pixel position */
+#define MC_ITP_INFO_ITP_CASE_MASK (0xf << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H0V0 (0x0 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H1V0 (0x1 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H2V0 (0x2 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H3V0 (0x3 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H0V1 (0x4 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H1V1 (0x5 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H2V1 (0x6 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H3V1 (0x7 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H0V2 (0x8 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H1V2 (0x9 << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H2V2 (0xa << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H3V2 (0xb << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H0V3 (0xc << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H1V3 (0xd << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H2V3 (0xe << MC_ITP_INFO_ITP_CASE_BIT)
+ #define MC_ITP_INFO_ITP_CASE_H3V3 (0xf << MC_ITP_INFO_ITP_CASE_BIT)
+
+/* MC TAP Filter Coefficient 1 Register */
+#define MC_TAP_COEF1_TAP_COEF4_BIT 24
+#define MC_TAP_COEF1_TAP_COEF4_MASK (0xff << MC_TAP_COEF1_TAP_COEF4_BIT)
+#define MC_TAP_COEF1_TAP_COEF3_BIT 16
+#define MC_TAP_COEF1_TAP_COEF3_MASK (0xff << MC_TAP_COEF1_TAP_COEF3_BIT)
+#define MC_TAP_COEF1_TAP_COEF2_BIT 8
+#define MC_TAP_COEF1_TAP_COEF2_MASK (0xff << MC_TAP_COEF1_TAP_COEF2_BIT)
+#define MC_TAP_COEF1_TAP_COEF1_BIT 0
+#define MC_TAP_COEF1_TAP_COEF1_MASK (0xff << MC_TAP_COEF1_TAP_COEF1_BIT)
+
+/* MC TAP Filter Coefficient 2 Register */
+#define MC_TAP_COEF2_TAP_COEF8_BIT 24
+#define MC_TAP_COEF2_TAP_COEF8_MASK (0xff << MC_TAP_COEF2_TAP_COEF8_BIT)
+#define MC_TAP_COEF2_TAP_COEF7_BIT 16
+#define MC_TAP_COEF2_TAP_COEF7_MASK (0xff << MC_TAP_COEF2_TAP_COEF7_BIT)
+#define MC_TAP_COEF2_TAP_COEF6_BIT 8
+#define MC_TAP_COEF2_TAP_COEF6_MASK (0xff << MC_TAP_COEF2_TAP_COEF6_BIT)
+#define MC_TAP_COEF2_TAP_COEF5_BIT 0
+#define MC_TAP_COEF2_TAP_COEF5_MASK (0xff << MC_TAP_COEF2_TAP_COEF5_BIT)
+
+
+/*************************************************************************
+ * ME (Motion Estimation)
+ *************************************************************************/
+#define ME_CTRL (ME_BASE + 0x00) /* ME Control Register */
+#define ME_REF_ADDR (ME_BASE + 0x04) /* ME Reference Block Address Register */
+#define ME_CURR_ADDR (ME_BASE + 0x08) /* ME Current Block Address Register */
+#define ME_DIFF_ADDR (ME_BASE + 0x0C) /* ME Difference Address Register */
+#define ME_REF_STRD (ME_BASE + 0x10) /* ME Reference Frame Stride Register */
+#define ME_CURR_STRD (ME_BASE + 0x14) /* ME Current Frame Stride Register */
+#define ME_DIFF_STRD (ME_BASE + 0x18) /* ME Difference Frame Stride Register */
+#define ME_SETTINGS (ME_BASE + 0x1C) /* ME Settings Register */
+#define ME_MVD (ME_BASE + 0x20) /* ME Motion Vector Difference Register */
+#define ME_FLAG (ME_BASE + 0x24) /* ME Flag Register */
+
+#define REG_ME_CTRL REG32(ME_CTRL)
+#define REG_ME_REF_ADDR REG32(ME_REF_ADDR)
+#define REG_ME_CURR_ADDR REG32(ME_CURR_ADDR)
+#define REG_ME_DIFF_ADDR REG32(ME_DIFF_ADDR)
+#define REG_ME_REF_STRD REG32(ME_REF_STRD)
+#define REG_ME_CURR_STRD REG32(ME_CURR_STRD)
+#define REG_ME_DIFF_STRD REG32(ME_DIFF_STRD)
+#define REG_ME_SETTINGS REG32(ME_SETTINGS)
+#define REG_ME_MVD REG32(ME_MVD)
+#define REG_ME_FLAG REG32(ME_FLAG)
+
+
+/* ME Control Register */
+#define ME_CTRL_FLUSH (1 << 2) /* ME cache clear */
+#define ME_CTRL_RESET (1 << 1) /* ME reset */
+#define ME_CTRL_ENABLE (1 << 0) /* ME enable */
+
+/* ME Settings Register */
+#define ME_SETTINGS_SAD_GATE_BIT 16 /* The max SAD value which can be accepted */
+#define ME_SETTINGS_SAD_GATE_MASK (0xffff << ME_SETTINGS_SAD_GATE_BIT)
+#define ME_SETTINGS_STEP_NUM_BIT 0 /* The max step number the search process can not exceed */
+#define ME_SETTINGS_STEP_NUM_MASK (0x3f << ME_SETTINGS_STEP_NUM_BIT)
+
+/* ME Motion Vector Difference Register */
+#define ME_MVD_MVDY_BIT 16 /* The MVD value of coordinate-Y */
+#define ME_MVD_MVDY_MASK (0xffff << ME_MVD_MVDY_BIT)
+#define ME_MVD_MVDX_BIT 0 /* The MVD value of coordinate-X */
+#define ME_MVD_MVDX_MASK (0xffff << ME_MVD_MVDX_BIT)
+
+/* ME Flag Register */
+#define ME_FLAG_INTRA (1 << 1) /* Indicate the current MB will be predicted in intra mode */
+#define ME_FLAG_COMPLETED (1 << 0) /* The ME of the current part of the MB is completed */
+
+
+/*************************************************************************
+ * OTP (One Time Programmable Module)
+ *************************************************************************/
+#define OTP_ID0 (OTP_BASE + 0x00) /* ID0 Register */
+#define OTP_ID1 (OTP_BASE + 0x04) /* ID1 Register */
+#define OTP_ID2 (OTP_BASE + 0x08) /* ID2 Register */
+#define OTP_ID3 (OTP_BASE + 0x0C) /* ID3 Register */
+#define OTP_BR0 (OTP_BASE + 0x10) /* BOOTROM0 Register */
+#define OTP_BR1 (OTP_BASE + 0x14) /* BOOTROM1 Register */
+#define OTP_HW0 (OTP_BASE + 0x18) /* Chip Hardware 0 Register */
+#define OTP_HW1 (OTP_BASE + 0x1C) /* Chip Hardware 1 Register */
+
+#define REG_OTP_ID0 REG32(OTP_ID0)
+#define REG_OTP_ID1 REG32(OTP_ID1)
+#define REG_OTP_ID2 REG32(OTP_ID2)
+#define REG_OTP_ID3 REG32(OTP_ID3)
+#define REG_OTP_BR0 REG32(OTP_BR0)
+#define REG_OTP_BR1 REG32(OTP_BR1)
+#define REG_OTP_HW0 REG32(OTP_HW0)
+#define REG_OTP_HW1 REG32(OTP_HW1)
+
+/* ID0 Register */
+#define OTP_ID0_WID_BIT 24 /* Wafer ID */
+#define OTP_ID0_WID_MASK (0xff << OTP_ID0_WID_BIT)
+#define OTP_ID0_MID_BIT 16 /* MASK ID */
+#define OTP_ID0_MID_MASK (0xff << OTP_ID0_MID_BIT)
+#define OTP_ID0_FID_BIT 8 /* Foundary ID */
+#define OTP_ID0_FID_MASK (0xff << OTP_ID0_FID_BIT)
+#define OTP_ID0_PID_BIT 0 /* Product ID */
+#define OTP_ID0_PID_MASK (0xff << OTP_ID0_PID_BIT)
+
+/* ID1 Register */
+#define OTP_ID1_LID_BIT 8 /* Lot ID */
+#define OTP_ID1_LID_MASK (0xffffff << OTP_ID1_LID_BIT)
+#define OTP_ID1_TID_BIT 0 /* Test House ID */
+#define OTP_ID1_TID_MASK (0xff << OTP_ID1_TID_BIT)
+
+/* ID2 Register */
+#define OTP_ID2_XADR_BIT 24 /* Die X-dir Address */
+#define OTP_ID2_XADR_MASK (0xff << OTP_ID2_XADR_BIT)
+#define OTP_ID2_YADR_BIT 16 /* Die Y-dir Address */
+#define OTP_ID2_YADR_MASK (0xff << OTP_ID2_YADR_BIT)
+#define OTP_ID2_TDATE_BIT 0 /* Testing Date */
+#define OTP_ID2_TDATE_MASK (0xffff << OTP_ID2_TDATE_BIT)
+
+/* ID3 Register */
+#define OTP_ID3_CID_BIT 16 /* Customer ID */
+#define OTP_ID3_CID_MASK (0xffff << OTP_ID3_CID_BIT)
+#define OTP_ID3_CP_BIT 0 /* Chip Parameters */
+#define OTP_ID3_CP_MASK (0xffff << OTP_ID3_CP_BIT)
+
+/* BOOTROM1 Register */
+#define OTP_BR1_UDCBOOT_BIT 0
+#define OTP_BR1_UDCBOOT_MASK (0xff << OTP_BR1_UDCBOOT_BIT)
+ #define OTP_BR1_UDCBOOT_AUTO (0xf0 << OTP_BR1_UDCBOOT_BIT)
+ #define OTP_BR1_UDCBOOT_24M (0x0f << OTP_BR1_UDCBOOT_BIT) /* 24MHz OSC */
+ #define OTP_BR1_UDCBOOT_13M (0x0c << OTP_BR1_UDCBOOT_BIT) /* 13MHz OSC */
+ #define OTP_BR1_UDCBOOT_26M (0x03 << OTP_BR1_UDCBOOT_BIT) /* 26MHz OSC */
+ #define OTP_BR1_UDCBOOT_27M (0x00 << OTP_BR1_UDCBOOT_BIT) /* 27MHz OSC */
+
+/* Chip Hardware 1 Register */
+#define OTP_HW1_MC_EN (0x3 << 30) /* MC is enabled */
+#define OTP_HW1_ME_EN (0x3 << 28)
+#define OTP_HW1_DE_EN (0x3 << 26)
+#define OTP_HW1_IDCT_EN (0x3 << 24)
+#define OTP_HW1_UART3_EN (0x3 << 22)
+#define OTP_HW1_UART2_EN (0x3 << 20)
+#define OTP_HW1_UART1_EN (0x3 << 18)
+#define OTP_HW1_UART0_EN (0x3 << 16)
+#define OTP_HW1_SSI1_EN (0x3 << 14)
+#define OTP_HW1_SSI0_EN (0x3 << 12)
+#define OTP_HW1_MSC1_EN (0x3 << 10)
+#define OTP_HW1_MSC0_EN (0x3 << 8)
+#define OTP_HW1_UHC_EN (0x3 << 6)
+#define OTP_HW1_TVE_EN (0x3 << 4)
+#define OTP_HW1_TSSI_EN (0x3 << 2)
+#define OTP_HW1_CIM_EN (0x3 << 0)
+
+
+/*************************************************************************
+ * TSSI MPEG 2-TS slave interface
+ *************************************************************************/
+#define TSSI_ENA ( TSSI_BASE + 0x00 ) /* TSSI enable register */
+#define TSSI_CFG ( TSSI_BASE + 0x04 ) /* TSSI configure register */
+#define TSSI_CTRL ( TSSI_BASE + 0x08 ) /* TSSI control register */
+#define TSSI_STAT ( TSSI_BASE + 0x0c ) /* TSSI state register */
+#define TSSI_FIFO ( TSSI_BASE + 0x10 ) /* TSSI FIFO register */
+#define TSSI_PEN ( TSSI_BASE + 0x14 ) /* TSSI PID enable register */
+#define TSSI_PID(n) ( TSSI_BASE + 0x20 + 4*(n) ) /* TSSI PID filter register */
+#define TSSI_PID0 ( TSSI_BASE + 0x20 )
+#define TSSI_PID1 ( TSSI_BASE + 0x24 )
+#define TSSI_PID2 ( TSSI_BASE + 0x28 )
+#define TSSI_PID3 ( TSSI_BASE + 0x2c )
+#define TSSI_PID4 ( TSSI_BASE + 0x30 )
+#define TSSI_PID5 ( TSSI_BASE + 0x34 )
+#define TSSI_PID6 ( TSSI_BASE + 0x38 )
+#define TSSI_PID7 ( TSSI_BASE + 0x3c )
+#define TSSI_PID_MAX 8 /* max PID: 7 */
+
+#define REG_TSSI_ENA REG8( TSSI_ENA )
+#define REG_TSSI_CFG REG16( TSSI_CFG )
+#define REG_TSSI_CTRL REG8( TSSI_CTRL )
+#define REG_TSSI_STAT REG8( TSSI_STAT )
+#define REG_TSSI_FIFO REG32( TSSI_FIFO )
+#define REG_TSSI_PEN REG32( TSSI_PEN )
+#define REG_TSSI_PID(n) REG32( TSSI_PID(n) )
+#define REG_TSSI_PID0 REG32( TSSI_PID0 )
+#define REG_TSSI_PID1 REG32( TSSI_PID1 )
+#define REG_TSSI_PID2 REG32( TSSI_PID2 )
+#define REG_TSSI_PID3 REG32( TSSI_PID3 )
+#define REG_TSSI_PID4 REG32( TSSI_PID4 )
+#define REG_TSSI_PID5 REG32( TSSI_PID5 )
+#define REG_TSSI_PID6 REG32( TSSI_PID6 )
+#define REG_TSSI_PID7 REG32( TSSI_PID7 )
+
+/* TSSI enable register */
+#define TSSI_ENA_SFT_RST ( 1 << 7 ) /* soft reset bit */
+#define TSSI_ENA_PID_EN ( 1 << 2 ) /* soft filtering function enable bit */
+#define TSSI_ENA_DMA_EN ( 1 << 1 ) /* DMA enable bit */
+#define TSSI_ENA_ENA ( 1 << 0 ) /* TSSI enable bit */
+
+/* TSSI configure register */
+#define TSSI_CFG_TRIG_BIT 14 /* fifo trig number */
+#define TSSI_CFG_TRIG_MASK ( 0x3 << TSSI_CFG_TRIG_BIT)
+#define TSSI_CFG_TRIG_4 ( 0 << TSSI_CFG_TRIG_BIT)
+#define TSSI_CFG_TRIG_8 ( 1 << TSSI_CFG_TRIG_BIT)
+#define TSSI_CFG_TRIG_16 ( 2 << TSSI_CFG_TRIG_BIT)
+#define TSSI_CFG_END_WD ( 1 << 9 ) /* order of data in word */
+#define TSSI_CFG_END_BT ( 1 << 8 ) /* order of data in byte */
+#define TSSI_CFG_TSDI_H ( 1 << 7 ) /* data pin polarity */
+#define TSSI_CFG_USE_0 ( 1 << 6 ) /* serial mode data pin select */
+#define TSSI_CFG_USE_TSDI0 ( 0 << 6 ) /* TSDI0 as serial mode data pin */
+#define TSSI_CFG_USE_TSDI7 ( 1 << 6 ) /* TSDI7 as serial mode data pin */
+#define TSSI_CFG_TSCLK_CH ( 1 << 5 ) /* clk channel select */
+#define TSSI_CFG_PARAL ( 1 << 4 ) /* mode select */
+#define TSSI_CFG_PARAL_MODE ( 1 << 4 ) /* parallel select */
+#define TSSI_CFG_SERIAL_MODE ( 0 << 4 ) /* serial select */
+#define TSSI_CFG_TSCLK_P ( 1 << 3 ) /* clk edge select */
+#define TSSI_CFG_TSFRM_H ( 1 << 2 ) /* TSFRM polarity select */
+#define TSSI_CFG_TSSTR_H ( 1 << 1 ) /* TSSTR polarity select */
+#define TSSI_CFG_TSFAIL_H ( 1 << 0 ) /* TSFAIL polarity select */
+
+/* TSSI control register */
+#define TSSI_CTRL_OVRNM ( 1 << 1 ) /* FIFO overrun interrupt mask bit */
+#define TSSI_CTRL_TRIGM ( 1 << 0 ) /* FIFO trigger interrupt mask bit */
+
+/* TSSI state register */
+#define TSSI_STAT_OVRN ( 1 << 1 ) /* FIFO overrun interrupt flag bit */
+#define TSSI_STAT_TRIG ( 1 << 0 ) /* FIFO trigger interrupt flag bit */
+
+/* TSSI PID enable register */
+#define TSSI_PEN_EN00 ( 1 << 0 ) /* enable PID n */
+#define TSSI_PEN_EN10 ( 1 << 1 )
+#define TSSI_PEN_EN20 ( 1 << 2 )
+#define TSSI_PEN_EN30 ( 1 << 3 )
+#define TSSI_PEN_EN40 ( 1 << 4 )
+#define TSSI_PEN_EN50 ( 1 << 5 )
+#define TSSI_PEN_EN60 ( 1 << 6 )
+#define TSSI_PEN_EN70 ( 1 << 7 )
+#define TSSI_PEN_EN01 ( 1 << 16 )
+#define TSSI_PEN_EN11 ( 1 << 17 )
+#define TSSI_PEN_EN21 ( 1 << 18 )
+#define TSSI_PEN_EN31 ( 1 << 19 )
+#define TSSI_PEN_EN41 ( 1 << 20 )
+#define TSSI_PEN_EN51 ( 1 << 21 )
+#define TSSI_PEN_EN61 ( 1 << 22 )
+#define TSSI_PEN_EN71 ( 1 << 23 )
+#define TSSI_PEN_PID0 ( 1 << 31 ) /* PID filter enable PID0 */
+
+/* TSSI PID Filter Registers */
+#define TSSI_PID_PID1_BIT 16
+#define TSSI_PID_PID1_MASK (0x1FFF<<TSSI_PID_PID1_BIT)
+#define TSSI_PID_PID0_BIT 0
+#define TSSI_PID_PID0_MASK (0x1FFF<<TSSI_PID_PID0_BIT)
+
+
+/*************************************************************************
+ * IPU (Image Processing Unit)
+ *************************************************************************/
+#define IPU_V_BASE 0xB3080000
+#define IPU_P_BASE 0x13080000
+
+/* Register offset */
+#define REG_CTRL 0x0 /* IPU Control Register */
+#define REG_STATUS 0x4 /* IPU Status Register */
+#define REG_D_FMT 0x8 /* Data Format Register */
+#define REG_Y_ADDR 0xc /* Input Y or YUV422 Packaged Data Address Register */
+#define REG_U_ADDR 0x10 /* Input U Data Address Register */
+#define REG_V_ADDR 0x14 /* Input V Data Address Register */
+#define REG_IN_FM_GS 0x18 /* Input Geometric Size Register */
+#define REG_Y_STRIDE 0x1c /* Input Y Data Line Stride Register */
+#define REG_UV_STRIDE 0x20 /* Input UV Data Line Stride Register */
+#define REG_OUT_ADDR 0x24 /* Output Frame Start Address Register */
+#define REG_OUT_GS 0x28 /* Output Geometric Size Register */
+#define REG_OUT_STRIDE 0x2c /* Output Data Line Stride Register */
+#define REG_RSZ_COEF_INDEX 0x30 /* Resize Coefficients Table Index Register */
+#define REG_CSC_CO_COEF 0x34 /* CSC C0 Coefficient Register */
+#define REG_CSC_C1_COEF 0x38 /* CSC C1 Coefficient Register */
+#define REG_CSC_C2_COEF 0x3c /* CSC C2 Coefficient Register */
+#define REG_CSC_C3_COEF 0x40 /* CSC C3 Coefficient Register */
+#define REG_CSC_C4_COEF 0x44 /* CSC C4 Coefficient Register */
+#define HRSZ_LUT_BASE 0x48 /* Horizontal Resize Coefficients Look Up Table Register group */
+#define VRSZ_LUT_BASE 0x4c /* Virtical Resize Coefficients Look Up Table Register group */
+#define REG_CSC_OFSET_PARA 0x50 /* CSC Offset Parameter Register */
+#define REG_Y_PHY_T_ADDR 0x54 /* Input Y Physical Table Address Register */
+#define REG_U_PHY_T_ADDR 0x58 /* Input U Physical Table Address Register */
+#define REG_V_PHY_T_ADDR 0x5c /* Input V Physical Table Address Register */
+#define REG_OUT_PHY_T_ADDR 0x60 /* Output Physical Table Address Register */
+
+/* REG_CTRL: IPU Control Register */
+#define IPU_CE_SFT 0x0
+#define IPU_CE_MSK 0x1
+#define IPU_RUN_SFT 0x1
+#define IPU_RUN_MSK 0x1
+#define HRSZ_EN_SFT 0x2
+#define HRSZ_EN_MSK 0x1
+#define VRSZ_EN_SFT 0x3
+#define VRSZ_EN_MSK 0x1
+#define CSC_EN_SFT 0x4
+#define CSC_EN_MSK 0x1
+#define FM_IRQ_EN_SFT 0x5
+#define FM_IRQ_EN_MSK 0x1
+#define IPU_RST_SFT 0x6
+#define IPU_RST_MSK 0x1
+#define H_SCALE_SFT 0x8
+#define H_SCALE_MSK 0x1
+#define V_SCALE_SFT 0x9
+#define V_SCALE_MSK 0x1
+#define PKG_SEL_SFT 0xA
+#define PKG_SEL_MSK 0x1
+#define LCDC_SEL_SFT 0xB
+#define LCDC_SEL_MSK 0x1
+#define SPAGE_MAP_SFT 0xC
+#define SPAGE_MAP_MSK 0x1
+#define DPAGE_SEL_SFT 0xD
+#define DPAGE_SEL_MSK 0x1
+#define DISP_SEL_SFT 0xE
+#define DISP_SEL_MSK 0x1
+#define FIELD_CONF_EN_SFT 15
+#define FIELD_CONF_EN_MSK 1
+#define FIELD_SEL_SFT 16
+#define FIELD_SEL_MSK 1
+#define DFIX_SEL_SFT 17
+#define DFIX_SEL_MSK 1
+
+/* REG_STATUS: IPU Status Register */
+#define OUT_END_SFT 0x0
+#define OUT_END_MSK 0x1
+#define FMT_ERR_SFT 0x1
+#define FMT_ERR_MSK 0x1
+#define SIZE_ERR_SFT 0x2
+#define SIZE_ERR_MSK 0x1
+
+/* D_FMT: Data Format Register */
+#define IN_FMT_SFT 0x0
+#define IN_FMT_MSK 0x3
+#define IN_OFT_SFT 0x2
+#define IN_OFT_MSK 0x3
+#define YUV_PKG_OUT_SFT 0x10
+#define YUV_PKG_OUT_MSK 0x7
+#define OUT_FMT_SFT 0x13
+#define OUT_FMT_MSK 0x3
+#define RGB_OUT_OFT_SFT 0x15
+#define RGB_OUT_OFT_MSK 0x7
+#define RGB888_FMT_SFT 0x18
+#define RGB888_FMT_MSK 0x1
+
+/* IN_FM_GS: Input Geometric Size Register */
+#define IN_FM_H_SFT 0x0
+#define IN_FM_H_MSK 0xFFF
+#define IN_FM_W_SFT 0x10
+#define IN_FM_W_MSK 0xFFF
+
+/* Y_STRIDE: Input Y Data Line Stride Register */
+#define Y_S_SFT 0x0
+#define Y_S_MSK 0x3FFF
+
+/* UV_STRIDE: Input UV Data Line Stride Register */
+#define V_S_SFT 0x0
+#define V_S_MSK 0x1FFF
+#define U_S_SFT 0x10
+#define U_S_MSK 0x1FFF
+
+/* OUT_GS: Output Geometric Size Register */
+#define OUT_FM_H_SFT 0x0
+#define OUT_FM_H_MSK 0x1FFF
+#define OUT_FM_W_SFT 0x10
+#define OUT_FM_W_MSK 0x7FFF
+
+/* OUT_STRIDE: Output Data Line Stride Register */
+#define OUT_S_SFT 0x0
+#define OUT_S_MSK 0xFFFF
+
+/* RSZ_COEF_INDEX: Resize Coefficients Table Index Register */
+#define VE_IDX_SFT 0x0
+#define VE_IDX_MSK 0x1F
+#define HE_IDX_SFT 0x10
+#define HE_IDX_MSK 0x1F
+
+/* CSC_CX_COEF: CSC CX Coefficient Register */
+#define CX_COEF_SFT 0x0
+#define CX_COEF_MSK 0xFFF
+
+/* HRSZ_LUT_BASE, VRSZ_LUT_BASE: Resize Coefficients Look Up Table Register group */
+#define LUT_LEN 20
+
+#define OUT_N_SFT 0x0
+#define OUT_N_MSK 0x1
+#define IN_N_SFT 0x1
+#define IN_N_MSK 0x1
+#define W_COEF_SFT 0x2
+#define W_COEF_MSK 0x3FF
+
+/* CSC_OFSET_PARA: CSC Offset Parameter Register */
+#define CHROM_OF_SFT 0x10
+#define CHROM_OF_MSK 0xFF
+#define LUMA_OF_SFT 0x00
+#define LUMA_OF_MSK 0xFF
+
+
+#endif /* __JZ4750L_REGS_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750l/serial.h b/arch/mips/include/asm/mach-jz4750l/serial.h
new file mode 100644
index 00000000000..90ecac26bdd
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750l/serial.h
@@ -0,0 +1,30 @@
+/*
+ * linux/include/asm-mips/mach-jz4750l/serial.h
+ *
+ * Ingenic's JZ4750L common include.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: <cwjia@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_BOARD_SERIAL_H__
+#define __ASM_BOARD_SERIAL_H__
+
+#ifndef CONFIG_SERIAL_MANY_PORTS
+#undef RS_TABLE_SIZE
+#define RS_TABLE_SIZE 1
+#endif
+
+#define JZ_BASE_BAUD (12000000/16)
+
+#define JZ_SERIAL_PORT_DEFNS \
+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \
+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \
+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM },
+
+#endif /* __ASM_BORAD_SERIAL_H__ */
diff --git a/arch/mips/include/asm/mach-jz4750l/war.h b/arch/mips/include/asm/mach-jz4750l/war.h
new file mode 100644
index 00000000000..24187020ad3
--- /dev/null
+++ b/arch/mips/include/asm/mach-jz4750l/war.h
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_JZ4750L_WAR_H
+#define __ASM_MIPS_MACH_JZ4750L_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR 0
+#define R4600_V1_HIT_CACHEOP_WAR 0
+#define R4600_V2_HIT_CACHEOP_WAR 0
+#define R5432_CP0_INTERRUPT_WAR 0
+#define BCM1250_M3_WAR 0
+#define SIBYTE_1956_WAR 0
+#define MIPS4K_ICACHE_REFILL_WAR 0
+#define MIPS_CACHE_SYNC_WAR 0
+#define TX49XX_ICACHE_INDEX_INV_WAR 0
+#define RM9000_CDEX_SMP_WAR 0
+#define ICACHE_REFILLS_WORKAROUND_WAR 0
+#define R10000_LLSC_WAR 0
+#define MIPS34K_MISSED_ITLB_WAR 0
+
+#endif /* __ASM_MIPS_MACH_JZ4750L_WAR_H */
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
index ce47118e52b..2f58feba86a 100644
--- a/arch/mips/include/asm/ptrace.h
+++ b/arch/mips/include/asm/ptrace.h
@@ -135,7 +135,11 @@ extern int ptrace_set_watch_regs(struct task_struct *child,
/*
* Does the process account for user or for system time?
*/
+#if defined(CONFIG_JZ_TCSM)
+#define user_mode(regs) ((((regs)->cp0_status & KU_MASK) == KU_USER) || (((regs)->cp0_status & 0x08000000) == 0x08000000))
+# else
#define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER)
+#endif
#define instruction_pointer(regs) ((regs)->cp0_epc)
#define profile_pc(regs) instruction_pointer(regs)
diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h
index 387bf59f1e3..39b1cedbd32 100644
--- a/arch/mips/include/asm/r4kcache.h
+++ b/arch/mips/include/asm/r4kcache.h
@@ -17,6 +17,58 @@
#include <asm/cpu-features.h>
#include <asm/mipsmtregs.h>
+#ifdef CONFIG_JZRISC
+
+#define K0_TO_K1() \
+do { \
+ unsigned long __k0_addr; \
+ \
+ __asm__ __volatile__( \
+ "la %0, 1f\n\t" \
+ "or %0, %0, %1\n\t" \
+ "jr %0\n\t" \
+ "nop\n\t" \
+ "1: nop\n" \
+ : "=&r"(__k0_addr) \
+ : "r" (0x20000000) ); \
+} while(0)
+
+#define K1_TO_K0() \
+do { \
+ unsigned long __k0_addr; \
+ __asm__ __volatile__( \
+ "nop;nop;nop;nop;nop;nop;nop\n\t" \
+ "la %0, 1f\n\t" \
+ "jr %0\n\t" \
+ "nop\n\t" \
+ "1: nop\n" \
+ : "=&r" (__k0_addr)); \
+} while (0)
+
+#define INVALIDATE_BTB() \
+do { \
+ unsigned long tmp; \
+ __asm__ __volatile__( \
+ ".set mips32\n\t" \
+ "mfc0 %0, $16, 7\n\t" \
+ "nop\n\t" \
+ "ori %0, 2\n\t" \
+ "mtc0 %0, $16, 7\n\t" \
+ "nop\n\t" \
+ : "=&r" (tmp)); \
+} while (0)
+
+#define SYNC_WB() __asm__ __volatile__ ("sync")
+
+#else /* CONFIG_JZRISC */
+
+#define K0_TO_K1() do { } while (0)
+#define K1_TO_K0() do { } while (0)
+#define INVALIDATE_BTB() do { } while (0)
+#define SYNC_WB() do { } while (0)
+
+#endif /* CONFIG_JZRISC */
+
/*
* This macro return a properly sign-extended address suitable as base address
* for indexed cache operations. Two issues here:
@@ -144,6 +196,7 @@ static inline void flush_icache_line_indexed(unsigned long addr)
{
__iflush_prologue
cache_op(Index_Invalidate_I, addr);
+ INVALIDATE_BTB();
__iflush_epilogue
}
@@ -151,6 +204,7 @@ static inline void flush_dcache_line_indexed(unsigned long addr)
{
__dflush_prologue
cache_op(Index_Writeback_Inv_D, addr);
+ SYNC_WB();
__dflush_epilogue
}
@@ -163,6 +217,7 @@ static inline void flush_icache_line(unsigned long addr)
{
__iflush_prologue
cache_op(Hit_Invalidate_I, addr);
+ INVALIDATE_BTB();
__iflush_epilogue
}
@@ -170,6 +225,7 @@ static inline void flush_dcache_line(unsigned long addr)
{
__dflush_prologue
cache_op(Hit_Writeback_Inv_D, addr);
+ SYNC_WB();
__dflush_epilogue
}
@@ -177,6 +233,7 @@ static inline void invalidate_dcache_line(unsigned long addr)
{
__dflush_prologue
cache_op(Hit_Invalidate_D, addr);
+ SYNC_WB();
__dflush_epilogue
}
@@ -209,6 +266,7 @@ static inline void flush_scache_line(unsigned long addr)
static inline void protected_flush_icache_line(unsigned long addr)
{
protected_cache_op(Hit_Invalidate_I, addr);
+ INVALIDATE_BTB();
}
/*
@@ -220,6 +278,7 @@ static inline void protected_flush_icache_line(unsigned long addr)
static inline void protected_writeback_dcache_line(unsigned long addr)
{
protected_cache_op(Hit_Writeback_Inv_D, addr);
+ SYNC_WB();
}
static inline void protected_writeback_scache_line(unsigned long addr)
@@ -396,8 +455,12 @@ static inline void blast_##pfx##cache##lsize##_page_indexed(unsigned long page)
__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16)
__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16)
__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16)
+
+#ifndef CONFIG_JZRISC
__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32)
__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32)
+#endif
+
__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32)
__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 64)
__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
@@ -405,12 +468,125 @@ __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16)
+
+#ifndef CONFIG_JZRISC
__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32)
+#endif
+
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16)
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32)
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64)
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128)
+#ifdef CONFIG_JZRISC
+
+static inline void blast_dcache32(void)
+{
+ unsigned long start = INDEX_BASE;
+ unsigned long end = start + current_cpu_data.dcache.waysize;
+ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
+ unsigned long ws_end = current_cpu_data.dcache.ways <<
+ current_cpu_data.dcache.waybit;
+ unsigned long ws, addr;
+
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400)
+ cache32_unroll32(addr|ws,Index_Writeback_Inv_D);
+
+ SYNC_WB();
+}
+
+static inline void blast_dcache32_page(unsigned long page)
+{
+ unsigned long start = page;
+ unsigned long end = page + PAGE_SIZE;
+
+ do {
+ cache32_unroll32(start,Hit_Writeback_Inv_D);
+ start += 0x400;
+ } while (start < end);
+
+ SYNC_WB();
+}
+
+static inline void blast_dcache32_page_indexed(unsigned long page)
+{
+ unsigned long indexmask = current_cpu_data.dcache.waysize - 1;
+ unsigned long start = INDEX_BASE + (page & indexmask);
+ unsigned long end = start + PAGE_SIZE;
+ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
+ unsigned long ws_end = current_cpu_data.dcache.ways <<
+ current_cpu_data.dcache.waybit;
+ unsigned long ws, addr;
+
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400)
+ cache32_unroll32(addr|ws,Index_Writeback_Inv_D);
+
+ SYNC_WB();
+}
+
+static inline void blast_icache32(void)
+{
+ unsigned long start = INDEX_BASE;
+ unsigned long end = start + current_cpu_data.icache.waysize;
+ unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit;
+ unsigned long ws_end = current_cpu_data.icache.ways <<
+ current_cpu_data.icache.waybit;
+ unsigned long ws, addr;
+
+ K0_TO_K1();
+
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400)
+ cache32_unroll32(addr|ws,Index_Invalidate_I);
+
+ INVALIDATE_BTB();
+
+ K1_TO_K0();
+}
+
+static inline void blast_icache32_page(unsigned long page)
+{
+ unsigned long start = page;
+ unsigned long end = page + PAGE_SIZE;
+
+ K0_TO_K1();
+
+ do {
+ cache32_unroll32(start,Hit_Invalidate_I);
+ start += 0x400;
+ } while (start < end);
+
+ INVALIDATE_BTB();
+
+ K1_TO_K0();
+}
+
+static inline void blast_icache32_page_indexed(unsigned long page)
+{
+ unsigned long indexmask = current_cpu_data.icache.waysize - 1;
+ unsigned long start = INDEX_BASE + (page & indexmask);
+ unsigned long end = start + PAGE_SIZE;
+ unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit;
+ unsigned long ws_end = current_cpu_data.icache.ways <<
+ current_cpu_data.icache.waybit;
+ unsigned long ws, addr;
+
+ K0_TO_K1();
+
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+ for (addr = start; addr < end; addr += 0x400)
+ cache32_unroll32(addr|ws,Index_Invalidate_I);
+
+ INVALIDATE_BTB();
+
+ K1_TO_K0();
+}
+
+#endif /* CONFIG_JZRISC */
+
+
/* build blast_xxx_range, protected_blast_xxx_range */
#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
@@ -432,13 +608,76 @@ static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
__##pfx##flush_epilogue \
}
+#ifndef CONFIG_JZRISC
__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_)
+#endif
+
__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_)
+
+#ifndef CONFIG_JZRISC
__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_)
__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, )
+#endif
+
__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, )
/* blast_inv_dcache_range */
__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, )
__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, )
+#ifdef CONFIG_JZRISC
+
+static inline void protected_blast_dcache_range(unsigned long start,
+ unsigned long end)
+{
+ unsigned long lsize = cpu_dcache_line_size();
+ unsigned long addr = start & ~(lsize - 1);
+ unsigned long aend = (end - 1) & ~(lsize - 1);
+
+ while (1) {
+ protected_cache_op(Hit_Writeback_Inv_D, addr);
+ if (addr == aend)
+ break;
+ addr += lsize;
+ }
+ SYNC_WB();
+}
+
+static inline void protected_blast_icache_range(unsigned long start,
+ unsigned long end)
+{
+ unsigned long lsize = cpu_icache_line_size();
+ unsigned long addr = start & ~(lsize - 1);
+ unsigned long aend = (end - 1) & ~(lsize - 1);
+
+ K0_TO_K1();
+
+ while (1) {
+ protected_cache_op(Hit_Invalidate_I, addr);
+ if (addr == aend)
+ break;
+ addr += lsize;
+ }
+ INVALIDATE_BTB();
+
+ K1_TO_K0();
+}
+
+static inline void blast_dcache_range(unsigned long start,
+ unsigned long end)
+{
+ unsigned long lsize = cpu_dcache_line_size();
+ unsigned long addr = start & ~(lsize - 1);
+ unsigned long aend = (end - 1) & ~(lsize - 1);
+
+ while (1) {
+ cache_op(Hit_Writeback_Inv_D, addr);
+ if (addr == aend)
+ break;
+ addr += lsize;
+ }
+ SYNC_WB();
+}
+
+#endif /* CONFIG_JZRISC */
+
#endif /* _ASM_R4KCACHE_H */
diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h
index db0fa7b5aea..52e0605703f 100644
--- a/arch/mips/include/asm/stackframe.h
+++ b/arch/mips/include/asm/stackframe.h
@@ -344,6 +344,11 @@
mfc0 a0, CP0_STATUS
ori a0, STATMASK
xori a0, STATMASK
+
+#if defined(CONFIG_JZSOC)
+ la v1, 0xf7ffffff
+ and a0, a0, v1
+#endif
mtc0 a0, CP0_STATUS
li v1, 0xff00
and a0, v1
@@ -462,6 +467,13 @@
li t1, ST0_CU0 | STATMASK
or t0, t1
xori t0, STATMASK
+
+#if defined(CONFIG_JZSOC)
+ la t1, 0xf7ffffff
+ and t0, t0, t1
+ li t1, ST0_CU0 | STATMASK
+#endif
+
mtc0 t0, CP0_STATUS
#else /* CONFIG_MIPS_MT_SMTC */
/*
@@ -497,6 +509,12 @@
li t1, ST0_CU0 | STATMASK
or t0, t1
xori t0, STATMASK & ~1
+
+#if defined(CONFIG_JZSOC)
+ la t1, 0xf7ffffff
+ and t0, t0, t1
+ li t1, ST0_CU0 | STATMASK
+#endif
mtc0 t0, CP0_STATUS
#else /* CONFIG_MIPS_MT_SMTC */
/*
@@ -565,6 +583,13 @@
#endif
or t0, t1
xori t0, STATMASK & ~1
+
+#if defined(CONFIG_JZSOC)
+ la t1, 0xf7ffffff
+ and t0, t0, t1
+ li t1, ST0_CU0 | (STATMASK & ~1)
+#endif
+
mtc0 t0, CP0_STATUS
#ifdef CONFIG_MIPS_MT_SMTC
_ehb
diff --git a/arch/mips/jz4730/Makefile b/arch/mips/jz4730/Makefile
new file mode 100644
index 00000000000..d84b6b6cfd3
--- /dev/null
+++ b/arch/mips/jz4730/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile for the Ingenic JZ4730.
+#
+
+# Object file lists.
+
+obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
+ platform.o i2c.o
+
+obj-$(CONFIG_PROC_FS) += proc.o
+
+# board specific support
+
+obj-$(CONFIG_JZ4730_PMP) += board-pmp.o
+
+# CPU Frequency scaling support
+
+obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o
+
+# PM support
+
+obj-$(CONFIG_PM_LEGACY) +=pm.o sleep.o
diff --git a/arch/mips/jz4730/board-pmp.c b/arch/mips/jz4730/board-pmp.c
new file mode 100644
index 00000000000..00860c1ced2
--- /dev/null
+++ b/arch/mips/jz4730/board-pmp.c
@@ -0,0 +1,109 @@
+/*
+ * linux/arch/mips/jz4730/board-pmp.c
+ *
+ * JZ4730 PMP board setup routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+
+#include <asm/jzsoc.h>
+
+extern void (*jz_timer_callback)(void);
+
+static void dancing(void)
+{
+ static unsigned int count = 0;
+
+ count ++;
+ count &= 1;
+ if (count)
+ __gpio_set_pin(GPIO_LED_EN);
+ else
+ __gpio_clear_pin(GPIO_LED_EN);
+}
+
+static void pmp_timer_ack(void)
+{
+ static unsigned int count = 0;
+ count ++;
+ if (count % 100 == 0) {
+ count = 0;
+ dancing();
+ }
+}
+
+static void __init board_cpm_setup(void)
+{
+ __cpm_start_all();
+}
+
+static void __init board_gpio_setup(void)
+{
+ /*
+ * Most of the gpios have been setup in the bootloader.
+ */
+
+ __harb_usb0_uhc();
+ __gpio_as_dma();
+ __gpio_as_eth();
+ __gpio_as_usb();
+ __gpio_as_lcd_master();
+#if defined(CONFIG_I2S_AK4642EN)
+ __gpio_as_scc1();
+#endif
+#if defined(CONFIG_I2S_TSC2301) || defined(CONFIG_I2S_TLC320AIC23)
+ __gpio_as_ssi();
+#endif
+ //__gpio_as_ac97();
+#if defined(CONFIG_I2S_TSC2301) || defined(CONFIG_I2S_TLC320AIC23) || defined(CONFIG_I2S_CS42L51)
+ __gpio_as_i2s_slave();
+#endif
+ __gpio_as_cim();
+ __gpio_as_msc();
+
+ __gpio_as_output(GPIO_LED_EN);
+ __gpio_set_pin(GPIO_LED_EN);
+
+ __gpio_as_output(GPIO_DISP_OFF_N);
+ __gpio_set_pin(GPIO_DISP_OFF_N);
+ __gpio_as_output(GPIO_PWM0);
+ __gpio_set_pin(GPIO_PWM0);
+
+ __gpio_as_input(GPIO_RTC_IRQ);
+ __gpio_as_output(GPIO_USB_CLK_EN);
+ __gpio_set_pin(GPIO_USB_CLK_EN);
+
+ __gpio_as_input(GPIO_CHARG_STAT);
+ __gpio_disable_pull(GPIO_CHARG_STAT);
+
+ __gpio_as_input(GPIO_UDC_HOTPLUG);
+ __gpio_disable_pull(GPIO_UDC_HOTPLUG);
+ __gpio_disable_pull(54); /* fixed ic bug, the pull of gpio pin 86 is as pin 54 */
+}
+
+void __init jz_board_setup(void)
+{
+ printk("JZ4730 PMP board setup\n");
+
+ board_cpm_setup();
+ board_gpio_setup();
+
+ jz_timer_callback = pmp_timer_ack;
+}
diff --git a/arch/mips/jz4730/cpufreq.c b/arch/mips/jz4730/cpufreq.c
new file mode 100644
index 00000000000..1bf47136aea
--- /dev/null
+++ b/arch/mips/jz4730/cpufreq.c
@@ -0,0 +1,596 @@
+
+/*
+ * linux/arch/mips/jz4730/cpufreq.c
+ *
+ * cpufreq driver for JZ4730
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/cpufreq.h>
+
+#include <asm/jzsoc.h>
+#include <asm/processor.h>
+
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+ "cpufreq-jz4730", msg)
+
+#undef CHANGE_PLL
+
+#define PLL_UNCHANGED 0
+#define PLL_GOES_UP 1
+#define PLL_GOES_DOWN 2
+
+#define PLL_WAIT_500NS (500*(__cpm_get_iclk()/1000000000))
+
+/* Saved the boot-time parameters */
+static struct {
+ /* SDRAM parameters */
+ unsigned int mclk; /* memory clock, KHz */
+ unsigned int tras; /* RAS pulse width, cycles of mclk */
+ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */
+ unsigned int tpc; /* RAS Precharge time, cycles of mclk */
+ unsigned int trwl; /* Write Precharge Time, cycles of mclk */
+ unsigned int trc; /* RAS Cycle Time, cycles of mclk */
+ unsigned int rtcor; /* Refresh Time Constant */
+ unsigned int sdram_initialized;
+
+ /* LCD parameters */
+ unsigned int lcd_clk; /* LCD clock, Hz */
+ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */
+ unsigned int lcd_clks_initialized;
+} boot_config;
+
+struct jz4730_freq_percpu_info {
+ struct cpufreq_frequency_table table[7];
+};
+
+static struct jz4730_freq_percpu_info jz4730_freq_table;
+
+/*
+ * This contains the registers value for an operating point.
+ * If only part of a register needs to change then there is
+ * a mask value for that register.
+ * When going to a new operating point the current register
+ * value is ANDed with the ~mask and ORed with the new value.
+ */
+struct dpm_regs {
+ u32 cfcr; /* Clock Freq Control Register */
+ u32 cfcr_mask; /* Clock Freq Control Register mask */
+ u32 cfcr2; /* Clock Freq Control Register 2 */
+ u32 cfcr2_mask; /* Clock Freq Control Register 2 mask */
+ u32 plcr1; /* PLL1 Control Register */
+ u32 plcr1_mask; /* PLL1 Control Register mask */
+ u32 pll_up_flag; /* New PLL freq is higher than current or not */
+};
+
+extern jz_clocks_t jz_clocks;
+
+static void jz_update_clocks(void)
+{
+ /* Next clocks must be updated if we have changed
+ * the PLL or divisors.
+ */
+ jz_clocks.iclk = __cpm_get_iclk();
+ jz_clocks.sclk = __cpm_get_sclk();
+ jz_clocks.mclk = __cpm_get_mclk();
+ jz_clocks.pclk = __cpm_get_pclk();
+ jz_clocks.lcdclk = __cpm_get_lcdclk();
+ jz_clocks.pixclk = __cpm_get_pixclk();
+}
+
+static void
+jz_init_boot_config(void)
+{
+ if (!boot_config.lcd_clks_initialized) {
+ /* the first time to scale pll */
+ boot_config.lcd_clk = __cpm_get_lcdclk();
+ boot_config.lcdpix_clk = __cpm_get_pixclk();
+ boot_config.lcd_clks_initialized = 1;
+ }
+
+ if (!boot_config.sdram_initialized) {
+ /* the first time to scale frequencies */
+ unsigned int dmcr, rtcor;
+ unsigned int tras, rcd, tpc, trwl, trc;
+
+ dmcr = REG_EMC_DMCR;
+ rtcor = REG_EMC_RTCOR;
+
+ tras = (dmcr >> 13) & 0x7;
+ rcd = (dmcr >> 11) & 0x3;
+ tpc = (dmcr >> 8) & 0x7;
+ trwl = (dmcr >> 5) & 0x3;
+ trc = (dmcr >> 2) & 0x7;
+
+ boot_config.mclk = __cpm_get_mclk() / 1000;
+ boot_config.tras = tras + 4;
+ boot_config.rcd = rcd + 1;
+ boot_config.tpc = tpc + 1;
+ boot_config.trwl = trwl + 1;
+ boot_config.trc = trc * 2 + 1;
+ boot_config.rtcor = rtcor;
+
+ boot_config.sdram_initialized = 1;
+ }
+}
+
+static void jz_update_dram_rtcor(unsigned int new_mclk)
+{
+ unsigned int rtcor;
+
+ new_mclk /= 1000;
+ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk;
+ rtcor--;
+
+ if (rtcor < 1) rtcor = 1;
+ if (rtcor > 255) rtcor = 255;
+
+ REG_EMC_RTCOR = rtcor;
+ REG_EMC_RTCNT = rtcor;
+}
+
+static void jz_update_dram_dmcr(unsigned int new_mclk)
+{
+ unsigned int dmcr;
+ unsigned int tras, rcd, tpc, trwl, trc;
+ unsigned int valid_time, new_time; /* ns */
+
+ new_mclk /= 1000;
+ tras = boot_config.tras * new_mclk / boot_config.mclk;
+ rcd = boot_config.rcd * new_mclk / boot_config.mclk;
+ tpc = boot_config.tpc * new_mclk / boot_config.mclk;
+ trwl = boot_config.trwl * new_mclk / boot_config.mclk;
+ trc = boot_config.trc * new_mclk / boot_config.mclk;
+
+ /* Validation checking */
+ valid_time = (boot_config.tras * 1000000) / boot_config.mclk;
+ new_time = (tras * 1000000) / new_mclk;
+ if (new_time < valid_time) tras += 1;
+
+ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk;
+ new_time = (rcd * 1000000) / new_mclk;
+ if (new_time < valid_time) rcd += 1;
+
+ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk;
+ new_time = (tpc * 1000000) / new_mclk;
+ if (new_time < valid_time) tpc += 1;
+
+ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk;
+ new_time = (trwl * 1000000) / new_mclk;
+ if (new_time < valid_time) trwl += 1;
+
+ valid_time = (boot_config.trc * 1000000) / boot_config.mclk;
+ new_time = (trc * 1000000) / new_mclk;
+ if (new_time < valid_time) trc += 2;
+
+ tras = (tras < 4) ? 4: tras;
+ tras = (tras > 11) ? 11: tras;
+ tras -= 4;
+
+ rcd = (rcd < 1) ? 1: rcd;
+ rcd = (rcd > 4) ? 4: rcd;
+ rcd -= 1;
+
+ tpc = (tpc < 1) ? 1: tpc;
+ tpc = (tpc > 8) ? 8: tpc;
+ tpc -= 1;
+
+ trwl = (trwl < 1) ? 1: trwl;
+ trwl = (trwl > 4) ? 4: trwl;
+ trwl -= 1;
+
+ trc = (trc < 1) ? 1: trc;
+ trc = (trc > 15) ? 15: trc;
+ trc /= 2;
+
+ dmcr = REG_EMC_DMCR;
+
+ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK);
+ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT));
+
+ REG_EMC_DMCR = dmcr;
+}
+
+static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk)
+{
+ /* No risk, no fun: run with interrupts on! */
+ if (new_mclk > cur_mclk) {
+ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL
+ * and TRC of DMCR before changing the frequency.
+ */
+ jz_update_dram_dmcr(new_mclk);
+ } else {
+ /* We're going SLOWER: first update RTCOR value
+ * before changing the frequency.
+ */
+ jz_update_dram_rtcor(new_mclk);
+ }
+}
+
+static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk)
+{
+ /* No risk, no fun: run with interrupts on! */
+ if (new_mclk > cur_mclk) {
+ /* We're going FASTER, so update RTCOR
+ * after changing the frequency
+ */
+ jz_update_dram_rtcor(new_mclk);
+ } else {
+ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL
+ * and TRC of DMCR after changing the frequency.
+ */
+ jz_update_dram_dmcr(new_mclk);
+ }
+}
+
+static void jz_scale_divisors(struct dpm_regs *regs)
+{
+ unsigned int cfcr;
+ unsigned int cur_mclk, new_mclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned int tmp = 0, wait = PLL_WAIT_500NS;
+
+ cfcr = REG_CPM_CFCR;
+ cfcr &= ~((unsigned long)regs->cfcr_mask);
+ cfcr |= regs->cfcr;
+ cfcr |= CPM_CFCR_UPE; /* update immediately */
+
+ cur_mclk = __cpm_get_mclk();
+ new_mclk = __cpm_get_pllout() / div[(cfcr & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT];
+
+ /* Update some DRAM parameters before changing frequency */
+ jz_update_dram_prev(cur_mclk, new_mclk);
+
+ /* update register to change the clocks.
+ * align this code to a cache line.
+ */
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "li %3,0\n\t"
+ "1:\n\t"
+ "bne %3,%2,1b\n\t"
+ "addi %3, 1\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CFCR), "r" (cfcr), "r" (wait), "r" (tmp));
+
+ /* Update some other DRAM parameters after changing frequency */
+ jz_update_dram_post(cur_mclk, new_mclk);
+}
+
+#ifdef CHANGE_PLL
+/* Maintain the LCD clock and pixel clock */
+static void jz_scale_lcd_divisors(struct dpm_regs *regs)
+{
+ unsigned int new_pll, new_lcd_div, new_lcdpix_div;
+ unsigned int cfcr;
+ unsigned int tmp = 0, wait = PLL_WAIT_500NS;
+
+ if (!boot_config.lcd_clks_initialized) return;
+
+ new_pll = __cpm_get_pllout();
+ new_lcd_div = new_pll / boot_config.lcd_clk;
+ new_lcdpix_div = new_pll / boot_config.lcdpix_clk;
+
+ if (new_lcd_div < 1)
+ new_lcd_div = 1;
+ if (new_lcd_div > 16)
+ new_lcd_div = 16;
+
+ if (new_lcdpix_div < 1)
+ new_lcdpix_div = 1;
+ if (new_lcdpix_div > 512)
+ new_lcdpix_div = 512;
+
+ REG_CPM_CFCR2 = new_lcdpix_div - 1;
+
+ cfcr = REG_CPM_CFCR;
+ cfcr &= ~CPM_CFCR_LFR_MASK;
+ cfcr |= ((new_lcd_div - 1) << CPM_CFCR_LFR_BIT);
+ cfcr |= CPM_CFCR_UPE; /* update immediately */
+
+ /* update register to change the clocks.
+ * align this code to a cache line.
+ */
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "li %3,0\n\t"
+ "1:\n\t"
+ "bne %3,%2,1b\n\t"
+ "addi %3, 1\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CFCR), "r" (cfcr), "r" (wait), "r" (tmp));
+}
+
+static void jz_scale_pll(struct dpm_regs *regs)
+{
+ unsigned int plcr1;
+ unsigned int cur_mclk, new_mclk, new_pll;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ int od[] = {1, 2, 2, 4};
+
+ plcr1 = REG_CPM_PLCR1;
+ plcr1 &= ~(regs->plcr1_mask | CPM_PLCR1_PLL1S | CPM_PLCR1_PLL1EN | CPM_PLCR1_PLL1ST_MASK);
+ regs->plcr1 &= ~CPM_PLCR1_PLL1EN;
+ plcr1 |= (regs->plcr1 | 0xff);
+
+ /* Update some DRAM parameters before changing frequency */
+ new_pll = JZ_EXTAL * ((plcr1>>23)+2) / ((((plcr1>>18)&0x1f)+2) * od[(plcr1>>16)&0x03]);
+ cur_mclk = __cpm_get_mclk();
+ new_mclk = new_pll / div[(REG_CPM_CFCR>>16) & 0xf];
+
+ /*
+ * Update some SDRAM parameters
+ */
+ jz_update_dram_prev(cur_mclk, new_mclk);
+
+ /*
+ * Update PLL, align code to cache line.
+ */
+ plcr1 |= CPM_PLCR1_PLL1EN;
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_PLCR1), "r" (plcr1));
+
+ /* Update some other DRAM parameters after changing frequency */
+ jz_update_dram_post(cur_mclk, new_mclk);
+}
+#endif
+
+static void jz4730_transition(struct dpm_regs *regs)
+{
+ /*
+ * Get and save some boot-time conditions.
+ */
+ jz_init_boot_config();
+
+#ifdef CHANGE_PLL
+ /*
+ * Disable LCD before scaling pll.
+ * LCD and LCD pixel clocks should not be changed even if the PLL
+ * output frequency has been changed.
+ */
+ REG_LCD_CTRL &= ~LCD_CTRL_ENA;
+#endif
+ /*
+ * Stop module clocks before scaling PLL
+ */
+ __cpm_stop_eth();
+ __cpm_stop_aic_pclk();
+ __cpm_stop_aic_bitclk();
+
+ /* ... add more as necessary */
+
+ if (regs->pll_up_flag == PLL_GOES_UP) {
+ /* the pll frequency is going up, so change dividors first */
+ jz_scale_divisors(regs);
+#ifdef CHANGE_PLL
+ jz_scale_pll(regs);
+#endif
+ }
+ else if (regs->pll_up_flag == PLL_GOES_DOWN) {
+ /* the pll frequency is going down, so change pll first */
+#ifdef CHANGE_PLL
+ jz_scale_pll(regs);
+#endif
+ jz_scale_divisors(regs);
+ }
+ else {
+ /* the pll frequency is unchanged, so change divisors only */
+ jz_scale_divisors(regs);
+ }
+
+ /*
+ * Restart module clocks before scaling PLL
+ */
+ __cpm_start_eth();
+ __cpm_start_aic_pclk();
+ __cpm_start_aic_bitclk();
+
+ /* ... add more as necessary */
+
+#ifdef CHANGE_PLL
+ /* Scale the LCD divisors after scaling pll */
+ if (regs->pll_up_flag != PLL_UNCHANGED) {
+ jz_scale_lcd_divisors(regs);
+ }
+
+ /* Enable LCD controller */
+ REG_LCD_CTRL &= ~LCD_CTRL_DIS;
+ REG_LCD_CTRL |= LCD_CTRL_ENA;
+#endif
+
+ /* Update system clocks */
+ jz_update_clocks();
+}
+
+extern unsigned int idle_times;
+static unsigned int jz4730_freq_get(unsigned int cpu)
+{
+ return (__cpm_get_iclk() / 1000);
+}
+
+static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs)
+{
+ int n2FR[33] = {
+ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
+ 9
+ };
+ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */
+ unsigned int div_of_cclk, new_freq, i;
+
+ regs->pll_up_flag = PLL_UNCHANGED;
+ regs->cfcr_mask = CPM_CFCR_IFR_MASK | CPM_CFCR_SFR_MASK | CPM_CFCR_PFR_MASK | CPM_CFCR_MFR_MASK;
+
+ new_freq = jz4730_freq_table.table[index].frequency;
+
+ do {
+ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq);
+ } while (div_of_cclk==0);
+
+ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) {
+ for(i = 1; i<4; i++) {
+ div[i] = 3;
+ }
+ } else {
+ for(i = 1; i<4; i++) {
+ div[i] = 2;
+ }
+ }
+
+ for(i = 0; i<4; i++) {
+ div[i] *= div_of_cclk;
+ }
+
+ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]);
+
+ regs->cfcr = (n2FR[div[0]] << CPM_CFCR_IFR_BIT) |
+ (n2FR[div[1]] << CPM_CFCR_SFR_BIT) |
+ (n2FR[div[2]] << CPM_CFCR_PFR_BIT) |
+ (n2FR[div[3]] << CPM_CFCR_MFR_BIT);
+
+ return div_of_cclk;
+}
+
+static void jz4730_set_cpu_divider_index(unsigned int cpu, unsigned int index)
+{
+ unsigned long divisor, old_divisor;
+ struct cpufreq_freqs freqs;
+ struct dpm_regs regs;
+
+ old_divisor = __cpm_get_pllout() / __cpm_get_iclk();
+ divisor = index_to_divisor(index, &regs);
+
+ freqs.old = __cpm_get_iclk() / 1000;
+ freqs.new = __cpm_get_pllout() / (1000 * divisor);
+ freqs.cpu = cpu;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ if (old_divisor != divisor)
+ jz4730_transition(&regs);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+}
+
+static int jz4730_freq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int new_index = 0;
+
+ if (cpufreq_frequency_table_target(policy,
+ &jz4730_freq_table.table[0],
+ target_freq, relation, &new_index))
+ return -EINVAL;
+
+ jz4730_set_cpu_divider_index(policy->cpu, new_index);
+
+ dprintk("new frequency is %d KHz (REG_CPM_CFCR:0x%x)\n", __cpm_get_iclk() / 1000, REG_CPM_CFCR);
+
+ return 0;
+}
+
+static int jz4730_freq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy,
+ &jz4730_freq_table.table[0]);
+}
+
+static int __init jz4730_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+
+ struct cpufreq_frequency_table *table = &jz4730_freq_table.table[0];
+ unsigned int MAX_FREQ;
+
+ dprintk(KERN_INFO "Jz4730 cpufreq driver\n");
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->cur = MAX_FREQ = __cpm_get_iclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ policy->cpuinfo.min_freq = MAX_FREQ/8;
+ policy->cpuinfo.max_freq = MAX_FREQ;
+ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */
+
+ table[0].index = 0;
+ table[0].frequency = MAX_FREQ/8;
+ table[1].index = 1;
+ table[1].frequency = MAX_FREQ/6;
+ table[2].index = 2;
+ table[2].frequency = MAX_FREQ/4;
+ table[3].index = 3;
+ table[3].frequency = MAX_FREQ/3;
+ table[4].index = 4;
+ table[4].frequency = MAX_FREQ/2;
+ table[5].index = 5;
+ table[5].frequency = MAX_FREQ;
+ table[6].index = 6;
+ table[6].frequency = CPUFREQ_TABLE_END;
+
+ return cpufreq_frequency_table_cpuinfo(policy, table);
+}
+
+static struct cpufreq_driver cpufreq_jz4730_driver = {
+// .flags = CPUFREQ_STICKY,
+ .init = jz4730_cpufreq_driver_init,
+ .verify = jz4730_freq_verify,
+ .target = jz4730_freq_target,
+ .get = jz4730_freq_get,
+ .name = "jz4730",
+};
+
+static int __init jz4730_cpufreq_init(void)
+{
+ return cpufreq_register_driver(&cpufreq_jz4730_driver);
+}
+
+static void __exit jz4730_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&cpufreq_jz4730_driver);
+}
+
+module_init(jz4730_cpufreq_init);
+module_exit(jz4730_cpufreq_exit);
+
+MODULE_AUTHOR("Regen <lhhuang@ingenic.cn>");
+MODULE_DESCRIPTION("cpufreq driver for Jz4730");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/mips/jz4730/dma.c b/arch/mips/jz4730/dma.c
new file mode 100644
index 00000000000..ca7d5498ba4
--- /dev/null
+++ b/arch/mips/jz4730/dma.c
@@ -0,0 +1,509 @@
+/*
+ * linux/arch/mips/jz4730/dma.c
+ *
+ * JZ4730 DMA PC-like APIs.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/soundcard.h>
+
+#include <asm/system.h>
+#include <asm/addrspace.h>
+#include <asm/jzsoc.h>
+
+/*
+ * A note on resource allocation:
+ *
+ * All drivers needing DMA channels, should allocate and release them
+ * through the public routines `jz_request_dma()' and `jz_free_dma()'.
+ *
+ * In order to avoid problems, all processes should allocate resources in
+ * the same sequence and release them in the reverse order.
+ *
+ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ.
+ * When releasing them, first release the IRQ, then release the DMA. The
+ * main reason for this order is that, if you are requesting the DMA buffer
+ * done interrupt, you won't know the irq number until the DMA channel is
+ * returned from jz_request_dma().
+ */
+
+struct jz_dma_chan jz_dma_table[NUM_DMA] = {
+ {dev_id:-1,},
+ {dev_id:-1,},
+ {dev_id:-1,},
+ {dev_id:-1,},
+ {dev_id:-1,},
+ {dev_id:-1,},
+};
+
+
+// Device FIFO addresses and default DMA modes
+static const struct {
+ unsigned int fifo_addr;
+ unsigned int dma_mode;
+ unsigned int dma_source;
+} dma_dev_table[NUM_DMA_DEV] = {
+ {CPHYSADDR(UART0_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT},
+ {CPHYSADDR(UART0_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART0IN},
+ {CPHYSADDR(UART1_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT},
+ {CPHYSADDR(UART1_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART1IN},
+ {CPHYSADDR(UART2_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT},
+ {CPHYSADDR(UART2_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART2IN},
+ {CPHYSADDR(UART3_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT},
+ {CPHYSADDR(UART3_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART3IN},
+ {CPHYSADDR(SSI_DR), DMA_32bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_SSIOUT},
+ {CPHYSADDR(SSI_DR), DMA_32bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_SSIIN},
+ {CPHYSADDR(MSC_TXFIFO), DMA_32bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_MSCOUT},
+ {CPHYSADDR(MSC_RXFIFO), DMA_32bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_MSCIN},
+ {CPHYSADDR(AIC_DR), DMA_32bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT},
+ {CPHYSADDR(AIC_DR), DMA_32bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_AICIN},
+ {0, DMA_AUTOINIT, 0},
+};
+
+
+int jz_dma_read_proc(char *buf, char **start, off_t fpos,
+ int length, int *eof, void *data)
+{
+ int i, len = 0;
+ struct jz_dma_chan *chan;
+
+ for (i = 0; i < NUM_DMA; i++) {
+ if ((chan = get_dma_chan(i)) != NULL) {
+ len += sprintf(buf + len, "%2d: %s\n",
+ i, chan->dev_str);
+ }
+ }
+
+ if (fpos >= len) {
+ *start = buf;
+ *eof = 1;
+ return 0;
+ }
+ *start = buf + fpos;
+ if ((len -= fpos) > length)
+ return length;
+ *eof = 1;
+ return len;
+}
+
+
+void dump_jz_dma_channel(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan;
+
+ if (dmanr > NUM_DMA)
+ return;
+ chan = &jz_dma_table[dmanr];
+
+ printk(KERN_INFO "DMA%d Register Dump:\n", dmanr);
+ printk(KERN_INFO " DMACR= 0x%08x\n", REG_DMAC_DMACR);
+ printk(KERN_INFO " DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr));
+ printk(KERN_INFO " DDAR = 0x%08x\n", REG_DMAC_DDAR(dmanr));
+ printk(KERN_INFO " DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr));
+ printk(KERN_INFO " DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr));
+ printk(KERN_INFO " DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr));
+}
+
+
+/**
+ * jz_request_dma - dynamically allcate an idle DMA channel to return
+ * @dev_id: the specified dma device id or DMA_ID_RAW_REQ
+ * @dev_str: the specified dma device string name
+ * @irqhandler: the irq handler, or NULL
+ * @irqflags: the irq handler flags
+ * @irq_dev_id: the irq handler device id for shared irq
+ *
+ * Finds a free channel, and binds the requested device to it.
+ * Returns the allocated channel number, or negative on error.
+ * Requests the DMA done IRQ if irqhandler != NULL.
+ *
+*/
+int jz_request_dma(int dev_id, const char *dev_str,
+ irqreturn_t (*irqhandler)(int, void *),
+ unsigned long irqflags,
+ void *irq_dev_id)
+{
+ struct jz_dma_chan *chan;
+ int i, ret;
+
+ if (dev_id < 0 || dev_id >= NUM_DMA_DEV)
+ return -EINVAL;
+
+ for (i = 0; i < NUM_DMA; i++) {
+ if (jz_dma_table[i].dev_id < 0)
+ break;
+ }
+ if (i == NUM_DMA)
+ return -ENODEV;
+
+ chan = &jz_dma_table[i];
+
+ if (irqhandler) {
+ chan->irq = IRQ_DMA_0 + i; // see intc.h
+ chan->irq_dev = irq_dev_id;
+ if ((ret = request_irq(chan->irq, irqhandler, irqflags,
+ dev_str, chan->irq_dev))) {
+ chan->irq = 0;
+ chan->irq_dev = NULL;
+ return ret;
+ }
+ } else {
+ chan->irq = 0;
+ chan->irq_dev = NULL;
+ }
+
+ // fill it in
+ chan->io = i;
+ chan->dev_id = dev_id;
+ chan->dev_str = dev_str;
+ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
+ chan->mode = dma_dev_table[dev_id].dma_mode;
+ chan->source = dma_dev_table[dev_id].dma_source;
+
+ return i;
+}
+
+void jz_free_dma(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan) {
+ printk("Trying to free DMA%d\n", dmanr);
+ return;
+ }
+
+ disable_dma(dmanr);
+ if (chan->irq)
+ free_irq(chan->irq, chan->irq_dev);
+
+ chan->irq = 0;
+ chan->irq_dev = NULL;
+ chan->dev_id = -1;
+}
+
+void jz_set_dma_dest_width(int dmanr, int nbit)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ chan->mode &= ~DMAC_DCCSR_DWDH_MASK;
+ switch (nbit) {
+ case 8:
+ chan->mode |= DMAC_DCCSR_DWDH_8;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCCSR_DWDH_16;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCCSR_DWDH_32;
+ break;
+ }
+}
+
+void jz_set_dma_src_width(int dmanr, int nbit)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ chan->mode &= ~DMAC_DCCSR_SWDH_MASK;
+ switch (nbit) {
+ case 8:
+ chan->mode |= DMAC_DCCSR_SWDH_8;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCCSR_SWDH_16;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCCSR_SWDH_32;
+ break;
+ }
+}
+
+void jz_set_dma_block_size(int dmanr, int nbyte)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ chan->mode &= ~DMAC_DCCSR_DS_MASK;
+ switch (nbyte) {
+ case 1:
+ chan->mode |= DMAC_DCCSR_DS_8b;
+ break;
+ case 2:
+ chan->mode |= DMAC_DCCSR_DS_16b;
+ break;
+ case 4:
+ chan->mode |= DMAC_DCCSR_DS_32b;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCCSR_DS_16B;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCCSR_DS_32B;
+ break;
+ }
+}
+
+/**
+ * jz_set_dma_mode - do the raw settings for the specified DMA channel
+ * @dmanr: the specified DMA channel
+ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE
+ * @dma_mode: dma raw mode
+ * @dma_source: dma raw request source
+ * @fifo_addr: dma raw device fifo address
+ *
+ * Ensure call jz_request_dma(DMA_ID_RAW_REQ, ...) first, then call
+ * jz_set_dma_mode() rather than set_dma_mode() if you work with
+ * and external request dma device.
+ *
+ * NOTE: Don not dynamically allocate dma channel if one external request
+ * dma device will occupy this channel.
+*/
+int jz_set_dma_mode(unsigned int dmanr, unsigned int mode,
+ unsigned int dma_mode, unsigned int dma_source,
+ unsigned int fifo_addr)
+{
+ int dev_id, i;
+ struct jz_dma_chan *chan;
+
+ if (dmanr > NUM_DMA)
+ return -ENODEV;
+ for (i = 0; i < NUM_DMA; i++) {
+ if (jz_dma_table[i].dev_id < 0)
+ break;
+ }
+ if (i == NUM_DMA)
+ return -ENODEV;
+
+ chan = &jz_dma_table[dmanr];
+ dev_id = chan->dev_id;
+ if (dev_id > 0) {
+ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n",
+ __FUNCTION__, dmanr);
+ return -ENODEV;
+ }
+
+ /* clone it from the dynamically allocated. */
+ if (i != dmanr) {
+ chan->irq = jz_dma_table[i].irq;
+ chan->irq_dev = jz_dma_table[i].irq_dev;
+ chan->dev_str = jz_dma_table[i].dev_str;
+ jz_dma_table[i].irq = 0;
+ jz_dma_table[i].irq_dev = NULL;
+ jz_dma_table[i].dev_id = -1;
+ }
+ chan->dev_id = DMA_ID_RAW_SET;
+ chan->io = dmanr;
+ chan->fifo_addr = fifo_addr;
+ chan->mode = dma_mode;
+ chan->source = dma_source;
+
+ set_dma_mode(dmanr, dma_mode);
+
+ return dmanr;
+}
+
+void enable_dma(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+
+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR);
+ __dmac_enable_channel(dmanr);
+ if (chan->irq)
+ __dmac_channel_enable_irq(dmanr);
+}
+
+#define DMA_DISABLE_POLL 0x5000
+
+void disable_dma(unsigned int dmanr)
+{
+ int i;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ if (!__dmac_channel_enabled(dmanr))
+ return;
+
+ for (i = 0; i < DMA_DISABLE_POLL; i++)
+ if (__dmac_channel_transmit_end_detected(dmanr))
+ break;
+#if 0
+ if (i == DMA_DISABLE_POLL)
+ printk(KERN_INFO "disable_dma: poll expired!\n");
+#endif
+
+ __dmac_disable_channel(dmanr);
+ if (chan->irq)
+ __dmac_channel_disable_irq(dmanr);
+}
+
+/* note: DMA_MODE_MASK is simulated by sw, DCCSR_MODE_MASK mask hw bits */
+void set_dma_mode(unsigned int dmanr, unsigned int mode)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR);
+ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM);
+ mode &= DMA_MODE_MASK;
+ if (mode == DMA_MODE_READ) {
+ chan->mode |= DMAC_DCCSR_DAM;
+ chan->mode &= ~DMAC_DCCSR_SAM;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode |= DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM;
+ chan->mode &= ~DMAC_DCCSR_DAM;
+ } else {
+ printk(KERN_DEBUG "set_dma_mode() support DMA_MODE_READ or DMA_MODE_WRITE!\n");
+ }
+ REG_DMAC_DCCSR(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+}
+
+void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ switch (audio_fmt) {
+ case AFMT_U8:
+ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
+ break;
+ case AFMT_S16_LE:
+ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
+ if (mode == DMA_MODE_READ) {
+ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR);
+ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ;
+ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCCSR_DAM;
+ chan->mode &= ~DMAC_DCCSR_SAM;
+ } else if (mode == DMA_MODE_WRITE) {
+ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR);
+ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM |DMAC_DCCSR_DAM);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM;
+ chan->mode &= ~DMAC_DCCSR_DAM;
+ } else
+ printk("jz_set_oss_dma() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+
+ REG_DMAC_DCCSR(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+ break;
+ }
+}
+
+void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ switch (audio_fmt) {
+ case 8:
+ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
+ break;
+ case 16:
+ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
+ if (mode == DMA_MODE_READ) {
+ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR);
+ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ;
+ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCCSR_DAM;
+ chan->mode &= ~DMAC_DCCSR_SAM;
+ } else if (mode == DMA_MODE_WRITE) {
+ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR);
+ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM;
+ chan->mode &= ~DMAC_DCCSR_DAM;
+ } else
+ printk("jz_set_alsa_dma() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+
+ REG_DMAC_DCCSR(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+ break;
+ }
+}
+
+void set_dma_addr(unsigned int dmanr, unsigned int a)
+{
+ unsigned int mode;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ mode = chan->mode & DMA_MODE_MASK;
+ if (mode == DMA_MODE_READ) {
+ REG_DMAC_DSAR(chan->io) = chan->fifo_addr;
+ REG_DMAC_DDAR(chan->io) = a;
+ } else if (mode == DMA_MODE_WRITE) {
+ REG_DMAC_DSAR(chan->io) = a;
+ REG_DMAC_DDAR(chan->io) = chan->fifo_addr;
+ } else
+ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n");
+}
+
+void set_dma_count(unsigned int dmanr, unsigned int count)
+{
+ unsigned int mode;
+ int dma_ds[] = {4, 1, 2, 16, 32};
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return;
+ mode = (chan->mode & DMAC_DCCSR_DS_MASK) >> DMAC_DCCSR_DS_BIT;
+ count = count / dma_ds[mode];
+ REG_DMAC_DTCR(chan->io) = count;
+}
+
+int get_dma_residue(unsigned int dmanr)
+{
+ int count;
+ unsigned int mode;
+ int dma_ds[] = {4, 1, 2, 16, 32};
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+
+ mode = (chan->mode & DMAC_DCCSR_DS_MASK) >> DMAC_DCCSR_DS_BIT;
+ count = REG_DMAC_DTCR(chan->io);
+ count = count * dma_ds[mode];
+
+ return count;
+}
+
+EXPORT_SYMBOL(jz_dma_table);
+EXPORT_SYMBOL(jz_request_dma);
+EXPORT_SYMBOL(jz_free_dma);
+EXPORT_SYMBOL(jz_set_dma_src_width);
+EXPORT_SYMBOL(jz_set_dma_dest_width);
+EXPORT_SYMBOL(jz_set_dma_block_size);
+EXPORT_SYMBOL(jz_set_dma_mode);
+EXPORT_SYMBOL(set_dma_mode);
+EXPORT_SYMBOL(jz_set_oss_dma);
+EXPORT_SYMBOL(jz_set_alsa_dma);
+EXPORT_SYMBOL(set_dma_addr);
+EXPORT_SYMBOL(set_dma_count);
+EXPORT_SYMBOL(get_dma_residue);
+EXPORT_SYMBOL(enable_dma);
+EXPORT_SYMBOL(disable_dma);
+EXPORT_SYMBOL(dump_jz_dma_channel);
diff --git a/arch/mips/jz4730/i2c.c b/arch/mips/jz4730/i2c.c
new file mode 100644
index 00000000000..91f55a7a34c
--- /dev/null
+++ b/arch/mips/jz4730/i2c.c
@@ -0,0 +1,214 @@
+/*
+ * linux/arch/mips/jz4730/i2c.c
+ *
+ * JZ4730 I2C APIs.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/addrspace.h>
+
+#include <asm/jzsoc.h>
+
+/* I2C protocol */
+#define I2C_READ 1
+#define I2C_WRITE 0
+
+#define TIMEOUT 1000
+
+/*
+ * I2C bus protocol basic routines
+ */
+static int i2c_put_data(unsigned char data)
+{
+ unsigned int timeout = TIMEOUT * 10;
+
+ __i2c_write(data);
+ __i2c_set_drf();
+ while (__i2c_check_drf() != 0);
+ while (!__i2c_transmit_ended());
+ while (!__i2c_received_ack() && timeout)
+ timeout--;
+
+ if (timeout)
+ return 0;
+ else
+ return -ETIMEDOUT;
+}
+
+static int i2c_get_data(unsigned char *data, int ack)
+{
+ int timeout = TIMEOUT*10;
+
+ if (!ack)
+ __i2c_send_nack();
+ else
+ __i2c_send_ack();
+
+ while (__i2c_check_drf() == 0 && timeout)
+ timeout--;
+
+ if (timeout) {
+ if (!ack)
+ __i2c_send_stop();
+ *data = __i2c_read();
+ __i2c_clear_drf();
+ return 0;
+ } else
+ return -ETIMEDOUT;
+}
+
+/*
+ * I2C interface
+ */
+void i2c_open(void)
+{
+ __i2c_set_clk(jz_clocks.devclk, 10000); /* default 10 KHz */
+ __i2c_enable();
+}
+
+void i2c_close(void)
+{
+ udelay(300); /* wait for STOP goes over. */
+ __i2c_disable();
+}
+
+void i2c_setclk(unsigned int i2cclk)
+{
+ __i2c_set_clk(jz_clocks.devclk, i2cclk);
+}
+
+int i2c_lseek(unsigned char device, unsigned char offset)
+{
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_err;
+ if (i2c_put_data(offset) < 0)
+ goto address_err;
+ return 0;
+ device_err:
+ printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device);
+ __i2c_send_stop();
+ return -ENODEV;
+ address_err:
+ printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device);
+ __i2c_send_stop();
+ return -EREMOTEIO;
+}
+
+int i2c_read(unsigned char device, unsigned char *buf,
+ unsigned char address, int count)
+{
+ int cnt = count;
+ int timeout = 5;
+
+L_try_again:
+
+ if (timeout < 0)
+ goto L_timeout;
+
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_werr;
+ if (i2c_put_data(address) < 0)
+ goto address_err;
+
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_READ ) < 0)
+ goto device_rerr;
+ __i2c_send_ack(); /* Master sends ACK for continue reading */
+ while (cnt) {
+ if (cnt == 1) {
+ if (i2c_get_data(buf, 0) < 0)
+ break;
+ } else {
+ if (i2c_get_data(buf, 1) < 0)
+ break;
+ }
+ cnt--;
+ buf++;
+ }
+
+ __i2c_send_stop();
+ return count - cnt;
+ device_rerr:
+ device_werr:
+ address_err:
+ timeout --;
+ __i2c_send_stop();
+ goto L_try_again;
+
+L_timeout:
+ __i2c_send_stop();
+ printk("Read I2C device 0x%2x failed.\n", device);
+ return -ENODEV;
+}
+
+int i2c_write(unsigned char device, unsigned char *buf,
+ unsigned char address, int count)
+{
+ int cnt = count;
+ int cnt_in_pg;
+ int timeout = 5;
+ unsigned char *tmpbuf;
+ unsigned char tmpaddr;
+
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+
+ W_try_again:
+ if (timeout < 0)
+ goto W_timeout;
+
+ cnt = count;
+ tmpbuf = (unsigned char *)buf;
+ tmpaddr = address;
+
+ start_write_page:
+ cnt_in_pg = 0;
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_err;
+ if (i2c_put_data(tmpaddr) < 0)
+ goto address_err;
+ while (cnt) {
+ if (++cnt_in_pg > 8) {
+ __i2c_send_stop();
+ mdelay(1);
+ tmpaddr += 8;
+ goto start_write_page;
+ }
+ if (i2c_put_data(*tmpbuf) < 0)
+ break;
+ cnt--;
+ tmpbuf++;
+ }
+ __i2c_send_stop();
+ return count - cnt;
+ device_err:
+ address_err:
+ timeout--;
+ __i2c_send_stop();
+ goto W_try_again;
+
+ W_timeout:
+ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device);
+ __i2c_send_stop();
+ return -ENODEV;
+}
+
+EXPORT_SYMBOL(i2c_open);
+EXPORT_SYMBOL(i2c_close);
+EXPORT_SYMBOL(i2c_setclk);
+EXPORT_SYMBOL(i2c_read);
+EXPORT_SYMBOL(i2c_write);
diff --git a/arch/mips/jz4730/irq.c b/arch/mips/jz4730/irq.c
new file mode 100644
index 00000000000..393393d37b5
--- /dev/null
+++ b/arch/mips/jz4730/irq.c
@@ -0,0 +1,267 @@
+/*
+ * linux/arch/mips/jz4730/irq.c
+ *
+ * JZ4730 interrupt routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+/*
+ * INTC irq type
+ */
+
+static void enable_intc_irq(unsigned int irq)
+{
+ __intc_unmask_irq(irq);
+}
+
+static void disable_intc_irq(unsigned int irq)
+{
+ __intc_mask_irq(irq);
+}
+
+static void mask_and_ack_intc_irq(unsigned int irq)
+{
+ __intc_mask_irq(irq);
+ __intc_ack_irq(irq);
+}
+
+static void end_intc_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_intc_irq(irq);
+ }
+}
+
+static unsigned int startup_intc_irq(unsigned int irq)
+{
+ enable_intc_irq(irq);
+ return 0;
+}
+
+static void shutdown_intc_irq(unsigned int irq)
+{
+ disable_intc_irq(irq);
+}
+
+static struct irq_chip intc_irq_type = {
+ .typename = "INTC",
+ .startup = startup_intc_irq,
+ .shutdown = shutdown_intc_irq,
+ .unmask = enable_intc_irq,
+ .mask = disable_intc_irq,
+ .ack = mask_and_ack_intc_irq,
+ .end = end_intc_irq,
+};
+
+/*
+ * GPIO irq type
+ */
+
+static void enable_gpio_irq(unsigned int irq)
+{
+ unsigned int intc_irq;
+
+ if (irq < (IRQ_GPIO_0 + 32)) {
+ intc_irq = IRQ_GPIO0;
+ }
+ else if (irq < (IRQ_GPIO_0 + 64)) {
+ intc_irq = IRQ_GPIO1;
+ }
+ else if (irq < (IRQ_GPIO_0 + 96)) {
+ intc_irq = IRQ_GPIO2;
+ }
+ else {
+ intc_irq = IRQ_GPIO3;
+ }
+
+ enable_intc_irq(intc_irq);
+ __gpio_unmask_irq(irq - IRQ_GPIO_0);
+}
+
+static void disable_gpio_irq(unsigned int irq)
+{
+ __gpio_mask_irq(irq - IRQ_GPIO_0);
+}
+
+static void mask_and_ack_gpio_irq(unsigned int irq)
+{
+ __gpio_mask_irq(irq - IRQ_GPIO_0);
+ __gpio_ack_irq(irq - IRQ_GPIO_0);
+}
+
+static void end_gpio_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_gpio_irq(irq);
+ }
+}
+
+static unsigned int startup_gpio_irq(unsigned int irq)
+{
+ enable_gpio_irq(irq);
+ return 0;
+}
+
+static void shutdown_gpio_irq(unsigned int irq)
+{
+ disable_gpio_irq(irq);
+}
+
+static struct irq_chip gpio_irq_type = {
+ .typename = "GPIO",
+ .startup = startup_gpio_irq,
+ .shutdown = shutdown_gpio_irq,
+ .unmask = enable_gpio_irq,
+ .mask = disable_gpio_irq,
+ .ack = mask_and_ack_gpio_irq,
+ .end = end_gpio_irq,
+};
+
+/*
+ * DMA irq type
+ */
+
+static void enable_dma_irq(unsigned int irq)
+{
+ __intc_unmask_irq(IRQ_DMAC);
+ __dmac_channel_enable_irq(irq - IRQ_DMA_0);
+}
+
+static void disable_dma_irq(unsigned int irq)
+{
+ __dmac_channel_disable_irq(irq - IRQ_DMA_0);
+}
+
+static void mask_and_ack_dma_irq(unsigned int irq)
+{
+ __intc_ack_irq(IRQ_DMAC);
+ __dmac_channel_disable_irq(irq - IRQ_DMA_0);
+}
+
+static void end_dma_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_dma_irq(irq);
+ }
+}
+
+static unsigned int startup_dma_irq(unsigned int irq)
+{
+ enable_dma_irq(irq);
+ return 0;
+}
+
+static void shutdown_dma_irq(unsigned int irq)
+{
+ disable_dma_irq(irq);
+}
+
+static struct irq_chip dma_irq_type = {
+ .typename = "DMA",
+ .startup = startup_dma_irq,
+ .shutdown = shutdown_dma_irq,
+ .unmask = enable_dma_irq,
+ .mask = disable_dma_irq,
+ .ack = mask_and_ack_dma_irq,
+ .end = end_dma_irq,
+};
+
+//----------------------------------------------------------------------
+
+void __init arch_init_irq(void)
+{
+ int i;
+
+ clear_c0_status(0xff04); /* clear ERL */
+ set_c0_status(0x0400); /* set IP2 */
+
+ /* Set up INTC irq
+ */
+ for (i = 0; i < 32; i++) {
+ disable_intc_irq(i);
+ set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq);
+
+ }
+
+ /* Set up DMAC irq
+ */
+ for (i = 0; i < NUM_DMA; i++) {
+ disable_dma_irq(IRQ_DMA_0 + i);
+ set_irq_chip_and_handler(IRQ_DMA_0 + i, &dma_irq_type, handle_level_irq);
+ }
+
+ /* Set up GPIO irq
+ */
+ for (i = 0; i < NUM_GPIO; i++) {
+ disable_gpio_irq(IRQ_GPIO_0 + i);
+ set_irq_chip_and_handler(IRQ_GPIO_0 + i, &gpio_irq_type, handle_level_irq);
+ }
+}
+
+static int plat_real_irq(int irq)
+{
+ switch (irq) {
+ case IRQ_GPIO0:
+ irq = __gpio_group_irq(0) + IRQ_GPIO_0;
+ break;
+ case IRQ_GPIO1:
+ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32;
+ break;
+ case IRQ_GPIO2:
+ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64;
+ break;
+ case IRQ_GPIO3:
+ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96;
+ break;
+ case IRQ_DMAC:
+ irq = __dmac_get_irq() + IRQ_DMA_0;
+ break;
+ }
+
+ return irq;
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ int irq = 0;
+ static unsigned long intc_ipr = 0;
+
+ intc_ipr |= REG_INTC_IPR;
+
+ if (!intc_ipr) return;
+
+ irq = ffs(intc_ipr) - 1;
+ intc_ipr &= ~(1<<irq);
+
+ irq = plat_real_irq(irq);
+
+ do_IRQ(irq);
+}
diff --git a/arch/mips/jz4730/platform.c b/arch/mips/jz4730/platform.c
new file mode 100644
index 00000000000..2e3b47c7c2e
--- /dev/null
+++ b/arch/mips/jz4730/platform.c
@@ -0,0 +1,140 @@
+/*
+ * Platform device support for Jz4730 SoC.
+ *
+ * Copyright 2007, Peter <jlwei@ingenic.cn>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/resource.h>
+
+#include <asm/jzsoc.h>
+
+/* OHCI (USB full speed host controller) */
+static struct resource jz_usb_ohci_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap
+ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_UHC,
+ .end = IRQ_UHC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32)0;
+
+static struct platform_device jz_usb_ohci_device = {
+ .name = "jz-ohci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ohci_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources),
+ .resource = jz_usb_ohci_resources,
+};
+
+/*** LCD controller ***/
+static struct resource jz_lcd_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(LCD_BASE),
+ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_LCD,
+ .end = IRQ_LCD,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 jz_lcd_dmamask = ~(u32)0;
+
+static struct platform_device jz_lcd_device = {
+ .name = "jz-lcd",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_lcd_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_lcd_resources),
+ .resource = jz_lcd_resources,
+};
+
+/* UDC (USB gadget controller) */
+static struct resource jz_usb_gdt_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(UDC_BASE),
+ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_UDC,
+ .end = IRQ_UDC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 udc_dmamask = ~(u32)0;
+
+static struct platform_device jz_usb_gdt_device = {
+ .name = "jz-udc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &udc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources),
+ .resource = jz_usb_gdt_resources,
+};
+
+/** MMC/SD controller **/
+static struct resource jz_mmc_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(MSC_BASE),
+ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_MSC,
+ .end = IRQ_MSC,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 jz_mmc_dmamask = ~(u32)0;
+
+static struct platform_device jz_mmc_device = {
+ .name = "jz-mmc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_mmc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_mmc_resources),
+ .resource = jz_mmc_resources,
+};
+
+/* All */
+static struct platform_device *jz_platform_devices[] __initdata = {
+ &jz_usb_ohci_device,
+ &jz_lcd_device,
+ &jz_usb_gdt_device,
+ &jz_mmc_device,
+};
+
+static int __init jz_platform_init(void)
+{
+ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
+}
+
+arch_initcall(jz_platform_init);
diff --git a/arch/mips/jz4730/pm.c b/arch/mips/jz4730/pm.c
new file mode 100644
index 00000000000..a46e9c39140
--- /dev/null
+++ b/arch/mips/jz4730/pm.c
@@ -0,0 +1,1098 @@
+/*
+ * linux/arch/mips/jz4730/pm.c
+ *
+ * Jz4730 Power Management Routines
+ *
+ * Copyright 2005 Ingenic Semiconductor
+ * Wei Jianli <jlwei@ingenic.cn>
+ * Huang Lihong<lhhuang@ingenic.cn>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/pm_legacy.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+
+#include <asm/cacheops.h>
+#include <asm/jzsoc.h>
+
+extern void jz_cpu_suspend(void);
+extern void jz_cpu_resume(void);
+
+static void jz_board_pm_suspend(void);
+
+#define SAVE(x,s) sleep_save[SLEEP_SAVE_##x] = REG##s(x)
+#define RESTORE(x,s) REG##s(x) = sleep_save[SLEEP_SAVE_##x]
+
+/*
+ * List of global jz4730 peripheral registers to preserve.
+ * More ones like core register and general purpose register values
+ * are preserved with the stack pointer in sleep.S.
+ */
+enum { SLEEP_SAVE_START = 0,
+
+ /* CPM */
+ SLEEP_SAVE_CPM_MSCR, SLEEP_SAVE_CPM_PLCR1,
+
+ /* WDT */
+ SLEEP_SAVE_WDT_WTCNT, SLEEP_SAVE_WDT_WTCSR,
+
+ /* OST */
+ SLEEP_SAVE_OST_TER,
+ SLEEP_SAVE_OST_TCSR0, SLEEP_SAVE_OST_TCSR1, SLEEP_SAVE_OST_TCSR2,
+ SLEEP_SAVE_OST_TRDR0, SLEEP_SAVE_OST_TRDR1, SLEEP_SAVE_OST_TRDR2,
+ SLEEP_SAVE_OST_TCNT0, SLEEP_SAVE_OST_TCNT1, SLEEP_SAVE_OST_TCNT2,
+
+ /* HARB */
+ SLEEP_SAVE_HARB_HAPOR, SLEEP_SAVE_HARB_HMCTR, SLEEP_SAVE_HARB_HMLTR,
+
+ /* EMC */
+ SLEEP_SAVE_EMC_SMCR0, SLEEP_SAVE_EMC_SMCR1, SLEEP_SAVE_EMC_SMCR2, SLEEP_SAVE_EMC_SMCR3,
+ SLEEP_SAVE_EMC_SMCR4, SLEEP_SAVE_EMC_SMCR5,
+
+ /* GPIO */
+ SLEEP_SAVE_GPIO_GPDR0, SLEEP_SAVE_GPIO_GPDR1, SLEEP_SAVE_GPIO_GPDR2, SLEEP_SAVE_GPIO_GPDR3,
+ SLEEP_SAVE_GPIO_GPDIR0, SLEEP_SAVE_GPIO_GPDIR1, SLEEP_SAVE_GPIO_GPDIR2, SLEEP_SAVE_GPIO_GPDIR3,
+ SLEEP_SAVE_GPIO_GPODR0, SLEEP_SAVE_GPIO_GPODR1, SLEEP_SAVE_GPIO_GPODR2, SLEEP_SAVE_GPIO_GPODR3,
+ SLEEP_SAVE_GPIO_GPPUR0, SLEEP_SAVE_GPIO_GPPUR1, SLEEP_SAVE_GPIO_GPPUR2, SLEEP_SAVE_GPIO_GPPUR3,
+ SLEEP_SAVE_GPIO_GPALR0, SLEEP_SAVE_GPIO_GPALR1, SLEEP_SAVE_GPIO_GPALR2, SLEEP_SAVE_GPIO_GPALR3,
+ SLEEP_SAVE_GPIO_GPAUR0, SLEEP_SAVE_GPIO_GPAUR1, SLEEP_SAVE_GPIO_GPAUR2, SLEEP_SAVE_GPIO_GPAUR3,
+ SLEEP_SAVE_GPIO_GPIDLR0, SLEEP_SAVE_GPIO_GPIDLR1, SLEEP_SAVE_GPIO_GPIDLR2, SLEEP_SAVE_GPIO_GPIDLR3,
+ SLEEP_SAVE_GPIO_GPIDUR0, SLEEP_SAVE_GPIO_GPIDUR1, SLEEP_SAVE_GPIO_GPIDUR2, SLEEP_SAVE_GPIO_GPIDUR3,
+ SLEEP_SAVE_GPIO_GPIER0, SLEEP_SAVE_GPIO_GPIER1, SLEEP_SAVE_GPIO_GPIER2, SLEEP_SAVE_GPIO_GPIER3,
+ SLEEP_SAVE_GPIO_GPIMR0, SLEEP_SAVE_GPIO_GPIMR1, SLEEP_SAVE_GPIO_GPIMR2, SLEEP_SAVE_GPIO_GPIMR3,
+ SLEEP_SAVE_GPIO_GPFR0, SLEEP_SAVE_GPIO_GPFR1, SLEEP_SAVE_GPIO_GPFR2, SLEEP_SAVE_GPIO_GPFR3,
+
+ /* UART(0-3) */
+ SLEEP_SAVE_UART0_IER, SLEEP_SAVE_UART0_LCR, SLEEP_SAVE_UART0_MCR, SLEEP_SAVE_UART0_SPR, SLEEP_SAVE_UART0_DLLR, SLEEP_SAVE_UART0_DLHR,
+ SLEEP_SAVE_UART1_IER, SLEEP_SAVE_UART1_LCR, SLEEP_SAVE_UART1_MCR, SLEEP_SAVE_UART1_SPR, SLEEP_SAVE_UART1_DLLR, SLEEP_SAVE_UART1_DLHR,
+ SLEEP_SAVE_UART2_IER, SLEEP_SAVE_UART2_LCR, SLEEP_SAVE_UART2_MCR, SLEEP_SAVE_UART2_SPR, SLEEP_SAVE_UART2_DLLR, SLEEP_SAVE_UART2_DLHR,
+ SLEEP_SAVE_UART3_IER, SLEEP_SAVE_UART3_LCR, SLEEP_SAVE_UART3_MCR, SLEEP_SAVE_UART3_SPR, SLEEP_SAVE_UART3_DLLR, SLEEP_SAVE_UART3_DLHR,
+
+ /* DMAC */
+ SLEEP_SAVE_DMAC_DMACR,
+ SLEEP_SAVE_DMAC_DSAR0, SLEEP_SAVE_DMAC_DSAR1, SLEEP_SAVE_DMAC_DSAR2, SLEEP_SAVE_DMAC_DSAR3, SLEEP_SAVE_DMAC_DSAR4, SLEEP_SAVE_DMAC_DSAR5, SLEEP_SAVE_DMAC_DSAR6, SLEEP_SAVE_DMAC_DSAR7,
+ SLEEP_SAVE_DMAC_DDAR0, SLEEP_SAVE_DMAC_DDAR1, SLEEP_SAVE_DMAC_DDAR2, SLEEP_SAVE_DMAC_DDAR3, SLEEP_SAVE_DMAC_DDAR4, SLEEP_SAVE_DMAC_DDAR5, SLEEP_SAVE_DMAC_DDAR6, SLEEP_SAVE_DMAC_DDAR7,
+ SLEEP_SAVE_DMAC_DTCR0, SLEEP_SAVE_DMAC_DTCR1, SLEEP_SAVE_DMAC_DTCR2, SLEEP_SAVE_DMAC_DTCR3, SLEEP_SAVE_DMAC_DTCR4, SLEEP_SAVE_DMAC_DTCR5, SLEEP_SAVE_DMAC_DTCR6, SLEEP_SAVE_DMAC_DTCR7,
+ SLEEP_SAVE_DMAC_DRSR0, SLEEP_SAVE_DMAC_DRSR1, SLEEP_SAVE_DMAC_DRSR2, SLEEP_SAVE_DMAC_DRSR3, SLEEP_SAVE_DMAC_DRSR4, SLEEP_SAVE_DMAC_DRSR5, SLEEP_SAVE_DMAC_DRSR6, SLEEP_SAVE_DMAC_DRSR7,
+ SLEEP_SAVE_DMAC_DCCSR0, SLEEP_SAVE_DMAC_DCCSR1, SLEEP_SAVE_DMAC_DCCSR2, SLEEP_SAVE_DMAC_DCCSR3, SLEEP_SAVE_DMAC_DCCSR4, SLEEP_SAVE_DMAC_DCCSR5, SLEEP_SAVE_DMAC_DCCSR6, SLEEP_SAVE_DMAC_DCCSR7,
+
+ /* INTC */
+ SLEEP_SAVE_INTC_IPR, SLEEP_SAVE_INTC_ISR, SLEEP_SAVE_INTC_IMR,
+
+ /* Checksum */
+ SLEEP_SAVE_CKSUM,
+
+ SLEEP_SAVE_SIZE
+};
+
+static unsigned long sleep_save[SLEEP_SAVE_SIZE];
+
+static int jz_pm_do_suspend(void)
+{
+ unsigned long checksum = 0;
+ unsigned long imr = REG_INTC_IMR;
+ int i;
+
+ printk("Put cpu into suspend mode.\n");
+
+ /* Mask all interrupts */
+ REG_INTC_IMSR = 0xffffffff;
+
+ /* Preserve current time */
+ REG_RTC_RSR = xtime.tv_sec;
+
+ REG_CPM_OCR |= CPM_OCR_SUSPEND_PHY0; /* suspend USB PHY 0 */
+ REG_CPM_OCR |= CPM_OCR_SUSPEND_PHY1; /* suspend USB PHY 1 */
+ REG_CPM_OCR |= CPM_OCR_EXT_RTC_CLK; /* select the external RTC clock (32.768KHz) */
+
+ /* Disable NAND ctroller */
+ REG_EMC_NFCSR &= ~(EMC_NFCSR_NFE | EMC_NFCSR_FCE);
+
+ /*
+ * Temporary solution. This won't be necessary once
+ * we move this support into the device drivers.
+ * Save the on-chip modules
+ */
+ SAVE(UART0_LCR, 8); SAVE(UART0_MCR, 8); SAVE(UART0_SPR, 8);
+ REG8(UART0_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
+ SAVE(UART0_DLLR, 8); SAVE(UART0_DLHR, 8);
+ REG8(UART0_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
+ SAVE(UART0_IER, 8);
+
+ SAVE(UART1_LCR, 8); SAVE(UART1_MCR, 8); SAVE(UART1_SPR, 8);
+ REG8(UART1_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
+ SAVE(UART1_DLLR, 8); SAVE(UART1_DLHR, 8);
+ REG8(UART1_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
+ SAVE(UART1_IER, 8);
+
+ SAVE(UART2_LCR, 8); SAVE(UART2_MCR, 8); SAVE(UART2_SPR, 8);
+ REG8(UART2_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
+ SAVE(UART2_DLLR, 8); SAVE(UART2_DLHR, 8);
+ REG8(UART2_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
+ SAVE(UART2_IER, 8);
+
+ SAVE(UART3_LCR, 8); SAVE(UART3_MCR, 8); SAVE(UART3_SPR, 8);
+ REG8(UART3_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
+ SAVE(UART3_DLLR, 8); SAVE(UART3_DLHR, 8);
+ REG8(UART3_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
+ SAVE(UART3_IER, 8);
+
+ /* Save vital registers */
+
+ SAVE(OST_TER, 8);
+ SAVE(OST_TCSR0, 16); SAVE(OST_TCSR1, 16); SAVE(OST_TCSR2, 16);
+ SAVE(OST_TRDR0, 32); SAVE(OST_TRDR1, 32); SAVE(OST_TRDR2, 32);
+ SAVE(OST_TCNT0, 32); SAVE(OST_TCNT1, 32); SAVE(OST_TCNT2, 32);
+
+ SAVE(HARB_HAPOR, 32); SAVE(HARB_HMCTR, 32); SAVE(HARB_HMLTR, 32);
+
+ SAVE(EMC_SMCR0, 32); SAVE(EMC_SMCR1, 32); SAVE(EMC_SMCR2, 32); SAVE(EMC_SMCR3, 32);
+ SAVE(EMC_SMCR4, 32); SAVE(EMC_SMCR5, 32);
+
+ SAVE(GPIO_GPDR0, 32); SAVE(GPIO_GPDR1, 32); SAVE(GPIO_GPDR2, 32);
+ SAVE(GPIO_GPDR3, 32);
+ SAVE(GPIO_GPDIR0, 32); SAVE(GPIO_GPDIR1, 32); SAVE(GPIO_GPDIR2, 32);
+ SAVE(GPIO_GPDIR3, 32);
+ SAVE(GPIO_GPODR0, 32); SAVE(GPIO_GPODR1, 32); SAVE(GPIO_GPODR2, 32);
+ SAVE(GPIO_GPODR3, 32);
+ SAVE(GPIO_GPPUR0, 32); SAVE(GPIO_GPPUR1, 32); SAVE(GPIO_GPPUR2, 32);
+ SAVE(GPIO_GPPUR3, 32);
+ SAVE(GPIO_GPALR0, 32); SAVE(GPIO_GPALR1, 32); SAVE(GPIO_GPALR2, 32);
+ SAVE(GPIO_GPALR3, 32);
+ SAVE(GPIO_GPAUR0, 32); SAVE(GPIO_GPAUR1, 32); SAVE(GPIO_GPAUR2, 32);
+ SAVE(GPIO_GPAUR3, 32);
+ SAVE(GPIO_GPIDLR0, 32); SAVE(GPIO_GPIDLR1, 32); SAVE(GPIO_GPIDLR2, 32);
+ SAVE(GPIO_GPIDLR3, 32);
+ SAVE(GPIO_GPIDUR0, 32); SAVE(GPIO_GPIDUR1, 32); SAVE(GPIO_GPIDUR2, 32);
+ SAVE(GPIO_GPIDUR3, 32);
+ SAVE(GPIO_GPIER0, 32); SAVE(GPIO_GPIER1, 32); SAVE(GPIO_GPIER2, 32);
+ SAVE(GPIO_GPIER3, 32);
+ SAVE(GPIO_GPIMR0, 32); SAVE(GPIO_GPIMR1, 32); SAVE(GPIO_GPIMR2, 32);
+ SAVE(GPIO_GPIMR3, 32);
+ SAVE(GPIO_GPFR0, 32); SAVE(GPIO_GPFR1, 32); SAVE(GPIO_GPFR2, 32);
+ SAVE(GPIO_GPFR3, 32);
+
+ SAVE(DMAC_DMACR, 32);
+ SAVE(DMAC_DSAR0, 32); SAVE(DMAC_DSAR1, 32); SAVE(DMAC_DSAR2, 32); SAVE(DMAC_DSAR3, 32); SAVE(DMAC_DSAR4, 32); SAVE(DMAC_DSAR5, 32); SAVE(DMAC_DSAR6, 32); SAVE(DMAC_DSAR7, 32);
+ SAVE(DMAC_DDAR0, 32); SAVE(DMAC_DDAR1, 32); SAVE(DMAC_DDAR2, 32); SAVE(DMAC_DDAR3, 32); SAVE(DMAC_DDAR4, 32); SAVE(DMAC_DDAR5, 32); SAVE(DMAC_DDAR6, 32); SAVE(DMAC_DDAR7, 32);
+ SAVE(DMAC_DTCR0, 32); SAVE(DMAC_DTCR1, 32); SAVE(DMAC_DTCR2, 32); SAVE(DMAC_DTCR3, 32); SAVE(DMAC_DTCR4, 32); SAVE(DMAC_DTCR5, 32); SAVE(DMAC_DTCR6, 32); SAVE(DMAC_DTCR7, 32);
+ SAVE(DMAC_DRSR0, 32); SAVE(DMAC_DRSR1, 32); SAVE(DMAC_DRSR2, 32); SAVE(DMAC_DRSR3, 32); SAVE(DMAC_DRSR4, 32); SAVE(DMAC_DRSR5, 32); SAVE(DMAC_DRSR6, 32); SAVE(DMAC_DRSR7, 32);
+ SAVE(DMAC_DCCSR0, 32); SAVE(DMAC_DCCSR1, 32); SAVE(DMAC_DCCSR2, 32); SAVE(DMAC_DCCSR3, 32); SAVE(DMAC_DCCSR4, 32); SAVE(DMAC_DCCSR5, 32); SAVE(DMAC_DCCSR6, 32); SAVE(DMAC_DCCSR7, 32);
+
+ SAVE(INTC_IPR, 32);SAVE(INTC_ISR, 32);SAVE(INTC_IMR, 32);
+
+ SAVE(WDT_WTCNT, 32);SAVE(WDT_WTCSR, 8);
+
+ /* Mask all interrupts */
+ REG_INTC_IMSR = 0xffffffff;
+
+ /* Save module clocks */
+ SAVE(CPM_MSCR, 32);
+
+ /* Save PLL */
+ SAVE(CPM_PLCR1, 32);
+
+ /* Stop module clocks */
+ __cpm_stop_uart0();
+ __cpm_stop_uart1();
+ __cpm_stop_uart2();
+ __cpm_stop_uart3();
+ __cpm_stop_uhc();
+ __cpm_stop_udc();
+ __cpm_stop_eth();
+ __cpm_stop_cim();
+ __cpm_stop_kbc();
+ __cpm_stop_scc();
+ __cpm_stop_ssi();
+ __cpm_stop_ost();
+
+ /* platform-specific pm routine */
+ jz_board_pm_suspend();
+
+ /* Clear previous reset status */
+ REG_CPM_RSTR &= ~(CPM_RSTR_HR | CPM_RSTR_WR | CPM_RSTR_SR);
+
+ /* Set resume return address */
+ REG_CPM_SPR = virt_to_phys(jz_cpu_resume);
+
+ /* Before sleeping, calculate and save a checksum */
+ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
+ checksum += sleep_save[i];
+ sleep_save[SLEEP_SAVE_CKSUM] = checksum;
+
+ /* *** go zzz *** */
+ jz_cpu_suspend();
+#if 0
+ /* after sleeping, validate the checksum */
+ checksum = 0;
+ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
+ checksum += sleep_save[i];
+
+ /* if invalid, display message and wait for a hardware reset */
+ if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) {
+ /** Add platform-specific message display codes here **/
+ while (1);
+ }
+#endif
+ /* Restore PLL */
+ RESTORE(CPM_PLCR1, 32);
+
+ /* Restore module clocks */
+ RESTORE(CPM_MSCR, 32);
+
+ /* Ensure not to come back here if it wasn't intended */
+ REG_CPM_SPR = 0;
+
+ /* Restore registers */
+
+ RESTORE(GPIO_GPDR0, 32); RESTORE(GPIO_GPDR1, 32); RESTORE(GPIO_GPDR2, 32);
+ RESTORE(GPIO_GPDR3, 32);
+ RESTORE(GPIO_GPDIR0, 32); RESTORE(GPIO_GPDIR1, 32); RESTORE(GPIO_GPDIR2, 32);
+ RESTORE(GPIO_GPDIR3, 32);
+ RESTORE(GPIO_GPODR0, 32); RESTORE(GPIO_GPODR1, 32); RESTORE(GPIO_GPODR2, 32);
+ RESTORE(GPIO_GPODR3, 32);
+ RESTORE(GPIO_GPPUR0, 32); RESTORE(GPIO_GPPUR1, 32); RESTORE(GPIO_GPPUR2, 32);
+ RESTORE(GPIO_GPPUR3, 32);
+ RESTORE(GPIO_GPALR0, 32); RESTORE(GPIO_GPALR1, 32); RESTORE(GPIO_GPALR2, 32);
+ RESTORE(GPIO_GPALR3, 32);
+ RESTORE(GPIO_GPAUR0, 32); RESTORE(GPIO_GPAUR1, 32); RESTORE(GPIO_GPAUR2, 32);
+ RESTORE(GPIO_GPAUR3, 32);
+ RESTORE(GPIO_GPIDLR0, 32);RESTORE(GPIO_GPIDLR1, 32);RESTORE(GPIO_GPIDLR2, 32);
+ RESTORE(GPIO_GPIDLR3, 32);
+ RESTORE(GPIO_GPIDUR0, 32);RESTORE(GPIO_GPIDUR1, 32);RESTORE(GPIO_GPIDUR2, 32);
+ RESTORE(GPIO_GPIDUR3, 32);
+ RESTORE(GPIO_GPIER0, 32); RESTORE(GPIO_GPIER1, 32); RESTORE(GPIO_GPIER2, 32);
+ RESTORE(GPIO_GPIER3, 32);
+ RESTORE(GPIO_GPIMR0, 32); RESTORE(GPIO_GPIMR1, 32); RESTORE(GPIO_GPIMR2, 32);
+ RESTORE(GPIO_GPIMR3, 32);
+ RESTORE(GPIO_GPFR0, 32); RESTORE(GPIO_GPFR1, 32); RESTORE(GPIO_GPFR2, 32);
+ RESTORE(GPIO_GPFR3, 32);
+
+ RESTORE(EMC_SMCR0, 32); RESTORE(EMC_SMCR1, 32); RESTORE(EMC_SMCR2, 32); RESTORE(EMC_SMCR3, 32);
+ RESTORE(EMC_SMCR4, 32); RESTORE(EMC_SMCR5, 32);
+
+ RESTORE(HARB_HAPOR, 32); RESTORE(HARB_HMCTR, 32); RESTORE(HARB_HMLTR, 32);
+
+ RESTORE(OST_TCNT0, 32); RESTORE(OST_TCNT1, 32); RESTORE(OST_TCNT2, 32);
+ RESTORE(OST_TRDR0, 32); RESTORE(OST_TRDR1, 32); RESTORE(OST_TRDR2, 32);
+ RESTORE(OST_TCSR0, 16); RESTORE(OST_TCSR1, 16); RESTORE(OST_TCSR2, 16);
+ RESTORE(OST_TER, 8);
+
+ RESTORE(DMAC_DMACR, 32);
+ RESTORE(DMAC_DSAR0, 32); RESTORE(DMAC_DSAR1, 32); RESTORE(DMAC_DSAR2, 32); RESTORE(DMAC_DSAR3, 32); RESTORE(DMAC_DSAR4, 32); RESTORE(DMAC_DSAR5, 32); RESTORE(DMAC_DSAR6, 32); RESTORE(DMAC_DSAR7, 32);
+ RESTORE(DMAC_DDAR0, 32); RESTORE(DMAC_DDAR1, 32); RESTORE(DMAC_DDAR2, 32); RESTORE(DMAC_DDAR3, 32); RESTORE(DMAC_DDAR4, 32); RESTORE(DMAC_DDAR5, 32); RESTORE(DMAC_DDAR6, 32); RESTORE(DMAC_DDAR7, 32);
+ RESTORE(DMAC_DTCR0, 32); RESTORE(DMAC_DTCR1, 32); RESTORE(DMAC_DTCR2, 32); RESTORE(DMAC_DTCR3, 32); RESTORE(DMAC_DTCR4, 32); RESTORE(DMAC_DTCR5, 32); RESTORE(DMAC_DTCR6, 32); RESTORE(DMAC_DTCR7, 32);
+ RESTORE(DMAC_DRSR0, 32); RESTORE(DMAC_DRSR1, 32); RESTORE(DMAC_DRSR2, 32); RESTORE(DMAC_DRSR3, 32); RESTORE(DMAC_DRSR4, 32); RESTORE(DMAC_DRSR5, 32); RESTORE(DMAC_DRSR6, 32); RESTORE(DMAC_DRSR7, 32);
+ RESTORE(DMAC_DCCSR0, 32); RESTORE(DMAC_DCCSR1, 32); RESTORE(DMAC_DCCSR2, 32); RESTORE(DMAC_DCCSR3, 32); RESTORE(DMAC_DCCSR4, 32); RESTORE(DMAC_DCCSR5, 32); RESTORE(DMAC_DCCSR6, 32); RESTORE(DMAC_DCCSR7, 32);
+
+ RESTORE(INTC_IPR, 32);RESTORE(INTC_ISR, 32);RESTORE(INTC_IMR, 32);
+
+ REG_WDT_WTCNT = 0; RESTORE(WDT_WTCSR, 8);
+
+ /*
+ * Temporary solution. This won't be necessary once
+ * we move this support into the device drivers.
+ * Restore the on-chip modules.
+ */
+
+ /* FIFO control reg, write-only */
+ REG8(UART0_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE;
+ REG8(UART1_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE;
+ REG8(UART2_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE;
+ REG8(UART3_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE;
+
+ REG8(UART0_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
+ RESTORE(UART0_DLLR, 8); RESTORE(UART0_DLHR, 8);
+ REG8(UART0_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
+ RESTORE(UART0_IER, 8);
+ RESTORE(UART0_MCR, 8); RESTORE(UART0_SPR, 8); RESTORE(UART0_LCR, 8);
+
+ REG8(UART1_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
+ RESTORE(UART1_DLLR, 8); RESTORE(UART1_DLHR, 8);
+ REG8(UART1_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
+ RESTORE(UART1_IER, 8);
+ RESTORE(UART1_MCR, 8); RESTORE(UART1_SPR, 8); RESTORE(UART1_LCR, 8);
+
+ REG8(UART2_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
+ RESTORE(UART2_DLLR, 8); RESTORE(UART2_DLHR, 8);
+ REG8(UART2_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
+ RESTORE(UART2_IER, 8);
+ RESTORE(UART2_MCR, 8); RESTORE(UART2_SPR, 8); RESTORE(UART2_LCR, 8);
+
+ REG8(UART3_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
+ RESTORE(UART3_DLLR, 8); RESTORE(UART3_DLHR, 8);
+ REG8(UART3_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
+ RESTORE(UART3_IER, 8);
+ RESTORE(UART3_MCR, 8); RESTORE(UART3_SPR, 8); RESTORE(UART3_LCR, 8);
+
+ REG_CPM_OCR &= ~CPM_OCR_SUSPEND_PHY0; /* resume USB PHY 0 */
+ REG_CPM_OCR &= ~CPM_OCR_SUSPEND_PHY1; /* resume USB PHY 1 */
+#if 0
+ REG_CPM_OCR &= ~CPM_OCR_EXT_RTC_CLK; /* use internal RTC clock (JZ_EXTAL/128 Hz) */
+#else
+ REG_CPM_OCR |= CPM_OCR_EXT_RTC_CLK; /* use external RTC clock (32.768 KHz) */
+#endif
+
+ /* Enable NAND ctroller */
+ REG_EMC_NFCSR |= EMC_NFCSR_NFE;
+
+ /* Restore current time */
+ xtime.tv_sec = REG_RTC_RSR;
+
+ /* Restore interrupts */
+ REG_INTC_IMSR = imr;
+ REG_INTC_IMCR = ~imr;
+
+ return 0;
+}
+
+/* NOTES:
+ * 1: Pins that are floated (NC) should be set as input and pull-enable.
+ * 2: Pins that are pull-up or pull-down by outside should be set as input
+ * and pull-disable.
+ * 3: Pins that are connected to a chipset should be set as pull-disable.
+ */
+static void jz_board_pm_gpio_setup(void)
+{
+ /* CIM_D0(IN)/PULL-UP/GP0 */
+ __gpio_as_input(0);
+ __gpio_enable_pull(0);
+
+ /* CIM_D1(IN)/PULL-UP/GP1 */
+ __gpio_as_input(1);
+ __gpio_enable_pull(1);
+
+ /* CIM_D2(IN)/PULL-UP/GP2 */
+ __gpio_as_input(2);
+ __gpio_enable_pull(2);
+
+ /* CIM_D3(IN)/PULL-UP/GP3 */
+ __gpio_as_input(3);
+ __gpio_enable_pull(3);
+
+ /* CIM_D4(IN)/PULL-DOWN/GP4 */
+ __gpio_as_input(4);
+ __gpio_enable_pull(4);
+
+ /* CIM_D5(IN)/PULL-DOWN/GP5 */
+ __gpio_as_input(5);
+ __gpio_enable_pull(5);
+
+ /* CIM_D6(IN)/PULL-DOWN/GP6 */
+ __gpio_as_input(6);
+ __gpio_enable_pull(6);
+
+ /* CIM_D7(IN)/PULL-DOWN/GP7 */
+ __gpio_as_input(7);
+ __gpio_enable_pull(7);
+
+ /* CIM_VSYNC(IN)/PULL-DOWN/GP8 */
+ __gpio_as_input(8);
+ __gpio_enable_pull(8);
+
+ /* CIM_HSYNC(IN)/PULL-UP/GP9 */
+ __gpio_as_input(9);
+ __gpio_enable_pull(9);
+
+ /* CIM_PCLK(IN)/PULL-DOWN/GP10 */
+ __gpio_as_input(10);
+ __gpio_enable_pull(10);
+
+ /* CIM_MCLK(OUT)/PULL-DOWN/GP11 */
+ __gpio_as_input(11);
+ __gpio_enable_pull(11);
+
+ /* DMA_DREQ0(IN)/CHIP_MODE/PULL-UP/GP12 */
+ __gpio_as_input(12);
+ __gpio_enable_pull(12);
+
+ /* DMA_DACK0(OUT)/PULL-UP/GP13 */ /* GPIO13 */
+ __gpio_as_input(13);
+ __gpio_disable_pull(13);
+
+ /* GP14 */
+ /* GP15 */
+
+ /* RXD3(IN)/PULL-UP/GP16 */
+ __gpio_as_input(16);
+ __gpio_enable_pull(16);
+
+ /* CTS3(IN)/PULL-UP/GP17 */
+ __gpio_as_input(17);
+ __gpio_enable_pull(17);
+
+ /* GP18 */
+ /* GP19 */
+ /* GP20 */
+
+ /* TXD3(OUT)/PULL-UP/GP21 */
+ __gpio_as_input(21);
+ __gpio_enable_pull(21);
+
+ /* GP22 */
+
+ /* RTS3(OUT)/PULL-UP/GP23 */
+ __gpio_as_input(23);
+ __gpio_enable_pull(23);
+
+ /* RXD1(IN)/PULL-UP/GP24 */ /* IR_RXD */
+ __gpio_as_input(24);
+ __gpio_enable_pull(24);
+
+ /* TXD1(OUT)/PULL-UP/GP25 */ /* IR_TXD */
+ __gpio_disable_pull(25);
+ __gpio_as_output(25);
+ __cpm_set_pin(25);
+
+ /* DMA_AEN(OUT)/PULL-UP/GP26 */ /* CIM_PWD_N */
+ __gpio_as_input(26);
+ __gpio_disable_pull(26);
+
+ /* DMA_EOP(OUT)/PULL-UP/GP27 */ /* SW4 */
+ __gpio_as_input(27);
+ __gpio_disable_pull(27);
+
+ /* USB_CLK(IN)/PULL-UP/GP28 */
+ __gpio_as_input(28);
+ __gpio_disable_pull(28);
+
+ /* USB_PPWR0(OUT)/PULL-UP/GP29 */ /* USB_CLK_EN */
+ __gpio_disable_pull(29);
+ __gpio_as_output(29);
+ __cpm_clear_pin(29); /* disable USB 48MHz clock */
+
+ /* GP30 */
+ /* GP31 */
+
+ /* PS2_KCLK(IO)/PULL-UP/GP32 */
+ __gpio_as_input(32);
+ __gpio_enable_pull(32);
+
+ /* PS2_KDATA(IO)/PULL-UP/GP33 */ /* CIM_RST */
+ __gpio_as_input(33);
+ __gpio_enable_pull(33);
+
+ /* MSC_D0(IO)/PULL-UP/GP34 */
+ __gpio_as_input(34);
+ __gpio_disable_pull(34);
+
+ /* MSC_D1(IO)/PULL-UP/GP35 */
+ __gpio_as_input(35);
+ __gpio_disable_pull(35);
+
+ /* MSC_D2(IO)/PULL-UP/GP36 */
+ __gpio_as_input(36);
+ __gpio_disable_pull(36);
+
+ /* MSC_D3(IO)/PULL-UP/GP37 */
+ __gpio_as_input(37);
+ __gpio_disable_pull(37);
+
+ /* MSC_CMD(IO)/PULL-UP/GP38 */
+ __gpio_as_input(38);
+ __gpio_disable_pull(38);
+
+ /* MSC_CLK(OUT)/PULL-UP/GP39 */
+ __gpio_as_input(39);
+ __gpio_enable_pull(39);
+
+ /* LCD_D0(OUT)/PULL-UP/GP40 */
+ __gpio_as_input(40);
+ __gpio_enable_pull(40);
+
+ /* LCD_D1(OUT)/PULL-UP/GP41 */
+ __gpio_as_input(41);
+ __gpio_enable_pull(41);
+
+ /* LCD_D2(OUT)/PULL-UP/GP42 */
+ __gpio_as_input(42);
+ __gpio_enable_pull(42);
+
+ /* LCD_D3(OUT)/PULL-UP/GP43 */
+ __gpio_as_input(43);
+ __gpio_enable_pull(43);
+
+ /* LCD_D4(OUT)/PULL-UP/GP44 */
+ __gpio_as_input(44);
+ __gpio_enable_pull(44);
+
+ /* LCD_D5(OUT)/PULL-UP/GP45 */
+ __gpio_as_input(45);
+ __gpio_enable_pull(45);
+
+ /* LCD_D6(OUT)/PULL-UP/GP46 */
+ __gpio_as_input(46);
+ __gpio_enable_pull(46);
+
+ /* LCD_D7(OUT)/PULL-UP/GP47 */
+ __gpio_as_input(47);
+ __gpio_enable_pull(47);
+
+ /* LCD_D8(OUT)/PULL-DOWN/GP48 */
+ __gpio_as_input(48);
+ __gpio_enable_pull(48);
+
+ /* LCD_D9(OUT)/PULL-DOWN/GP49 */
+ __gpio_as_input(49);
+ __gpio_enable_pull(49);
+
+ /* LCD_D10(OUT)/PULL-DOWN/GP50 */
+ __gpio_as_input(50);
+ __gpio_enable_pull(50);
+
+ /* LCD_D11(OUT)/PULL-DOWN/GP51 */
+ __gpio_as_input(51);
+ __gpio_enable_pull(51);
+
+ /* LCD_D12(OUT)/PULL-DOWN/GP52 */
+ __gpio_as_input(52);
+ __gpio_enable_pull(52);
+
+ /* LCD_D13(OUT)/PULL-DOWN/GP53 */
+ __gpio_as_input(53);
+ __gpio_enable_pull(53);
+
+ /* LCD_D14(OUT)/PULL-DOWN/GP54 */
+ __gpio_as_input(54);
+ __gpio_enable_pull(54);
+
+ /* LCD_D15(OUT)/PULL-DOWN/GP55 */
+ __gpio_as_input(55);
+ __gpio_enable_pull(55);
+
+ /* LCD_VSYNC(IN)/PULL-DOWN/GP56 */
+ __gpio_as_input(56);
+ __gpio_enable_pull(56);
+
+ /* LCD_HSYNC(IN)/PULL-UP/GP57 */
+ __gpio_as_input(57);
+ __gpio_enable_pull(57);
+
+ /* LCD_PCLK(IN)/PULL-DOWN/GP58 */
+ __gpio_as_input(58);
+ __gpio_enable_pull(58);
+
+ /* LCD_DE(OUT)/PULL-DOWN/GP59 */
+ __gpio_as_input(59);
+ __gpio_enable_pull(59);
+
+ /* LCD_SPL(OUT)/PULL-UP/GP60 */
+ __gpio_as_input(60);
+ __gpio_disable_pull(60);
+
+ /* LCD_CLS(OUT)/PULL-UP/GP61 */
+ __gpio_as_input(61);
+ __gpio_disable_pull(61);
+
+ /* LCD_PS(OUT)/PULL-UP/GP62 */
+ __gpio_as_input(62);
+ __gpio_disable_pull(62);
+
+ /* LCD_REV(OUT)/PULL-UP/GP63 */
+ __gpio_as_input(63);
+ __gpio_enable_pull(63);
+
+ /* SCC0_DAT(IO)/PULL-UP/GP64 */ /* Keypad */
+ __gpio_as_input(64);
+ __gpio_enable_pull(64);
+
+ /* SCC1_DAT(IO)/PULL-UP/GP65 */ /* SW5 */
+ __gpio_as_input(65);
+ __gpio_disable_pull(65);
+
+ /* SCC0_CLK(OUT)/PULL-UP/GP66 */ /* PW_O */
+ __gpio_disable_pull(66);
+ __gpio_as_output(66);
+ __cpm_set_pin(66);
+
+ /* SCC1_CLK(OUT)/PULL-UP/GP67 */ /* SW6 */
+ __gpio_as_input(67);
+ __gpio_disable_pull(67);
+
+ /* SYS_CLK(OUT)/PULL-UP/GP68 */ /* I2S_CLK */
+ __gpio_disable_pull(68);
+
+ /* ACRESET_N(OUT)/PULL-UP/GP69 */ /* AK4642 PDN */
+ __gpio_disable_pull(69);
+ __gpio_as_output(69);
+ __cpm_clear_pin(69);
+
+ /* SDATA_OUT(OUT)/PULL-UP/GP70 */ /* I2S_DIN */
+ __gpio_disable_pull(70);
+
+ /* SDATA_IN(IN)/PULL-UP/GP71 */ /* I2S_DOUT */
+ __gpio_disable_pull(71);
+
+ /* SSI_CLK(OUT)/PULL-UP/GP72 */ /* SSI_CLK */
+ __gpio_as_input(72);
+ __gpio_enable_pull(72);
+
+ /* SSI_CE1_N(OUT)/PULL-UP/GP73 */ /* SSI_CE1_N */
+ __gpio_as_input(73);
+ __gpio_enable_pull(73);
+
+ /* SSI_DT(OUT)/PULL-UP/GP74 */ /* SSI_DT */
+ __gpio_as_input(74);
+ __gpio_enable_pull(74);
+
+ /* SSI_DR(IN)/PULL-UP/GP75 */ /* SSI_DR */
+ __gpio_as_input(75);
+ __gpio_enable_pull(75);
+
+ /* SSI_CE2_N(OUT)/SSI_GPC/PULL-UP/GP76 */
+ __gpio_as_input(76);
+ __gpio_enable_pull(76);
+
+ /* BITCLK_IN(IN)/PULL-UP/GP77 */ /* I2S_BITCLK */
+ __gpio_disable_pull(77);
+
+ /* SYNC_IN(IN)/PULL-UP/GP78 */ /* I2S_LRCIN */
+ __gpio_disable_pull(78);
+
+ /* FRE_N(OUT)/PULL-UP/GP79 */
+ __gpio_enable_pull(79);
+ __gpio_as_input(79);
+
+ /* FWE_N(OUT)/PULL-UP/GP80 */
+ __gpio_enable_pull(80);
+ __gpio_as_input(80);
+
+ /* FRB_N(IN)/PULL-UP/GP81 */
+ __gpio_enable_pull(81);
+ __gpio_as_input(81);
+
+ /* DCS1_N(OUT)/PULL-UP/GP82 */ /* SD_WP */
+ __gpio_as_input(82);
+ __gpio_enable_pull(82);
+
+ /* CS1_N(OUT)/PULL-UP/GP83 */ /* JACK_PLUG */
+ __gpio_as_input(83);
+ __gpio_disable_pull(83);
+
+ /* CS2_N(OUT)/PULL-UP/GP84 */ /* DC_DETE */
+ __gpio_as_input(84);
+ __gpio_disable_pull(84);
+
+ /* CS3_N(OUT)/PULL-UP/GP85 */ /* NAND CS# */
+ __gpio_enable_pull(85);
+ __gpio_as_input(85);
+
+ /* CS4_N/(OUT)PULL-UP/GP86 */ /* PULL_OFF */
+ __gpio_disable_pull(86);
+ __gpio_as_output(86);
+// __cpm_set_pin(86);
+ __cpm_clear_pin(86);
+
+ /* CS5_N(OUT)/PULL-UP/GP87 */ /* IR_SD */
+ __gpio_as_input(87);
+ __gpio_disable_pull(87);
+
+ /* INPACK_N(IN)/PULL-UP/GP88 */ /* SW7 */
+ __gpio_as_input(88);
+ __gpio_disable_pull(88);
+
+ /* BVD2(IN)/PULL-UP/GP89 */ /* SW8 */
+ __gpio_as_input(89);
+ __gpio_disable_pull(89);
+
+ /* PCE1_N(OUT)/PULL-UP/GP90 */ /* SD_CD_N */
+ __gpio_as_input(90);
+ __gpio_enable_pull(90);
+
+ /* PSKTSEL_N(OUT)/PULL-UP/GP91 */ /* SD_VCC_3V_EN_N */
+ __gpio_disable_pull(91);
+ __gpio_as_output(91);
+ __cpm_clear_pin(91);
+
+ /* IOIS16_N(IN)/PULL-UP/GP92 */ /* LED_EN */
+ __gpio_disable_pull(92);
+ __gpio_as_output(92);
+ __cpm_clear_pin(92);
+
+ /* PCE2_N(OUT)/PULL-UP/GP93 */ /* LCD_DISP_OFF_N */
+ __gpio_disable_pull(93);
+ __gpio_as_input(93);
+
+ /* PWM0(OUT)/PULL-UP/GP94 */ /* LCD backlight off */
+ __gpio_disable_pull(94);
+ __gpio_as_output(94);
+ __cpm_clear_pin(94);
+
+ /* PWM1(OUT)/PULL-UP/GP95 */
+ __gpio_disable_pull(95);
+ __gpio_as_output(95);
+ __cpm_clear_pin(95);
+
+ /* PRT(OUT)/PULL-UP/GP96 */ /* RTC_IRQ */
+ __gpio_as_input(96);
+ __gpio_disable_pull(96);
+
+ /* PRT(OUT)/PULL-UP/GP97 */ /* PW_I */
+ __gpio_as_input(97);
+ __gpio_disable_pull(97);
+
+ /* PRT(OUT)/PULL-UP/GP98 */ /* Keypad */
+ __gpio_as_input(98);
+ __gpio_disable_pull(98);
+
+ /* PRT(OUT)/PULL-UP/GP99 */ /* Keypad */
+ __gpio_as_input(99);
+ __gpio_disable_pull(99);
+
+ /* PRT(OUT)/PULL-UP/GP100 */ /* Keypad */
+ __gpio_as_input(100);
+ __gpio_disable_pull(100);
+
+ /* PRT(OUT)/PULL-UP/GP101 */ /* Keypad */
+ __gpio_as_input(101);
+ __gpio_disable_pull(101);
+
+ /* PRT(OUT)/PULL-UP/GP102 */ /* Keypad */
+ __gpio_as_input(102);
+ __gpio_disable_pull(102);
+
+ /* PRT(OUT)/PULL-UP/GP103 */ /* Keypad */
+ __gpio_as_input(103);
+ __gpio_enable_pull(103);
+
+ /* PRT(OUT)/PULL-UP/GP104 */ /* Keypad */
+ __gpio_as_input(104);
+ __gpio_enable_pull(104);
+
+ /* PRT(OUT)/PULL-UP/GP105 */ /* Keypad */
+ __gpio_as_input(105);
+ __gpio_enable_pull(105);
+
+ /* PRT(OUT)/PULL-UP/GP106 */ /* 5V_ON */
+ __gpio_disable_pull(106);
+ __gpio_as_output(106);
+ __cpm_clear_pin(106);
+
+ /* PRT(IN)/PULL-UP/GP107 */ /* GSM_BOOT */
+ __gpio_as_input(107);
+ __gpio_enable_pull(107);
+
+ /* PRT(IN)/PULL-UP/GP108 */ /* GSM_RESET */
+ __gpio_as_input(108);
+ __gpio_enable_pull(108);
+
+ /* PRT(IN)/PULL-UP/GP109 */ /* GSM_EN */
+ __gpio_as_input(109);
+ __gpio_enable_pull(109);
+
+ /* PRT(IN)/PULL-UP/GP110 */ /* GSM_RING */
+ __gpio_as_input(110);
+ __gpio_enable_pull(110);
+
+ /* PRT(IN)/UART2_RXD/PULL-UP/GP111 */ /* Keypad */
+ __gpio_as_input(111);
+ __gpio_enable_pull(111);
+
+ /* MII_TX_EN(OUT)/PULL-UP/GP112 */
+ __gpio_as_input(112);
+ __gpio_enable_pull(112);
+
+ /* MII_RX_DV(IN)/PULL-UP/GP113 */
+ __gpio_as_input(113);
+ __gpio_enable_pull(113);
+
+ /* MII_RX_ER(IN)/PULL-UP/GP114 */
+ __gpio_as_input(114);
+ __gpio_enable_pull(114);
+
+ /* MII_COL(IN)/PULL-UP/GP115 */
+ __gpio_as_input(115);
+ __gpio_enable_pull(115);
+
+ /* MII_CRS(IN)/PULL-UP/GP116 */
+ __gpio_as_input(116);
+ __gpio_enable_pull(116);
+
+ /* MII_TXD0(OUT)/PULL-UP/GP117 */
+ __gpio_as_input(117);
+ __gpio_enable_pull(117);
+
+ /* MII_TXD1(OUT)/PULL-UP/GP118 */
+ __gpio_as_input(118);
+ __gpio_enable_pull(118);
+
+ /* MII_TXD2(OUT)/PULL-UP/GP119 */
+ __gpio_as_input(119);
+ __gpio_enable_pull(119);
+
+ /* MII_TXD3(OUT)/PULL-UP/GP120 */
+ __gpio_as_input(120);
+ __gpio_enable_pull(120);
+
+ /* MII_RXD0(IN)/PULL-UP/GP121 */
+ __gpio_as_input(121);
+ __gpio_enable_pull(121);
+
+ /* MII_RXD1(IN)/PULL-UP/GP122 */
+ __gpio_as_input(122);
+ __gpio_enable_pull(122);
+
+ /* MII_RXD2(IN)/PULL-UP/GP123 */
+ __gpio_as_input(123);
+ __gpio_enable_pull(123);
+
+ /* MII_RXD3(IN)/PULL-UP/GP124 */
+ __gpio_as_input(124);
+ __gpio_enable_pull(124);
+
+ /* UART2_TXD(OUT)/PULL-UP/GP125 */ /* CHARG_STAT */
+ __gpio_as_output(125);
+ __gpio_disable_pull(125);
+ __cpm_clear_pin(125);
+
+ /* UART0_RXD(IN)/PULL-UP/GP126 */
+ __gpio_as_input(126);
+ __gpio_enable_pull(126);
+
+ /* UART0_TXD(OUT)/PULL-UP/GP127 */
+ __gpio_as_input(127);
+ __gpio_enable_pull(127);
+}
+
+/*
+ * In order to save power most, all gpio pins should be put to their
+ * proper states during low power mode.
+ */
+static void jz_board_pm_suspend(void)
+{
+ /* Setup the state of all the GPIO pins during low-power mode */
+ jz_board_pm_gpio_setup();
+
+ /* Allow next interrupts to wakeup the system.
+ */
+ REG_CPM_WER = 0; /* Clear all first */
+
+ /* RTC alarm */
+ REG_CPM_WER |= 1 << 0;
+ REG_CPM_WRER |= 1 << 0;
+ REG_CPM_WFER |= 1 << 0;
+ __gpio_as_irq_rise_edge(96);
+
+ /* Power_I key */
+ REG_CPM_WER |= 1 << 1;
+ REG_CPM_WRER |= 1 << 1;
+ REG_CPM_WFER |= 1 << 1;
+ __gpio_as_irq_rise_edge(97);
+
+ /* enable INTC irq */
+ __intc_unmask_irq(IRQ_GPIO3);
+
+#if 0
+ /* Enable RTC alarm */
+ REG_CPM_WER |= CPM_WER_WERTC;
+ REG_RTC_RGR = 32767;
+ REG_RTC_RCR &= ~RTC_RCR_AE;
+ REG_RTC_RSR = 0;
+ REG_RTC_RSAR = 30;
+ REG_RTC_RCR = RTC_RCR_AE | RTC_RCR_AIE | RTC_RCR_START;
+#endif
+}
+
+/*
+ * We don't use sleep mode of jz4730 for it has bug, the suspend mode
+ * implemented by hibernate mode is used instead of it.
+ */
+static int jz_pm_do_sleep(void)
+{
+ printk("It was deprecated, please use /proc/sys/pm/suspend.\n");
+#if 0
+ unsigned long imr = REG_INTC_IMR;
+
+ /* Preserve current time */
+ REG_RTC_RSR = xtime.tv_sec;
+
+ /* Mask all interrupts */
+ REG_INTC_IMSR = 0xffffffff;
+
+ /* Just allow next interrupts to wakeup the system.
+ * Note: modify this according to your system.
+ */
+ /* RTC alarm */
+ __gpio_as_irq_fall_edge(96); /* GPIO 96 */
+
+ /* POWER_I key */
+ __gpio_as_irq_rise_edge(97); /* GPIO 97 */
+
+ /* Enable INTC */
+ __intc_unmask_irq(IRQ_GPIO3);
+
+ /* Disable modules e.g. LCD backlight */
+
+ /* Stop module clocks */
+ __cpm_stop_uhc();
+
+ /* Enter SLEEP mode
+ * Put SDRAM into self-refresh mode.
+ */
+ REG_CPM_LPCR &= ~CPM_LPCR_LPM_MASK;
+ REG_CPM_LPCR |= CPM_LPCR_LPM_SLEEP;
+
+ __asm__(".set\tmips3\n\t"
+ ".set noreorder\n\t"
+ ".align 5\n\t"
+ "wait\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ ".set\tmips0");
+
+ /* Restore to IDLE mode */
+ REG_CPM_LPCR &= ~CPM_LPCR_LPM_MASK;
+ REG_CPM_LPCR |= CPM_LPCR_LPM_IDLE;
+
+ /* Restore clock of usb host */
+ __cpm_start_uhc();
+
+ /* Restore interrupts */
+ REG_INTC_IMSR = imr;
+ REG_INTC_IMCR = ~imr;
+
+ /* Restore current time */
+ xtime.tv_sec = REG_RTC_RSR;
+#endif
+ return 0;
+}
+
+#define K0BASE KSEG0
+void jz_flush_cache_all(void)
+{
+ unsigned long addr;
+
+ /* Clear CP0 TagLo */
+ asm volatile ("mtc0 $0, $28\n\t"::);
+
+ for (addr = K0BASE; addr < (K0BASE + 0x4000); addr += 32) {
+ asm volatile (
+ ".set mips3\n\t"
+ " cache %0, 0(%1)\n\t"
+ ".set mips2\n\t"
+ :
+ : "I" (Index_Writeback_Inv_D), "r"(addr));
+
+ asm volatile (
+ ".set mips3\n\t"
+ " cache %0, 0(%1)\n\t"
+ ".set mips2\n\t"
+ :
+ : "I" (Index_Store_Tag_I), "r"(addr));
+ }
+
+ asm volatile ("sync\n\t"::);
+
+ /* invalidate BTB */
+ asm volatile (
+ ".set mips32\n\t"
+ " mfc0 %0, $16, 7\n\t"
+ " nop\n\t"
+ " ori $0, 2\n\t"
+ " mtc0 %0, $16, 7\n\t"
+ " nop\n\t"
+ ".set mips2\n\t"
+ :
+ : "r"(addr));
+}
+
+/* Put CPU to HIBERNATE mode */
+int jz_pm_suspend(void)
+{
+ int retval;
+
+ pm_send_all(PM_SUSPEND, (void *)3);
+
+ retval = jz_pm_do_suspend();
+
+ pm_send_all(PM_RESUME, (void *)0);
+
+ return retval;
+}
+
+#if 0
+/* Put CPU to SLEEP mode */
+int jz_pm_sleep(void)
+{
+ return jz_pm_do_sleep();
+}
+
+/* Put CPU to IDLE mode, used for dpm in linux 2.4 */
+void jz_pm_idle(void)
+{
+ local_irq_disable();
+ if (!need_resched()) {
+ local_irq_enable();
+ cpu_wait();
+ }
+}
+#endif
+
+#ifdef CONFIG_SYSCTL
+
+/*
+ * Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6
+ * when all the PM interfaces exist nicely.
+ */
+#define CTL_PM_SUSPEND 1
+#define CTL_PM_HIBERNATE 2
+
+/*----------------------------------------------------------------------------
+ * Power Management sleep sysctl proc interface
+ *
+ * A write to /proc/sys/pm/suspend invokes this function
+ * which initiates a sleep.
+ *--------------------------------------------------------------------------*/
+static int sysctl_jz_pm_sleep(void)
+{
+ return jz_pm_suspend();
+}
+
+static struct ctl_table pm_table[] =
+{
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "suspend",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0600,
+ .proc_handler = &sysctl_jz_pm_sleep,
+ },
+ { .ctl_name = 0}
+};
+
+static struct ctl_table pm_dir_table[] =
+{
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "pm",
+ .mode = 0555,
+ .child = pm_table,
+ },
+ { .ctl_name = 0}
+};
+
+#endif /* CONFIG_SYSCTL */
+
+/*
+ * Initialize power interface
+ */
+static int __init jz_pm_init(void)
+{
+ printk("Power Management for JZ\n");
+
+#ifdef CONFIG_SYSCTL
+ register_sysctl_table(pm_dir_table);
+#endif
+
+ return 0;
+}
+
+module_init(jz_pm_init);
diff --git a/arch/mips/jz4730/proc.c b/arch/mips/jz4730/proc.c
new file mode 100644
index 00000000000..49585bc5a14
--- /dev/null
+++ b/arch/mips/jz4730/proc.c
@@ -0,0 +1,292 @@
+/*
+ * linux/arch/mips/jz4730/proc.c
+ *
+ * /proc/jz/ procfs for on-chip peripherals.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+
+struct proc_dir_entry *proc_jz_root;
+
+/*
+ * EMC Module
+ */
+static int emc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len += sprintf (page+len, "BCR: 0x%08x\n", REG_EMC_BCR);
+ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4, REG_EMC_SMCR5);
+ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4, REG_EMC_SACR5);
+ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR);
+ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR);
+ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR);
+ len += sprintf (page+len, "DMAR(0-1): 0x%08x 0x%08x\n", REG_EMC_DMAR1, REG_EMC_DMAR2);
+ return len;
+}
+
+/*
+ * Power Manager Module
+ */
+static int pmc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long lpcr = REG_CPM_LPCR;
+ unsigned long mscr = REG_CPM_MSCR;
+
+ len += sprintf (page+len, "LPCR : 0x%08lx\n", lpcr);
+ len += sprintf (page+len, "Low Power Mode : %s\n",
+ ((lpcr & CPM_LPCR_LPM_MASK) == (CPM_LPCR_LPM_IDLE)) ?
+ "idle" : (((lpcr & CPM_LPCR_LPM_MASK) == (CPM_LPCR_LPM_SLEEP)) ? "sleep" : "hibernate"));
+ len += sprintf (page+len, "Doze Mode : %s\n",
+ (lpcr & CPM_LPCR_DOZE) ? "on" : "off");
+ if (lpcr & CPM_LPCR_DOZE)
+ len += sprintf (page+len, " duty : %d\n", (int)((lpcr & CPM_LPCR_DUTY_MASK) >> CPM_LPCR_DUTY_BIT));
+ len += sprintf (page+len, "CKO1 : %s\n",
+ (REG_CPM_CFCR & CPM_CFCR_CKOEN1) ? "enable" : "disable");
+ len += sprintf (page+len, "UART0 : %s\n",
+ (mscr & CPM_MSCR_MSTP_UART0) ? "stopped" : "running");
+ len += sprintf (page+len, "UART1 : %s\n",
+ (mscr & CPM_MSCR_MSTP_UART1) ? "stopped" : "running");
+ len += sprintf (page+len, "UART2 : %s\n",
+ (mscr & CPM_MSCR_MSTP_UART2) ? "stopped" : "running");
+ len += sprintf (page+len, "UART3 : %s\n",
+ (mscr & CPM_MSCR_MSTP_UART3) ? "stopped" : "running");
+ len += sprintf (page+len, "OST : %s\n",
+ (mscr & CPM_MSCR_MSTP_OST) ? "stopped" : "running");
+ len += sprintf (page+len, "DMAC : %s\n",
+ (mscr & CPM_MSCR_MSTP_DMAC) ? "stopped" : "running");
+ len += sprintf (page+len, "ETH : %s\n",
+ (mscr & CPM_MSCR_MSTP_ETH) ? "stopped" : "running");
+ len += sprintf (page+len, "UHC/UDC : %s\n",
+ (mscr & CPM_MSCR_MSTP_UHC) ? "stopped" : "running");
+ len += sprintf (page+len, "PWM0 : %s\n",
+ (mscr & CPM_MSCR_MSTP_PWM0) ? "stopped" : "running");
+ len += sprintf (page+len, "PWM1 : %s\n",
+ (mscr & CPM_MSCR_MSTP_PWM1) ? "stopped" : "running");
+ len += sprintf (page+len, "I2C : %s\n",
+ (mscr & CPM_MSCR_MSTP_I2C) ? "stopped" : "running");
+ len += sprintf (page+len, "SSI : %s\n",
+ (mscr & CPM_MSCR_MSTP_SSI) ? "stopped" : "running");
+ len += sprintf (page+len, "SCC : %s\n",
+ (mscr & CPM_MSCR_MSTP_SCC) ? "stopped" : "running");
+ return len;
+}
+
+static int pmc_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+ REG_CPM_MSCR = simple_strtoul(buffer, 0, 16);
+ return count;
+}
+
+/*
+ * Clock Generation Module
+ */
+static int cgm_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned int cfcr = REG_CPM_CFCR;
+ unsigned int plcr1 = REG_CPM_PLCR1;
+ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned int od[4] = {1, 2, 2, 4};
+
+
+ len += sprintf (page+len, "PLCR1 : 0x%08x\n", plcr1);
+ len += sprintf (page+len, "CFCR : 0x%08x\n", cfcr);
+ len += sprintf (page+len, "PLL : %s\n",
+ (plcr1 & CPM_PLCR1_PLL1EN) ? "ON" : "OFF");
+ len += sprintf (page+len, "NF:NR:NO : %d:%d:%d\n",
+ __cpm_plcr1_fd() + 2,
+ __cpm_plcr1_rd() + 2,
+ od[__cpm_plcr1_od()]
+ );
+ len += sprintf (page+len, "I:S:M:P : %d:%d:%d:%d\n",
+ div[(cfcr & CPM_CFCR_IFR_MASK) >> CPM_CFCR_IFR_BIT],
+ div[(cfcr & CPM_CFCR_SFR_MASK) >> CPM_CFCR_SFR_BIT],
+ div[(cfcr & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT],
+ div[(cfcr & CPM_CFCR_PFR_MASK) >> CPM_CFCR_PFR_BIT]
+ );
+ len += sprintf (page+len, "PLL Freq : %d MHz\n", __cpm_get_pllout()/1000000);
+ len += sprintf (page+len, "ICLK : %d MHz\n", __cpm_get_iclk()/1000000);
+ len += sprintf (page+len, "SCLK : %d MHz\n", __cpm_get_sclk()/1000000);
+ len += sprintf (page+len, "MCLK : %d MHz\n", __cpm_get_mclk()/1000000);
+ len += sprintf (page+len, "PCLK : %d MHz\n", __cpm_get_pclk()/1000000);
+ len += sprintf (page+len, "DEVCLK : %d MHz\n", __cpm_get_devclk()/1000000);
+ len += sprintf (page+len, "RTCCLK : %d KHz\n", __cpm_get_rtcclk()/1000);
+ len += sprintf (page+len, "USBCLK : %d MHz\n", __cpm_get_usbclk()/1000000);
+#if defined(CONFIG_FB_JZ)
+ len += sprintf (page+len, "LCDCLK : %d MHz\n", __cpm_get_lcdclk()/1000000);
+ len += sprintf (page+len, "PIXCLK : %d MHz\n", __cpm_get_pixclk()/1000000);
+#endif
+ return len;
+}
+
+static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ REG_CPM_CFCR = simple_strtoul(buffer, 0, 16);
+ return count;
+}
+
+/*
+ * WDT
+ */
+static int wdt_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len += sprintf (page+len, "WDT_WTCSR : 0x%08x\n", REG_WDT_WTCSR);
+ len += sprintf (page+len, "WDT_WTCNT : 0x%08x\n", REG_WDT_WTCNT);
+
+ return len;
+}
+
+static int wdt_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ unsigned long cnt = simple_strtoul(buffer, 0, 16);
+
+ REG_WDT_WTCNT = cnt;
+ REG_WDT_WTCSR = WDT_WTCSR_START;
+
+ return count;
+}
+
+/*
+ * PWM
+ */
+
+static int proc_jz_pwm_read_byte(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ return sprintf (page, "0x%02x\n", REG8(data));
+}
+
+static int proc_jz_pwm_read_word(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ return sprintf (page, "0x%04x\n", REG16(data));
+}
+
+static int proc_jz_pwm_write_byte(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ REG8(data) = simple_strtoul(buffer, 0, 16);
+ return count;
+}
+
+static int proc_jz_pwm_write_word(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ REG16(data) = simple_strtoul(buffer, 0, 16);
+ return count;
+}
+
+#define PWM_NUM 2
+
+static int jz_pwm_proc_init(void)
+{
+ struct proc_dir_entry *proc_jz_pwm, *res;
+ char name[16];
+ unsigned char i;
+
+ for (i = 0; i < PWM_NUM; i++) {
+ sprintf(name, "pwm%d", i);
+ proc_jz_pwm = proc_mkdir(name, proc_jz_root);
+ res = create_proc_entry("control", 0600, proc_jz_pwm);
+ if ( res) {
+ res->read_proc = proc_jz_pwm_read_byte;
+ res->write_proc = proc_jz_pwm_write_byte;
+ if (i)
+ res->data = (void * )PWM_CTR(1);
+ else
+ res->data = (void * )PWM_CTR(0);
+ }
+ res = create_proc_entry("period", 0600, proc_jz_pwm);
+ if ( res) {
+ res->read_proc = proc_jz_pwm_read_word;
+ res->write_proc = proc_jz_pwm_write_word;
+ if (i)
+ res->data = (void *)PWM_PER(1);
+ else
+ res->data = (void *)PWM_PER(0);
+ }
+ res = create_proc_entry("duty", 0600, proc_jz_pwm);
+ if ( res) {
+ res->read_proc = proc_jz_pwm_read_word;
+ res->write_proc = proc_jz_pwm_write_word;
+ if (i)
+ res->data = (void * )PWM_DUT(1);
+ else
+ res->data = (void * )PWM_DUT(0);
+ }
+ }
+ return 0;
+}
+
+/*
+ * /proc/jz/xxx entry
+ *
+ */
+static int __init jz_proc_init(void)
+{
+ struct proc_dir_entry *entry;
+
+ /* create /proc/jz */
+ proc_jz_root = proc_mkdir("jz", 0);
+
+ /* create /proc/jz/emc */
+ entry = create_proc_entry("emc", 0644, proc_jz_root);
+ if (entry) {
+ entry->read_proc = emc_read_proc;
+ entry->write_proc = NULL;
+ entry->data = NULL;
+ }
+
+ /* create /proc/jz/pmc */
+ entry = create_proc_entry("pmc", 0644, proc_jz_root);
+ if (entry) {
+ entry->read_proc = pmc_read_proc;
+ entry->write_proc = pmc_write_proc;
+ entry->data = NULL;
+ }
+
+ /* create /proc/jz/cgm */
+ entry = create_proc_entry("cgm", 0644, proc_jz_root);
+ if (entry) {
+ entry->read_proc = cgm_read_proc;
+ entry->write_proc = cgm_write_proc;
+ entry->data = NULL;
+ }
+
+ /* create /proc/jz/wdt */
+ entry = create_proc_entry("wdt", 0644, proc_jz_root);
+ if (entry) {
+ entry->read_proc = wdt_read_proc;
+ entry->write_proc = wdt_write_proc;
+ entry->data = NULL;
+ }
+
+ /* PWM */
+ jz_pwm_proc_init();
+
+ return 0;
+}
+
+__initcall(jz_proc_init);
diff --git a/arch/mips/jz4730/prom.c b/arch/mips/jz4730/prom.c
new file mode 100644
index 00000000000..5a5f6b8e6dc
--- /dev/null
+++ b/arch/mips/jz4730/prom.c
@@ -0,0 +1,198 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * PROM library initialisation code, supports YAMON and U-Boot.
+ *
+ * Copyright 2000, 2001, 2006 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * This file was derived from Carsten Langgaard's
+ * arch/mips/mips-boards/xx files.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/jzsoc.h>
+
+/* #define DEBUG_CMDLINE */
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+char * prom_getcmdline(void)
+{
+ return &(arcs_cmdline[0]);
+}
+
+void prom_init_cmdline(void)
+{
+ char *cp;
+ int actr;
+
+ actr = 1; /* Always ignore argv[0] */
+
+ cp = &(arcs_cmdline[0]);
+ while(actr < prom_argc) {
+ strcpy(cp, prom_argv[actr]);
+ cp += strlen(prom_argv[actr]);
+ *cp++ = ' ';
+ actr++;
+ }
+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+ --cp;
+ if (prom_argc > 1)
+ *cp = '\0';
+
+}
+
+
+char *prom_getenv(char *envname)
+{
+#if 0
+ /*
+ * Return a pointer to the given environment variable.
+ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
+ */
+
+ char **env = prom_envp;
+ int i = strlen(envname);
+ int yamon = (*env && strchr(*env, '=') == NULL);
+
+ while (*env) {
+ if (yamon) {
+ if (strcmp(envname, *env++) == 0)
+ return *env;
+ } else {
+ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
+ return *env + i + 1;
+ }
+ env++;
+ }
+#endif
+ return NULL;
+}
+
+inline unsigned char str2hexnum(unsigned char c)
+{
+ if(c >= '0' && c <= '9')
+ return c - '0';
+ if(c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if(c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return 0; /* foo */
+}
+
+inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+ int i;
+
+ for(i = 0; i < 6; i++) {
+ unsigned char num;
+
+ if((*str == '.') || (*str == ':'))
+ str++;
+ num = str2hexnum(*str++) << 4;
+ num |= (str2hexnum(*str++));
+ ea[i] = num;
+ }
+}
+
+int get_ethernet_addr(char *ethernet_addr)
+{
+ char *ethaddr_str;
+
+ ethaddr_str = prom_getenv("ethaddr");
+ if (!ethaddr_str) {
+ printk("ethaddr not set in boot prom\n");
+ return -1;
+ }
+ str2eaddr(ethernet_addr, ethaddr_str);
+
+#if 0
+ {
+ int i;
+
+ printk("get_ethernet_addr: ");
+ for (i=0; i<5; i++)
+ printk("%02x:", (unsigned char)*(ethernet_addr+i));
+ printk("%02x\n", *(ethernet_addr+i));
+ }
+#endif
+
+ return 0;
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+void __init prom_init(void)
+{
+ unsigned char *memsize_str;
+ unsigned long memsize;
+
+ prom_argc = (int) fw_arg0;
+ prom_argv = (char **) fw_arg1;
+ prom_envp = (char **) fw_arg2;
+
+ mips_machtype = MACH_INGENIC_JZ4730;
+
+ prom_init_cmdline();
+ memsize_str = prom_getenv("memsize");
+ if (!memsize_str) {
+ memsize = 0x04000000;
+ } else {
+ memsize = simple_strtol(memsize_str, NULL, 0);
+ }
+ add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
+/* used by early printk */
+void prom_putchar(char c)
+{
+ volatile u8 *uart_lsr = (volatile u8 *)(UART3_BASE + OFF_LSR);
+ volatile u8 *uart_tdr = (volatile u8 *)(UART3_BASE + OFF_TDR);
+
+ /* Wait for fifo to shift out some bytes */
+ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) );
+
+ *uart_tdr = (u8)c;
+}
+
+const char *get_system_type(void)
+{
+ return "JZ4730";
+}
+
+EXPORT_SYMBOL(prom_getcmdline);
+EXPORT_SYMBOL(get_ethernet_addr);
+EXPORT_SYMBOL(str2eaddr);
diff --git a/arch/mips/jz4730/reset.c b/arch/mips/jz4730/reset.c
new file mode 100644
index 00000000000..4c9e20c9253
--- /dev/null
+++ b/arch/mips/jz4730/reset.c
@@ -0,0 +1,40 @@
+/*
+ * linux/arch/mips/jz4730/reset.c
+ *
+ * JZ4730 reset routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+void jz_restart(char *command)
+{
+ __wdt_set_count(0xffffffff-32); /* reset after 1/1024 s */
+ __wdt_start();
+ while (1);
+}
+
+void jz_halt(void)
+{
+ __wdt_set_count(0xffffffff-32); /* reset after 1/1024 s */
+ __wdt_start();
+ while (1);
+}
+
+void jz_power_off(void)
+{
+ jz_halt();
+}
diff --git a/arch/mips/jz4730/setup.c b/arch/mips/jz4730/setup.c
new file mode 100644
index 00000000000..4594b5626cc
--- /dev/null
+++ b/arch/mips/jz4730/setup.c
@@ -0,0 +1,182 @@
+/*
+ * linux/arch/mips/jz4730/setup.c
+ *
+ * JZ4730 CPU common setup routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/ioport.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+#include <asm/pgtable.h>
+#include <asm/time.h>
+#include <asm/jzsoc.h>
+
+#ifdef CONFIG_PC_KEYB
+#include <asm/keyboard.h>
+#endif
+
+jz_clocks_t jz_clocks;
+
+extern char * __init prom_getcmdline(void);
+extern void __init jz_board_setup(void);
+extern void jz_restart(char *);
+extern void jz_halt(void);
+extern void jz_power_off(void);
+extern void jz_time_init(void);
+
+static void __init sysclocks_setup(void)
+{
+#ifndef CONFIG_JZ4730_URANUS
+ jz_clocks.iclk = __cpm_get_iclk();
+ jz_clocks.sclk = __cpm_get_sclk();
+ jz_clocks.mclk = __cpm_get_mclk();
+ jz_clocks.pclk = __cpm_get_pclk();
+ jz_clocks.devclk = __cpm_get_devclk();
+ jz_clocks.rtcclk = __cpm_get_rtcclk();
+ jz_clocks.uartclk = __cpm_get_uartclk();
+ jz_clocks.lcdclk = __cpm_get_lcdclk();
+ jz_clocks.pixclk = __cpm_get_pixclk();
+ jz_clocks.usbclk = __cpm_get_usbclk();
+ jz_clocks.i2sclk = __cpm_get_i2sclk();
+ jz_clocks.mscclk = __cpm_get_mscclk();
+#else /* URANUS FPGA */
+
+#define FPGACLK 8000000
+
+ jz_clocks.iclk = FPGACLK;
+ jz_clocks.sclk = FPGACLK;
+ jz_clocks.mclk = FPGACLK;
+ jz_clocks.devclk = FPGACLK;
+ jz_clocks.rtcclk = FPGACLK;
+ jz_clocks.uartclk = FPGACLK;
+ jz_clocks.pixclk = FPGACLK;
+ jz_clocks.lcdclk = FPGACLK;
+ jz_clocks.usbclk = FPGACLK;
+ jz_clocks.i2sclk = FPGACLK;
+ jz_clocks.mscclk = FPGACLK;
+#endif
+
+ printk("CPU clock: %dMHz, System clock: %dMHz, Memory clock: %dMHz, Peripheral clock: %dMHz\n",
+ (jz_clocks.iclk + 500000) / 1000000,
+ (jz_clocks.sclk + 500000) / 1000000,
+ (jz_clocks.mclk + 500000) / 1000000,
+ (jz_clocks.pclk + 500000) / 1000000);
+}
+
+static void __init soc_cpm_setup(void)
+{
+ __cpm_idle_mode();
+ __cpm_enable_cko1();
+ __cpm_start_all();
+
+ /* get system clocks */
+ sysclocks_setup();
+}
+
+static void __init soc_harb_setup(void)
+{
+// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */
+// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */
+ __harb_set_priority(0x08); /* DMAC>LCD>CIM>ETH>USB>CIM */
+// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */
+}
+
+static void __init soc_emc_setup(void)
+{
+}
+
+static void __init soc_dmac_setup(void)
+{
+ __dmac_enable_all_channels();
+}
+
+static void __init jz_soc_setup(void)
+{
+ soc_cpm_setup();
+ soc_harb_setup();
+ soc_emc_setup();
+ soc_dmac_setup();
+}
+
+static void __init jz_serial_setup(void)
+{
+#ifdef CONFIG_SERIAL_8250
+ struct uart_port s;
+
+ memset(&s, 0, sizeof(s));
+
+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
+ s.iotype = UPIO_MEM;
+ s.regshift = 2;
+ s.uartclk = jz_clocks.uartclk;
+
+ s.line = 0;
+ s.membase = (u8 *)UART0_BASE;
+ s.irq = IRQ_UART0;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS0 setup failed!\n");
+ }
+
+ s.line = 1;
+ s.membase = (u8 *)UART1_BASE;
+ s.irq = IRQ_UART1;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS1 setup failed!\n");
+ }
+
+ s.line = 2;
+ s.membase = (u8 *)UART2_BASE;
+ s.irq = IRQ_UART2;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS2 setup failed!\n");
+ }
+
+ s.line = 3;
+ s.membase = (u8 *)UART3_BASE;
+ s.irq = IRQ_UART3;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS3 setup failed!\n");
+ }
+#endif
+}
+
+void __init plat_mem_setup(void)
+{
+ char *argptr;
+
+ argptr = prom_getcmdline();
+
+ /* IO/MEM resources. */
+ set_io_port_base(0);
+ ioport_resource.start = 0x00000000;
+ ioport_resource.end = 0xffffffff;
+ iomem_resource.start = 0x00000000;
+ iomem_resource.end = 0xffffffff;
+
+ _machine_restart = jz_restart;
+ _machine_halt = jz_halt;
+ pm_power_off = jz_power_off;
+
+ jz_soc_setup(); /* soc specific setup */
+ jz_serial_setup(); /* serial port setup */
+ jz_board_setup(); /* board specific setup */
+}
diff --git a/arch/mips/jz4730/sleep.S b/arch/mips/jz4730/sleep.S
new file mode 100644
index 00000000000..9ee9e703603
--- /dev/null
+++ b/arch/mips/jz4730/sleep.S
@@ -0,0 +1,307 @@
+/*
+ * linux/arch/mips/jz4730/sleep.S
+ *
+ * jz4730 Assembler Sleep/WakeUp Management Routines
+ *
+ * Copyright (C) 2005 Ingenic Semiconductor
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/mach-jz4730/regs.h>
+
+ .text
+ .set noreorder
+ .set noat
+
+ .extern jz_flush_cache_all
+
+/*
+ * jz_cpu_suspend()
+ *
+ * Forces CPU into hibernate mode
+ */
+
+ .globl jz_cpu_suspend
+jz_cpu_suspend:
+
+ /* save hi, lo and general registers except k0($26) and k1($27) (total 32) */
+ move k0, sp
+ addiu k0, k0, -(32*4)
+ mfhi k1
+ sw $0, 0(k0)
+ sw $1, 4(k0)
+ sw k1, 120(k0) /* hi */
+ mflo k1
+ sw $2, 8(k0)
+ sw $3, 12(k0)
+ sw k1, 124(k0) /* lo */
+ sw $4, 16(k0)
+ sw $5, 20(k0)
+ sw $6, 24(k0)
+ sw $7, 28(k0)
+ sw $8, 32(k0)
+ sw $9, 36(k0)
+ sw $10, 40(k0)
+ sw $11, 44(k0)
+ sw $12, 48(k0)
+ sw $13, 52(k0)
+ sw $14, 56(k0)
+ sw $15, 60(k0)
+ sw $16, 64(k0)
+ sw $17, 68(k0)
+ sw $18, 72(k0)
+ sw $19, 76(k0)
+ sw $20, 80(k0)
+ sw $21, 84(k0)
+ sw $22, 88(k0)
+ sw $23, 92(k0)
+ sw $24, 96(k0)
+ sw $25, 100(k0)
+ sw $28, 104(k0)
+ sw $29, 108(k0) /* saved sp */
+ sw $30, 112(k0)
+ sw $31, 116(k0) /* saved ra */
+ move sp, k0
+
+ /* save CP0 registers and sp (total 26) */
+ move k0, sp
+ addiu k0, k0, -(26*4)
+
+ mfc0 $1, CP0_INDEX
+ mfc0 $2, CP0_RANDOM
+ mfc0 $3, CP0_ENTRYLO0
+ mfc0 $4, CP0_ENTRYLO1
+ mfc0 $5, CP0_CONTEXT
+ mfc0 $6, CP0_PAGEMASK
+ mfc0 $7, CP0_WIRED
+ mfc0 $8, CP0_BADVADDR
+ mfc0 $9, CP0_ENTRYHI
+ mfc0 $10, CP0_STATUS
+/* mfc0 $11, $12, 1*/ /* IntCtl */
+ mfc0 $12, CP0_CAUSE
+ mfc0 $13, CP0_EPC
+/* mfc0 $14, $15, 1*/ /* EBase */
+ mfc0 $15, CP0_CONFIG
+/* mfc0 $16, CP0_CONFIG, 7*/ /* Config 7 */
+ mfc0 $17, CP0_LLADDR
+ mfc0 $18, CP0_WATCHLO
+ mfc0 $19, CP0_WATCHHI
+ mfc0 $20, CP0_DEBUG
+ mfc0 $21, CP0_DEPC
+ mfc0 $22, CP0_ECC
+ mfc0 $23, CP0_TAGLO
+ mfc0 $24, CP0_ERROREPC
+ mfc0 $25, CP0_DESAVE
+
+ sw $1, 0(k0)
+ sw $2, 4(k0)
+ sw $3, 8(k0)
+ sw $4, 12(k0)
+ sw $5, 16(k0)
+ sw $6, 20(k0)
+ sw $7, 24(k0)
+ sw $8, 28(k0)
+ sw $9, 32(k0)
+ sw $10, 36(k0)
+ sw $11, 40(k0)
+ sw $12, 44(k0)
+ sw $13, 48(k0)
+ sw $14, 52(k0)
+ sw $15, 56(k0)
+ sw $16, 60(k0)
+ sw $17, 64(k0)
+ sw $18, 68(k0)
+ sw $19, 72(k0)
+ sw $20, 76(k0)
+ sw $21, 80(k0)
+ sw $22, 84(k0)
+ sw $23, 88(k0)
+ sw $24, 92(k0)
+ sw $25, 96(k0)
+ sw $29, 100(k0) /* saved sp */
+ move sp, k0
+
+ /* preserve virtual address of stack */
+ la k0, suspend_save_sp
+ sw sp, 0(k0)
+
+ /* flush caches and write buffers */
+ jal jz_flush_cache_all
+ nop
+
+ /* set new sdram refresh constant */
+ li t0, 1
+ la t1, EMC_RTCOR
+ sh t0, 0(t1)
+
+ /* disable PLL */
+ la t0, CPM_PLCR1
+ sw $0, 0(t0)
+
+ /* put CPU to hibernate mode */
+ la t0, CPM_LPCR
+ lw t1, 0(t0)
+ li t2, ~CPM_LPCR_LPM_MASK
+ and t1, t2
+ ori t1, CPM_LPCR_LPM_HIBERNATE
+
+ .align 5
+ /* align execution to a cache line */
+ j 1f
+
+ .align 5
+1:
+ /* all needed values are now in registers.
+ * These last instructions should be in cache
+ */
+ nop
+ nop
+
+ /* set hibernate mode */
+ sw t1, 0(t0)
+ nop
+
+ /* enter hibernate mode */
+ .set mips3
+ wait
+ nop
+ .set mips2
+
+2: j 2b /* loop waiting for suspended */
+ nop
+
+/*
+ * jz_cpu_resume()
+ *
+ * entry point from bootloader into kernel during resume
+ */
+
+ .align 5
+ .globl jz_cpu_resume
+jz_cpu_resume:
+ /* clear SCR.HGP */
+ la t0, CPM_SCR
+ lw t1, 0(t0)
+ li t2, ~CPM_SCR_HGP
+ and t1, t2
+ sw t1, 0(t0)
+
+ /* restore LPCR.LPM to IDLE mode */
+ la t0, CPM_LPCR
+ lw t1, 0(t0)
+ li t2, ~CPM_LPCR_LPM_MASK
+ and t1, t2
+ ori t1, CPM_LPCR_LPM_IDLE
+ sw t1, 0(t0)
+
+ /* restore saved sp */
+ la t0, suspend_save_sp
+ lw sp, 0(t0)
+
+ /* restore CP0 registers */
+ move k0, sp
+ lw $1, 0(k0)
+ lw $2, 4(k0)
+ lw $3, 8(k0)
+ lw $4, 12(k0)
+ lw $5, 16(k0)
+ lw $6, 20(k0)
+ lw $7, 24(k0)
+ lw $8, 28(k0)
+ lw $9, 32(k0)
+ lw $10, 36(k0)
+ lw $11, 40(k0)
+ lw $12, 44(k0)
+ lw $13, 48(k0)
+ lw $14, 52(k0)
+ lw $15, 56(k0)
+ lw $16, 60(k0)
+ lw $17, 64(k0)
+ lw $18, 68(k0)
+ lw $19, 72(k0)
+ lw $20, 76(k0)
+ lw $21, 80(k0)
+ lw $22, 84(k0)
+ lw $23, 88(k0)
+ lw $24, 92(k0)
+ lw $25, 96(k0)
+ lw $29, 100(k0) /* saved sp */
+
+ mtc0 $1, CP0_INDEX
+ mtc0 $2, CP0_RANDOM
+ mtc0 $3, CP0_ENTRYLO0
+ mtc0 $4, CP0_ENTRYLO1
+ mtc0 $5, CP0_CONTEXT
+ mtc0 $6, CP0_PAGEMASK
+ mtc0 $7, CP0_WIRED
+ mtc0 $8, CP0_BADVADDR
+ mtc0 $9, CP0_ENTRYHI
+ mtc0 $10, CP0_STATUS
+/* mtc0 $11, $12, 1*/ /* IntCtl */
+ mtc0 $12, CP0_CAUSE
+ mtc0 $13, CP0_EPC
+/* mtc0 $14, $15, 1*/ /* EBase */
+ mtc0 $15, CP0_CONFIG
+/* mtc0 $16, CP0_CONFIG, 7*/ /* Config 7 */
+ mtc0 $17, CP0_LLADDR
+ mtc0 $18, CP0_WATCHLO
+ mtc0 $19, CP0_WATCHHI
+ mtc0 $20, CP0_DEBUG
+ mtc0 $21, CP0_DEPC
+ mtc0 $22, CP0_ECC
+ mtc0 $23, CP0_TAGLO
+ mtc0 $24, CP0_ERROREPC
+ mtc0 $25, CP0_DESAVE
+
+ /* restore general registers */
+ move k0, sp
+ lw k1, 120(k0) /* hi */
+ lw $0, 0(k0)
+ lw $1, 4(k0)
+ mthi k1
+ lw k1, 124(k0) /* lo */
+ lw $2, 8(k0)
+ lw $3, 12(k0)
+ mtlo k1
+ lw $4, 16(k0)
+ lw $5, 20(k0)
+ lw $6, 24(k0)
+ lw $7, 28(k0)
+ lw $8, 32(k0)
+ lw $9, 36(k0)
+ lw $10, 40(k0)
+ lw $11, 44(k0)
+ lw $12, 48(k0)
+ lw $13, 52(k0)
+ lw $14, 56(k0)
+ lw $15, 60(k0)
+ lw $16, 64(k0)
+ lw $17, 68(k0)
+ lw $18, 72(k0)
+ lw $19, 76(k0)
+ lw $20, 80(k0)
+ lw $21, 84(k0)
+ lw $22, 88(k0)
+ lw $23, 92(k0)
+ lw $24, 96(k0)
+ lw $25, 100(k0)
+ lw $28, 104(k0)
+ lw $29, 108(k0) /* saved sp */
+ lw $30, 112(k0)
+ lw $31, 116(k0) /* saved ra */
+
+ /* return to caller */
+ jr ra
+ nop
+
+suspend_save_sp:
+ .word 0 /* preserve sp here */
+
+ .set reorder
diff --git a/arch/mips/jz4730/time.c b/arch/mips/jz4730/time.c
new file mode 100644
index 00000000000..4aa3e453254
--- /dev/null
+++ b/arch/mips/jz4730/time.c
@@ -0,0 +1,129 @@
+/*
+ * linux/arch/mips/jz4730/time.c
+ *
+ * Setting up the clock on the JZ4730 boards.
+ *
+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/clockchips.h>
+
+#include <asm/time.h>
+#include <asm/jzsoc.h>
+
+#define JZ_TIMER_CHAN 0
+#define JZ_TIMER_IRQ IRQ_OST0
+#define JZ_TIMER_CLOCK JZ_EXTAL
+
+static unsigned int timer_latch;
+
+void (*jz_timer_callback)(void);
+
+static void jz_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static struct clock_event_device jz_clockevent_device = {
+ .name = "jz-timer",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+
+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
+
+ .rating = 300,
+ .irq = JZ_TIMER_IRQ,
+ .set_mode = jz_set_mode,
+};
+
+static irqreturn_t jz_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd = dev_id;
+
+ __ost_clear_uf(JZ_TIMER_CHAN); /* ACK timer */
+
+ if (jz_timer_callback)
+ jz_timer_callback();
+
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction jz_irqaction = {
+ .handler = jz_timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_PERCPU,
+ .name = "jz-timer",
+};
+
+cycle_t jz_get_cycles(struct clocksource *cs)
+{
+ unsigned int jz_timer_cnt;
+#if 0 /* clock source use pll, read directly */
+ jz_timer_cnt = timer_latch - REG_OST_TCNT(JZ_TIMER_CHAN);
+#else /* clock source use RTCClock or Extall Clock, wait read ready */
+ jz_timer_cnt = REG_OST_TCNT(JZ_TIMER_CHAN); /* dummy read */
+ while ( __ost_is_busy(JZ_TIMER_CHAN) ) ; /* wait read ready */
+ jz_timer_cnt = timer_latch - REG_OST_TCRB(JZ_TIMER_CHAN);
+#endif
+
+ /* convert jiffes to jz timer cycles */
+ return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + jz_timer_cnt);
+}
+
+static struct clocksource clocksource_jz = {
+ .name = "jz_clocksource",
+ .rating = 300,
+ .read = jz_get_cycles,
+ .mask = 0xFFFFFFFF,
+ .shift = 10, /* control clocksource.mult's accuracy */
+ .flags = CLOCK_SOURCE_WATCHDOG,
+};
+
+static int __init jz_clocksource_init(void)
+{
+ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift);
+ clocksource_register(&clocksource_jz);
+ return 0;
+}
+
+static void __init jz_timer_setup(void)
+{
+ struct clock_event_device *cd = &jz_clockevent_device;
+ struct irqaction *action = &jz_irqaction;
+ unsigned int cpu = smp_processor_id();
+
+ jz_clocksource_init();
+ cd->cpumask = cpumask_of(cpu);
+ clockevents_register_device(cd);
+ action->dev_id = cd;
+ setup_irq(JZ_TIMER_IRQ, &jz_irqaction);
+}
+
+void __init plat_time_init(void)
+{
+ /* Init timer, timer clock soure use extal clock */
+ timer_latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ;
+ __ost_set_mode(JZ_TIMER_CHAN, OST_TCSR_UIE | OST_TCSR_CKS_EXTAL);
+ __ost_set_reload(JZ_TIMER_CHAN, timer_latch);
+ __ost_set_count(JZ_TIMER_CHAN, timer_latch);
+ __ost_enable_channel(JZ_TIMER_CHAN);
+
+ jz_timer_setup();
+}
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
new file mode 100644
index 00000000000..ac4d3cd2dbe
--- /dev/null
+++ b/arch/mips/jz4740/Makefile
@@ -0,0 +1,26 @@
+#
+# Makefile for the Ingenic JZ4740.
+#
+
+# Object file lists.
+
+obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
+ platform.o i2c.o
+
+obj-$(CONFIG_PROC_FS) += proc.o
+
+# board specific support
+
+obj-$(CONFIG_JZ4740_PAVO) += board-pavo.o
+obj-$(CONFIG_JZ4740_LEO) += board-leo.o
+obj-$(CONFIG_JZ4740_LYRA) += board-lyra.o
+obj-$(CONFIG_JZ4725_DIPPER) += board-dipper.o
+obj-$(CONFIG_JZ4720_VIRGO) += board-virgo.o
+
+# PM support
+
+obj-$(CONFIG_PM) +=pm.o
+
+# CPU Frequency scaling support
+
+obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o
diff --git a/arch/mips/jz4740/board-dipper.c b/arch/mips/jz4740/board-dipper.c
new file mode 100644
index 00000000000..ca3022501ce
--- /dev/null
+++ b/arch/mips/jz4740/board-dipper.c
@@ -0,0 +1,117 @@
+/*
+ * linux/arch/mips/jz4740/board-dipper.c
+ *
+ * JZ4725 Dipper board setup routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+
+#include <asm/jzsoc.h>
+
+extern void (*jz_timer_callback)(void);
+
+#if 0
+static void dancing(void)
+{
+ static unsigned int count = 0;
+
+ count ++;
+ count &= 1;
+
+ if (count)
+ __gpio_set_pin(GPIO_LED_EN);
+ else
+ __gpio_clear_pin(GPIO_LED_EN);
+}
+#endif
+
+static void dipper_timer_callback(void)
+{
+ static unsigned long count = 0;
+
+ if ((++count) % 50 == 0) {
+// dancing();
+ count = 0;
+ }
+}
+
+static void __init board_cpm_setup(void)
+{
+ /* Stop unused module clocks here.
+ * We have started all module clocks at arch/mips/jz4740/setup.c.
+ */
+}
+
+static void __init board_gpio_setup(void)
+{
+ /*
+ * Most of the GPIO pins should have been initialized by the boot-loader
+ */
+
+ /*
+ * Initialize MSC pins
+ */
+ __gpio_as_msc();
+
+ /*
+ * Initialize Smart LCD pins
+ */
+// __gpio_as_slcd_18bit();
+
+ /*
+ * Initialize SSI pins
+ */
+ __gpio_as_ssi();
+
+ /*
+ * Initialize I2C pins
+ */
+ __gpio_as_i2c();
+
+ /*
+ * Initialize Other pins
+ */
+ __gpio_as_output(GPIO_SD_VCC_EN_N);
+ __gpio_clear_pin(GPIO_SD_VCC_EN_N);
+
+ __gpio_as_input(GPIO_SD_CD_N);
+ __gpio_disable_pull(GPIO_SD_CD_N);
+
+ __gpio_as_input(GPIO_SD_WP);
+ __gpio_disable_pull(GPIO_SD_WP);
+
+ __gpio_as_input(GPIO_DC_DETE_N);
+ __gpio_as_input(GPIO_CHARG_STAT_N);
+ __gpio_as_input(GPIO_USB_DETE);
+
+ __gpio_as_output(GPIO_DISP_OFF_N);
+
+// __gpio_as_output(GPIO_LED_EN);
+}
+
+void __init jz_board_setup(void)
+{
+ printk("JZ4725 DIPPER board setup\n");
+
+ board_cpm_setup();
+ board_gpio_setup();
+
+ jz_timer_callback = dipper_timer_callback;
+}
diff --git a/arch/mips/jz4740/board-leo.c b/arch/mips/jz4740/board-leo.c
new file mode 100644
index 00000000000..912636ae895
--- /dev/null
+++ b/arch/mips/jz4740/board-leo.c
@@ -0,0 +1,67 @@
+/*
+ * linux/arch/mips/jz4740/board-leo.c
+ *
+ * JZ4740 LEO board setup routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+
+#include <asm/jzsoc.h>
+
+extern void (*jz_timer_callback)(void);
+
+static void dancing(void)
+{
+ static unsigned char slash[] = "\\|/-";
+ static volatile unsigned char *p = (unsigned char *)0xb6000016;
+ static unsigned int count = 0;
+ *p = slash[count++];
+ count &= 3;
+}
+
+static void leo_timer_callback(void)
+{
+ static unsigned long count = 0;
+
+ if ((++count) % 10 == 0) {
+ dancing();
+ count = 0;
+ }
+}
+
+static void __init board_cpm_setup(void)
+{
+ /* Stop unused module clocks here.
+ * We have started all module clocks at arch/mips/jz4740/setup.c.
+ */
+}
+
+static void __init board_gpio_setup(void)
+{
+ /* All GPIO pins should have been initialized by the boot-loader */
+}
+
+void __init jz_board_setup(void)
+{
+ board_cpm_setup();
+ board_gpio_setup();
+ printk(" BOARD SETUP");
+ jz_timer_callback = leo_timer_callback;
+}
diff --git a/arch/mips/jz4740/board-lyra.c b/arch/mips/jz4740/board-lyra.c
new file mode 100644
index 00000000000..ea56626804a
--- /dev/null
+++ b/arch/mips/jz4740/board-lyra.c
@@ -0,0 +1,114 @@
+/*
+ * linux/arch/mips/jz4740/board-lyra.c
+ *
+ * JZ4740 LYRA board setup routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+
+#include <asm/jzsoc.h>
+
+extern void (*jz_timer_callback)(void);
+
+static void dancing(void)
+{
+ static unsigned int count = 0;
+
+ count ++;
+ count &= 1;
+ if (count)
+ __gpio_set_pin(GPIO_LED_EN);
+ else
+ __gpio_clear_pin(GPIO_LED_EN);
+}
+
+static void lyra_timer_callback(void)
+{
+ static unsigned long count = 0;
+
+ if ((++count) % 50 == 0) {
+ dancing();
+ count = 0;
+ }
+}
+
+static void __init board_cpm_setup(void)
+{
+ /* Stop unused module clocks here.
+ * We have started all module clocks at arch/mips/jz4740/setup.c.
+ */
+}
+
+static void __init board_gpio_setup(void)
+{
+ /*
+ * Most of the GPIO pins should have been initialized by the boot-loader
+ */
+
+ /*
+ * Initialize MSC pins
+ */
+ __gpio_as_msc();
+
+ /*
+ * Initialize LCD pins
+ */
+ __gpio_as_lcd_18bit();
+
+ /*
+ * Initialize SSI pins
+ */
+ __gpio_as_ssi();
+
+ /*
+ * Initialize I2C pins
+ */
+ __gpio_as_i2c();
+
+ /*
+ * Initialize Other pins
+ */
+ __gpio_as_output(GPIO_SD_VCC_EN_N);
+ __gpio_clear_pin(GPIO_SD_VCC_EN_N);
+
+ __gpio_as_input(GPIO_SD_CD_N);
+ __gpio_disable_pull(GPIO_SD_CD_N);
+
+ __gpio_as_input(GPIO_SD_WP);
+ __gpio_disable_pull(GPIO_SD_WP);
+
+ __gpio_as_input(GPIO_DC_DETE_N);
+ __gpio_as_input(GPIO_CHARG_STAT_N);
+ __gpio_as_input(GPIO_USB_DETE);
+
+ __gpio_as_output(GPIO_DISP_OFF_N);
+
+ __gpio_as_output(GPIO_LED_EN);
+}
+
+void __init jz_board_setup(void)
+{
+ printk("JZ4740 LYRA board setup\n");
+
+ board_cpm_setup();
+ board_gpio_setup();
+
+ jz_timer_callback = lyra_timer_callback;
+}
diff --git a/arch/mips/jz4740/board-pavo.c b/arch/mips/jz4740/board-pavo.c
new file mode 100644
index 00000000000..f121a7fcf6c
--- /dev/null
+++ b/arch/mips/jz4740/board-pavo.c
@@ -0,0 +1,114 @@
+/*
+ * linux/arch/mips/jz4740/board-pavo.c
+ *
+ * JZ4740 PAVO board setup routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+
+#include <asm/jzsoc.h>
+
+extern void (*jz_timer_callback)(void);
+
+static void dancing(void)
+{
+ static unsigned int count = 0;
+
+ count ++;
+ count &= 1;
+ if (count)
+ __gpio_set_pin(GPIO_LED_EN);
+ else
+ __gpio_clear_pin(GPIO_LED_EN);
+}
+
+static void pavo_timer_callback(void)
+{
+ static unsigned long count = 0;
+
+ if ((++count) % 50 == 0) {
+ dancing();
+ count = 0;
+ }
+}
+
+static void __init board_cpm_setup(void)
+{
+ /* Stop unused module clocks here.
+ * We have started all module clocks at arch/mips/jz4740/setup.c.
+ */
+}
+
+static void __init board_gpio_setup(void)
+{
+ /*
+ * Most of the GPIO pins should have been initialized by the boot-loader
+ */
+
+ /*
+ * Initialize MSC pins
+ */
+ __gpio_as_msc();
+
+ /*
+ * Initialize LCD pins
+ */
+ __gpio_as_lcd_18bit();
+
+ /*
+ * Initialize SSI pins
+ */
+ __gpio_as_ssi();
+
+ /*
+ * Initialize I2C pins
+ */
+ __gpio_as_i2c();
+
+ /*
+ * Initialize Other pins
+ */
+ __gpio_as_output(GPIO_SD_VCC_EN_N);
+ __gpio_clear_pin(GPIO_SD_VCC_EN_N);
+
+ __gpio_as_input(GPIO_SD_CD_N);
+ __gpio_disable_pull(GPIO_SD_CD_N);
+
+ __gpio_as_input(GPIO_SD_WP);
+ __gpio_disable_pull(GPIO_SD_WP);
+
+// __gpio_as_input(GPIO_DC_DETE_N);
+ __gpio_as_input(GPIO_CHARG_STAT_N);
+ __gpio_as_input(GPIO_USB_DETE);
+
+ __gpio_as_output(GPIO_DISP_OFF_N);
+
+ __gpio_as_output(GPIO_LED_EN);
+}
+
+void __init jz_board_setup(void)
+{
+ printk("JZ4740 PAVO board setup\n");
+
+ board_cpm_setup();
+ board_gpio_setup();
+
+ jz_timer_callback = pavo_timer_callback;
+}
diff --git a/arch/mips/jz4740/board-virgo.c b/arch/mips/jz4740/board-virgo.c
new file mode 100644
index 00000000000..1429877b80d
--- /dev/null
+++ b/arch/mips/jz4740/board-virgo.c
@@ -0,0 +1,114 @@
+/*
+ * linux/arch/mips/jz4740/board-virgo.c
+ *
+ * JZ4720 VIRGO board setup routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+
+#include <asm/jzsoc.h>
+
+extern void (*jz_timer_callback)(void);
+
+static void dancing(void)
+{
+ static unsigned int count = 0;
+
+ count ++;
+ count &= 1;
+ if (count)
+ __gpio_set_pin(GPIO_LED_EN);
+ else
+ __gpio_clear_pin(GPIO_LED_EN);
+}
+
+static void virgo_timer_callback(void)
+{
+ static unsigned long count = 0;
+
+ if ((++count) % 50 == 0) {
+ dancing();
+ count = 0;
+ }
+}
+
+static void __init board_cpm_setup(void)
+{
+ /* Stop unused module clocks here.
+ * We have started all module clocks at arch/mips/jz4740/setup.c.
+ */
+}
+
+static void __init board_gpio_setup(void)
+{
+ /*
+ * Most of the GPIO pins should have been initialized by the boot-loader
+ */
+
+ /*
+ * Initialize MSC pins
+ */
+ __gpio_as_msc();
+
+ /*
+ * Initialize LCD pins
+ */
+// __gpio_as_lcd_18bit();
+
+ /*
+ * Initialize SSI pins
+ */
+ __gpio_as_ssi();
+
+ /*
+ * Initialize I2C pins
+ */
+ __gpio_as_i2c();
+
+ /*
+ * Initialize Other pins
+ */
+ __gpio_as_output(GPIO_SD_VCC_EN_N);
+ __gpio_clear_pin(GPIO_SD_VCC_EN_N);
+
+ __gpio_as_input(GPIO_SD_CD_N);
+ __gpio_disable_pull(GPIO_SD_CD_N);
+
+// __gpio_as_input(GPIO_SD_WP);
+// __gpio_disable_pull(GPIO_SD_WP);
+
+ __gpio_as_input(GPIO_DC_DETE_N);
+// __gpio_as_input(GPIO_CHARG_STAT_N);
+ __gpio_as_input(GPIO_USB_DETE);
+
+ __gpio_as_output(GPIO_DISP_OFF_N);
+
+// __gpio_as_output(GPIO_LED_EN);
+}
+
+void __init jz_board_setup(void)
+{
+ printk("JZ4720 VIRGO board setup\n");
+
+ board_cpm_setup();
+ board_gpio_setup();
+
+ jz_timer_callback = virgo_timer_callback;
+}
diff --git a/arch/mips/jz4740/cpufreq.c b/arch/mips/jz4740/cpufreq.c
new file mode 100644
index 00000000000..d646a1e2e0b
--- /dev/null
+++ b/arch/mips/jz4740/cpufreq.c
@@ -0,0 +1,602 @@
+/*
+ * linux/arch/mips/jz4740/cpufreq.c
+ *
+ * cpufreq driver for JZ4740
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/cpufreq.h>
+
+#include <asm/jzsoc.h>
+#include <asm/processor.h>
+
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+ "cpufreq-jz4740", msg)
+
+#undef CHANGE_PLL
+
+#define PLL_UNCHANGED 0
+#define PLL_GOES_UP 1
+#define PLL_GOES_DOWN 2
+
+#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000))
+
+/* Saved the boot-time parameters */
+static struct {
+ /* SDRAM parameters */
+ unsigned int mclk; /* memory clock, KHz */
+ unsigned int tras; /* RAS pulse width, cycles of mclk */
+ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */
+ unsigned int tpc; /* RAS Precharge time, cycles of mclk */
+ unsigned int trwl; /* Write Precharge Time, cycles of mclk */
+ unsigned int trc; /* RAS Cycle Time, cycles of mclk */
+ unsigned int rtcor; /* Refresh Time Constant */
+ unsigned int sdram_initialized;
+
+ /* LCD parameters */
+ unsigned int lcd_clk; /* LCD clock, Hz */
+ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */
+ unsigned int lcd_clks_initialized;
+} boot_config;
+
+struct jz4740_freq_percpu_info {
+ struct cpufreq_frequency_table table[7];
+};
+
+static struct jz4740_freq_percpu_info jz4740_freq_table;
+
+/*
+ * This contains the registers value for an operating point.
+ * If only part of a register needs to change then there is
+ * a mask value for that register.
+ * When going to a new operating point the current register
+ * value is ANDed with the ~mask and ORed with the new value.
+ */
+struct dpm_regs {
+ u32 cpccr; /* Clock Freq Control Register */
+ u32 cpccr_mask; /* Clock Freq Control Register mask */
+ u32 cppcr; /* PLL1 Control Register */
+ u32 cppcr_mask; /* PLL1 Control Register mask */
+ u32 pll_up_flag; /* New PLL freq is higher than current or not */
+};
+
+extern jz_clocks_t jz_clocks;
+
+static void jz_update_clocks(void)
+{
+ /* Next clocks must be updated if we have changed
+ * the PLL or divisors.
+ */
+ jz_clocks.cclk = __cpm_get_cclk();
+ jz_clocks.hclk = __cpm_get_hclk();
+ jz_clocks.mclk = __cpm_get_mclk();
+ jz_clocks.pclk = __cpm_get_pclk();
+ jz_clocks.lcdclk = __cpm_get_lcdclk();
+ jz_clocks.pixclk = __cpm_get_pixclk();
+ jz_clocks.i2sclk = __cpm_get_i2sclk();
+ jz_clocks.usbclk = __cpm_get_usbclk();
+ jz_clocks.mscclk = __cpm_get_mscclk();
+}
+
+static void
+jz_init_boot_config(void)
+{
+ if (!boot_config.lcd_clks_initialized) {
+ /* the first time to scale pll */
+ boot_config.lcd_clk = __cpm_get_lcdclk();
+ boot_config.lcdpix_clk = __cpm_get_pixclk();
+ boot_config.lcd_clks_initialized = 1;
+ }
+
+ if (!boot_config.sdram_initialized) {
+ /* the first time to scale frequencies */
+ unsigned int dmcr, rtcor;
+ unsigned int tras, rcd, tpc, trwl, trc;
+
+ dmcr = REG_EMC_DMCR;
+ rtcor = REG_EMC_RTCOR;
+
+ tras = (dmcr >> 13) & 0x7;
+ rcd = (dmcr >> 11) & 0x3;
+ tpc = (dmcr >> 8) & 0x7;
+ trwl = (dmcr >> 5) & 0x3;
+ trc = (dmcr >> 2) & 0x7;
+
+ boot_config.mclk = __cpm_get_mclk() / 1000;
+ boot_config.tras = tras + 4;
+ boot_config.rcd = rcd + 1;
+ boot_config.tpc = tpc + 1;
+ boot_config.trwl = trwl + 1;
+ boot_config.trc = trc * 2 + 1;
+ boot_config.rtcor = rtcor;
+
+ boot_config.sdram_initialized = 1;
+ }
+}
+
+static void jz_update_dram_rtcor(unsigned int new_mclk)
+{
+ unsigned int rtcor;
+
+ new_mclk /= 1000;
+ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk;
+ rtcor--;
+
+ if (rtcor < 1) rtcor = 1;
+ if (rtcor > 255) rtcor = 255;
+
+ REG_EMC_RTCOR = rtcor;
+ REG_EMC_RTCNT = rtcor;
+}
+
+static void jz_update_dram_dmcr(unsigned int new_mclk)
+{
+ unsigned int dmcr;
+ unsigned int tras, rcd, tpc, trwl, trc;
+ unsigned int valid_time, new_time; /* ns */
+
+ new_mclk /= 1000;
+ tras = boot_config.tras * new_mclk / boot_config.mclk;
+ rcd = boot_config.rcd * new_mclk / boot_config.mclk;
+ tpc = boot_config.tpc * new_mclk / boot_config.mclk;
+ trwl = boot_config.trwl * new_mclk / boot_config.mclk;
+ trc = boot_config.trc * new_mclk / boot_config.mclk;
+
+ /* Validation checking */
+ valid_time = (boot_config.tras * 1000000) / boot_config.mclk;
+ new_time = (tras * 1000000) / new_mclk;
+ if (new_time < valid_time) tras += 1;
+
+ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk;
+ new_time = (rcd * 1000000) / new_mclk;
+ if (new_time < valid_time) rcd += 1;
+
+ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk;
+ new_time = (tpc * 1000000) / new_mclk;
+ if (new_time < valid_time) tpc += 1;
+
+ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk;
+ new_time = (trwl * 1000000) / new_mclk;
+ if (new_time < valid_time) trwl += 1;
+
+ valid_time = (boot_config.trc * 1000000) / boot_config.mclk;
+ new_time = (trc * 1000000) / new_mclk;
+ if (new_time < valid_time) trc += 2;
+
+ tras = (tras < 4) ? 4: tras;
+ tras = (tras > 11) ? 11: tras;
+ tras -= 4;
+
+ rcd = (rcd < 1) ? 1: rcd;
+ rcd = (rcd > 4) ? 4: rcd;
+ rcd -= 1;
+
+ tpc = (tpc < 1) ? 1: tpc;
+ tpc = (tpc > 8) ? 8: tpc;
+ tpc -= 1;
+
+ trwl = (trwl < 1) ? 1: trwl;
+ trwl = (trwl > 4) ? 4: trwl;
+ trwl -= 1;
+
+ trc = (trc < 1) ? 1: trc;
+ trc = (trc > 15) ? 15: trc;
+ trc /= 2;
+
+ dmcr = REG_EMC_DMCR;
+
+ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK);
+ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT));
+
+ REG_EMC_DMCR = dmcr;
+}
+
+static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk)
+{
+ /* No risk, no fun: run with interrupts on! */
+ if (new_mclk > cur_mclk) {
+ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL
+ * and TRC of DMCR before changing the frequency.
+ */
+ jz_update_dram_dmcr(new_mclk);
+ } else {
+ /* We're going SLOWER: first update RTCOR value
+ * before changing the frequency.
+ */
+ jz_update_dram_rtcor(new_mclk);
+ }
+}
+
+static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk)
+{
+ /* No risk, no fun: run with interrupts on! */
+ if (new_mclk > cur_mclk) {
+ /* We're going FASTER, so update RTCOR
+ * after changing the frequency
+ */
+ jz_update_dram_rtcor(new_mclk);
+ } else {
+ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL
+ * and TRC of DMCR after changing the frequency.
+ */
+ jz_update_dram_dmcr(new_mclk);
+ }
+}
+
+static void jz_scale_divisors(struct dpm_regs *regs)
+{
+ unsigned int cpccr;
+ unsigned int cur_mclk, new_mclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned int tmp = 0, wait = PLL_WAIT_500NS;
+
+ cpccr = REG_CPM_CPCCR;
+ cpccr &= ~((unsigned long)regs->cpccr_mask);
+ cpccr |= regs->cpccr;
+ cpccr |= CPM_CPCCR_CE; /* update immediately */
+
+ cur_mclk = __cpm_get_mclk();
+ new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT];
+
+ /* Update some DRAM parameters before changing frequency */
+ jz_update_dram_prev(cur_mclk, new_mclk);
+
+ /* update register to change the clocks.
+ * align this code to a cache line.
+ */
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "li %3,0\n\t"
+ "1:\n\t"
+ "bne %3,%2,1b\n\t"
+ "addi %3, 1\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
+
+ /* Update some other DRAM parameters after changing frequency */
+ jz_update_dram_post(cur_mclk, new_mclk);
+}
+
+#ifdef CHANGE_PLL
+/* Maintain the LCD clock and pixel clock */
+static void jz_scale_lcd_divisors(struct dpm_regs *regs)
+{
+ unsigned int new_pll, new_lcd_div, new_lcdpix_div;
+ unsigned int cpccr;
+ unsigned int tmp = 0, wait = PLL_WAIT_500NS;
+
+ if (!boot_config.lcd_clks_initialized) return;
+
+ new_pll = __cpm_get_pllout();
+ new_lcd_div = new_pll / boot_config.lcd_clk;
+ new_lcdpix_div = new_pll / boot_config.lcdpix_clk;
+
+ if (new_lcd_div < 1)
+ new_lcd_div = 1;
+ if (new_lcd_div > 16)
+ new_lcd_div = 16;
+
+ if (new_lcdpix_div < 1)
+ new_lcdpix_div = 1;
+ if (new_lcdpix_div > 512)
+ new_lcdpix_div = 512;
+
+// REG_CPM_CPCCR2 = new_lcdpix_div - 1;
+
+ cpccr = REG_CPM_CPCCR;
+ cpccr &= ~CPM_CPCCR_LDIV_MASK;
+ cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT);
+ cpccr |= CPM_CPCCR_CE; /* update immediately */
+
+ /* update register to change the clocks.
+ * align this code to a cache line.
+ */
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "li %3,0\n\t"
+ "1:\n\t"
+ "bne %3,%2,1b\n\t"
+ "addi %3, 1\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
+}
+
+static void jz_scale_pll(struct dpm_regs *regs)
+{
+ unsigned int cppcr;
+ unsigned int cur_mclk, new_mclk, new_pll;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ int od[] = {1, 2, 2, 4};
+
+ cppcr = REG_CPM_CPPCR;
+ cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK);
+ regs->cppcr &= ~CPM_CPPCR_PLLEN;
+ cppcr |= (regs->cppcr | 0xff);
+
+ /* Update some DRAM parameters before changing frequency */
+ new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]);
+ cur_mclk = __cpm_get_mclk();
+ new_mclk = new_pll / div[(REG_CPM_CPCCR>>CPM_CPCCR_MDIV_BIT) & 0xf];
+
+ /*
+ * Update some SDRAM parameters
+ */
+ jz_update_dram_prev(cur_mclk, new_mclk);
+
+ /*
+ * Update PLL, align code to cache line.
+ */
+ cppcr |= CPM_CPPCR_PLLEN;
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CPPCR), "r" (cppcr));
+
+ /* Update some other DRAM parameters after changing frequency */
+ jz_update_dram_post(cur_mclk, new_mclk);
+}
+#endif
+
+static void jz4740_transition(struct dpm_regs *regs)
+{
+ /*
+ * Get and save some boot-time conditions.
+ */
+ jz_init_boot_config();
+
+#ifdef CHANGE_PLL
+ /*
+ * Disable LCD before scaling pll.
+ * LCD and LCD pixel clocks should not be changed even if the PLL
+ * output frequency has been changed.
+ */
+ REG_LCD_CTRL &= ~LCD_CTRL_ENA;
+
+ /*
+ * Stop module clocks before scaling PLL
+ */
+ __cpm_stop_eth();
+ __cpm_stop_aic(1);
+ __cpm_stop_aic(2);
+#endif
+
+ /* ... add more as necessary */
+
+ if (regs->pll_up_flag == PLL_GOES_UP) {
+ /* the pll frequency is going up, so change dividors first */
+ jz_scale_divisors(regs);
+#ifdef CHANGE_PLL
+ jz_scale_pll(regs);
+#endif
+ }
+ else if (regs->pll_up_flag == PLL_GOES_DOWN) {
+ /* the pll frequency is going down, so change pll first */
+#ifdef CHANGE_PLL
+ jz_scale_pll(regs);
+#endif
+ jz_scale_divisors(regs);
+ }
+ else {
+ /* the pll frequency is unchanged, so change divisors only */
+ jz_scale_divisors(regs);
+ }
+
+#ifdef CHANGE_PLL
+ /*
+ * Restart module clocks before scaling PLL
+ */
+ __cpm_start_eth();
+ __cpm_start_aic(1);
+ __cpm_start_aic(2);
+
+ /* ... add more as necessary */
+
+ /* Scale the LCD divisors after scaling pll */
+ if (regs->pll_up_flag != PLL_UNCHANGED) {
+ jz_scale_lcd_divisors(regs);
+ }
+
+ /* Enable LCD controller */
+ REG_LCD_CTRL &= ~LCD_CTRL_DIS;
+ REG_LCD_CTRL |= LCD_CTRL_ENA;
+#endif
+
+ /* Update system clocks */
+ jz_update_clocks();
+}
+
+extern unsigned int idle_times;
+static unsigned int jz4740_freq_get(unsigned int cpu)
+{
+ return (__cpm_get_cclk() / 1000);
+}
+
+static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs)
+{
+ int n2FR[33] = {
+ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
+ 9
+ };
+ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */
+ unsigned int div_of_cclk, new_freq, i;
+
+ regs->pll_up_flag = PLL_UNCHANGED;
+ regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK;
+
+ new_freq = jz4740_freq_table.table[index].frequency;
+
+ do {
+ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq);
+ } while (div_of_cclk==0);
+
+ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) {
+ for(i = 1; i<4; i++) {
+ div[i] = 3;
+ }
+ } else {
+ for(i = 1; i<4; i++) {
+ div[i] = 2;
+ }
+ }
+
+ for(i = 0; i<4; i++) {
+ div[i] *= div_of_cclk;
+ }
+
+ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]);
+
+ regs->cpccr =
+ (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
+ (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
+ (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
+ (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT);
+
+ return div_of_cclk;
+}
+
+static void jz4740_set_cpu_divider_index(unsigned int cpu, unsigned int index)
+{
+ unsigned long divisor, old_divisor;
+ struct cpufreq_freqs freqs;
+ struct dpm_regs regs;
+
+ old_divisor = __cpm_get_pllout() / __cpm_get_cclk();
+ divisor = index_to_divisor(index, &regs);
+
+ freqs.old = __cpm_get_cclk() / 1000;
+ freqs.new = __cpm_get_pllout() / (1000 * divisor);
+ freqs.cpu = cpu;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ if (old_divisor != divisor)
+ jz4740_transition(&regs);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+}
+
+static int jz4740_freq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int new_index = 0;
+
+ if (cpufreq_frequency_table_target(policy,
+ &jz4740_freq_table.table[0],
+ target_freq, relation, &new_index))
+ return -EINVAL;
+
+ jz4740_set_cpu_divider_index(policy->cpu, new_index);
+
+ dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR);
+
+ return 0;
+}
+
+static int jz4740_freq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy,
+ &jz4740_freq_table.table[0]);
+}
+
+static int __init jz4740_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+
+ struct cpufreq_frequency_table *table = &jz4740_freq_table.table[0];
+ unsigned int MAX_FREQ;
+
+ dprintk(KERN_INFO "Jz4740 cpufreq driver\n");
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ policy->cpuinfo.min_freq = MAX_FREQ/8;
+ policy->cpuinfo.max_freq = MAX_FREQ;
+ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */
+
+ table[0].index = 0;
+ table[0].frequency = MAX_FREQ/8;
+ table[1].index = 1;
+ table[1].frequency = MAX_FREQ/6;
+ table[2].index = 2;
+ table[2].frequency = MAX_FREQ/4;
+ table[3].index = 3;
+ table[3].frequency = MAX_FREQ/3;
+ table[4].index = 4;
+ table[4].frequency = MAX_FREQ/2;
+ table[5].index = 5;
+ table[5].frequency = MAX_FREQ;
+ table[6].index = 6;
+ table[6].frequency = CPUFREQ_TABLE_END;
+
+#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
+ cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */
+#endif
+
+ return cpufreq_frequency_table_cpuinfo(policy, table);
+}
+
+static struct cpufreq_driver cpufreq_jz4740_driver = {
+// .flags = CPUFREQ_STICKY,
+ .init = jz4740_cpufreq_driver_init,
+ .verify = jz4740_freq_verify,
+ .target = jz4740_freq_target,
+ .get = jz4740_freq_get,
+ .name = "jz4740",
+};
+
+static int __init jz4740_cpufreq_init(void)
+{
+ return cpufreq_register_driver(&cpufreq_jz4740_driver);
+}
+
+static void __exit jz4740_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&cpufreq_jz4740_driver);
+}
+
+module_init(jz4740_cpufreq_init);
+module_exit(jz4740_cpufreq_exit);
+
+MODULE_AUTHOR("Regen <lhhuang@ingenic.cn>");
+MODULE_DESCRIPTION("cpufreq driver for Jz4740");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/mips/jz4740/dma.c b/arch/mips/jz4740/dma.c
new file mode 100644
index 00000000000..dd5055e599a
--- /dev/null
+++ b/arch/mips/jz4740/dma.c
@@ -0,0 +1,768 @@
+/*
+ * linux/arch/mips/jz4740/dma.c
+ *
+ * Support functions for the JZ4740 internal DMA channels.
+ * No-descriptor transfer only.
+ * Descriptor transfer should also call jz_request_dma() to get a free
+ * channel and call jz_free_dma() to free the channel. And driver should
+ * build the DMA descriptor and setup the DMA channel by itself.
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/soundcard.h>
+
+#include <asm/system.h>
+#include <asm/addrspace.h>
+#include <asm/jzsoc.h>
+
+/*
+ * A note on resource allocation:
+ *
+ * All drivers needing DMA channels, should allocate and release them
+ * through the public routines `jz_request_dma()' and `jz_free_dma()'.
+ *
+ * In order to avoid problems, all processes should allocate resources in
+ * the same sequence and release them in the reverse order.
+ *
+ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ.
+ * When releasing them, first release the IRQ, then release the DMA. The
+ * main reason for this order is that, if you are requesting the DMA buffer
+ * done interrupt, you won't know the irq number until the DMA channel is
+ * returned from jz_request_dma().
+ */
+
+struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = {
+ {dev_id:-1,},
+ {dev_id:-1,},
+ {dev_id:-1,},
+ {dev_id:-1,},
+ {dev_id:-1,},
+ {dev_id:-1,},
+};
+
+// Device FIFO addresses and default DMA modes
+static const struct {
+ unsigned int fifo_addr;
+ unsigned int dma_mode;
+ unsigned int dma_source;
+} dma_dev_table[DMA_ID_MAX] = {
+ {CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT},
+ {CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN},
+ {CPHYSADDR(SSI_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSIOUT},
+ {CPHYSADDR(SSI_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSIIN},
+ {CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT},
+ {CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN},
+ {CPHYSADDR(MSC_TXFIFO), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSCOUT},
+ {CPHYSADDR(MSC_RXFIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSCIN},
+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU},
+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO},
+ {},
+};
+
+
+int jz_dma_read_proc(char *buf, char **start, off_t fpos,
+ int length, int *eof, void *data)
+{
+ int i, len = 0;
+ struct jz_dma_chan *chan;
+
+ for (i = 0; i < MAX_DMA_NUM; i++) {
+ if ((chan = get_dma_chan(i)) != NULL) {
+ len += sprintf(buf + len, "%2d: %s\n",
+ i, chan->dev_str);
+ }
+ }
+
+ if (fpos >= len) {
+ *start = buf;
+ *eof = 1;
+ return 0;
+ }
+ *start = buf + fpos;
+ if ((len -= fpos) > length)
+ return length;
+ *eof = 1;
+ return len;
+}
+
+
+void dump_jz_dma_channel(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan;
+
+ if (dmanr > MAX_DMA_NUM)
+ return;
+ chan = &jz_dma_table[dmanr];
+
+ printk("DMA%d Registers:\n", dmanr);
+ printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR);
+ printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr));
+ printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr));
+ printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr));
+ printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr));
+ printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr));
+ printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr));
+ printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr));
+ printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR);
+}
+
+
+/**
+ * jz_request_dma - dynamically allcate an idle DMA channel to return
+ * @dev_id: the specified dma device id or DMA_ID_RAW_SET
+ * @dev_str: the specified dma device string name
+ * @irqhandler: the irq handler, or NULL
+ * @irqflags: the irq handler flags
+ * @irq_dev_id: the irq handler device id for shared irq
+ *
+ * Finds a free channel, and binds the requested device to it.
+ * Returns the allocated channel number, or negative on error.
+ * Requests the DMA done IRQ if irqhandler != NULL.
+ *
+*/
+/*int jz_request_dma(int dev_id, const char *dev_str,
+ void (*irqhandler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ void *irq_dev_id)
+*/
+
+int jz_request_dma(int dev_id, const char *dev_str,
+ irqreturn_t (*irqhandler)(int, void *),
+ unsigned long irqflags,
+ void *irq_dev_id)
+{
+ struct jz_dma_chan *chan;
+ int i, ret;
+
+ if (dev_id < 0 || dev_id >= DMA_ID_MAX)
+ return -EINVAL;
+
+ for (i = 0; i < MAX_DMA_NUM; i++) {
+ if (jz_dma_table[i].dev_id < 0)
+ break;
+ }
+ if (i == MAX_DMA_NUM) /* no free channel */
+ return -ENODEV;
+
+ /* we got a free channel */
+ chan = &jz_dma_table[i];
+
+ if (irqhandler) {
+ chan->irq = IRQ_DMA_0 + i; // allocate irq number
+ chan->irq_dev = irq_dev_id;
+ if ((ret = request_irq(chan->irq, irqhandler, irqflags,
+ dev_str, chan->irq_dev))) {
+ chan->irq = -1;
+ chan->irq_dev = NULL;
+ return ret;
+ }
+ } else {
+ chan->irq = -1;
+ chan->irq_dev = NULL;
+ }
+
+ // fill it in
+ chan->io = i;
+ chan->dev_id = dev_id;
+ chan->dev_str = dev_str;
+ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
+ chan->mode = dma_dev_table[dev_id].dma_mode;
+ chan->source = dma_dev_table[dev_id].dma_source;
+
+ return i;
+}
+
+void jz_free_dma(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan) {
+ printk("Trying to free DMA%d\n", dmanr);
+ return;
+ }
+
+ disable_dma(dmanr);
+ if (chan->irq)
+ free_irq(chan->irq, chan->irq_dev);
+
+ chan->irq = -1;
+ chan->irq_dev = NULL;
+ chan->dev_id = -1;
+}
+
+void jz_set_dma_dest_width(int dmanr, int nbit)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode &= ~DMAC_DCMD_DWDH_MASK;
+ switch (nbit) {
+ case 8:
+ chan->mode |= DMAC_DCMD_DWDH_8;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCMD_DWDH_16;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCMD_DWDH_32;
+ break;
+ }
+}
+
+void jz_set_dma_src_width(int dmanr, int nbit)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode &= ~DMAC_DCMD_SWDH_MASK;
+ switch (nbit) {
+ case 8:
+ chan->mode |= DMAC_DCMD_SWDH_8;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCMD_SWDH_16;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCMD_SWDH_32;
+ break;
+ }
+}
+
+void jz_set_dma_block_size(int dmanr, int nbyte)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode &= ~DMAC_DCMD_DS_MASK;
+ switch (nbyte) {
+ case 1:
+ chan->mode |= DMAC_DCMD_DS_8BIT;
+ break;
+ case 2:
+ chan->mode |= DMAC_DCMD_DS_16BIT;
+ break;
+ case 4:
+ chan->mode |= DMAC_DCMD_DS_32BIT;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCMD_DS_16BYTE;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCMD_DS_32BYTE;
+ break;
+ }
+}
+
+unsigned int jz_get_dma_command(int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ return chan->mode;
+}
+
+/**
+ * jz_set_dma_mode - do the raw settings for the specified DMA channel
+ * @dmanr: the specified DMA channel
+ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE
+ * @dma_mode: dma raw mode
+ * @dma_source: dma raw request source
+ * @fifo_addr: dma raw device fifo address
+ *
+ * Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call
+ * jz_set_dma_mode() rather than set_dma_mode() if you work with
+ * and external request dma device.
+ *
+ * NOTE: Don not dynamically allocate dma channel if one external request
+ * dma device will occupy this channel.
+*/
+int jz_set_dma_mode(unsigned int dmanr, unsigned int mode,
+ unsigned int dma_mode, unsigned int dma_source,
+ unsigned int fifo_addr)
+{
+ int dev_id, i;
+ struct jz_dma_chan *chan;
+
+ if (dmanr > MAX_DMA_NUM)
+ return -ENODEV;
+ for (i = 0; i < MAX_DMA_NUM; i++) {
+ if (jz_dma_table[i].dev_id < 0)
+ break;
+ }
+ if (i == MAX_DMA_NUM)
+ return -ENODEV;
+
+ chan = &jz_dma_table[dmanr];
+ dev_id = chan->dev_id;
+ if (dev_id > 0) {
+ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n",
+ __FUNCTION__, dmanr);
+ return -ENODEV;
+ }
+
+ /* clone it from the dynamically allocated. */
+ if (i != dmanr) {
+ chan->irq = jz_dma_table[i].irq;
+ chan->irq_dev = jz_dma_table[i].irq_dev;
+ chan->dev_str = jz_dma_table[i].dev_str;
+ jz_dma_table[i].irq = 0;
+ jz_dma_table[i].irq_dev = NULL;
+ jz_dma_table[i].dev_id = -1;
+ }
+ chan->dev_id = DMA_ID_RAW_SET;
+ chan->io = dmanr;
+ chan->fifo_addr = fifo_addr;
+ chan->mode = dma_mode;
+ chan->source = dma_source;
+
+ set_dma_mode(dmanr, dma_mode);
+
+ return dmanr;
+}
+
+void enable_dma(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+ REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */
+ __dmac_enable_channel(dmanr);
+ if (chan->irq)
+ __dmac_channel_enable_irq(dmanr);
+}
+
+#define DMA_DISABLE_POLL 0x10000
+
+void disable_dma(unsigned int dmanr)
+{
+ int i;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ if (!__dmac_channel_enabled(dmanr))
+ return;
+
+ for (i = 0; i < DMA_DISABLE_POLL; i++)
+ if (__dmac_channel_transmit_end_detected(dmanr))
+ break;
+#if 0
+ if (i == DMA_DISABLE_POLL)
+ printk(KERN_INFO "disable_dma: poll expired!\n");
+#endif
+
+ __dmac_disable_channel(dmanr);
+ if (chan->irq)
+ __dmac_channel_disable_irq(dmanr);
+}
+
+/* Note: DMA_MODE_MASK is simulated by sw */
+void set_dma_mode(unsigned int dmanr, unsigned int mode)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ if (mode == DMA_MODE_READ) {
+ chan->mode |= DMAC_DCMD_DAI;
+ chan->mode &= ~DMAC_DCMD_SAI;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode |= DMAC_DCMD_SAI;
+ chan->mode &= ~DMAC_DCMD_DAI;
+ } else {
+ printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+ }
+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+}
+
+void set_dma_addr(unsigned int dmanr, unsigned int phyaddr)
+{
+ unsigned int mode;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ mode = chan->mode & DMA_MODE_MASK;
+ if (mode == DMA_MODE_READ) {
+ REG_DMAC_DSAR(chan->io) = chan->fifo_addr;
+ REG_DMAC_DTAR(chan->io) = phyaddr;
+ } else if (mode == DMA_MODE_WRITE) {
+ REG_DMAC_DSAR(chan->io) = phyaddr;
+ REG_DMAC_DTAR(chan->io) = chan->fifo_addr;
+ } else
+ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n");
+}
+
+void set_dma_count(unsigned int dmanr, unsigned int bytecnt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ int dma_ds[] = {4, 1, 2, 16, 32};
+ unsigned int ds;
+
+ if (!chan)
+ return;
+
+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
+ REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count
+}
+
+unsigned int get_dma_residue(unsigned int dmanr)
+{
+ unsigned int count, ds;
+ int dma_ds[] = {4, 1, 2, 16, 32};
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+
+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
+ count = REG_DMAC_DTCR(chan->io);
+ count = count * dma_ds[ds];
+
+ return count;
+}
+
+void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ switch (audio_fmt) {
+ case AFMT_U8:
+ /* burst mode : 32BIT */
+ break;
+ case AFMT_S16_LE:
+ /* burst mode : 16BYTE */
+ if (mode == DMA_MODE_READ) {
+ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_DAI;
+ chan->mode &= ~DMAC_DCMD_SAI;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_SAI;
+ chan->mode &= ~DMAC_DCMD_DAI;
+ } else
+ printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+
+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+ break;
+ }
+}
+
+void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ switch (audio_fmt) {
+ case 8:
+ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
+ break;
+ case 16:
+ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
+ if (mode == DMA_MODE_READ) {
+ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_DAI;
+ chan->mode &= ~DMAC_DCMD_SAI;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_SAI;
+ chan->mode &= ~DMAC_DCMD_DAI;
+ } else
+ printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+
+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+ break;
+ }
+}
+
+#undef JZ4740_DMAC_TEST_ENABLE
+
+#ifdef JZ4740_DMAC_TEST_ENABLE
+
+/*
+ * DMA test: external address <--> external address
+ */
+#define TEST_DMA_SIZE 16*1024
+
+static jz_dma_desc *dma_desc;
+
+static int dma_chan;
+static dma_addr_t dma_desc_phys_addr;
+static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr;
+
+static int dma_check_result(void *src, void *dst, int size)
+{
+ unsigned int addr1, addr2, i, err = 0;
+
+ addr1 = (unsigned int)src;
+ addr2 = (unsigned int)dst;
+
+ for (i = 0; i < size; i += 4) {
+ if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) {
+ err++;
+ printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2);
+ }
+ addr1 += 4;
+ addr2 += 4;
+ }
+ printk("check DMA result err=%d\n", err);
+ return err;
+}
+
+static void jz4740_dma_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ printk("jz4740_dma_irq %d\n", irq);
+
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+
+ if (__dmac_channel_transmit_halt_detected(dma_chan)) {
+ printk("DMA HALT\n");
+ __dmac_channel_clear_transmit_halt(dma_chan);
+ }
+
+ if (__dmac_channel_address_error_detected(dma_chan)) {
+ printk("DMA ADDR ERROR\n");
+ __dmac_channel_clear_address_error(dma_chan);
+ }
+
+ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) {
+ printk("DMA DESC INVALID\n");
+ __dmac_channel_clear_descriptor_invalid(dma_chan);
+ }
+
+ if (__dmac_channel_count_terminated_detected(dma_chan)) {
+ printk("DMA CT\n");
+ __dmac_channel_clear_count_terminated(dma_chan);
+ }
+
+ if (__dmac_channel_transmit_end_detected(dma_chan)) {
+ printk("DMA TT\n");
+ __dmac_channel_clear_transmit_end(dma_chan);
+ dump_jz_dma_channel(dma_chan);
+ dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE);
+ }
+
+ /* free buffers */
+ printk("free DMA buffers\n");
+ free_pages(dma_src_addr, 2);
+ free_pages(dma_dst_addr, 2);
+
+ if (dma_desc)
+ free_pages((unsigned int)dma_desc, 0);
+
+ /* free dma */
+ jz_free_dma(dma_chan);
+}
+
+void dma_nodesc_test(void)
+{
+ unsigned int addr, i;
+
+ printk("dma_nodesc_test\n");
+
+ /* Request DMA channel and setup irq handler */
+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4740_dma_irq,
+ SA_INTERRUPT, NULL);
+ if (dma_chan < 0) {
+ printk("Setup irq failed\n");
+ return;
+ }
+
+ printk("Requested DMA channel = %d\n", dma_chan);
+
+ /* Allocate DMA buffers */
+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+
+ dma_src_phys_addr = CPHYSADDR(dma_src_addr);
+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
+
+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
+
+ /* Prepare data for source buffer */
+ addr = (unsigned int)dma_src_addr;
+ for (i = 0; i < TEST_DMA_SIZE; i += 4) {
+ *(volatile unsigned int *)addr = addr;
+ addr += 4;
+ }
+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
+
+ /* Init target buffer */
+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
+
+ /* Init DMA module */
+ printk("Starting DMA\n");
+ REG_DMAC_DMACR = 0;
+ REG_DMAC_DCCSR(dma_chan) = 0;
+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr;
+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr;
+ REG_DMAC_DTCR(dma_chan) = 512;
+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE;
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
+ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */
+
+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
+}
+
+void dma_desc_test(void)
+{
+ unsigned int next, addr, i;
+ static jz_dma_desc *desc;
+
+ printk("dma_desc_test\n");
+
+ /* Request DMA channel and setup irq handler */
+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4740_dma_irq,
+ SA_INTERRUPT, NULL);
+ if (dma_chan < 0) {
+ printk("Setup irq failed\n");
+ return;
+ }
+
+ printk("Requested DMA channel = %d\n", dma_chan);
+
+ /* Allocate DMA buffers */
+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+
+ dma_src_phys_addr = CPHYSADDR(dma_src_addr);
+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
+
+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
+
+ /* Prepare data for source buffer */
+ addr = (unsigned int)dma_src_addr;
+ for (i = 0; i < TEST_DMA_SIZE; i += 4) {
+ *(volatile unsigned int *)addr = addr;
+ addr += 4;
+ }
+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
+
+ /* Init target buffer */
+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
+
+ /* Allocate DMA descriptors */
+ dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0);
+ dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc);
+
+ printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr);
+
+ /* Setup DMA descriptors */
+ desc = dma_desc;
+ next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
+ desc->dsadr = dma_src_phys_addr; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr; /* DMA target address */
+ desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */
+
+ desc++;
+ next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
+ desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */
+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
+
+ desc++;
+ next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
+ desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */
+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
+
+ desc++;
+ next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE;
+ desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */
+ desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */
+
+ dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc)));
+
+ /* Setup DMA descriptor address */
+ REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr;
+
+ /* Setup request source */
+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
+
+ /* Setup DMA channel control/status register */
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */
+
+ /* Enable DMA */
+ REG_DMAC_DMACR = DMAC_DMACR_DMAE;
+
+ /* DMA doorbell set -- start DMA now ... */
+ REG_DMAC_DMADBSR = 1 << dma_chan;
+
+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
+}
+
+#endif
+
+//EXPORT_SYMBOL_NOVERS(jz_dma_table);
+EXPORT_SYMBOL(jz_dma_table);
+EXPORT_SYMBOL(jz_request_dma);
+EXPORT_SYMBOL(jz_free_dma);
+EXPORT_SYMBOL(jz_set_dma_src_width);
+EXPORT_SYMBOL(jz_set_dma_dest_width);
+EXPORT_SYMBOL(jz_set_dma_block_size);
+EXPORT_SYMBOL(jz_set_dma_mode);
+EXPORT_SYMBOL(set_dma_mode);
+EXPORT_SYMBOL(jz_set_oss_dma);
+EXPORT_SYMBOL(jz_set_alsa_dma);
+EXPORT_SYMBOL(set_dma_addr);
+EXPORT_SYMBOL(set_dma_count);
+EXPORT_SYMBOL(get_dma_residue);
+EXPORT_SYMBOL(enable_dma);
+EXPORT_SYMBOL(disable_dma);
+EXPORT_SYMBOL(dump_jz_dma_channel);
diff --git a/arch/mips/jz4740/i2c.c b/arch/mips/jz4740/i2c.c
new file mode 100644
index 00000000000..3080fdfa8d0
--- /dev/null
+++ b/arch/mips/jz4740/i2c.c
@@ -0,0 +1,273 @@
+/*
+ * linux/arch/mips/jz4740/i2c.c
+ *
+ * Jz4740 I2C routines.
+ *
+ * Copyright (C) 2005,2006 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/addrspace.h>
+
+#include <asm/jzsoc.h>
+
+/* I2C protocol */
+#define I2C_READ 1
+#define I2C_WRITE 0
+
+#define TIMEOUT 1000
+
+/*
+ * I2C bus protocol basic routines
+ */
+static int i2c_put_data(unsigned char data)
+{
+ unsigned int timeout = TIMEOUT*10;
+
+ __i2c_write(data);
+ __i2c_set_drf();
+ while (__i2c_check_drf() != 0);
+ while (!__i2c_transmit_ended());
+ while (!__i2c_received_ack() && timeout)
+ timeout--;
+
+ if (timeout)
+ return 0;
+ else
+ return -ETIMEDOUT;
+}
+
+#ifdef CONFIG_JZ_TPANEL_ATA2508
+static int i2c_put_data_nack(unsigned char data)
+{
+ unsigned int timeout = TIMEOUT*10;
+
+ __i2c_write(data);
+ __i2c_set_drf();
+ while (__i2c_check_drf() != 0);
+ while (!__i2c_transmit_ended());
+ while (timeout--);
+ return 0;
+}
+#endif
+
+static int i2c_get_data(unsigned char *data, int ack)
+{
+ int timeout = TIMEOUT*10;
+
+ if (!ack)
+ __i2c_send_nack();
+ else
+ __i2c_send_ack();
+
+ while (__i2c_check_drf() == 0 && timeout)
+ timeout--;
+
+ if (timeout) {
+ if (!ack)
+ __i2c_send_stop();
+ *data = __i2c_read();
+ __i2c_clear_drf();
+ return 0;
+ } else
+ return -ETIMEDOUT;
+}
+
+/*
+ * I2C interface
+ */
+void i2c_open(void)
+{
+ __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */
+ __i2c_enable();
+}
+
+void i2c_close(void)
+{
+ udelay(300); /* wait for STOP goes over. */
+ __i2c_disable();
+}
+
+void i2c_setclk(unsigned int i2cclk)
+{
+ __i2c_set_clk(jz_clocks.extalclk, i2cclk);
+}
+
+int i2c_lseek(unsigned char device, unsigned char offset)
+{
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_err;
+ if (i2c_put_data(offset) < 0)
+ goto address_err;
+ return 0;
+ device_err:
+ printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device);
+ __i2c_send_stop();
+ return -ENODEV;
+ address_err:
+ printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device);
+ __i2c_send_stop();
+ return -EREMOTEIO;
+}
+
+int i2c_read(unsigned char device, unsigned char *buf,
+ unsigned char address, int count)
+{
+ int cnt = count;
+ int timeout = 5;
+
+L_try_again:
+
+ if (timeout < 0)
+ goto L_timeout;
+
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_werr;
+ if (i2c_put_data(address) < 0)
+ goto address_err;
+
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_READ ) < 0)
+ goto device_rerr;
+ __i2c_send_ack(); /* Master sends ACK for continue reading */
+ while (cnt) {
+ if (cnt == 1) {
+ if (i2c_get_data(buf, 0) < 0)
+ break;
+ } else {
+ if (i2c_get_data(buf, 1) < 0)
+ break;
+ }
+ cnt--;
+ buf++;
+ }
+
+ __i2c_send_stop();
+ return count - cnt;
+ device_rerr:
+ device_werr:
+ address_err:
+ timeout --;
+ __i2c_send_stop();
+ goto L_try_again;
+
+L_timeout:
+ __i2c_send_stop();
+ printk("Read I2C device 0x%2x failed.\n", device);
+ return -ENODEV;
+}
+
+int i2c_write(unsigned char device, unsigned char *buf,
+ unsigned char address, int count)
+{
+ int cnt = count;
+ int cnt_in_pg;
+ int timeout = 5;
+ unsigned char *tmpbuf;
+ unsigned char tmpaddr;
+
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+
+ W_try_again:
+ if (timeout < 0)
+ goto W_timeout;
+
+ cnt = count;
+ tmpbuf = (unsigned char *)buf;
+ tmpaddr = address;
+
+ start_write_page:
+ cnt_in_pg = 0;
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_err;
+#ifdef CONFIG_JZ_TPANEL_ATA2508
+ if (address == 0xff) {
+ if (i2c_put_data_nack(tmpaddr) < 0)
+ goto address_err;
+ while (cnt) {
+ if (++cnt_in_pg > 8) {
+ __i2c_send_stop();
+ mdelay(1);
+ tmpaddr += 8;
+ goto start_write_page;
+ }
+ if (i2c_put_data_nack(*tmpbuf) < 0)
+ break;
+ cnt--;
+ tmpbuf++;
+ }
+ }
+ else {
+
+ if (i2c_put_data(tmpaddr) < 0)
+ goto address_err;
+ while (cnt) {
+ if (++cnt_in_pg > 8) {
+ __i2c_send_stop();
+ mdelay(1);
+ tmpaddr += 8;
+ goto start_write_page;
+ }
+ if (i2c_put_data(*tmpbuf) < 0)
+ break;
+ cnt--;
+ tmpbuf++;
+ }
+ }
+#else
+ if (i2c_put_data(tmpaddr) < 0)
+ goto address_err;
+ while (cnt) {
+ if (++cnt_in_pg > 8) {
+ __i2c_send_stop();
+ mdelay(1);
+ tmpaddr += 8;
+ goto start_write_page;
+ }
+ if (i2c_put_data(*tmpbuf) < 0)
+ break;
+ cnt--;
+ tmpbuf++;
+ }
+#endif
+ __i2c_send_stop();
+ return count - cnt;
+ device_err:
+ address_err:
+ timeout--;
+ __i2c_send_stop();
+ goto W_try_again;
+
+ W_timeout:
+ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device);
+ __i2c_send_stop();
+ return -ENODEV;
+}
+
+EXPORT_SYMBOL(i2c_open);
+EXPORT_SYMBOL(i2c_close);
+EXPORT_SYMBOL(i2c_setclk);
+EXPORT_SYMBOL(i2c_read);
+EXPORT_SYMBOL(i2c_write);
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c
new file mode 100644
index 00000000000..9b776cf4516
--- /dev/null
+++ b/arch/mips/jz4740/irq.c
@@ -0,0 +1,266 @@
+/*
+ * linux/arch/mips/jz4740/irq.c
+ *
+ * JZ4740 interrupt routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+/*
+ * INTC irq type
+ */
+
+static void enable_intc_irq(unsigned int irq)
+{
+ __intc_unmask_irq(irq);
+}
+
+static void disable_intc_irq(unsigned int irq)
+{
+ __intc_mask_irq(irq);
+}
+
+static void mask_and_ack_intc_irq(unsigned int irq)
+{
+ __intc_mask_irq(irq);
+ __intc_ack_irq(irq);
+}
+
+static void end_intc_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_intc_irq(irq);
+ }
+}
+
+static unsigned int startup_intc_irq(unsigned int irq)
+{
+ enable_intc_irq(irq);
+ return 0;
+}
+
+static void shutdown_intc_irq(unsigned int irq)
+{
+ disable_intc_irq(irq);
+}
+
+static struct irq_chip intc_irq_type = {
+ .typename = "INTC",
+ .startup = startup_intc_irq,
+ .shutdown = shutdown_intc_irq,
+ .unmask = enable_intc_irq,
+ .mask = disable_intc_irq,
+ .ack = mask_and_ack_intc_irq,
+ .end = end_intc_irq,
+};
+
+/*
+ * GPIO irq type
+ */
+
+static void enable_gpio_irq(unsigned int irq)
+{
+ unsigned int intc_irq;
+
+ if (irq < (IRQ_GPIO_0 + 32)) {
+ intc_irq = IRQ_GPIO0;
+ }
+ else if (irq < (IRQ_GPIO_0 + 64)) {
+ intc_irq = IRQ_GPIO1;
+ }
+ else if (irq < (IRQ_GPIO_0 + 96)) {
+ intc_irq = IRQ_GPIO2;
+ }
+ else {
+ intc_irq = IRQ_GPIO3;
+ }
+
+ enable_intc_irq(intc_irq);
+ __gpio_unmask_irq(irq - IRQ_GPIO_0);
+}
+
+static void disable_gpio_irq(unsigned int irq)
+{
+ __gpio_mask_irq(irq - IRQ_GPIO_0);
+}
+
+static void mask_and_ack_gpio_irq(unsigned int irq)
+{
+ __gpio_mask_irq(irq - IRQ_GPIO_0);
+ __gpio_ack_irq(irq - IRQ_GPIO_0);
+}
+
+static void end_gpio_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_gpio_irq(irq);
+ }
+}
+
+static unsigned int startup_gpio_irq(unsigned int irq)
+{
+ enable_gpio_irq(irq);
+ return 0;
+}
+
+static void shutdown_gpio_irq(unsigned int irq)
+{
+ disable_gpio_irq(irq);
+}
+
+static struct irq_chip gpio_irq_type = {
+ .typename = "GPIO",
+ .startup = startup_gpio_irq,
+ .shutdown = shutdown_gpio_irq,
+ .unmask = enable_gpio_irq,
+ .mask = disable_gpio_irq,
+ .ack = mask_and_ack_gpio_irq,
+ .end = end_gpio_irq,
+};
+
+/*
+ * DMA irq type
+ */
+
+static void enable_dma_irq(unsigned int irq)
+{
+ __intc_unmask_irq(IRQ_DMAC);
+ __dmac_channel_enable_irq(irq - IRQ_DMA_0);
+}
+
+static void disable_dma_irq(unsigned int irq)
+{
+ __dmac_channel_disable_irq(irq - IRQ_DMA_0);
+}
+
+static void mask_and_ack_dma_irq(unsigned int irq)
+{
+ __intc_ack_irq(IRQ_DMAC);
+ __dmac_channel_disable_irq(irq - IRQ_DMA_0);
+}
+
+static void end_dma_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_dma_irq(irq);
+ }
+}
+
+static unsigned int startup_dma_irq(unsigned int irq)
+{
+ enable_dma_irq(irq);
+ return 0;
+}
+
+static void shutdown_dma_irq(unsigned int irq)
+{
+ disable_dma_irq(irq);
+}
+
+static struct irq_chip dma_irq_type = {
+ .typename = "DMA",
+ .startup = startup_dma_irq,
+ .shutdown = shutdown_dma_irq,
+ .unmask = enable_dma_irq,
+ .mask = disable_dma_irq,
+ .ack = mask_and_ack_dma_irq,
+ .end = end_dma_irq,
+};
+
+//----------------------------------------------------------------------
+
+void __init arch_init_irq(void)
+{
+ int i;
+
+ /* CPU level interrupts is still not handled. */
+ clear_c0_status(0xff04); /* clear ERL */
+ set_c0_status(0x0400); /* set IP2 */
+
+ /* Set up INTC irq
+ */
+ for (i = 0; i < 32; i++) {
+ disable_intc_irq(i);
+ set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq);
+ }
+
+ /* Set up DMAC irq
+ */
+ for (i = 0; i < NUM_DMA; i++) {
+ disable_dma_irq(IRQ_DMA_0 + i);
+ set_irq_chip_and_handler(IRQ_DMA_0 + i, &dma_irq_type, handle_level_irq);
+ }
+
+ /* Set up GPIO irq
+ */
+ for (i = 0; i < NUM_GPIO; i++) {
+ disable_gpio_irq(IRQ_GPIO_0 + i);
+ set_irq_chip_and_handler(IRQ_GPIO_0 + i, &gpio_irq_type, handle_level_irq);
+ }
+}
+
+static int plat_real_irq(int irq)
+{
+ switch (irq) {
+ case IRQ_GPIO0:
+ irq = __gpio_group_irq(0) + IRQ_GPIO_0;
+ break;
+ case IRQ_GPIO1:
+ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32;
+ break;
+ case IRQ_GPIO2:
+ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64;
+ break;
+ case IRQ_GPIO3:
+ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96;
+ break;
+ case IRQ_DMAC:
+ irq = __dmac_get_irq() + IRQ_DMA_0;
+ break;
+ }
+
+ return irq;
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ int irq = 0;
+ static unsigned long intc_ipr = 0;
+
+ intc_ipr |= REG_INTC_IPR;
+
+ if (!intc_ipr) return;
+
+ irq = ffs(intc_ipr) - 1;
+ intc_ipr &= ~(1<<irq);
+
+ irq = plat_real_irq(irq);
+ do_IRQ(irq);
+}
diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
new file mode 100644
index 00000000000..4ce8e3ae462
--- /dev/null
+++ b/arch/mips/jz4740/platform.c
@@ -0,0 +1,169 @@
+/*
+ * Platform device support for Jz4740 SoC.
+ *
+ * Copyright 2007, <yliu@ingenic.cn>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/resource.h>
+
+#include <asm/jzsoc.h>
+
+/* OHCI (USB full speed host controller) */
+static struct resource jz_usb_ohci_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap
+ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_UHC,
+ .end = IRQ_UHC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32)0;
+
+static struct platform_device jz_usb_ohci_device = {
+ .name = "jz-ohci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ohci_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources),
+ .resource = jz_usb_ohci_resources,
+};
+
+/*** LCD controller ***/
+static struct resource jz_lcd_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(LCD_BASE),
+ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_LCD,
+ .end = IRQ_LCD,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 jz_lcd_dmamask = ~(u32)0;
+
+static struct platform_device jz_lcd_device = {
+ .name = "jz-lcd",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_lcd_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_lcd_resources),
+ .resource = jz_lcd_resources,
+};
+
+/* UDC (USB gadget controller) */
+static struct resource jz_usb_gdt_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(UDC_BASE),
+ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_UDC,
+ .end = IRQ_UDC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 udc_dmamask = ~(u32)0;
+
+static struct platform_device jz_usb_gdt_device = {
+ .name = "jz-udc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &udc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources),
+ .resource = jz_usb_gdt_resources,
+};
+
+/** MMC/SD controller **/
+static struct resource jz_mmc_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(MSC_BASE),
+ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_MSC,
+ .end = IRQ_MSC,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 jz_mmc_dmamask = ~(u32)0;
+
+static struct platform_device jz_mmc_device = {
+ .name = "jz-mmc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_mmc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_mmc_resources),
+ .resource = jz_mmc_resources,
+};
+
+/** I2C controller **/
+static struct resource jz_i2c_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(I2C_BASE),
+ .end = CPHYSADDR(I2C_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 jz_i2c_dmamask = ~(u32)0;
+
+static struct platform_device jz_i2c_device = {
+ .name = "jz_i2c",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_i2c_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_i2c_resources),
+ .resource = jz_i2c_resources,
+};
+
+/* All */
+static struct platform_device *jz_platform_devices[] __initdata = {
+ &jz_usb_ohci_device,
+ &jz_lcd_device,
+ &jz_usb_gdt_device,
+ &jz_mmc_device,
+ &jz_i2c_device,
+};
+
+static int __init jz_platform_init(void)
+{
+ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
+}
+
+arch_initcall(jz_platform_init);
diff --git a/arch/mips/jz4740/pm.c b/arch/mips/jz4740/pm.c
new file mode 100644
index 00000000000..b687f380fe4
--- /dev/null
+++ b/arch/mips/jz4740/pm.c
@@ -0,0 +1,400 @@
+/*
+ * linux/arch/mips/jz4740/common/pm.c
+ *
+ * JZ4740 Power Management Routines
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/suspend.h>
+
+#include <asm/cacheops.h>
+#include <asm/jzsoc.h>
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+#define GPIO_WAKEUP 125 /* set SW7(GPIO 125) as WAKEUP key */
+
+/*
+ * __gpio_as_sleep set all pins to pull-disable, and set all pins as input
+ * except sdram, nand flash pins and the pins which can be used as CS1_N
+ * to CS4_N for chip select.
+ */
+#define __gpio_as_sleep() \
+do { \
+ REG_GPIO_PXFUNC(1) = ~0x9ff9ffff; \
+ REG_GPIO_PXSELC(1) = ~0x9ff9ffff; \
+ REG_GPIO_PXDIRC(1) = ~0x9ff9ffff; \
+ REG_GPIO_PXPES(1) = 0xffffffff; \
+ REG_GPIO_PXFUNC(2) = ~0x37000000; \
+ REG_GPIO_PXSELC(2) = ~0x37000000; \
+ REG_GPIO_PXDIRC(2) = ~0x37000000; \
+ REG_GPIO_PXPES(2) = 0xffffffff; \
+ REG_GPIO_PXFUNC(3) = 0xffffffff; \
+ REG_GPIO_PXSELC(3) = 0xffffffff; \
+ REG_GPIO_PXDIRC(3) = 0xffffffff; \
+ REG_GPIO_PXPES(3) = 0xffffffff; \
+} while (0)
+
+static int jz_pm_do_hibernate(void)
+{
+ printk("Put CPU into hibernate mode.\n");
+
+ /* Mask all interrupts */
+ REG_INTC_IMSR = 0xffffffff;
+
+ /*
+ * RTC Wakeup or 1Hz interrupt can be enabled or disabled
+ * through RTC driver's ioctl (linux/driver/char/rtc_jz.c).
+ */
+
+ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT);
+
+ /* Set reset pin low-level assertion time after wakeup: must > 60ms */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */
+
+ /* Scratch pad register to be reserved */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HSPR = 0x12345678;
+
+ /* clear wakeup status register */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HWRSR = 0x0;
+
+ /* Put CPU to power down mode */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HCR = RTC_HCR_PD;
+
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ while(1);
+
+ /* We can't get here */
+ return 0;
+}
+
+/* NOTES:
+ * 1: Pins that are floated (NC) should be set as input and pull-enable.
+ * 2: Pins that are pull-up or pull-down by outside should be set as input
+ * and pull-disable.
+ * 3: Pins that are connected to a chip except sdram and nand flash
+ * should be set as input and pull-disable, too.
+ */
+static void jz_board_do_sleep(unsigned long *ptr)
+{
+ unsigned char i;
+
+ /* Print messages of GPIO registers for debug */
+ for(i=0;i<4;i++) {
+ dprintk("run dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
+ }
+
+ /* Save GPIO registers */
+ for(i = 1; i < 4; i++) {
+ *ptr++ = REG_GPIO_PXFUN(i);
+ *ptr++ = REG_GPIO_PXSEL(i);
+ *ptr++ = REG_GPIO_PXDIR(i);
+ *ptr++ = REG_GPIO_PXPE(i);
+ *ptr++ = REG_GPIO_PXIM(i);
+ *ptr++ = REG_GPIO_PXDAT(i);
+ *ptr++ = REG_GPIO_PXTRG(i);
+ }
+
+ /*
+ * Set all pins to pull-disable, and set all pins as input except
+ * sdram, nand flash pins and the pins which can be used as CS1_N
+ * to CS4_N for chip select.
+ */
+ __gpio_as_sleep();
+
+ /*
+ * Set proper status for GPB25 to GPB28 which can be used as CS1_N to CS4_N.
+ * Keep the pins' function used for chip select(CS) here according to your
+ * system to avoid chip select crashing with sdram when resuming from sleep mode.
+ */
+
+#if defined(CONFIG_JZ4740_PAVO)
+ /* GPB25/CS1_N is used as chip select for nand flash, shouldn't be change. */
+
+ /* GPB26/CS2_N is connected to nand flash, needn't be changed. */
+
+ /* GPB27/CS3_N is used as EXT_INT for CS8900 on debug board, it should be set as input.*/
+ __gpio_as_input(32+27);
+
+ /* GPB28/CS4_N is used as cs8900's chip select, shouldn't be changed. */
+#endif
+
+ /*
+ * Enable pull for NC pins here according to your system
+ */
+
+#if defined(CONFIG_JZ4740_PAVO)
+ /* GPB30-27 <-> J1: WE_N RD_N CS4_N EXT_INT */
+ for(i=27;i<31;i++) {
+ __gpio_enable_pull(32+i);
+ }
+
+ /* GPC27<-> WAIT_N */
+ __gpio_enable_pull(32*2+27);
+
+ /* GPD16<->SD_WP; GPD13-10<->MSC_D0-3; GPD9<->MSC_CMD; GPD8<->MSC_CLK */
+ __gpio_enable_pull(32*3+16);
+ for(i=8;i<14;i++) {
+ __gpio_enable_pull(32*3+i);
+ }
+#endif
+
+ /*
+ * If you must set some GPIOs as output to high level or low level,
+ * you can set them here, using:
+ * __gpio_as_output(n);
+ * __gpio_set_pin(n); or __gpio_clear_pin(n);
+ */
+
+#if defined(CONFIG_JZ4740_PAVO)
+ /* GPD16 which is used as AMPEN_N should be set to high to disable audio amplifier */
+ __gpio_set_pin(32*3+4);
+#endif
+
+#ifdef DEBUG
+ /* Keep uart0 function for printing debug message */
+ __gpio_as_uart0();
+
+ /* Print messages of GPIO registers for debug */
+ for(i=0;i<4;i++) {
+ dprintk("sleep dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
+ }
+#endif
+}
+
+static void jz_board_do_resume(unsigned long *ptr)
+{
+ unsigned char i;
+
+ /* Restore GPIO registers */
+ for(i = 1; i < 4; i++) {
+ REG_GPIO_PXFUNS(i) = *ptr;
+ REG_GPIO_PXFUNC(i) = ~(*ptr++);
+
+ REG_GPIO_PXSELS(i) = *ptr;
+ REG_GPIO_PXSELC(i) = ~(*ptr++);
+
+ REG_GPIO_PXDIRS(i) = *ptr;
+ REG_GPIO_PXDIRC(i) = ~(*ptr++);
+
+ REG_GPIO_PXPES(i) = *ptr;
+ REG_GPIO_PXPEC(i) = ~(*ptr++);
+
+ REG_GPIO_PXIMS(i)=*ptr;
+ REG_GPIO_PXIMC(i)=~(*ptr++);
+
+ REG_GPIO_PXDATS(i)=*ptr;
+ REG_GPIO_PXDATC(i)=~(*ptr++);
+
+ REG_GPIO_PXTRGS(i)=*ptr;
+ REG_GPIO_PXTRGC(i)=~(*ptr++);
+ }
+
+ /* Print messages of GPIO registers for debug */
+ for(i=0;i<4;i++) {
+ dprintk("resume dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
+ }
+}
+
+
+
+static int jz_pm_do_sleep(void)
+{
+ unsigned long delta;
+ unsigned long nfcsr = REG_EMC_NFCSR;
+ unsigned long scr = REG_CPM_SCR;
+ unsigned long imr = REG_INTC_IMR;
+ unsigned long sadc = REG_SADC_ENA;
+ unsigned long sleep_gpio_save[7*3];
+
+ printk("Put CPU into sleep mode.\n");
+
+ /* Preserve current time */
+ delta = xtime.tv_sec - REG_RTC_RSR;
+
+ /* Disable nand flash */
+ REG_EMC_NFCSR = ~0xff;
+
+ /* stop sadc */
+ REG_SADC_ENA &= ~0x7;
+ while((REG_SADC_ENA & 0x7) != 0);
+ udelay(100);
+
+ /*stop udc and usb*/
+ REG_CPM_SCR &= ~( 1<<6 | 1<<7);
+ REG_CPM_SCR |= 0<<6 | 1<<7;
+
+ /* Sleep on-board modules */
+ jz_board_do_sleep(sleep_gpio_save);
+
+ /* Mask all interrupts */
+ REG_INTC_IMSR = 0xffffffff;
+
+ /* Just allow following interrupts to wakeup the system.
+ * Note: modify this according to your system.
+ */
+
+ /* enable RTC alarm */
+ __intc_unmask_irq(IRQ_RTC);
+#if 0
+ /* make system wake up after n seconds by RTC alarm */
+ unsigned int v, n;
+ n = 10;
+ while (!__rtc_write_ready());
+ __rtc_enable_alarm();
+ while (!__rtc_write_ready());
+ __rtc_enable_alarm_irq();
+ while (!__rtc_write_ready());
+ v = __rtc_get_second();
+ while (!__rtc_write_ready());
+ __rtc_set_alarm_second(v+n);
+#endif
+
+ /* WAKEUP key */
+ __gpio_as_irq_rise_edge(GPIO_WAKEUP);
+ __gpio_unmask_irq(GPIO_WAKEUP);
+ __intc_unmask_irq(IRQ_GPIO3); /* IRQ_GPIOn depends on GPIO_WAKEUP */
+
+ /* Enter SLEEP mode */
+ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
+ REG_CPM_LCR |= CPM_LCR_LPM_SLEEP;
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0");
+
+ /* Restore to IDLE mode */
+ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
+ REG_CPM_LCR |= CPM_LCR_LPM_IDLE;
+
+ /* Restore nand flash control register */
+ REG_EMC_NFCSR = nfcsr;
+
+ /* Restore interrupts */
+ REG_INTC_IMSR = imr;
+ REG_INTC_IMCR = ~imr;
+
+ /* Restore sadc */
+ REG_SADC_ENA = sadc;
+
+ /* Resume on-board modules */
+ jz_board_do_resume(sleep_gpio_save);
+
+ /* Restore sleep control register */
+ REG_CPM_SCR = scr;
+
+ /* Restore current time */
+ xtime.tv_sec = REG_RTC_RSR + delta;
+
+ return 0;
+}
+
+/* Put CPU to HIBERNATE mode */
+int jz_pm_hibernate(void)
+{
+ return jz_pm_do_hibernate();
+}
+
+#ifndef CONFIG_JZ_POWEROFF
+static irqreturn_t pm_irq_handler (int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+#endif
+
+/* Put CPU to SLEEP mode */
+int jz_pm_sleep(void)
+{
+ int retval;
+
+#ifndef CONFIG_JZ_POWEROFF
+ if ((retval = request_irq (IRQ_GPIO_0 + GPIO_WAKEUP, pm_irq_handler, IRQF_DISABLED,
+ "PM", NULL))) {
+ printk ("PM could not get IRQ for GPIO_WAKEUP\n");
+ return retval;
+ }
+#endif
+
+ retval = jz_pm_do_sleep();
+
+#ifndef CONFIG_JZ_POWEROFF
+ free_irq (IRQ_GPIO_0 + GPIO_WAKEUP, NULL);
+#endif
+
+ return retval;
+}
+
+/*
+ * valid states, only support mem(sleep)
+ */
+static int jz_pm_valid(suspend_state_t state)
+{
+ return state == PM_SUSPEND_MEM;
+}
+
+/*
+ * Jz CPU enter save power mode
+ */
+static int jz_pm_enter(suspend_state_t state)
+{
+ return jz_pm_sleep();
+}
+
+static struct platform_suspend_ops jz_pm_ops = {
+ .valid = jz_pm_valid,
+ .enter = jz_pm_enter,
+};
+
+
+/*
+ * Initialize power interface
+ */
+int __init jz_pm_init(void)
+{
+ printk(JZ_SOC_NAME ": Power Management Interface Registered.\n");
+
+ suspend_set_ops(&jz_pm_ops);
+
+ return 0;
+}
+
+module_init(jz_pm_init);
diff --git a/arch/mips/jz4740/proc.c b/arch/mips/jz4740/proc.c
new file mode 100644
index 00000000000..229182b370a
--- /dev/null
+++ b/arch/mips/jz4740/proc.c
@@ -0,0 +1,834 @@
+/*
+ * linux/arch/mips/jz4740/proc.c
+ *
+ * /proc/jz/ procfs for jz4740 on-chip modules.
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/page-flags.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/jzsoc.h>
+
+//#define DEBUG 1
+#undef DEBUG
+
+/* Define this to reserve total 4MB contineous physical memory for IPU.
+ * MPlayer will use IPU to optimize the decoding process.
+ *
+ * If you do not want to run the MPlayer, you can comment it.
+ */
+#define CONFIG_RESERVE_IPU_MEM 1
+
+struct proc_dir_entry *proc_jz_root;
+
+
+/*
+ * EMC Modules
+ */
+static int emc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4);
+ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4);
+ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR);
+ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR);
+ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR);
+ return len;
+}
+
+/*
+ * Power Manager Module
+ */
+static int pmc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long lcr = REG_CPM_LCR;
+ unsigned long clkgr = REG_CPM_CLKGR;
+
+ len += sprintf (page+len, "Low Power Mode : %s\n",
+ ((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ?
+ "IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ?
+ "SLEEP" : "HIBERNATE"));
+ len += sprintf (page+len, "Doze Mode : %s\n",
+ (lcr & CPM_LCR_DOZE_ON) ? "on" : "off");
+ if (lcr & CPM_LCR_DOZE_ON)
+ len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT));
+ len += sprintf (page+len, "IPU : %s\n",
+ (clkgr & CPM_CLKGR_IPU) ? "stopped" : "running");
+ len += sprintf (page+len, "DMAC : %s\n",
+ (clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running");
+ len += sprintf (page+len, "UHC : %s\n",
+ (clkgr & CPM_CLKGR_UHC) ? "stopped" : "running");
+ len += sprintf (page+len, "UDC : %s\n",
+ (clkgr & CPM_CLKGR_UDC) ? "stopped" : "running");
+ len += sprintf (page+len, "LCD : %s\n",
+ (clkgr & CPM_CLKGR_LCD) ? "stopped" : "running");
+ len += sprintf (page+len, "CIM : %s\n",
+ (clkgr & CPM_CLKGR_CIM) ? "stopped" : "running");
+ len += sprintf (page+len, "SADC : %s\n",
+ (clkgr & CPM_CLKGR_SADC) ? "stopped" : "running");
+ len += sprintf (page+len, "MSC : %s\n",
+ (clkgr & CPM_CLKGR_MSC) ? "stopped" : "running");
+ len += sprintf (page+len, "AIC1 : %s\n",
+ (clkgr & CPM_CLKGR_AIC1) ? "stopped" : "running");
+ len += sprintf (page+len, "AIC2 : %s\n",
+ (clkgr & CPM_CLKGR_AIC2) ? "stopped" : "running");
+ len += sprintf (page+len, "SSI : %s\n",
+ (clkgr & CPM_CLKGR_SSI) ? "stopped" : "running");
+ len += sprintf (page+len, "I2C : %s\n",
+ (clkgr & CPM_CLKGR_I2C) ? "stopped" : "running");
+ len += sprintf (page+len, "RTC : %s\n",
+ (clkgr & CPM_CLKGR_RTC) ? "stopped" : "running");
+ len += sprintf (page+len, "TCU : %s\n",
+ (clkgr & CPM_CLKGR_TCU) ? "stopped" : "running");
+ len += sprintf (page+len, "UART1 : %s\n",
+ (clkgr & CPM_CLKGR_UART1) ? "stopped" : "running");
+ len += sprintf (page+len, "UART0 : %s\n",
+ (clkgr & CPM_CLKGR_UART0) ? "stopped" : "running");
+ return len;
+}
+
+static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16);
+ return count;
+}
+
+/*
+ * Clock Generation Module
+ */
+#define TO_MHZ(x) (x/1000000),(x%1000000)/10000
+#define TO_KHZ(x) (x/1000),(x%1000)/10
+
+static int cgm_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */
+ unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */
+ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned int od[4] = {1, 2, 2, 4};
+
+ len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr);
+ len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr);
+ len += sprintf (page+len, "PLL : %s\n",
+ (cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF");
+ len += sprintf (page+len, "m:n:o : %d:%d:%d\n",
+ __cpm_get_pllm() + 2,
+ __cpm_get_plln() + 2,
+ od[__cpm_get_pllod()]
+ );
+ len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n",
+ div[__cpm_get_cdiv()],
+ div[__cpm_get_hdiv()],
+ div[__cpm_get_mdiv()],
+ div[__cpm_get_pdiv()]
+ );
+ len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout()));
+ len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk()));
+ len += sprintf (page+len, "HCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_hclk()));
+ len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk()));
+ len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk()));
+ len += sprintf (page+len, "LCDCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_lcdclk()));
+ len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk()));
+ len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk()));
+ len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk()));
+ len += sprintf (page+len, "MSCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk()));
+ len += sprintf (page+len, "EXTALCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk()));
+ len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk()));
+
+ return len;
+}
+
+static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16);
+ return count;
+}
+
+/*
+ * MMC/SD hotplug
+ */
+
+#ifndef MSC_HOTPLUG_PIN
+#define MSC_HOTPLUG_PIN 90
+#endif
+
+static int mmc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+#if defined(CONFIG_JZ4740_LYRA)
+ if (!(__gpio_get_pin(MSC_HOTPLUG_PIN)))
+#else
+ if (__gpio_get_pin(MSC_HOTPLUG_PIN))
+#endif
+ len += sprintf (page+len, "REMOVE\n");
+ else
+ len += sprintf (page+len, "INSERT\n");
+
+ return len;
+}
+
+#ifdef CONFIG_RESERVE_IPU_MEM
+
+/* USAGE:
+ * echo n > /proc/jz/ipu // n = [1,...,9], alloc mem, 2^n pages.
+ * echo FF > /proc/jz/ipu // 255, free all buffer
+ * echo xxxx > /proc/jz/ipu // free buffer which addr is xxxx
+ * echo llll > /proc/jz/ipu // add_wired_entry(l,l,l,l)
+ * echo 0 > /proc/jz/ipu // debug, print ipu_buf
+ * od -X /proc/jz/ipu // read mem addr
+ */
+
+typedef struct _ipu_buf {
+ unsigned int addr; /* phys addr */
+ unsigned int page_shift;
+} ipu_buf_t;
+
+#define IPU_BUF_MAX 4 /* 4 buffers */
+
+static struct _ipu_buf ipu_buf[IPU_BUF_MAX];
+static int ipu_buf_cnt = 0;
+static unsigned char g_asid=0;
+
+extern void local_flush_tlb_all(void);
+
+/* CP0 hazard avoidance. */
+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
+ "nop; nop; nop; nop; nop; nop;\n\t" \
+ ".set reorder\n\t")
+void show_tlb(void)
+{
+#define ASID_MASK 0xFF
+
+ unsigned long flags;
+ unsigned int old_ctx;
+ unsigned int entry;
+ unsigned int entrylo0, entrylo1, entryhi;
+ unsigned int pagemask;
+
+ local_irq_save(flags);
+
+ /* Save old context */
+ old_ctx = (read_c0_entryhi() & 0xff);
+
+ printk("TLB content:\n");
+ entry = 0;
+ while(entry < 32) {
+ write_c0_index(entry);
+ BARRIER;
+ tlb_read();
+ BARRIER;
+ entryhi = read_c0_entryhi();
+ entrylo0 = read_c0_entrylo0();
+ entrylo1 = read_c0_entrylo1();
+ pagemask = read_c0_pagemask();
+ printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK);
+ printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : "");
+ printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : "");
+
+ printk("\t\tpagemask=0x%08x", pagemask);
+ printk("\tentryhi=0x%08x\n", entryhi);
+ printk("\t\tentrylo0=0x%08x", entrylo0);
+ printk("\tentrylo1=0x%08x\n", entrylo1);
+
+ entry++;
+ }
+ BARRIER;
+ write_c0_entryhi(old_ctx);
+
+ local_irq_restore(flags);
+}
+
+static void ipu_add_wired_entry(unsigned long pid,
+ unsigned long entrylo0, unsigned long entrylo1,
+ unsigned long entryhi, unsigned long pagemask)
+{
+ unsigned long flags;
+ unsigned long wired;
+ unsigned long old_pagemask;
+ unsigned long old_ctx;
+ struct task_struct *g, *p;
+
+ /* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */
+ wired = read_c0_wired();
+ if (wired) return;
+
+ do_each_thread(g, p) {
+ if (p->pid == pid )
+ g_asid = p->mm->context[0];
+ } while_each_thread(g, p);
+
+ local_irq_save(flags);
+
+ entrylo0 = entrylo0 >> 6; /* PFN */
+ entrylo0 |= 0x6 | (0 << 3); /* Write-through cacheable, dirty, valid */
+
+ /* Save old context and create impossible VPN2 value */
+ old_ctx = read_c0_entryhi() & 0xff;
+ old_pagemask = read_c0_pagemask();
+ write_c0_wired(wired + 1);
+ write_c0_index(wired);
+ BARRIER;
+ entryhi &= ~0xff; /* new add, 20070906 */
+ entryhi |= g_asid; /* new add, 20070906 */
+// entryhi |= old_ctx; /* new add, 20070906 */
+ write_c0_pagemask(pagemask);
+ write_c0_entryhi(entryhi);
+ write_c0_entrylo0(entrylo0);
+ write_c0_entrylo1(entrylo1);
+ BARRIER;
+ tlb_write_indexed();
+ BARRIER;
+
+ write_c0_entryhi(old_ctx);
+ BARRIER;
+ write_c0_pagemask(old_pagemask);
+ local_flush_tlb_all();
+ local_irq_restore(flags);
+#if defined(DEBUG)
+ printk("\nold_ctx=%03d\n", old_ctx);
+
+ show_tlb();
+#endif
+}
+
+static void ipu_del_wired_entry( void )
+{
+ unsigned long flags;
+ unsigned long wired;
+
+ /* Free all lock entry */
+ local_irq_save(flags);
+ wired = read_c0_wired();
+ if (wired)
+ write_c0_wired(0);
+ local_irq_restore(flags);
+}
+
+static inline void ipu_buf_get( unsigned int page_shift )
+{
+ unsigned char * virt_addr;
+ int i;
+ for ( i=0; i< IPU_BUF_MAX; ++i ) {
+ if ( ipu_buf[i].addr == 0 ) {
+ break;
+ }
+ }
+
+ if ( (ipu_buf_cnt = i) == IPU_BUF_MAX ) {
+ printk("Error, no free ipu buffer.\n");
+ return ;
+ }
+
+ virt_addr = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift);
+
+ if ( virt_addr ) {
+ ipu_buf[ipu_buf_cnt].addr = (unsigned int)virt_to_phys((void *)virt_addr);
+ ipu_buf[ipu_buf_cnt].page_shift = page_shift;
+
+ for (i = 0; i < (1<<page_shift); i++) {
+ SetPageReserved(virt_to_page(virt_addr));
+ virt_addr += PAGE_SIZE;
+ }
+ }
+ else {
+ printk("get memory Failed.\n");
+ }
+}
+
+static inline void ipu_buf_free( unsigned int phys_addr )
+{
+ unsigned char * virt_addr, *addr;
+ int cnt, i;
+
+ if ( phys_addr == 0 )
+ return ;
+
+ for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt )
+ if ( phys_addr == ipu_buf[cnt].addr )
+ break;
+
+ if ( cnt == IPU_BUF_MAX ) { /* addr not in the ipu buffers */
+ printk("Invalid addr:0x%08x\n", (unsigned int)phys_addr);
+ }
+
+ virt_addr = (unsigned char *)phys_to_virt(ipu_buf[cnt].addr);
+ addr = virt_addr;
+ for (i = 0; i < (1<<ipu_buf[cnt].page_shift); i++) {
+ ClearPageReserved(virt_to_page(addr));
+ addr += PAGE_SIZE;
+ }
+
+ if ( cnt == 0 )
+ ipu_del_wired_entry();
+
+ free_pages((unsigned long )virt_addr, ipu_buf[cnt].page_shift);
+
+ ipu_buf[cnt].addr = 0;
+ ipu_buf[cnt].page_shift = 0;
+}
+
+static int ipu_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ /* read as binary */
+ unsigned int * pint;
+ pint = (unsigned int *) (page+len);
+
+ if ( ipu_buf_cnt >= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */
+ printk("no free buffer.\n");
+ *pint = 0;
+ }
+ else
+ *pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */
+ len += sizeof(unsigned int);
+
+#if defined(DEBUG)
+ show_tlb();
+#endif
+ return len;
+
+}
+
+static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ unsigned int val ;
+ int cnt,i;
+ char buf[12];
+ unsigned long pid, entrylo0, entrylo1, entryhi, pagemask;
+#if defined(DEBUG)
+ printk("ipu write count=%u\n", count);
+#endif
+ if (count == (8*5+1)) {
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer+8*0, 8);
+ pid = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer+8*1, 8);
+ entrylo0 = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer+8*2, 8);
+ entrylo1 = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer+8*3, 8);
+ entryhi = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer+8*4, 8);
+ pagemask = simple_strtoul(buf, 0, 16);
+
+#if defined(DEBUG)
+ printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n",
+ pid, entrylo0, entrylo1, entryhi, pagemask);
+#endif
+ ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask);
+ return 41;
+ } else if ( count <= 8+1 ) {
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer, 8);
+ val = simple_strtoul(buf, 0, 16);
+ } else if (count == 44) {
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer, 10);
+ pid = simple_strtoul(buf, 0, 16);
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer + 11, 10);
+ entryhi = simple_strtoul(buf, 0, 16);//vaddr
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer + 22, 10);
+ entrylo0 = simple_strtoul(buf, 0, 16);//paddr
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer + 33, 10);
+ pagemask = simple_strtoul(buf, 0, 16);
+ pagemask = 0x3ff << 13; /* Fixed to 4MB page size */
+ ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask);
+ return 44;
+ } else {
+ printk("ipu write count error, count=%d\n.", (unsigned int)count);
+ return -1;
+ }
+
+ /* val: 1-9, page_shift, val>= 10: ipu_buf.addr */
+ if ( val == 0 ) { /* debug, print ipu_buf info */
+ for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt)
+ printk("ipu_buf[%d]: addr=0x%08x, page_shift=%d\n",
+ cnt, ipu_buf[cnt].addr, ipu_buf[cnt].page_shift );
+#if defined(DEBUG)
+ show_tlb();
+#endif
+ }
+ else if ( 0< val && val < 10 ) {
+ ipu_buf_get(val);
+ }
+ else if ( val == 0xff ) { /* 255: free all ipu_buf */
+ for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt ) {
+ ipu_buf_free(ipu_buf[cnt].addr);
+ }
+ }
+ else {
+ ipu_buf_free(val);
+ }
+
+ return count;
+}
+
+/***********************************************************************
+ * IPU memory management (used by mplayer and other apps)
+ *
+ * We reserved 4MB memory for IPU
+ * The memory base address is jz_ipu_framebuf
+ */
+
+/* Usage:
+ *
+ * echo n > /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages
+ * echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx
+ * echo FF > /proc/jz/ipu // FF, free all buffers
+ * od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer
+ */
+
+//#define DEBUG_IMEM 1
+
+#define IMEM_MAX_ORDER 10 /* max 2^10 * 4096 = 4MB */
+
+static unsigned int jz_imem_base; /* physical base address of ipu memory */
+
+static unsigned int allocated_phys_addr = 0;
+
+/*
+ * Allocated buffer list
+ */
+typedef struct imem_list {
+ unsigned int phys_start; /* physical start addr */
+ unsigned int phys_end; /* physical end addr */
+ struct imem_list *next;
+} imem_list_t;
+
+static struct imem_list *imem_list_head = NULL; /* up sorted by phys_start */
+
+#ifdef DEBUG_IMEM
+static void dump_imem_list(void)
+{
+ struct imem_list *imem;
+
+ printk("*** dump_imem_list 0x%x ***\n", (u32)imem_list_head);
+ imem = imem_list_head;
+ while (imem) {
+ printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next);
+ imem = imem->next;
+ }
+}
+#endif
+
+/* allocate 2^order pages inside the 4MB memory */
+static int imem_alloc(unsigned int order)
+{
+ int alloc_ok = 0;
+ unsigned int start, end;
+ unsigned int size = (1 << order) * PAGE_SIZE;
+ struct imem_list *imem, *imemn, *imemp;
+
+ allocated_phys_addr = 0;
+
+ start = jz_imem_base;
+ end = start + (1 << IMEM_MAX_ORDER) * PAGE_SIZE;
+
+ imem = imem_list_head;
+ while (imem) {
+ if ((imem->phys_start - start) >= size) {
+ /* we got a valid address range */
+ alloc_ok = 1;
+ break;
+ }
+
+ start = imem->phys_end + 1;
+ imem = imem->next;
+ }
+
+ if (!alloc_ok) {
+ if ((end - start) >= size)
+ alloc_ok = 1;
+ }
+
+ if (alloc_ok) {
+ end = start + size - 1;
+ allocated_phys_addr = start;
+
+ /* add to imem_list, up sorted by phys_start */
+ imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL);
+ if (!imemn) {
+ return -ENOMEM;
+ }
+ imemn->phys_start = start;
+ imemn->phys_end = end;
+ imemn->next = NULL;
+
+ if (!imem_list_head)
+ imem_list_head = imemn;
+ else {
+ imem = imemp = imem_list_head;
+ while (imem) {
+ if (start < imem->phys_start) {
+ break;
+ }
+
+ imemp = imem;
+ imem = imem->next;
+ }
+
+ if (imem == imem_list_head) {
+ imem_list_head = imemn;
+ imemn->next = imem;
+ }
+ else {
+ imemn->next = imemp->next;
+ imemp->next = imemn;
+ }
+ }
+ }
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+ return 0;
+}
+
+static void imem_free(unsigned int phys_addr)
+{
+ struct imem_list *imem, *imemp;
+
+ imem = imemp = imem_list_head;
+ while (imem) {
+ if (phys_addr == imem->phys_start) {
+ if (imem == imem_list_head) {
+ imem_list_head = imem->next;
+ }
+ else {
+ imemp->next = imem->next;
+ }
+
+ kfree(imem);
+ break;
+ }
+
+ imemp = imem;
+ imem = imem->next;
+ }
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+}
+
+static void imem_free_all(void)
+{
+ struct imem_list *imem;
+
+ imem = imem_list_head;
+ while (imem) {
+ kfree(imem);
+ imem = imem->next;
+ }
+
+ imem_list_head = NULL;
+
+ allocated_phys_addr = 0;
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+}
+
+/*
+ * Return the allocated buffer address and the max order of free buffer
+ */
+static int imem_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned int start_addr, end_addr, max_order, max_size;
+ struct imem_list *imem;
+
+ unsigned int *tmp = (unsigned int *)(page + len);
+
+ start_addr = jz_imem_base;
+ end_addr = start_addr + (1 << IMEM_MAX_ORDER) * PAGE_SIZE;
+
+ if (!imem_list_head)
+ max_size = end_addr - start_addr;
+ else {
+ max_size = 0;
+ imem = imem_list_head;
+ while (imem) {
+ if (max_size < (imem->phys_start - start_addr))
+ max_size = imem->phys_start - start_addr;
+
+ start_addr = imem->phys_end + 1;
+ imem = imem->next;
+ }
+
+ if (max_size < (end_addr - start_addr))
+ max_size = end_addr - start_addr;
+ }
+
+ if (max_size > 0) {
+ max_order = get_order(max_size);
+ if (((1 << max_order) * PAGE_SIZE) > max_size)
+ max_order--;
+ }
+ else {
+ max_order = 0xffffffff; /* No any free buffer */
+ }
+
+ *tmp++ = allocated_phys_addr; /* address allocated by 'echo n > /proc/jz/imem' */
+ *tmp = max_order; /* max order of current free buffers */
+
+ len += 2 * sizeof(unsigned int);
+
+ return len;
+}
+
+static int imem_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ unsigned int val;
+
+ val = simple_strtoul(buffer, 0, 16);
+
+ if (val == 0xff) {
+ /* free all memory */
+ imem_free_all();
+ ipu_del_wired_entry();
+ }
+ else if ((val >= 0) && (val <= IMEM_MAX_ORDER)) {
+ /* allocate 2^val pages */
+ imem_alloc(val);
+ }
+ else {
+ /* free buffer which phys_addr is val */
+ imem_free(val);
+ }
+
+ return count;
+}
+
+#endif /* CONFIG_RESERVE_IPU_MEM */
+
+/*
+ * /proc/jz/xxx entry
+ *
+ */
+static int __init jz_proc_init(void)
+{
+ struct proc_dir_entry *res;
+#ifdef CONFIG_RESERVE_IPU_MEM
+ unsigned int virt_addr, i;
+#endif
+
+ proc_jz_root = proc_mkdir("jz", 0);
+
+ /* External Memory Controller */
+ res = create_proc_entry("emc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = emc_read_proc;
+ res->write_proc = NULL;
+ res->data = NULL;
+ }
+
+ /* Power Management Controller */
+ res = create_proc_entry("pmc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = pmc_read_proc;
+ res->write_proc = pmc_write_proc;
+ res->data = NULL;
+ }
+
+ /* Clock Generation Module */
+ res = create_proc_entry("cgm", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = cgm_read_proc;
+ res->write_proc = cgm_write_proc;
+ res->data = NULL;
+ }
+
+ /* mmc hotplug */
+ res = create_proc_entry("mmc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = mmc_read_proc;
+ res->write_proc = NULL;
+ res->data = NULL;
+ }
+
+#ifdef CONFIG_RESERVE_IPU_MEM
+ /* Image process unit */
+ res = create_proc_entry("ipu", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = ipu_read_proc;
+ res->write_proc = ipu_write_proc;
+ res->data = NULL;
+ }
+
+ /*
+ * Reserve a 4MB memory for IPU on JZ4740.
+ */
+ jz_imem_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM_MAX_ORDER);
+ if (jz_imem_base) {
+ /* imem (IPU memory management) */
+ res = create_proc_entry("imem", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = imem_read_proc;
+ res->write_proc = imem_write_proc;
+ res->data = NULL;
+ }
+
+ /* Set page reserved */
+ virt_addr = jz_imem_base;
+ for (i = 0; i < (1 << IMEM_MAX_ORDER); i++) {
+ SetPageReserved(virt_to_page((void *)virt_addr));
+ virt_addr += PAGE_SIZE;
+ }
+
+ /* Convert to physical address */
+ jz_imem_base = virt_to_phys((void *)jz_imem_base);
+
+ printk("Total %dMB memory at 0x%x was reserved for IPU\n",
+ (unsigned int)((1 << IMEM_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem_base);
+ }
+#endif
+
+ return 0;
+}
+
+__initcall(jz_proc_init);
diff --git a/arch/mips/jz4740/prom.c b/arch/mips/jz4740/prom.c
new file mode 100644
index 00000000000..4068939764b
--- /dev/null
+++ b/arch/mips/jz4740/prom.c
@@ -0,0 +1,198 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * PROM library initialisation code, supports YAMON and U-Boot.
+ *
+ * Copyright 2000, 2001, 2006 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * This file was derived from Carsten Langgaard's
+ * arch/mips/mips-boards/xx files.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/jzsoc.h>
+
+/* #define DEBUG_CMDLINE */
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+char * prom_getcmdline(void)
+{
+ return &(arcs_cmdline[0]);
+}
+
+void prom_init_cmdline(void)
+{
+ char *cp;
+ int actr;
+
+ actr = 1; /* Always ignore argv[0] */
+
+ cp = &(arcs_cmdline[0]);
+ while(actr < prom_argc) {
+ strcpy(cp, prom_argv[actr]);
+ cp += strlen(prom_argv[actr]);
+ *cp++ = ' ';
+ actr++;
+ }
+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+ --cp;
+ if (prom_argc > 1)
+ *cp = '\0';
+
+}
+
+
+char *prom_getenv(char *envname)
+{
+#if 0
+ /*
+ * Return a pointer to the given environment variable.
+ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
+ */
+
+ char **env = prom_envp;
+ int i = strlen(envname);
+ int yamon = (*env && strchr(*env, '=') == NULL);
+
+ while (*env) {
+ if (yamon) {
+ if (strcmp(envname, *env++) == 0)
+ return *env;
+ } else {
+ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
+ return *env + i + 1;
+ }
+ env++;
+ }
+#endif
+ return NULL;
+}
+
+inline unsigned char str2hexnum(unsigned char c)
+{
+ if(c >= '0' && c <= '9')
+ return c - '0';
+ if(c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if(c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return 0; /* foo */
+}
+
+inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+ int i;
+
+ for(i = 0; i < 6; i++) {
+ unsigned char num;
+
+ if((*str == '.') || (*str == ':'))
+ str++;
+ num = str2hexnum(*str++) << 4;
+ num |= (str2hexnum(*str++));
+ ea[i] = num;
+ }
+}
+
+int get_ethernet_addr(char *ethernet_addr)
+{
+ char *ethaddr_str;
+
+ ethaddr_str = prom_getenv("ethaddr");
+ if (!ethaddr_str) {
+ printk("ethaddr not set in boot prom\n");
+ return -1;
+ }
+ str2eaddr(ethernet_addr, ethaddr_str);
+
+#if 0
+ {
+ int i;
+
+ printk("get_ethernet_addr: ");
+ for (i=0; i<5; i++)
+ printk("%02x:", (unsigned char)*(ethernet_addr+i));
+ printk("%02x\n", *(ethernet_addr+i));
+ }
+#endif
+
+ return 0;
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+void __init prom_init(void)
+{
+ unsigned char *memsize_str;
+ unsigned long memsize;
+
+ prom_argc = (int) fw_arg0;
+ prom_argv = (char **) fw_arg1;
+ prom_envp = (char **) fw_arg2;
+
+ mips_machtype = MACH_INGENIC_JZ4740;
+
+ prom_init_cmdline();
+ memsize_str = prom_getenv("memsize");
+ if (!memsize_str) {
+ memsize = 0x04000000;
+ } else {
+ memsize = simple_strtol(memsize_str, NULL, 0);
+ }
+ add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
+/* used by early printk */
+void prom_putchar(char c)
+{
+ volatile u8 *uart_lsr = (volatile u8 *)(UART0_BASE + OFF_LSR);
+ volatile u8 *uart_tdr = (volatile u8 *)(UART0_BASE + OFF_TDR);
+
+ /* Wait for fifo to shift out some bytes */
+ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) );
+
+ *uart_tdr = (u8)c;
+}
+
+const char *get_system_type(void)
+{
+ return "JZ4740";
+}
+
+EXPORT_SYMBOL(prom_getcmdline);
+EXPORT_SYMBOL(get_ethernet_addr);
+EXPORT_SYMBOL(str2eaddr);
diff --git a/arch/mips/jz4740/reset.c b/arch/mips/jz4740/reset.c
new file mode 100644
index 00000000000..c33a37362ca
--- /dev/null
+++ b/arch/mips/jz4740/reset.c
@@ -0,0 +1,42 @@
+/*
+ * linux/arch/mips/jz4740/reset.c
+ *
+ * JZ4740 reset routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <yliu@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+void jz_restart(char *command)
+{
+ printk("Restarting after 4 ms\n");
+ REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN;
+ REG_WDT_TCNT = 0;
+ REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */
+ REG_TCU_TSCR = TCU_TSSR_WDTSC; /* enable wdt clock */
+ REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */
+ while (1);
+}
+
+void jz_halt(void)
+{
+ printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+
+ while (1)
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0");
+}
+
diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
new file mode 100644
index 00000000000..33d4643f291
--- /dev/null
+++ b/arch/mips/jz4740/setup.c
@@ -0,0 +1,182 @@
+/*
+ * linux/arch/mips/jz4740/common/setup.c
+ *
+ * JZ4740 common setup routines.
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/ioport.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+#include <asm/pgtable.h>
+#include <asm/time.h>
+#include <asm/jzsoc.h>
+
+#ifdef CONFIG_PC_KEYB
+#include <asm/keyboard.h>
+#endif
+
+jz_clocks_t jz_clocks;
+
+extern char * __init prom_getcmdline(void);
+extern void __init jz_board_setup(void);
+extern void jz_restart(char *);
+extern void jz_halt(void);
+extern void jz_pm_hibernate(void);
+extern void jz_time_init(void);
+
+static void __init sysclocks_setup(void)
+{
+#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */
+ jz_clocks.cclk = __cpm_get_cclk();
+ jz_clocks.hclk = __cpm_get_hclk();
+ jz_clocks.pclk = __cpm_get_pclk();
+ jz_clocks.mclk = __cpm_get_mclk();
+ jz_clocks.lcdclk = __cpm_get_lcdclk();
+ jz_clocks.pixclk = __cpm_get_pixclk();
+ jz_clocks.i2sclk = __cpm_get_i2sclk();
+ jz_clocks.usbclk = __cpm_get_usbclk();
+ jz_clocks.mscclk = __cpm_get_mscclk();
+ jz_clocks.extalclk = __cpm_get_extalclk();
+ jz_clocks.rtcclk = __cpm_get_rtcclk();
+#else
+
+#define FPGACLK 8000000
+
+ jz_clocks.cclk = FPGACLK;
+ jz_clocks.hclk = FPGACLK;
+ jz_clocks.pclk = FPGACLK;
+ jz_clocks.mclk = FPGACLK;
+ jz_clocks.lcdclk = FPGACLK;
+ jz_clocks.pixclk = FPGACLK;
+ jz_clocks.i2sclk = FPGACLK;
+ jz_clocks.usbclk = FPGACLK;
+ jz_clocks.mscclk = FPGACLK;
+ jz_clocks.extalclk = FPGACLK;
+ jz_clocks.rtcclk = FPGACLK;
+#endif
+
+ printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n",
+ (jz_clocks.cclk + 500000) / 1000000,
+ (jz_clocks.hclk + 500000) / 1000000,
+ (jz_clocks.pclk + 500000) / 1000000,
+ (jz_clocks.mclk + 500000) / 1000000);
+}
+
+static void __init soc_cpm_setup(void)
+{
+ /* Start all module clocks
+ */
+ __cpm_start_all();
+
+ /* Enable CKO to external memory */
+ __cpm_enable_cko();
+
+ /* CPU enters IDLE mode when executing 'wait' instruction */
+ __cpm_idle_mode();
+
+ /* Setup system clocks */
+ sysclocks_setup();
+}
+
+static void __init soc_harb_setup(void)
+{
+// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */
+// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */
+// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */
+}
+
+static void __init soc_emc_setup(void)
+{
+}
+
+static void __init soc_dmac_setup(void)
+{
+ __dmac_enable_module();
+}
+
+static void __init jz_soc_setup(void)
+{
+ soc_cpm_setup();
+ soc_harb_setup();
+ soc_emc_setup();
+ soc_dmac_setup();
+}
+
+static void __init jz_serial_setup(void)
+{
+#ifdef CONFIG_SERIAL_8250
+ struct uart_port s;
+ REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */
+ memset(&s, 0, sizeof(s));
+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
+ s.iotype = SERIAL_IO_MEM;
+ s.regshift = 2;
+ s.uartclk = jz_clocks.extalclk ;
+
+ s.line = 0;
+ s.membase = (u8 *)UART0_BASE;
+ s.irq = IRQ_UART0;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS0 setup failed!\n");
+ }
+
+ s.line = 1;
+ s.membase = (u8 *)UART1_BASE;
+ s.irq = IRQ_UART1;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS1 setup failed!\n");
+ }
+#endif
+}
+
+void __init plat_mem_setup(void)
+{
+ char *argptr;
+
+ argptr = prom_getcmdline();
+
+ /* IO/MEM resources. Which will be the addtion value in `inX' and
+ * `outX' macros defined in asm/io.h */
+ set_io_port_base(0);
+ ioport_resource.start = 0x00000000;
+ ioport_resource.end = 0xffffffff;
+ iomem_resource.start = 0x00000000;
+ iomem_resource.end = 0xffffffff;
+
+ _machine_restart = jz_restart;
+ _machine_halt = jz_halt;
+ pm_power_off = jz_pm_hibernate;
+
+ jz_soc_setup();
+ jz_serial_setup();
+ jz_board_setup();
+}
+
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
new file mode 100644
index 00000000000..e9f63ee1d1a
--- /dev/null
+++ b/arch/mips/jz4740/time.c
@@ -0,0 +1,158 @@
+/*
+ * linux/arch/mips/jz4740/time.c
+ *
+ * Setting up the clock on the JZ4740 boards.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/clockchips.h>
+
+#include <asm/time.h>
+#include <asm/jzsoc.h>
+
+/* This is for machines which generate the exact clock. */
+
+#define JZ_TIMER_CHAN 0
+#define JZ_TIMER_IRQ IRQ_TCU0
+
+#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */
+
+static struct clocksource clocksource_jz; /* Jz clock source */
+static struct clock_event_device jz_clockevent_device; /* Jz clock event */
+
+void (*jz_timer_callback)(void);
+
+static irqreturn_t jz_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd = dev_id;
+
+ REG_TCU_TFCR = 1 << JZ_TIMER_CHAN; /* ACK timer */
+
+ if (jz_timer_callback)
+ jz_timer_callback();
+
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction jz_irqaction = {
+ .handler = jz_timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+ .name = "jz-timerirq",
+};
+
+
+cycle_t jz_get_cycles(struct clocksource *cs)
+{
+ /* convert jiffes to jz timer cycles */
+ return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_TCNT(JZ_TIMER_CHAN));
+}
+
+static struct clocksource clocksource_jz = {
+ .name = "jz_clocksource",
+ .rating = 300,
+ .read = jz_get_cycles,
+ .mask = 0xFFFF,
+ .shift = 10,
+ .flags = CLOCK_SOURCE_WATCHDOG,
+};
+
+static int __init jz_clocksource_init(void)
+{
+ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift);
+ clocksource_register(&clocksource_jz);
+ return 0;
+}
+
+static int jz_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ return 0;
+}
+
+static void jz_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static struct clock_event_device jz_clockevent_device = {
+ .name = "jz-clockenvent",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */
+
+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
+ .rating = 300,
+ .irq = JZ_TIMER_IRQ,
+ .set_mode = jz_set_mode,
+ .set_next_event = jz_set_next_event,
+};
+
+static void __init jz_clockevent_init(void)
+{
+ struct clock_event_device *cd = &jz_clockevent_device;
+ unsigned int cpu = smp_processor_id();
+
+ cd->cpumask = cpumask_of(cpu);
+ clockevents_register_device(cd);
+}
+
+static void __init jz_timer_setup(void)
+{
+ jz_clocksource_init(); /* init jz clock source */
+ jz_clockevent_init(); /* init jz clock event */
+
+ /*
+ * Make irqs happen for the system timer
+ */
+ jz_irqaction.dev_id = &jz_clockevent_device;
+ setup_irq(JZ_TIMER_IRQ, &jz_irqaction);
+}
+
+
+void __init plat_time_init(void)
+{
+ unsigned int latch;
+ /* Init timer */
+ latch = ( JZ_TIMER_CLOCK + (HZ>>1)) / HZ;
+
+ REG_TCU_TCSR(JZ_TIMER_CHAN) = TCU_TCSR_PRESCALE16 | TCU_TCSR_EXT_EN;
+ REG_TCU_TCNT(JZ_TIMER_CHAN) = 0;
+ REG_TCU_TDHR(JZ_TIMER_CHAN) = 0;
+ REG_TCU_TDFR(JZ_TIMER_CHAN) = latch;
+
+ REG_TCU_TMSR = (1 << (JZ_TIMER_CHAN + 16)); /* mask half irq */
+ REG_TCU_TMCR = (1 << JZ_TIMER_CHAN); /* unmask full irq */
+ REG_TCU_TSCR = (1 << JZ_TIMER_CHAN); /* enable timer clock */
+ REG_TCU_TESR = (1 << JZ_TIMER_CHAN); /* start counting up */
+
+ jz_timer_setup();
+}
diff --git a/arch/mips/jz4750/Makefile b/arch/mips/jz4750/Makefile
new file mode 100644
index 00000000000..7dcc3b4861c
--- /dev/null
+++ b/arch/mips/jz4750/Makefile
@@ -0,0 +1,23 @@
+#
+# Makefile for the Ingenic JZ4750.
+#
+
+# Object file lists.
+
+obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
+ platform.o i2c.o
+
+obj-$(CONFIG_PROC_FS) += proc.o
+
+# board specific support
+
+obj-$(CONFIG_JZ4750_FUWA) += board-fuwa.o
+obj-$(CONFIG_JZ4750_APUS) += board-apus.o
+
+# PM support
+
+obj-$(CONFIG_PM) +=pm.o
+
+# CPU Frequency scaling support
+
+obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o
diff --git a/arch/mips/jz4750/board-apus.c b/arch/mips/jz4750/board-apus.c
new file mode 100644
index 00000000000..7347dfaa56e
--- /dev/null
+++ b/arch/mips/jz4750/board-apus.c
@@ -0,0 +1,64 @@
+/*
+ * linux/arch/mips/jz4750/board-apus.c
+ *
+ * JZ4750 APUS board setup routines.
+ *
+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+
+#include <asm/jzsoc.h>
+
+extern void (*jz_timer_callback)(void);
+
+static void dancing(void)
+{
+}
+
+static void apus_timer_callback(void)
+{
+ static unsigned long count = 0;
+
+ if ((++count) % 50 == 0) {
+ dancing();
+ count = 0;
+ }
+}
+
+static void __init board_cpm_setup(void)
+{
+ /* Stop unused module clocks here.
+ * We have started all module clocks at arch/mips/jz4750/setup.c.
+ */
+}
+
+static void __init board_gpio_setup(void)
+{
+ __gpio_as_pcm();
+}
+
+void __init jz_board_setup(void)
+{
+ printk("JZ4750 APUS board setup\n");
+
+ board_cpm_setup();
+ board_gpio_setup();
+
+ jz_timer_callback = apus_timer_callback;
+}
diff --git a/arch/mips/jz4750/board-fuwa.c b/arch/mips/jz4750/board-fuwa.c
new file mode 100644
index 00000000000..c5aae06a739
--- /dev/null
+++ b/arch/mips/jz4750/board-fuwa.c
@@ -0,0 +1,105 @@
+/*
+ * linux/arch/mips/jz4750/board-fuwa.c
+ *
+ * JZ4750 FUWA board setup routines.
+ *
+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+
+#include <asm/jzsoc.h>
+
+extern void (*jz_timer_callback)(void);
+
+static void dancing(void)
+{
+ static unsigned char slash[] = "\\|/-";
+// static volatile unsigned char *p = (unsigned char *)0xb6000058;
+ static volatile unsigned char *p = (unsigned char *)0xb6000016;
+ static unsigned int count = 0;
+ *p = slash[count++];
+ count &= 3;
+}
+
+static void fuwa_timer_callback(void)
+{
+ static unsigned long count = 0;
+
+ if ((++count) % 50 == 0) {
+ dancing();
+ count = 0;
+ }
+}
+
+static void __init board_cpm_setup(void)
+{
+ /* Stop unused module clocks here.
+ * We have started all module clocks at arch/mips/jz4750/setup.c.
+ */
+}
+
+static void __init board_gpio_setup(void)
+{
+ /*
+ * Initialize SDRAM pins
+ */
+
+ /* PORT A: D0 ~ D31 */
+ REG_GPIO_PXFUNS(0) = 0xffffffff;
+ REG_GPIO_PXSELC(0) = 0xffffffff;
+
+ /* PORT B: A0 ~ A16, DCS#, RAS#, CAS#, CKE#, RDWE#, CKO#, WE0# */
+ REG_GPIO_PXFUNS(1) = 0x81f9ffff;
+ REG_GPIO_PXSELC(1) = 0x81f9ffff;
+
+ /* PORT C: WE1#, WE2#, WE3# */
+ REG_GPIO_PXFUNS(2) = 0x07000000;
+ REG_GPIO_PXSELC(2) = 0x07000000;
+
+
+ /*
+ * Initialize UART0 pins
+ */
+
+ /* PORT D: TXD/RXD */
+ REG_GPIO_PXFUNS(3) = 0x06000000;
+ REG_GPIO_PXSELS(3) = 0x06000000;
+
+
+ /*
+ * Initialize LED pins
+ */
+ __gpio_as_lcd_18bit();
+
+ /* CS2# */
+ REG_GPIO_PXFUNS(1) = 0x04000000;
+ REG_GPIO_PXSELC(1) = 0x04000000;
+
+ __gpio_as_pcm();
+}
+
+void __init jz_board_setup(void)
+{
+ printk("JZ4750 FUWA board setup\n");
+
+ board_cpm_setup();
+ board_gpio_setup();
+
+ jz_timer_callback = fuwa_timer_callback;
+}
diff --git a/arch/mips/jz4750/board-slt50.c b/arch/mips/jz4750/board-slt50.c
new file mode 100644
index 00000000000..e8e20b4fb8e
--- /dev/null
+++ b/arch/mips/jz4750/board-slt50.c
@@ -0,0 +1,64 @@
+/*
+ * linux/arch/mips/jz4750/board-apus.c
+ *
+ * JZ4750 APUS board setup routines.
+ *
+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+
+#include <asm/jzsoc.h>
+
+extern void (*jz_timer_callback)(void);
+
+static void dancing(void)
+{
+}
+
+static void apus_timer_callback(void)
+{
+ static unsigned long count = 0;
+
+ if ((++count) % 50 == 0) {
+ dancing();
+ count = 0;
+ }
+}
+
+static void __init board_cpm_setup(void)
+{
+ /* Stop unused module clocks here.
+ * We have started all module clocks at arch/mips/jz4750/setup.c.
+ */
+}
+
+static void __init board_gpio_setup(void)
+{
+ __gpio_as_pcm();
+}
+
+void __init jz_board_setup(void)
+{
+ printk("JZ4750 SLT_50 board setup\n");
+
+ board_cpm_setup();
+ board_gpio_setup();
+
+ jz_timer_callback = apus_timer_callback;
+}
diff --git a/arch/mips/jz4750/cpufreq.c b/arch/mips/jz4750/cpufreq.c
new file mode 100644
index 00000000000..83f98b1cd32
--- /dev/null
+++ b/arch/mips/jz4750/cpufreq.c
@@ -0,0 +1,601 @@
+/*
+ * linux/arch/mips/jz4750/cpufreq.c
+ *
+ * cpufreq driver for JZ4750
+ *
+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/cpufreq.h>
+
+#include <asm/jzsoc.h>
+#include <asm/processor.h>
+
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+ "cpufreq-jz4750", msg)
+
+#undef CHANGE_PLL
+
+#define PLL_UNCHANGED 0
+#define PLL_GOES_UP 1
+#define PLL_GOES_DOWN 2
+
+#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000))
+
+/* Saved the boot-time parameters */
+static struct {
+ /* SDRAM parameters */
+ unsigned int mclk; /* memory clock, KHz */
+ unsigned int tras; /* RAS pulse width, cycles of mclk */
+ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */
+ unsigned int tpc; /* RAS Precharge time, cycles of mclk */
+ unsigned int trwl; /* Write Precharge Time, cycles of mclk */
+ unsigned int trc; /* RAS Cycle Time, cycles of mclk */
+ unsigned int rtcor; /* Refresh Time Constant */
+ unsigned int sdram_initialized;
+
+ /* LCD parameters */
+ unsigned int lcd_clk; /* LCD clock, Hz */
+ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */
+ unsigned int lcd_clks_initialized;
+} boot_config;
+
+struct jz4750_freq_percpu_info {
+ struct cpufreq_frequency_table table[7];
+};
+
+static struct jz4750_freq_percpu_info jz4750_freq_table;
+
+/*
+ * This contains the registers value for an operating point.
+ * If only part of a register needs to change then there is
+ * a mask value for that register.
+ * When going to a new operating point the current register
+ * value is ANDed with the ~mask and ORed with the new value.
+ */
+struct dpm_regs {
+ u32 cpccr; /* Clock Freq Control Register */
+ u32 cpccr_mask; /* Clock Freq Control Register mask */
+ u32 cppcr; /* PLL1 Control Register */
+ u32 cppcr_mask; /* PLL1 Control Register mask */
+ u32 pll_up_flag; /* New PLL freq is higher than current or not */
+};
+
+extern jz_clocks_t jz_clocks;
+
+static void jz_update_clocks(void)
+{
+ /* Next clocks must be updated if we have changed
+ * the PLL or divisors.
+ */
+ jz_clocks.cclk = __cpm_get_cclk();
+ jz_clocks.hclk = __cpm_get_hclk();
+ jz_clocks.mclk = __cpm_get_mclk();
+ jz_clocks.pclk = __cpm_get_pclk();
+ jz_clocks.lcdclk = __cpm_get_lcdclk();
+ jz_clocks.pixclk = __cpm_get_pixclk();
+ jz_clocks.i2sclk = __cpm_get_i2sclk();
+ jz_clocks.usbclk = __cpm_get_usbclk();
+ jz_clocks.mscclk = __cpm_get_mscclk(0);
+}
+
+static void
+jz_init_boot_config(void)
+{
+ if (!boot_config.lcd_clks_initialized) {
+ /* the first time to scale pll */
+ boot_config.lcd_clk = __cpm_get_lcdclk();
+ boot_config.lcdpix_clk = __cpm_get_pixclk();
+ boot_config.lcd_clks_initialized = 1;
+ }
+
+ if (!boot_config.sdram_initialized) {
+ /* the first time to scale frequencies */
+ unsigned int dmcr, rtcor;
+ unsigned int tras, rcd, tpc, trwl, trc;
+
+ dmcr = REG_EMC_DMCR;
+ rtcor = REG_EMC_RTCOR;
+
+ tras = (dmcr >> 13) & 0x7;
+ rcd = (dmcr >> 11) & 0x3;
+ tpc = (dmcr >> 8) & 0x7;
+ trwl = (dmcr >> 5) & 0x3;
+ trc = (dmcr >> 2) & 0x7;
+
+ boot_config.mclk = __cpm_get_mclk() / 1000;
+ boot_config.tras = tras + 4;
+ boot_config.rcd = rcd + 1;
+ boot_config.tpc = tpc + 1;
+ boot_config.trwl = trwl + 1;
+ boot_config.trc = trc * 2 + 1;
+ boot_config.rtcor = rtcor;
+
+ boot_config.sdram_initialized = 1;
+ }
+}
+
+static void jz_update_dram_rtcor(unsigned int new_mclk)
+{
+ unsigned int rtcor;
+
+ new_mclk /= 1000;
+ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk;
+ rtcor--;
+
+ if (rtcor < 1) rtcor = 1;
+ if (rtcor > 255) rtcor = 255;
+
+ REG_EMC_RTCOR = rtcor;
+ REG_EMC_RTCNT = rtcor;
+}
+
+static void jz_update_dram_dmcr(unsigned int new_mclk)
+{
+ unsigned int dmcr;
+ unsigned int tras, rcd, tpc, trwl, trc;
+ unsigned int valid_time, new_time; /* ns */
+
+ new_mclk /= 1000;
+ tras = boot_config.tras * new_mclk / boot_config.mclk;
+ rcd = boot_config.rcd * new_mclk / boot_config.mclk;
+ tpc = boot_config.tpc * new_mclk / boot_config.mclk;
+ trwl = boot_config.trwl * new_mclk / boot_config.mclk;
+ trc = boot_config.trc * new_mclk / boot_config.mclk;
+
+ /* Validation checking */
+ valid_time = (boot_config.tras * 1000000) / boot_config.mclk;
+ new_time = (tras * 1000000) / new_mclk;
+ if (new_time < valid_time) tras += 1;
+
+ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk;
+ new_time = (rcd * 1000000) / new_mclk;
+ if (new_time < valid_time) rcd += 1;
+
+ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk;
+ new_time = (tpc * 1000000) / new_mclk;
+ if (new_time < valid_time) tpc += 1;
+
+ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk;
+ new_time = (trwl * 1000000) / new_mclk;
+ if (new_time < valid_time) trwl += 1;
+
+ valid_time = (boot_config.trc * 1000000) / boot_config.mclk;
+ new_time = (trc * 1000000) / new_mclk;
+ if (new_time < valid_time) trc += 2;
+
+ tras = (tras < 4) ? 4: tras;
+ tras = (tras > 11) ? 11: tras;
+ tras -= 4;
+
+ rcd = (rcd < 1) ? 1: rcd;
+ rcd = (rcd > 4) ? 4: rcd;
+ rcd -= 1;
+
+ tpc = (tpc < 1) ? 1: tpc;
+ tpc = (tpc > 8) ? 8: tpc;
+ tpc -= 1;
+
+ trwl = (trwl < 1) ? 1: trwl;
+ trwl = (trwl > 4) ? 4: trwl;
+ trwl -= 1;
+
+ trc = (trc < 1) ? 1: trc;
+ trc = (trc > 15) ? 15: trc;
+ trc /= 2;
+
+ dmcr = REG_EMC_DMCR;
+
+ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK);
+ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT));
+
+ REG_EMC_DMCR = dmcr;
+}
+
+static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk)
+{
+ /* No risk, no fun: run with interrupts on! */
+ if (new_mclk > cur_mclk) {
+ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL
+ * and TRC of DMCR before changing the frequency.
+ */
+ jz_update_dram_dmcr(new_mclk);
+ } else {
+ /* We're going SLOWER: first update RTCOR value
+ * before changing the frequency.
+ */
+ jz_update_dram_rtcor(new_mclk);
+ }
+}
+
+static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk)
+{
+ /* No risk, no fun: run with interrupts on! */
+ if (new_mclk > cur_mclk) {
+ /* We're going FASTER, so update RTCOR
+ * after changing the frequency
+ */
+ jz_update_dram_rtcor(new_mclk);
+ } else {
+ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL
+ * and TRC of DMCR after changing the frequency.
+ */
+ jz_update_dram_dmcr(new_mclk);
+ }
+}
+
+static void jz_scale_divisors(struct dpm_regs *regs)
+{
+ unsigned int cpccr;
+ unsigned int cur_mclk, new_mclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned int tmp = 0, wait = PLL_WAIT_500NS;
+
+ cpccr = REG_CPM_CPCCR;
+ cpccr &= ~((unsigned long)regs->cpccr_mask);
+ cpccr |= regs->cpccr;
+ cpccr |= CPM_CPCCR_CE; /* update immediately */
+
+ cur_mclk = __cpm_get_mclk();
+ new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT];
+
+ /* Update some DRAM parameters before changing frequency */
+ jz_update_dram_prev(cur_mclk, new_mclk);
+
+ /* update register to change the clocks.
+ * align this code to a cache line.
+ */
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "li %3,0\n\t"
+ "1:\n\t"
+ "bne %3,%2,1b\n\t"
+ "addi %3, 1\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
+
+ /* Update some other DRAM parameters after changing frequency */
+ jz_update_dram_post(cur_mclk, new_mclk);
+}
+
+#ifdef CHANGE_PLL
+/* Maintain the LCD clock and pixel clock */
+static void jz_scale_lcd_divisors(struct dpm_regs *regs)
+{
+ unsigned int new_pll, new_lcd_div, new_lcdpix_div;
+ unsigned int cpccr;
+ unsigned int tmp = 0, wait = PLL_WAIT_500NS;
+
+ if (!boot_config.lcd_clks_initialized) return;
+
+ new_pll = __cpm_get_pllout();
+ new_lcd_div = new_pll / boot_config.lcd_clk;
+ new_lcdpix_div = new_pll / boot_config.lcdpix_clk;
+
+ if (new_lcd_div < 1)
+ new_lcd_div = 1;
+ if (new_lcd_div > 16)
+ new_lcd_div = 16;
+
+ if (new_lcdpix_div < 1)
+ new_lcdpix_div = 1;
+ if (new_lcdpix_div > 512)
+ new_lcdpix_div = 512;
+
+// REG_CPM_CPCCR2 = new_lcdpix_div - 1;
+
+ cpccr = REG_CPM_CPCCR;
+ cpccr &= ~CPM_CPCCR_LDIV_MASK;
+ cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT);
+ cpccr |= CPM_CPCCR_CE; /* update immediately */
+
+ /* update register to change the clocks.
+ * align this code to a cache line.
+ */
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "li %3,0\n\t"
+ "1:\n\t"
+ "bne %3,%2,1b\n\t"
+ "addi %3, 1\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
+}
+
+static void jz_scale_pll(struct dpm_regs *regs)
+{
+ unsigned int cppcr;
+ unsigned int cur_mclk, new_mclk, new_pll;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ int od[] = {1, 2, 2, 4};
+
+ cppcr = REG_CPM_CPPCR;
+ cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK);
+ regs->cppcr &= ~CPM_CPPCR_PLLEN;
+ cppcr |= (regs->cppcr | 0xff);
+
+ /* Update some DRAM parameters before changing frequency */
+ new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]);
+ cur_mclk = __cpm_get_mclk();
+ new_mclk = new_pll / div[(REG_CPM_CPCCR>>16) & 0xf];
+
+ /*
+ * Update some SDRAM parameters
+ */
+ jz_update_dram_prev(cur_mclk, new_mclk);
+
+ /*
+ * Update PLL, align code to cache line.
+ */
+ cppcr |= CPM_CPPCR_PLLEN;
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CPPCR), "r" (cppcr));
+
+ /* Update some other DRAM parameters after changing frequency */
+ jz_update_dram_post(cur_mclk, new_mclk);
+}
+#endif
+
+static void jz4750_transition(struct dpm_regs *regs)
+{
+ /*
+ * Get and save some boot-time conditions.
+ */
+ jz_init_boot_config();
+
+#ifdef CHANGE_PLL
+ /*
+ * Disable LCD before scaling pll.
+ * LCD and LCD pixel clocks should not be changed even if the PLL
+ * output frequency has been changed.
+ */
+ REG_LCD_CTRL &= ~LCD_CTRL_ENA;
+
+ /*
+ * Stop module clocks before scaling PLL
+ */
+ __cpm_stop_eth();
+ __cpm_stop_aic(1);
+ __cpm_stop_aic(2);
+#endif
+
+ /* ... add more as necessary */
+
+ if (regs->pll_up_flag == PLL_GOES_UP) {
+ /* the pll frequency is going up, so change dividors first */
+ jz_scale_divisors(regs);
+#ifdef CHANGE_PLL
+ jz_scale_pll(regs);
+#endif
+ }
+ else if (regs->pll_up_flag == PLL_GOES_DOWN) {
+ /* the pll frequency is going down, so change pll first */
+#ifdef CHANGE_PLL
+ jz_scale_pll(regs);
+#endif
+ jz_scale_divisors(regs);
+ }
+ else {
+ /* the pll frequency is unchanged, so change divisors only */
+ jz_scale_divisors(regs);
+ }
+
+#ifdef CHANGE_PLL
+ /*
+ * Restart module clocks before scaling PLL
+ */
+ __cpm_start_eth();
+ __cpm_start_aic(1);
+ __cpm_start_aic(2);
+
+ /* ... add more as necessary */
+
+ /* Scale the LCD divisors after scaling pll */
+ if (regs->pll_up_flag != PLL_UNCHANGED) {
+ jz_scale_lcd_divisors(regs);
+ }
+
+ /* Enable LCD controller */
+ REG_LCD_CTRL &= ~LCD_CTRL_DIS;
+ REG_LCD_CTRL |= LCD_CTRL_ENA;
+#endif
+
+ /* Update system clocks */
+ jz_update_clocks();
+}
+
+extern unsigned int idle_times;
+static unsigned int jz4750_freq_get(unsigned int cpu)
+{
+ return (__cpm_get_cclk() / 1000);
+}
+
+static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs)
+{
+ int n2FR[33] = {
+ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
+ 9
+ };
+ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */
+ unsigned int div_of_cclk, new_freq, i;
+
+ regs->pll_up_flag = PLL_UNCHANGED;
+ regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK;
+
+ new_freq = jz4750_freq_table.table[index].frequency;
+
+ do {
+ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq);
+ } while (div_of_cclk==0);
+
+ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) {
+ for(i = 1; i<4; i++) {
+ div[i] = 3;
+ }
+ } else {
+ for(i = 1; i<4; i++) {
+ div[i] = 2;
+ }
+ }
+
+ for(i = 0; i<4; i++) {
+ div[i] *= div_of_cclk;
+ }
+
+ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]);
+
+ regs->cpccr =
+ (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
+ (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
+ (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
+ (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT);
+
+ return div_of_cclk;
+}
+
+static void jz4750_set_cpu_divider_index(unsigned int cpu, unsigned int index)
+{
+ unsigned long divisor, old_divisor;
+ struct cpufreq_freqs freqs;
+ struct dpm_regs regs;
+
+ old_divisor = __cpm_get_pllout() / __cpm_get_cclk();
+ divisor = index_to_divisor(index, &regs);
+
+ freqs.old = __cpm_get_cclk() / 1000;
+ freqs.new = __cpm_get_pllout() / (1000 * divisor);
+ freqs.cpu = cpu;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ if (old_divisor != divisor)
+ jz4750_transition(&regs);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+}
+
+static int jz4750_freq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int new_index = 0;
+
+ if (cpufreq_frequency_table_target(policy,
+ &jz4750_freq_table.table[0],
+ target_freq, relation, &new_index))
+ return -EINVAL;
+
+ jz4750_set_cpu_divider_index(policy->cpu, new_index);
+
+ dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR);
+
+ return 0;
+}
+
+static int jz4750_freq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy,
+ &jz4750_freq_table.table[0]);
+}
+
+static int __init jz4750_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+
+ struct cpufreq_frequency_table *table = &jz4750_freq_table.table[0];
+ unsigned int MAX_FREQ;
+
+ dprintk(KERN_INFO "Jz4750 cpufreq driver\n");
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ policy->cpuinfo.min_freq = MAX_FREQ/8;
+ policy->cpuinfo.max_freq = MAX_FREQ;
+ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */
+
+ table[0].index = 0;
+ table[0].frequency = MAX_FREQ/8;
+ table[1].index = 1;
+ table[1].frequency = MAX_FREQ/6;
+ table[2].index = 2;
+ table[2].frequency = MAX_FREQ/4;
+ table[3].index = 3;
+ table[3].frequency = MAX_FREQ/3;
+ table[4].index = 4;
+ table[4].frequency = MAX_FREQ/2;
+ table[5].index = 5;
+ table[5].frequency = MAX_FREQ;
+ table[6].index = 6;
+ table[6].frequency = CPUFREQ_TABLE_END;
+
+#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
+ cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */
+#endif
+
+ return cpufreq_frequency_table_cpuinfo(policy, table);
+}
+
+static struct cpufreq_driver cpufreq_jz4750_driver = {
+// .flags = CPUFREQ_STICKY,
+ .init = jz4750_cpufreq_driver_init,
+ .verify = jz4750_freq_verify,
+ .target = jz4750_freq_target,
+ .get = jz4750_freq_get,
+ .name = "jz4750",
+};
+
+static int __init jz4750_cpufreq_init(void)
+{
+ return cpufreq_register_driver(&cpufreq_jz4750_driver);
+}
+
+static void __exit jz4750_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&cpufreq_jz4750_driver);
+}
+
+module_init(jz4750_cpufreq_init);
+module_exit(jz4750_cpufreq_exit);
+
+MODULE_AUTHOR("Regen <lhhuang@ingenic.cn>");
+MODULE_DESCRIPTION("cpufreq driver for Jz4750");
+MODULE_LICENSE("GPL");
diff --git a/arch/mips/jz4750/dma.c b/arch/mips/jz4750/dma.c
new file mode 100644
index 00000000000..2508111b44e
--- /dev/null
+++ b/arch/mips/jz4750/dma.c
@@ -0,0 +1,836 @@
+/*
+ * linux/arch/mips/jz4750/dma.c
+ *
+ * Support functions for the JZ4750 internal DMA channels.
+ * No-descriptor transfer only.
+ * Descriptor transfer should also call jz_request_dma() to get a free
+ * channel and call jz_free_dma() to free the channel. And driver should
+ * build the DMA descriptor and setup the DMA channel by itself.
+ *
+ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/soundcard.h>
+
+#include <asm/system.h>
+#include <asm/addrspace.h>
+#include <asm/jzsoc.h>
+
+/*
+ * A note on resource allocation:
+ *
+ * All drivers needing DMA channels, should allocate and release them
+ * through the public routines `jz_request_dma()' and `jz_free_dma()'.
+ *
+ * In order to avoid problems, all processes should allocate resources in
+ * the same sequence and release them in the reverse order.
+ *
+ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ.
+ * When releasing them, first release the IRQ, then release the DMA. The
+ * main reason for this order is that, if you are requesting the DMA buffer
+ * done interrupt, you won't know the irq number until the DMA channel is
+ * returned from jz_request_dma().
+ */
+
+struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = {
+ {dev_id:DMA_ID_BCH_ENC,}, /* DMAC0 channel 0, reserved for BCH */
+ {dev_id:-1,}, /* DMAC0 channel 1 */
+ {dev_id:-1,}, /* DMAC0 channel 2 */
+ {dev_id:-1,}, /* DMAC0 channel 3 */
+ {dev_id:-1,}, /* DMAC0 channel 4 */
+ {dev_id:-1,}, /* DMAC0 channel 5 */
+ {dev_id:-1,}, /* DMAC1 channel 0 */
+ {dev_id:-1,}, /* DMAC1 channel 1 */
+ {dev_id:-1,}, /* DMAC1 channel 2 */
+ {dev_id:-1,}, /* DMAC1 channel 3 */
+ {dev_id:-1,}, /* DMAC1 channel 4 */
+ {dev_id:-1,}, /* DMAC1 channel 5 */
+};
+
+// Device FIFO addresses and default DMA modes
+static const struct {
+ unsigned int fifo_addr;
+ unsigned int dma_mode;
+ unsigned int dma_source;
+} dma_dev_table[DMA_ID_MAX] = {
+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_EXT}, /* External request with DREQn */
+ {0x18000000, DMA_AUTOINIT, DMAC_DRSR_RS_NAND}, /* NAND request */
+ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_ENC},
+ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_DEC},
+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO},
+// {CPHYSADDR(TSSI_FIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_TSSIIN},
+ {CPHYSADDR(UART3_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT},
+ {CPHYSADDR(UART3_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART3IN},
+ {CPHYSADDR(UART2_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT},
+ {CPHYSADDR(UART2_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART2IN},
+ {CPHYSADDR(UART1_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT},
+ {CPHYSADDR(UART1_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART1IN},
+ {CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT},
+ {CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN},
+ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI0OUT},
+ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI0IN},
+ {CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT},
+ {CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN},
+ {CPHYSADDR(MSC_TXFIFO(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC0OUT},
+ {CPHYSADDR(MSC_RXFIFO(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC0IN},
+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU},
+ {SADC_TSDAT, DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SADC},/* Touch Screen Data Register */
+ {CPHYSADDR(MSC_TXFIFO(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC1OUT}, /* SSC1 TX */
+ {CPHYSADDR(MSC_RXFIFO(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC1IN}, /* SSC1 RX */
+ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI1OUT},
+ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI1IN},
+ {CPHYSADDR(PCM_DP), DMA_16BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_PMOUT},
+ {CPHYSADDR(PCM_DP), DMA_16BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_PMIN},
+ {},
+};
+
+
+int jz_dma_read_proc(char *buf, char **start, off_t fpos,
+ int length, int *eof, void *data)
+{
+ int i, len = 0;
+ struct jz_dma_chan *chan;
+
+ for (i = 0; i < MAX_DMA_NUM; i++) {
+ if ((chan = get_dma_chan(i)) != NULL) {
+ len += sprintf(buf + len, "%2d: %s\n",
+ i, chan->dev_str);
+ }
+ }
+
+ if (fpos >= len) {
+ *start = buf;
+ *eof = 1;
+ return 0;
+ }
+ *start = buf + fpos;
+ if ((len -= fpos) > length)
+ return length;
+ *eof = 1;
+ return len;
+}
+
+
+void dump_jz_dma_channel(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan;
+
+ if (dmanr > MAX_DMA_NUM)
+ return;
+ chan = &jz_dma_table[dmanr];
+
+ printk("DMA%d Registers:\n", dmanr);
+ printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR(chan->io/HALF_DMA_NUM));
+ printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr));
+ printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr));
+ printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr));
+ printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr));
+ printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr));
+ printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr));
+ printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr));
+ printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR(chan->io/HALF_DMA_NUM));
+}
+
+
+/**
+ * jz_request_dma - dynamically allcate an idle DMA channel to return
+ * @dev_id: the specified dma device id or DMA_ID_RAW_SET
+ * @dev_str: the specified dma device string name
+ * @irqhandler: the irq handler, or NULL
+ * @irqflags: the irq handler flags
+ * @irq_dev_id: the irq handler device id for shared irq
+ *
+ * Finds a free channel, and binds the requested device to it.
+ * Returns the allocated channel number, or negative on error.
+ * Requests the DMA done IRQ if irqhandler != NULL.
+ *
+*/
+/*int jz_request_dma(int dev_id, const char *dev_str,
+ void (*irqhandler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ void *irq_dev_id)
+*/
+
+int jz_request_dma(int dev_id, const char *dev_str,
+ irqreturn_t (*irqhandler)(int, void *),
+ unsigned long irqflags,
+ void *irq_dev_id)
+{
+ struct jz_dma_chan *chan;
+ int i, ret, chan0;
+
+ if (dev_id < 0 || dev_id >= DMA_ID_MAX)
+ return -EINVAL;
+
+ /* Because of a bug in DMA controller of jz4750, which causes auto
+ request and device request can't be allocated in a same DMA
+ controller, all device requests should be put in the second DMA
+ controller
+ */
+ if (dev_id > DMA_ID_AUTO)
+ chan0 = 6;
+ else
+ chan0 = 0;
+
+ for (i = chan0; i < MAX_DMA_NUM; i++) {
+ if (jz_dma_table[i].dev_id < 0)
+ break;
+ }
+ if (i == MAX_DMA_NUM) /* no free channel */
+ return -ENODEV;
+
+ /* we got a free channel */
+ chan = &jz_dma_table[i];
+
+ if (irqhandler) {
+ chan->irq = IRQ_DMA_0 + i; // allocate irq number
+ chan->irq_dev = irq_dev_id;
+ if ((ret = request_irq(chan->irq, irqhandler, irqflags,
+ dev_str, chan->irq_dev))) {
+ chan->irq = -1;
+ chan->irq_dev = NULL;
+ return ret;
+ }
+ } else {
+ chan->irq = -1;
+ chan->irq_dev = NULL;
+ }
+
+ // fill it in
+ chan->io = i;
+ chan->dev_id = dev_id;
+ chan->dev_str = dev_str;
+ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
+ chan->mode = dma_dev_table[dev_id].dma_mode;
+ chan->source = dma_dev_table[dev_id].dma_source;
+
+ if (i < 6)
+ REG_DMAC_DMACKE(0) = 1 << i;
+ else
+ REG_DMAC_DMACKE(1) = 1 << (i - 6);
+
+ return i;
+}
+
+void jz_free_dma(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan) {
+ printk("Trying to free DMA%d\n", dmanr);
+ return;
+ }
+
+ disable_dma(dmanr);
+ if (chan->irq)
+ free_irq(chan->irq, chan->irq_dev);
+
+ chan->irq = -1;
+ chan->irq_dev = NULL;
+ chan->dev_id = -1;
+}
+
+void jz_set_dma_dest_width(int dmanr, int nbit)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode &= ~DMAC_DCMD_DWDH_MASK;
+ switch (nbit) {
+ case 8:
+ chan->mode |= DMAC_DCMD_DWDH_8;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCMD_DWDH_16;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCMD_DWDH_32;
+ break;
+ }
+}
+
+void jz_set_dma_src_width(int dmanr, int nbit)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode &= ~DMAC_DCMD_SWDH_MASK;
+ switch (nbit) {
+ case 8:
+ chan->mode |= DMAC_DCMD_SWDH_8;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCMD_SWDH_16;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCMD_SWDH_32;
+ break;
+ }
+}
+
+void jz_set_dma_block_size(int dmanr, int nbyte)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode &= ~DMAC_DCMD_DS_MASK;
+ switch (nbyte) {
+ case 1:
+ chan->mode |= DMAC_DCMD_DS_8BIT;
+ break;
+ case 2:
+ chan->mode |= DMAC_DCMD_DS_16BIT;
+ break;
+ case 4:
+ chan->mode |= DMAC_DCMD_DS_32BIT;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCMD_DS_16BYTE;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCMD_DS_32BYTE;
+ break;
+ }
+}
+
+unsigned int jz_get_dma_command(int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ return chan->mode;
+}
+
+/**
+ * jz_set_dma_mode - do the raw settings for the specified DMA channel
+ * @dmanr: the specified DMA channel
+ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE
+ * @dma_mode: dma raw mode
+ * @dma_source: dma raw request source
+ * @fifo_addr: dma raw device fifo address
+ *
+ * Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call
+ * jz_set_dma_mode() rather than set_dma_mode() if you work with
+ * and external request dma device.
+ *
+ * NOTE: Don not dynamically allocate dma channel if one external request
+ * dma device will occupy this channel.
+*/
+int jz_set_dma_mode(unsigned int dmanr, unsigned int mode,
+ unsigned int dma_mode, unsigned int dma_source,
+ unsigned int fifo_addr)
+{
+ int dev_id, i;
+ struct jz_dma_chan *chan;
+
+ if (dmanr > MAX_DMA_NUM)
+ return -ENODEV;
+ for (i = 0; i < MAX_DMA_NUM; i++) {
+ if (jz_dma_table[i].dev_id < 0)
+ break;
+ }
+ if (i == MAX_DMA_NUM)
+ return -ENODEV;
+
+ chan = &jz_dma_table[dmanr];
+ dev_id = chan->dev_id;
+ if (dev_id > 0) {
+ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n",
+ __FUNCTION__, dmanr);
+ return -ENODEV;
+ }
+
+ /* clone it from the dynamically allocated. */
+ if (i != dmanr) {
+ chan->irq = jz_dma_table[i].irq;
+ chan->irq_dev = jz_dma_table[i].irq_dev;
+ chan->dev_str = jz_dma_table[i].dev_str;
+ jz_dma_table[i].irq = 0;
+ jz_dma_table[i].irq_dev = NULL;
+ jz_dma_table[i].dev_id = -1;
+ }
+ chan->dev_id = DMA_ID_RAW_SET;
+ chan->io = dmanr;
+ chan->fifo_addr = fifo_addr;
+ chan->mode = dma_mode;
+ chan->source = dma_source;
+
+ set_dma_mode(dmanr, dma_mode);
+
+ return dmanr;
+}
+
+void enable_dma(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+ REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */
+ __dmac_enable_channel(dmanr);
+ if (chan->irq)
+ __dmac_channel_enable_irq(dmanr);
+}
+
+#define DMA_DISABLE_POLL 0x10000
+
+void disable_dma(unsigned int dmanr)
+{
+ int i;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ if (!__dmac_channel_enabled(dmanr))
+ return;
+
+ for (i = 0; i < DMA_DISABLE_POLL; i++)
+ if (__dmac_channel_transmit_end_detected(dmanr))
+ break;
+#if 0
+ if (i == DMA_DISABLE_POLL)
+ printk(KERN_INFO "disable_dma: poll expired!\n");
+#endif
+
+ __dmac_disable_channel(dmanr);
+ if (chan->irq)
+ __dmac_channel_disable_irq(dmanr);
+}
+
+/* Note: DMA_MODE_MASK is simulated by sw */
+void set_dma_mode(unsigned int dmanr, unsigned int mode)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ if (mode == DMA_MODE_READ) {
+ chan->mode |= DMAC_DCMD_DAI;
+ chan->mode &= ~DMAC_DCMD_SAI;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode |= DMAC_DCMD_SAI;
+ chan->mode &= ~DMAC_DCMD_DAI;
+ } else {
+ printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+ }
+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+}
+
+void set_dma_addr(unsigned int dmanr, unsigned int phyaddr)
+{
+ unsigned int mode;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ mode = chan->mode & DMA_MODE_MASK;
+ if (mode == DMA_MODE_READ) {
+ REG_DMAC_DSAR(chan->io) = chan->fifo_addr;
+ REG_DMAC_DTAR(chan->io) = phyaddr;
+ } else if (mode == DMA_MODE_WRITE) {
+ REG_DMAC_DSAR(chan->io) = phyaddr;
+ REG_DMAC_DTAR(chan->io) = chan->fifo_addr;
+ } else
+ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n");
+}
+
+void set_dma_count(unsigned int dmanr, unsigned int bytecnt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ int dma_ds[] = {4, 1, 2, 16, 32};
+ unsigned int ds;
+
+ if (!chan)
+ return;
+
+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
+ REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count
+}
+
+unsigned int get_dma_residue(unsigned int dmanr)
+{
+ unsigned int count, ds;
+ int dma_ds[] = {4, 1, 2, 16, 32};
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+
+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
+ count = REG_DMAC_DTCR(chan->io);
+ count = count * dma_ds[ds];
+
+ return count;
+}
+
+void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ switch (audio_fmt) {
+ case AFMT_U8:
+ /* burst mode : 32BIT */
+ break;
+ case AFMT_S16_LE:
+ /* burst mode : 16BYTE */
+ if (mode == DMA_MODE_READ) {
+ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_DAI;
+ chan->mode &= ~DMAC_DCMD_SAI;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ //chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_SAI;
+ chan->mode &= ~DMAC_DCMD_DAI;
+ } else
+ printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+
+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+ break;
+ }
+}
+
+void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ switch (audio_fmt) {
+ case 8:
+ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
+ break;
+ case 16:
+ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
+ if (mode == DMA_MODE_READ) {
+ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_DAI;
+ chan->mode &= ~DMAC_DCMD_SAI;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_SAI;
+ chan->mode &= ~DMAC_DCMD_DAI;
+ } else
+ printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+
+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+ break;
+ }
+}
+
+//#define JZ4750_DMAC_TEST_ENABLE
+#undef JZ4750_DMAC_TEST_ENABLE
+
+#ifdef JZ4750_DMAC_TEST_ENABLE
+
+/*
+ * DMA test: external address <--> external address
+ */
+#define TEST_DMA_SIZE 16*1024
+
+static jz_dma_desc *dma_desc;
+
+static int dma_chan;
+static dma_addr_t dma_desc_phys_addr;
+static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr;
+
+static int dma_check_result(void *src, void *dst, int size)
+{
+ unsigned int addr1, addr2, i, err = 0;
+
+ addr1 = (unsigned int)src;
+ addr2 = (unsigned int)dst;
+
+ for (i = 0; i < size; i += 4) {
+ if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) {
+ err++;
+ printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2);
+ }
+ addr1 += 4;
+ addr2 += 4;
+ }
+ printk("check DMA result err=%d\n", err);
+ return err;
+}
+
+static irqreturn_t jz4750_dma_irq(int irq, void *dev_id)
+{
+ printk("jz4750_dma_irq %d\n", irq);
+
+
+ if (__dmac_channel_transmit_halt_detected(dma_chan)) {
+ printk("DMA HALT\n");
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ __dmac_channel_clear_transmit_halt(dma_chan);
+ }
+
+ if (__dmac_channel_address_error_detected(dma_chan)) {
+ printk("DMA ADDR ERROR\n");
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ REG_DMAC_DSAR(dma_chan) = 0; /* clear source address register */
+ REG_DMAC_DTAR(dma_chan) = 0; /* clear target address register */
+ __dmac_channel_clear_address_error(dma_chan);
+ }
+
+ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) {
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ printk("DMA DESC INVALID\n");
+ __dmac_channel_clear_descriptor_invalid(dma_chan);
+ }
+
+ if (__dmac_channel_count_terminated_detected(dma_chan)) {
+ printk("DMA CT\n");
+ __dmac_channel_clear_count_terminated(dma_chan);
+ }
+
+ if (__dmac_channel_transmit_end_detected(dma_chan)) {
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ printk("DMA TT\n");
+ __dmac_channel_clear_transmit_end(dma_chan);
+ dump_jz_dma_channel(dma_chan);
+ dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE);
+ }
+
+ return IRQ_HANDLED;
+}
+
+void dma_nodesc_test(void)
+{
+ unsigned int addr, i;
+
+ printk("dma_nodesc_test\n");
+
+ /* Request DMA channel and setup irq handler */
+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750_dma_irq,
+ IRQF_DISABLED, NULL);
+ if (dma_chan < 0) {
+ printk("Setup irq failed\n");
+ return;
+ }
+
+ printk("Requested DMA channel = %d\n", dma_chan);
+
+ /* Allocate DMA buffers */
+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+
+ dma_src_phys_addr = CPHYSADDR(dma_src_addr);
+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
+
+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
+
+ /* Prepare data for source buffer */
+ addr = (unsigned int)dma_src_addr;
+ for (i = 0; i < TEST_DMA_SIZE; i += 4) {
+ *(volatile unsigned int *)addr = addr;
+ addr += 4;
+ }
+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
+
+ /* Init target buffer */
+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
+
+ /* Init DMA module */
+ printk("Starting DMA\n");
+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0;
+ REG_DMAC_DCCSR(dma_chan) = 0;
+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr;
+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr;
+ REG_DMAC_DTCR(dma_chan) = 512;
+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE;
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */
+
+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
+
+ /* wait a long time, ensure transfer end */
+ printk("wait 3s...\n");
+ mdelay(3000); /* wait 3s */
+
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ /* free buffers */
+ printk("free DMA buffers\n");
+ free_pages(dma_src_addr, 2);
+ free_pages(dma_dst_addr, 2);
+
+ if (dma_desc)
+ free_pages((unsigned int)dma_desc, 0);
+
+ /* free dma */
+ jz_free_dma(dma_chan);
+}
+
+void dma_desc_test(void)
+{
+ unsigned int next, addr, i;
+ static jz_dma_desc *desc;
+
+ printk("dma_desc_test\n");
+
+ /* Request DMA channel and setup irq handler */
+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750_dma_irq,
+ IRQF_DISABLED, NULL);
+ if (dma_chan < 0) {
+ printk("Setup irq failed\n");
+ return;
+ }
+
+ printk("Requested DMA channel = %d\n", dma_chan);
+
+ /* Allocate DMA buffers */
+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+
+ dma_src_phys_addr = CPHYSADDR(dma_src_addr);
+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
+
+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
+
+ /* Prepare data for source buffer */
+ addr = (unsigned int)dma_src_addr;
+ for (i = 0; i < TEST_DMA_SIZE; i += 4) {
+ *(volatile unsigned int *)addr = addr;
+ addr += 4;
+ }
+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
+
+ /* Init target buffer */
+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
+
+ /* Allocate DMA descriptors */
+ dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0);
+ dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc);
+
+ printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr);
+
+ /* Setup DMA descriptors */
+ desc = dma_desc;
+ next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
+ desc->dsadr = dma_src_phys_addr; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr; /* DMA target address */
+ desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */
+
+ desc++;
+ next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
+ desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */
+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
+
+ desc++;
+ next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
+ desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */
+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
+
+ desc++;
+ next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE;
+ desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */
+ desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */
+
+ dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc)));
+
+ /* Setup DMA descriptor address */
+ REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr;
+
+ /* Setup request source */
+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
+
+ /* Setup DMA channel control/status register */
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */
+
+ /* Enable DMA */
+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE;
+
+ /* DMA doorbell set -- start DMA now ... */
+ REG_DMAC_DMADBSR(dma_chan/HALF_DMA_NUM) = 1 << dma_chan;
+
+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
+ /* wait a long time, ensure transfer end */
+ printk("wait 3s...\n");
+ mdelay(3000); /* wait 3s */
+
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ /* free buffers */
+ printk("free DMA buffers\n");
+ free_pages(dma_src_addr, 2);
+ free_pages(dma_dst_addr, 2);
+
+ if (dma_desc)
+ free_pages((unsigned int)dma_desc, 0);
+
+ /* free dma */
+ jz_free_dma(dma_chan);
+}
+
+#endif
+
+//EXPORT_SYMBOL_NOVERS(jz_dma_table);
+EXPORT_SYMBOL(jz_dma_table);
+EXPORT_SYMBOL(jz_request_dma);
+EXPORT_SYMBOL(jz_free_dma);
+EXPORT_SYMBOL(jz_set_dma_src_width);
+EXPORT_SYMBOL(jz_set_dma_dest_width);
+EXPORT_SYMBOL(jz_set_dma_block_size);
+EXPORT_SYMBOL(jz_set_dma_mode);
+EXPORT_SYMBOL(set_dma_mode);
+EXPORT_SYMBOL(jz_set_oss_dma);
+EXPORT_SYMBOL(jz_set_alsa_dma);
+EXPORT_SYMBOL(set_dma_addr);
+EXPORT_SYMBOL(set_dma_count);
+EXPORT_SYMBOL(get_dma_residue);
+EXPORT_SYMBOL(enable_dma);
+EXPORT_SYMBOL(disable_dma);
+EXPORT_SYMBOL(dump_jz_dma_channel);
diff --git a/arch/mips/jz4750/i2c.c b/arch/mips/jz4750/i2c.c
new file mode 100644
index 00000000000..13eb839d580
--- /dev/null
+++ b/arch/mips/jz4750/i2c.c
@@ -0,0 +1,388 @@
+/*
+ * linux/arch/mips/jz4750/i2c.c
+ *
+ * JZ4750 Simple I2C Driver.
+ *
+ * Copyright (c) 2005-2010 Ingenic Semiconductor Inc.
+ * Author: River <zwang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/jzsoc.h>
+
+#define I2C_BUS_TIMING_START_HOLD 1 /* us */
+#define I2C_BUS_TIMING_STOP_HOLD 10 /* us */
+
+#define I2C_CTRL_WAIT_ENABLE 1 /* us */
+#define I2C_CTRL_WAIT_DISABLE 1 /* us */
+
+#define PFX "I_I2C"
+
+#define D(fmt, args...) \
+// printk(KERN_ERR PFX": %s(): LINE: %d - "fmt"\n", __func__, __LINE__, ##args)
+
+#define E(fmt, args...) \
+ printk(KERN_ERR PFX": %s(): LINE: %d - "fmt"\n", __func__, __LINE__, ##args)
+
+/* Controller. */
+struct i2c_ctrl {
+ spinlock_t lock;
+
+ unsigned long clk;
+};
+
+static struct i2c_ctrl g_i2c_ctrl;
+
+static inline void i2c_ctrl_enable(void)
+{
+ D("Called.");
+
+ __i2c_enable();
+
+ udelay(I2C_CTRL_WAIT_ENABLE);
+
+ return;
+}
+
+static inline void i2c_ctrl_disable(void)
+{
+ D("Called.");
+
+ __i2c_disable();
+
+ udelay(I2C_CTRL_WAIT_DISABLE);
+
+ return;
+}
+
+static inline void i2c_ctrl_set_clk(unsigned long clk)
+{
+ struct i2c_ctrl *ctrl = &g_i2c_ctrl;
+
+ D("Called.");
+
+ if (ctrl->clk != clk) {
+ D("Set clock.");
+
+ __i2c_set_clk(jz_clocks.extalclk, clk);
+ ctrl->clk = clk;
+
+ mdelay(1);
+ }
+
+ return;
+}
+
+/*
+ * I2C bus protocol basic routines
+ */
+static inline int __i2c_put_data(unsigned char data, unsigned long timeout)
+{
+ unsigned long t;
+
+ __i2c_write(data);
+ __i2c_set_drf();
+
+ t = timeout;
+ while (__i2c_check_drf() != 0 && t)
+ t--;
+
+ if (!t) {
+ E("__i2c_check_drf() timeout, Data: 0x%x. timeout: %lu.", data, timeout);
+ return -ETIMEDOUT;
+ }
+
+ while (!__i2c_transmit_ended() && t)
+ t--;
+
+ if (!t) {
+ E("__i2c_transmit_ended() timeout, Data: 0x%x, timeout: %lu.", data, timeout);
+ return -ETIMEDOUT;
+ }
+
+ t = timeout;
+ while (!__i2c_received_ack() && t)
+ t--;
+
+ if (!t) {
+ E("__i2c_received_ack() timeout, Data: 0x%x, timeout: %lu.", data, timeout);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static inline int __i2c_get_data(unsigned char *data, int ack, unsigned long timeout)
+{
+ unsigned long t;
+
+ ack ? __i2c_send_ack() : __i2c_send_nack();
+
+ t = timeout;
+ while (__i2c_check_drf() == 0 && t)
+ t--;
+
+ if (!t) {
+ E("__i2c_check_drf() timeout. timeout: %lu", timeout);
+ return -ETIMEDOUT;
+ }
+
+ *data = __i2c_read();
+
+ __i2c_clear_drf();
+
+ return 0;
+}
+
+static inline int put_data(struct i_i2c_dev *dev, unsigned char data)
+{
+ return __i2c_put_data(data, dev->timing->timeout);
+}
+
+static inline int get_data(struct i_i2c_dev *dev, unsigned char *data, int ack)
+{
+ return __i2c_get_data(data, ack, dev->timing->timeout);
+}
+
+static inline void i2c_start(void)
+{
+ __i2c_send_start();
+
+ udelay(I2C_BUS_TIMING_START_HOLD);
+
+ return;
+}
+
+static inline void i2c_stop(void)
+{
+ __i2c_send_stop();
+
+ udelay(I2C_BUS_TIMING_STOP_HOLD);
+
+ return;
+}
+
+static inline int i2c_start_and_send_address(struct i_i2c_dev *dev, off_t off, int dir)
+{
+ unsigned int ra = ((dev->address << 1) & 0xff) | 0x1;
+ unsigned int wa = ((dev->address << 1) & 0xff);
+
+ int rv;
+
+ i2c_start();
+
+ if (put_data(dev, wa) < 0) {
+ E("Failed to send write address.");
+ rv = -ENODEV;
+ goto err;
+ }
+
+ if (dev->cap & I_I2C_CAP_16BIT_OFFSET_MSB) {
+ if (put_data(dev, (off >> 8) & 0xFF) < 0) {
+ E("Failed to send off >> 8 MSB.");
+ rv = -EINVAL;
+ goto err;
+ }
+ }
+
+ if (put_data(dev, (off & 0xFF)) < 0) {
+ E("Failed to send off.");
+ rv = -EINVAL;
+ goto err;
+ }
+
+ if (dev->cap & I_I2C_CAP_16BIT_OFFSET_LSB) {
+ if (put_data(dev, (off >> 8) & 0xFF) < 0) {
+ E("Failed to send off >> 8 LSB.");
+ rv = -EINVAL;
+ goto err;
+ }
+ }
+
+ if (dir == I_I2C_IO_DIR_READ) {
+ if (dev->flags & I_I2C_FLAG_STOP_BEFORE_RESTART)
+ i2c_stop();
+
+ i2c_start();
+
+ if (put_data(dev, ra) < 0) {
+ E("Failed to send read address.");
+ rv = -ENODEV;
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ i2c_stop();
+ return rv;
+}
+
+static inline int i2c_read_data(struct i_i2c_dev *dev, char *buf, size_t count)
+{
+ int i, rv;
+ int ack = 1;
+
+// D("buf: 0x%p, count: %d.", buf, count);
+
+ for (i = 0; i < count; i++) {
+ if (i == count - 1) {
+// D("Nack.");
+ ack = 0;
+ }
+
+ rv = get_data(dev, buf + i, ack);
+ if (rv) {
+ E("get_data() failed: rv: %d i: %d.", rv, i);
+ return rv;
+ }
+ }
+
+ return 0;
+}
+
+static inline int i2c_write_data(struct i_i2c_dev *dev, char *buf, size_t count)
+{
+ unsigned long i;
+ int rv;
+
+// D("buf: 0x%p, count: %d.", buf, count);
+
+ for (i = 0; i < count; i++) {
+ rv = put_data(dev, buf[i]);
+ if (rv) {
+ E("put_data() failed: %d.\n", rv);
+ return rv;
+ }
+ }
+
+ return 0;
+}
+
+static int do_i2c(struct i_i2c_dev *dev, off_t off, char *buf, size_t count, int dir)
+{
+ struct i2c_ctrl *ctrl = &g_i2c_ctrl;
+ struct i_i2c_timing *timing = dev->timing;
+
+ unsigned long flags;
+ unsigned long io_size, size;
+
+ unsigned long i;
+ int rv = 0;
+
+ spin_lock_irqsave(&ctrl->lock, flags);
+
+ i2c_ctrl_enable();
+ i2c_ctrl_set_clk(timing->clk);
+
+ io_size = dir ? dev->write_size : dev->read_size;
+ size = count < io_size ? count : io_size;
+
+ for (i = 0; i < count; i += io_size) {
+ rv = i2c_start_and_send_address(dev, off + i, dir);
+ if (rv) {
+ E("i2c_start_and_send_address() failed: %d, i: %lu.", rv, i);
+ i2c_stop();
+ goto err;
+ }
+
+// D("Pass send address.");
+
+ if (!dir)
+ rv = i2c_read_data(dev, buf + i, size);
+ else
+ rv = i2c_write_data(dev, buf + i, size);
+
+// D("Pass rw data.");
+
+ if (rv) {
+ E("i2c_read/write_data() failed: %d, i: %lu.", rv, i);
+ i2c_stop();
+ goto err;
+ }
+
+ i2c_stop();
+
+ if (dir)
+ mdelay(timing->t_wr);
+ }
+
+err:
+ i2c_ctrl_disable();
+
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+
+ return rv;
+}
+
+/*
+ * I2C interface
+ */
+int i_i2c_read_dev(struct i_i2c_dev *dev, off_t off, void *buf, size_t count)
+{
+ D("off: %d, buf: 0x%p, count: %d.", off, buf, count);
+
+ return do_i2c(dev, off, buf, count, 0);
+}
+EXPORT_SYMBOL(i_i2c_read_dev);
+
+int i_i2c_write_dev(struct i_i2c_dev *dev, off_t off, void *buf, size_t count)
+{
+ D("off: %d, buf: 0x%p, count: %d.", off, buf, count);
+
+ return do_i2c(dev, off, buf, count, 1);
+}
+EXPORT_SYMBOL(i_i2c_write_dev);
+
+int i_i2c_init_dev(struct i_i2c_dev *dev)
+{
+ struct i_i2c_timing *timing = dev->timing;
+
+ if (!timing) {
+ printk(KERN_ERR PFX": %s(): Please setup the timing of I2C device: 0x%p.\n", __func__, dev);
+ return -EINVAL;
+ }
+
+ if (!timing->timeout)
+ timing->timeout = (100 * 1000);
+
+ if (!timing->clk)
+ timing->clk = (100 * 1000); /* default 100 KHz */
+
+ if (!(dev->cap & I_I2C_CAP_SEQ_READ))
+ dev->read_size = 1;
+
+ if (!(dev->cap & I_I2C_CAP_SEQ_WRITE))
+ dev->write_size = 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(i_i2c_init_dev);
+
+static int __init i_i2c_init(void)
+{
+ struct i2c_ctrl *ctrl = &g_i2c_ctrl;
+
+ spin_lock_init(&ctrl->lock);
+
+ __gpio_as_i2c();
+
+ i2c_ctrl_set_clk(100 * 1000);
+
+ printk(KERN_INFO JZ_SOC_NAME": Simple I2C Driver Registered.\n");
+
+ return 0;
+}
+
+module_init(i_i2c_init);
diff --git a/arch/mips/jz4750/irq.c b/arch/mips/jz4750/irq.c
new file mode 100644
index 00000000000..8a91476cbc9
--- /dev/null
+++ b/arch/mips/jz4750/irq.c
@@ -0,0 +1,299 @@
+/*
+ * linux/arch/mips/jz4750/irq.c
+ *
+ * JZ4750 interrupt routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+/*
+ * INTC irq type
+ */
+
+static void enable_intc_irq(unsigned int irq)
+{
+ __intc_unmask_irq(irq);
+}
+
+static void disable_intc_irq(unsigned int irq)
+{
+ __intc_mask_irq(irq);
+}
+
+static void mask_and_ack_intc_irq(unsigned int irq)
+{
+ __intc_mask_irq(irq);
+ __intc_ack_irq(irq);
+}
+
+static void end_intc_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_intc_irq(irq);
+ }
+}
+
+static unsigned int startup_intc_irq(unsigned int irq)
+{
+ enable_intc_irq(irq);
+ return 0;
+}
+
+static void shutdown_intc_irq(unsigned int irq)
+{
+ disable_intc_irq(irq);
+}
+
+static struct irq_chip intc_irq_type = {
+ .typename = "INTC",
+ .startup = startup_intc_irq,
+ .shutdown = shutdown_intc_irq,
+ .unmask = enable_intc_irq,
+ .mask = disable_intc_irq,
+ .ack = mask_and_ack_intc_irq,
+ .end = end_intc_irq,
+};
+
+/*
+ * GPIO irq type
+ */
+
+static void enable_gpio_irq(unsigned int irq)
+{
+ unsigned int intc_irq;
+
+ if (irq < (IRQ_GPIO_0 + 32)) {
+ intc_irq = IRQ_GPIO0;
+ }
+ else if (irq < (IRQ_GPIO_0 + 64)) {
+ intc_irq = IRQ_GPIO1;
+ }
+ else if (irq < (IRQ_GPIO_0 + 96)) {
+ intc_irq = IRQ_GPIO2;
+ }
+ else if (irq < (IRQ_GPIO_0 + 128)) {
+ intc_irq = IRQ_GPIO3;
+ }
+ else if (irq < (IRQ_GPIO_0 + 160)) {
+ intc_irq = IRQ_GPIO4;
+ }
+ else {
+ intc_irq = IRQ_GPIO5;
+ }
+
+ enable_intc_irq(intc_irq);
+ __gpio_unmask_irq(irq - IRQ_GPIO_0);
+}
+
+static void disable_gpio_irq(unsigned int irq)
+{
+ __gpio_mask_irq(irq - IRQ_GPIO_0);
+}
+
+static void mask_and_ack_gpio_irq(unsigned int irq)
+{
+ __gpio_mask_irq(irq - IRQ_GPIO_0);
+ __gpio_ack_irq(irq - IRQ_GPIO_0);
+}
+
+static void end_gpio_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_gpio_irq(irq);
+ }
+}
+
+static unsigned int startup_gpio_irq(unsigned int irq)
+{
+ enable_gpio_irq(irq);
+ return 0;
+}
+
+static void shutdown_gpio_irq(unsigned int irq)
+{
+ disable_gpio_irq(irq);
+}
+
+static struct irq_chip gpio_irq_type = {
+ .typename = "GPIO",
+ .startup = startup_gpio_irq,
+ .shutdown = shutdown_gpio_irq,
+ .unmask = enable_gpio_irq,
+ .mask = disable_gpio_irq,
+ .ack = mask_and_ack_gpio_irq,
+ .end = end_gpio_irq,
+};
+
+/*
+ * DMA irq type
+ */
+
+static void enable_dma_irq(unsigned int irq)
+{
+ unsigned int intc_irq;
+
+ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */
+ intc_irq = IRQ_DMAC0;
+ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */
+ intc_irq = IRQ_DMAC1;
+ else {
+ printk("%s, unexpected dma irq #%d\n", __FILE__, irq);
+ return;
+ }
+ __intc_unmask_irq(intc_irq);
+ __dmac_channel_enable_irq(irq - IRQ_DMA_0);
+}
+
+static void disable_dma_irq(unsigned int irq)
+{
+ __dmac_channel_disable_irq(irq - IRQ_DMA_0);
+}
+
+static void mask_and_ack_dma_irq(unsigned int irq)
+{
+ unsigned int intc_irq;
+
+ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */
+ intc_irq = IRQ_DMAC0;
+ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */
+ intc_irq = IRQ_DMAC1;
+ else {
+ printk("%s, unexpected dma irq #%d\n", __FILE__, irq);
+ return ;
+ }
+ __intc_ack_irq(intc_irq);
+ __dmac_channel_ack_irq(irq-IRQ_DMA_0); /* needed?? add 20080506, Wolfgang */
+ __dmac_channel_disable_irq(irq - IRQ_DMA_0);
+}
+
+static void end_dma_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_dma_irq(irq);
+ }
+}
+
+static unsigned int startup_dma_irq(unsigned int irq)
+{
+ enable_dma_irq(irq);
+ return 0;
+}
+
+static void shutdown_dma_irq(unsigned int irq)
+{
+ disable_dma_irq(irq);
+}
+
+static struct irq_chip dma_irq_type = {
+ .typename = "DMA",
+ .startup = startup_dma_irq,
+ .shutdown = shutdown_dma_irq,
+ .unmask = enable_dma_irq,
+ .mask = disable_dma_irq,
+ .ack = mask_and_ack_dma_irq,
+ .end = end_dma_irq,
+};
+
+//----------------------------------------------------------------------
+
+void __init arch_init_irq(void)
+{
+ int i;
+
+ clear_c0_status(0xff04); /* clear ERL */
+ set_c0_status(0x0400); /* set IP2 */
+
+ /* Set up INTC irq
+ */
+ for (i = 0; i < 32; i++) {
+ disable_intc_irq(i);
+ set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq);
+ }
+
+ /* Set up DMAC irq
+ */
+ for (i = 0; i < NUM_DMA; i++) {
+ disable_dma_irq(IRQ_DMA_0 + i);
+ set_irq_chip_and_handler(IRQ_DMA_0 + i, &dma_irq_type, handle_level_irq);
+ }
+
+ /* Set up GPIO irq
+ */
+ for (i = 0; i < NUM_GPIO; i++) {
+ disable_gpio_irq(IRQ_GPIO_0 + i);
+ set_irq_chip_and_handler(IRQ_GPIO_0 + i, &gpio_irq_type, handle_level_irq);
+ }
+}
+
+static int plat_real_irq(int irq)
+{
+ switch (irq) {
+ case IRQ_GPIO0:
+ irq = __gpio_group_irq(0) + IRQ_GPIO_0;
+ break;
+ case IRQ_GPIO1:
+ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32;
+ break;
+ case IRQ_GPIO2:
+ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64;
+ break;
+ case IRQ_GPIO3:
+ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96;
+ break;
+ case IRQ_GPIO4:
+ irq = __gpio_group_irq(4) + IRQ_GPIO_0 + 128;
+ break;
+ case IRQ_GPIO5:
+ irq = __gpio_group_irq(5) + IRQ_GPIO_0 + 160;
+ break;
+ case IRQ_DMAC0:
+ case IRQ_DMAC1:
+ irq = __dmac_get_irq() + IRQ_DMA_0;
+ break;
+ }
+
+ return irq;
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ int irq = 0;
+ static unsigned long intc_ipr = 0;
+
+ intc_ipr |= REG_INTC_IPR;
+
+ if (!intc_ipr) return;
+
+ irq = ffs(intc_ipr) - 1;
+ intc_ipr &= ~(1<<irq);
+
+ irq = plat_real_irq(irq);
+ do_IRQ(irq);
+}
diff --git a/arch/mips/jz4750/platform.c b/arch/mips/jz4750/platform.c
new file mode 100644
index 00000000000..fa3c49a7729
--- /dev/null
+++ b/arch/mips/jz4750/platform.c
@@ -0,0 +1,173 @@
+/*
+ * Platform device support for Jz4740 SoC.
+ *
+ * Copyright 2007, <yliu@ingenic.cn>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/resource.h>
+
+#include <asm/jzsoc.h>
+
+/* OHCI (USB full speed host controller) */
+static struct resource jz_usb_ohci_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap
+ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_UHC,
+ .end = IRQ_UHC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32)0;
+
+static struct platform_device jz_usb_ohci_device = {
+ .name = "jz-ohci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ohci_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources),
+ .resource = jz_usb_ohci_resources,
+};
+
+/*** LCD controller ***/
+static struct resource jz_lcd_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(LCD_BASE),
+ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_LCD,
+ .end = IRQ_LCD,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 jz_lcd_dmamask = ~(u32)0;
+
+static struct platform_device jz_lcd_device = {
+ .name = "jz-lcd",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_lcd_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_lcd_resources),
+ .resource = jz_lcd_resources,
+};
+
+/* UDC (USB gadget controller) */
+static struct resource jz_usb_gdt_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(UDC_BASE),
+ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_UDC,
+ .end = IRQ_UDC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 udc_dmamask = ~(u32)0;
+
+static struct platform_device jz_usb_gdt_device = {
+ .name = "jz-udc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &udc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources),
+ .resource = jz_usb_gdt_resources,
+};
+
+/** MMC/SD controller **/
+static struct resource jz_mmc_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(MSC_BASE),
+ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_MSC0,
+ .end = IRQ_MSC0,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 jz_mmc_dmamask = ~(u32)0;
+
+static struct platform_device jz_mmc_device = {
+ .name = "jz-mmc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_mmc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_mmc_resources),
+ .resource = jz_mmc_resources,
+};
+
+
+/** I2C controller **/
+static struct resource jz_i2c_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(I2C_BASE),
+ .end = CPHYSADDR(I2C_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+#if 0
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ }
+#endif
+};
+
+static u64 jz_i2c_dmamask = ~(u32)0;
+static struct platform_device jz_i2c_device = {
+ .name = "jz_i2c",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_i2c_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_i2c_resources),
+ .resource = jz_i2c_resources,
+};
+
+
+
+/* All */
+static struct platform_device *jz_platform_devices[] __initdata = {
+ &jz_usb_ohci_device,
+ &jz_lcd_device,
+ &jz_usb_gdt_device,
+ &jz_mmc_device,
+ &jz_i2c_device,
+};
+
+static int __init jz_platform_init(void)
+{
+ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
+}
+
+arch_initcall(jz_platform_init);
diff --git a/arch/mips/jz4750/pm.c b/arch/mips/jz4750/pm.c
new file mode 100644
index 00000000000..10476e276e1
--- /dev/null
+++ b/arch/mips/jz4750/pm.c
@@ -0,0 +1,401 @@
+/*
+ * linux/arch/mips/jz4750/common/pm.c
+ *
+ * JZ4750 Power Management Routines
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+
+#include <asm/cacheops.h>
+#include <asm/jzsoc.h>
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+#define GPIO_PORT_NUM 6
+
+/*
+ * __gpio_as_sleep set all pins to pull-disable, and set all pins as input
+ * except sdram and the pins which can be used as CS1_N to CS4_N for chip select.
+ */
+
+#define __gpio_as_sleep() \
+do { \
+ REG_GPIO_PXFUNC(1) = ~0x03ff7fff; \
+ REG_GPIO_PXSELC(1) = ~0x03ff7fff; \
+ REG_GPIO_PXDIRC(1) = ~0x03ff7fff; \
+ REG_GPIO_PXPES(1) = 0xffffffff; \
+ REG_GPIO_PXFUNC(2) = ~0x01e00000; \
+ REG_GPIO_PXSELC(2) = ~0x01e00000; \
+ REG_GPIO_PXDIRC(2) = ~0x01e00000; \
+ REG_GPIO_PXPES(2) = 0xffffffff; \
+ REG_GPIO_PXFUNC(3) = 0xffffffff; \
+ REG_GPIO_PXSELC(3) = 0xffffffff; \
+ REG_GPIO_PXDIRC(3) = 0xffffffff; \
+ REG_GPIO_PXPEC(3) = 0xffffffff; \
+ REG_GPIO_PXFUNC(4) = 0xffffffff; \
+ REG_GPIO_PXSELC(4) = 0xffffffff; \
+ REG_GPIO_PXDIRC(4) = 0xffffffff; \
+ REG_GPIO_PXPES(4) = 0xffffffff; \
+ REG_GPIO_PXFUNC(5) = 0xffffffff; \
+ REG_GPIO_PXSELC(5) = 0xffffffff; \
+ REG_GPIO_PXDIRC(5) = 0xffffffff; \
+ REG_GPIO_PXPES(5) = 0xffffffff; \
+} while (0)
+
+static int jz_pm_do_hibernate(void)
+{
+ printk(JZ_SOC_NAME ": Put CPU into hibernate mode.\n");
+
+ /* Mask all interrupts */
+ REG_INTC_IMSR = 0xffffffff;
+
+ /*
+ * RTC Wakeup or 1Hz interrupt can be enabled or disabled
+ * through RTC driver's ioctl (linux/driver/char/rtc_jz.c).
+ */
+
+ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT);
+
+ /* Set reset pin low-level assertion time after wakeup: must > 60ms */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */
+
+ /* Scratch pad register to be reserved */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HSPR = 0x12345678;
+
+ /* clear wakeup status register */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HWRSR = 0x0;
+
+ /* Put CPU to power down mode */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HCR = RTC_HCR_PD;
+
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ while(1);
+
+ /* We can't get here */
+ return 0;
+}
+
+/* NOTES:
+ * 1: Pins that are floated (NC) should be set as input and pull-enable.
+ * 2: Pins that are pull-up or pull-down by outside should be set as input
+ * and pull-disable.
+ * 3: Pins that are connected to a chip except sdram and nand flash
+ * should be set as input and pull-disable, too.
+ */
+static void jz_board_do_sleep(unsigned long *ptr)
+{
+ unsigned char i;
+
+ /* Print messages of GPIO registers for debug */
+ for(i=0;i<GPIO_PORT_NUM;i++) {
+ dprintk("run dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
+ }
+
+ /* Save GPIO registers */
+ for(i = 1; i < GPIO_PORT_NUM; i++) {
+ *ptr++ = REG_GPIO_PXFUN(i);
+ *ptr++ = REG_GPIO_PXSEL(i);
+ *ptr++ = REG_GPIO_PXDIR(i);
+ *ptr++ = REG_GPIO_PXPE(i);
+ *ptr++ = REG_GPIO_PXIM(i);
+ *ptr++ = REG_GPIO_PXDAT(i);
+ *ptr++ = REG_GPIO_PXTRG(i);
+ }
+
+ /*
+ * Set all pins to pull-disable, and set all pins as input except
+ * sdram and the pins which can be used as CS1_N to CS4_N for chip select.
+ */
+ __gpio_as_sleep();
+
+ /*
+ * Set proper status for GPC21 to GPC24 which can be used as CS1_N to CS4_N.
+ * Keep the pins' function used for chip select(CS) here according to your
+ * system to avoid chip select crashing with sdram when resuming from sleep mode.
+ */
+
+#if defined(CONFIG_JZ4750_APUS)
+ /* GPB25/CS1_N is used as chip select for nand flash, shouldn't be change. */
+
+ /* GPB26/CS2_N is connected to nand flash, needn't be changed. */
+
+ /* GPB28/CS3_N is used as cs8900's chip select, shouldn't be changed. */
+
+ /* GPB27/CS4_N is used as NOR's chip select, shouldn't be changed. */
+#endif
+
+ /*
+ * Enable pull for NC pins here according to your system
+ */
+
+#if defined(CONFIG_JZ4750_APUS)
+#endif
+
+ /*
+ * If you must set some GPIOs as output to high level or low level,
+ * you can set them here, using:
+ * __gpio_as_output(n);
+ * __gpio_set_pin(n); or __gpio_clear_pin(n);
+ */
+
+#if defined(CONFIG_JZ4750_APUS)
+ /* GPC7 which is used as AMPEN_N should be set to high to disable audio amplifier */
+ __gpio_as_output(32*2+7);
+ __gpio_set_pin(32*2+7);
+#endif
+
+#ifdef DEBUG
+ /* Keep uart function for printing debug message */
+ __gpio_as_uart0();
+ __gpio_as_uart1();
+ __gpio_as_uart2();
+ __gpio_as_uart3();
+
+ /* Print messages of GPIO registers for debug */
+ for(i=0;i<GPIO_PORT_NUM;i++) {
+ dprintk("sleep dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
+ }
+#endif
+}
+
+static void jz_board_do_resume(unsigned long *ptr)
+{
+ unsigned char i;
+
+ /* Restore GPIO registers */
+ for(i = 1; i < GPIO_PORT_NUM; i++) {
+ REG_GPIO_PXFUNS(i) = *ptr;
+ REG_GPIO_PXFUNC(i) = ~(*ptr++);
+
+ REG_GPIO_PXSELS(i) = *ptr;
+ REG_GPIO_PXSELC(i) = ~(*ptr++);
+
+ REG_GPIO_PXDIRS(i) = *ptr;
+ REG_GPIO_PXDIRC(i) = ~(*ptr++);
+
+ REG_GPIO_PXPES(i) = *ptr;
+ REG_GPIO_PXPEC(i) = ~(*ptr++);
+
+ REG_GPIO_PXIMS(i)=*ptr;
+ REG_GPIO_PXIMC(i)=~(*ptr++);
+
+ REG_GPIO_PXDATS(i)=*ptr;
+ REG_GPIO_PXDATC(i)=~(*ptr++);
+
+ REG_GPIO_PXTRGS(i)=*ptr;
+ REG_GPIO_PXTRGC(i)=~(*ptr++);
+ }
+
+ /* Print messages of GPIO registers for debug */
+ for(i=0;i<GPIO_PORT_NUM;i++) {
+ dprintk("resume dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
+ }
+}
+
+static int jz_pm_do_sleep(void)
+{
+ unsigned long delta;
+ unsigned long nfcsr = REG_EMC_NFCSR;
+ unsigned long opcr = REG_CPM_OPCR;
+ unsigned long imr = REG_INTC_IMR;
+ unsigned long sadc = REG_SADC_ENA;
+ unsigned long sleep_gpio_save[7*(GPIO_PORT_NUM-1)];
+
+ printk(JZ_SOC_NAME": Put CPU into sleep mode.\n");
+
+ /* Preserve current time */
+ delta = xtime.tv_sec - REG_RTC_RSR;
+
+ /* Disable nand flash */
+ REG_EMC_NFCSR = ~0xff;
+
+ /* stop sadc */
+ REG_SADC_ENA &= ~0x7;
+ while((REG_SADC_ENA & 0x7) != 0);
+ udelay(100);
+
+ /*stop udc and usb*/
+ __cpm_suspend_uhcphy();
+ __cpm_suspend_udcphy();
+
+ /* Sleep on-board modules */
+ jz_board_do_sleep(sleep_gpio_save);
+
+ /* Mask all interrupts */
+ REG_INTC_IMSR = 0xffffffff;
+
+ /* Just allow following interrupts to wakeup the system.
+ * Note: modify this according to your system.
+ */
+
+ /* enable RTC alarm */
+ __intc_unmask_irq(IRQ_RTC);
+#if 0
+ /* make system wake up after n seconds by RTC alarm */
+ unsigned int v, n;
+ n = 10;
+ while (!__rtc_write_ready());
+ __rtc_enable_alarm();
+ while (!__rtc_write_ready());
+ __rtc_enable_alarm_irq();
+ while (!__rtc_write_ready());
+ v = __rtc_get_second();
+ while (!__rtc_write_ready());
+ __rtc_set_alarm_second(v+n);
+#endif
+
+ /* WAKEUP key */
+ __gpio_as_irq_rise_edge(GPIO_WAKEUP);
+ __gpio_unmask_irq(GPIO_WAKEUP);
+ __intc_unmask_irq(IRQ_GPIO0 - (GPIO_WAKEUP/32)); /* unmask IRQ_GPIOn depends on GPIO_WAKEUP */
+
+ /* disable externel clock Oscillator in sleep mode */
+ __cpm_disable_osc_in_sleep();
+ /* select 32K crystal as RTC clock in sleep mode */
+ __cpm_select_rtcclk_rtc();
+
+ /* Enter SLEEP mode */
+ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
+ REG_CPM_LCR |= CPM_LCR_LPM_SLEEP;
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0");
+
+ /* Restore to IDLE mode */
+ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
+ REG_CPM_LCR |= CPM_LCR_LPM_IDLE;
+
+ /* Restore nand flash control register */
+ REG_EMC_NFCSR = nfcsr;
+
+ /* Restore interrupts */
+ REG_INTC_IMSR = imr;
+ REG_INTC_IMCR = ~imr;
+
+ /* Restore sadc */
+ REG_SADC_ENA = sadc;
+
+ /* Resume on-board modules */
+ jz_board_do_resume(sleep_gpio_save);
+
+ /* Restore Oscillator and Power Control Register */
+ REG_CPM_OPCR = opcr;
+
+ /* Restore current time */
+ xtime.tv_sec = REG_RTC_RSR + delta;
+
+ return 0;
+}
+
+/* Put CPU to HIBERNATE mode */
+int jz_pm_hibernate(void)
+{
+ return jz_pm_do_hibernate();
+}
+
+#ifndef CONFIG_JZ_POWEROFF
+static irqreturn_t pm_irq_handler (int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+#endif
+
+/* Put CPU to SLEEP mode */
+int jz_pm_sleep(void)
+{
+ int retval;
+
+#ifndef CONFIG_JZ_POWEROFF
+ if ((retval = request_irq (IRQ_GPIO_0 + GPIO_WAKEUP, pm_irq_handler, IRQF_DISABLED,
+ "PM", NULL))) {
+ printk ("PM could not get IRQ for GPIO_WAKEUP\n");
+ return retval;
+ }
+#endif
+
+ jz_pm_do_sleep();
+
+#ifndef CONFIG_JZ_POWEROFF
+ free_irq (IRQ_GPIO_0 + GPIO_WAKEUP, NULL);
+#endif
+
+ return retval;
+}
+
+/*
+ * valid states, only support mem(sleep)
+ */
+static int jz_pm_valid(suspend_state_t state)
+{
+ return state == PM_SUSPEND_MEM;
+}
+
+/*
+ * Jz CPU enter save power mode
+ */
+static int jz_pm_enter(suspend_state_t state)
+{
+ return jz_pm_sleep();
+}
+
+static struct platform_suspend_ops jz_pm_ops = {
+ .valid = jz_pm_valid,
+ .enter = jz_pm_enter,
+};
+
+/*
+ * Initialize power interface
+ */
+int __init jz_pm_init(void)
+{
+ printk(JZ_SOC_NAME ": Power Management Interface Registered.\n");
+
+ suspend_set_ops(&jz_pm_ops);
+
+ return 0;
+}
+
+module_init(jz_pm_init);
diff --git a/arch/mips/jz4750/proc.c b/arch/mips/jz4750/proc.c
new file mode 100644
index 00000000000..c8f62408003
--- /dev/null
+++ b/arch/mips/jz4750/proc.c
@@ -0,0 +1,857 @@
+/*
+ * linux/arch/mips/jz4750/proc.c
+ *
+ * /proc/jz/ procfs for jz4750 on-chip modules.
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/page-flags.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/jzsoc.h>
+
+//#define DEBUG 1
+#undef DEBUG
+
+
+struct proc_dir_entry *proc_jz_root;
+
+
+/*
+ * EMC Modules
+ */
+static int emc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4);
+ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4);
+ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR);
+ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR);
+ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR);
+ return len;
+}
+
+/*
+ * Power Manager Module
+ */
+static int pmc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long lcr = REG_CPM_LCR;
+ unsigned long clkgr = REG_CPM_CLKGR;
+
+ len += sprintf (page+len, "Low Power Mode : %s\n",
+ ((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ?
+ "IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ?
+ "SLEEP" : "HIBERNATE"));
+ len += sprintf (page+len, "Doze Mode : %s\n",
+ (lcr & CPM_LCR_DOZE_ON) ? "on" : "off");
+ if (lcr & CPM_LCR_DOZE_ON)
+ len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT));
+ len += sprintf (page+len, "IPU : %s\n",
+ (clkgr & CPM_CLKGR_IPU) ? "stopped" : "running");
+ len += sprintf (page+len, "DMAC : %s\n",
+ (clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running");
+ len += sprintf (page+len, "UHC : %s\n",
+ (clkgr & CPM_CLKGR_UHC) ? "stopped" : "running");
+ len += sprintf (page+len, "UDC : %s\n",
+ (clkgr & CPM_CLKGR_UDC) ? "stopped" : "running");
+ len += sprintf (page+len, "LCD : %s\n",
+ (clkgr & CPM_CLKGR_LCD) ? "stopped" : "running");
+ len += sprintf (page+len, "CIM : %s\n",
+ (clkgr & CPM_CLKGR_CIM) ? "stopped" : "running");
+ len += sprintf (page+len, "SADC : %s\n",
+ (clkgr & CPM_CLKGR_SADC) ? "stopped" : "running");
+ len += sprintf (page+len, "MSC0 : %s\n",
+ (clkgr & CPM_CLKGR_MSC0) ? "stopped" : "running");
+ len += sprintf (page+len, "MSC1 : %s\n",
+ (clkgr & CPM_CLKGR_MSC1) ? "stopped" : "running");
+ len += sprintf (page+len, "AIC1 : %s\n",
+ (clkgr & CPM_CLKGR_AIC1) ? "stopped" : "running");
+ len += sprintf (page+len, "AIC2 : %s\n",
+ (clkgr & CPM_CLKGR_AIC2) ? "stopped" : "running");
+ len += sprintf (page+len, "SSI0 : %s\n",
+ (clkgr & CPM_CLKGR_SSI0) ? "stopped" : "running");
+ len += sprintf (page+len, "SSI1 : %s\n",
+ (clkgr & CPM_CLKGR_SSI1) ? "stopped" : "running");
+ len += sprintf (page+len, "I2C : %s\n",
+ (clkgr & CPM_CLKGR_I2C) ? "stopped" : "running");
+ len += sprintf (page+len, "RTC : %s\n",
+ (clkgr & CPM_CLKGR_RTC) ? "stopped" : "running");
+ len += sprintf (page+len, "TCU : %s\n",
+ (clkgr & CPM_CLKGR_TCU) ? "stopped" : "running");
+ len += sprintf (page+len, "UART1 : %s\n",
+ (clkgr & CPM_CLKGR_UART1) ? "stopped" : "running");
+ len += sprintf (page+len, "UART0 : %s\n",
+ (clkgr & CPM_CLKGR_UART0) ? "stopped" : "running");
+ return len;
+}
+
+static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16);
+ return count;
+}
+
+/*
+ * Clock Generation Module
+ */
+#define TO_MHZ(x) (x/1000000),(x%1000000)/10000
+#define TO_KHZ(x) (x/1000),(x%1000)/10
+
+static int cgm_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */
+ unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */
+ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned int od[4] = {1, 2, 2, 4};
+
+ len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr);
+ len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr);
+ len += sprintf (page+len, "PLL : %s\n",
+ (cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF");
+ len += sprintf (page+len, "m:n:o : %d:%d:%d\n",
+ __cpm_get_pllm() + 2,
+ __cpm_get_plln() + 2,
+ od[__cpm_get_pllod()]
+ );
+ len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n",
+ div[__cpm_get_cdiv()],
+ div[__cpm_get_hdiv()],
+ div[__cpm_get_mdiv()],
+ div[__cpm_get_pdiv()]
+ );
+ len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout()));
+ len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk()));
+ len += sprintf (page+len, "HCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_hclk()));
+ len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk()));
+ len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk()));
+ len += sprintf (page+len, "LCDCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_lcdclk()));
+ len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk()));
+ len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk()));
+ len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk()));
+ len += sprintf (page+len, "MSC0CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(0)));
+ len += sprintf (page+len, "MSC1CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(1)));
+ len += sprintf (page+len, "EXTALCLK0 : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk0()));
+ len += sprintf (page+len, "EXTALCLK(by CPM): %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk()));
+ len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk()));
+
+ return len;
+}
+
+static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16);
+ return count;
+}
+
+
+/* USAGE:
+ * echo n > /proc/jz/ipu // n = [1,...,9], alloc mem, 2^n pages.
+ * echo FF > /proc/jz/ipu // 255, free all buffer
+ * echo xxxx > /proc/jz/ipu // free buffer which addr is xxxx
+ * echo llll > /proc/jz/ipu // add_wired_entry(l,l,l,l)
+ * echo 0 > /proc/jz/ipu // debug, print ipu_buf
+ * od -X /proc/jz/ipu // read mem addr
+ */
+
+typedef struct _ipu_buf {
+ unsigned int addr; /* phys addr */
+ unsigned int page_shift;
+} ipu_buf_t;
+
+#define IPU_BUF_MAX 4 /* 4 buffers */
+
+static struct _ipu_buf ipu_buf[IPU_BUF_MAX];
+static int ipu_buf_cnt = 0;
+static unsigned char g_asid=0;
+
+extern void local_flush_tlb_all(void);
+
+/* CP0 hazard avoidance. */
+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
+ "nop; nop; nop; nop; nop; nop;\n\t" \
+ ".set reorder\n\t")
+void show_tlb(void)
+{
+#define ASID_MASK 0xFF
+
+ unsigned long flags;
+ unsigned int old_ctx;
+ unsigned int entry;
+ unsigned int entrylo0, entrylo1, entryhi;
+ unsigned int pagemask;
+
+ local_irq_save(flags);
+
+ /* Save old context */
+ old_ctx = (read_c0_entryhi() & 0xff);
+
+ printk("TLB content:\n");
+ entry = 0;
+ while(entry < 32) {
+ write_c0_index(entry);
+ BARRIER;
+ tlb_read();
+ BARRIER;
+ entryhi = read_c0_entryhi();
+ entrylo0 = read_c0_entrylo0();
+ entrylo1 = read_c0_entrylo1();
+ pagemask = read_c0_pagemask();
+ printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK);
+ printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : "");
+ printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : "");
+
+ printk("\t\tpagemask=0x%08x", pagemask);
+ printk("\tentryhi=0x%08x\n", entryhi);
+ printk("\t\tentrylo0=0x%08x", entrylo0);
+ printk("\tentrylo1=0x%08x\n", entrylo1);
+
+ entry++;
+ }
+ BARRIER;
+ write_c0_entryhi(old_ctx);
+
+ local_irq_restore(flags);
+}
+
+static void ipu_add_wired_entry(unsigned long pid,
+ unsigned long entrylo0, unsigned long entrylo1,
+ unsigned long entryhi, unsigned long pagemask)
+{
+ unsigned long flags;
+ unsigned long wired;
+ unsigned long old_pagemask;
+ unsigned long old_ctx;
+ struct task_struct *g, *p;
+
+ /* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */
+ entrylo0 = entrylo0 >> 6;
+ entrylo0 |= 0x6 | (0 << 3);
+ /*entrylo0 |= 0x6 | (1 << 3);*/
+
+ do_each_thread(g, p) {
+ if (p->pid == pid )
+ g_asid = p->mm->context[0];
+ } while_each_thread(g, p);
+
+ local_irq_save(flags);
+ /* Save old context and create impossible VPN2 value */
+ old_ctx = read_c0_entryhi() & 0xff;
+ old_pagemask = read_c0_pagemask();
+ wired = read_c0_wired();
+ write_c0_wired(wired + 1);
+ write_c0_index(wired);
+ BARRIER;
+ entryhi &= ~0xff; /* new add, 20070906 */
+ entryhi |= g_asid; /* new add, 20070906 */
+// entryhi |= old_ctx; /* new add, 20070906 */
+ write_c0_pagemask(pagemask);
+ write_c0_entryhi(entryhi);
+ write_c0_entrylo0(entrylo0);
+ write_c0_entrylo1(entrylo1);
+ BARRIER;
+ tlb_write_indexed();
+ BARRIER;
+
+ write_c0_entryhi(old_ctx);
+ BARRIER;
+ write_c0_pagemask(old_pagemask);
+ local_flush_tlb_all();
+ local_irq_restore(flags);
+#if defined(DEBUG)
+ printk("\nold_ctx=%03d\n", old_ctx);
+
+ show_tlb();
+#endif
+}
+
+static void ipu_del_wired_entry( void )
+{
+ unsigned long flags;
+ unsigned long wired;
+
+ local_irq_save(flags);
+ wired = read_c0_wired();
+ if (wired) {
+ write_c0_wired(0);
+ }
+ local_irq_restore(flags);
+}
+
+static inline void ipu_buf_get( unsigned int page_shift )
+{
+ unsigned char * virt_addr;
+ int i;
+ for ( i=0; i< IPU_BUF_MAX; ++i ) {
+ if ( ipu_buf[i].addr == 0 ) {
+ break;
+ }
+ }
+
+ if ( (ipu_buf_cnt = i) == IPU_BUF_MAX ) {
+ printk("Error, no free ipu buffer.\n");
+ return ;
+ }
+
+ virt_addr = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift);
+
+ if ( virt_addr ) {
+ ipu_buf[ipu_buf_cnt].addr = (unsigned int)virt_to_phys((void *)virt_addr);
+ ipu_buf[ipu_buf_cnt].page_shift = page_shift;
+
+ for (i = 0; i < (1<<page_shift); i++) {
+ SetPageReserved(virt_to_page(virt_addr));
+ virt_addr += PAGE_SIZE;
+ }
+ }
+ else {
+ printk("get memory Failed.\n");
+ }
+}
+
+static inline void ipu_buf_free( unsigned int phys_addr )
+{
+ unsigned char * virt_addr, *addr;
+ int cnt, i;
+
+ if ( phys_addr == 0 )
+ return ;
+
+ for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt )
+ if ( phys_addr == ipu_buf[cnt].addr )
+ break;
+
+ if ( cnt == IPU_BUF_MAX ) { /* addr not in the ipu buffers */
+ printk("Invalid addr:0x%08x\n", (unsigned int)phys_addr);
+ }
+
+ virt_addr = (unsigned char *)phys_to_virt(ipu_buf[cnt].addr);
+ addr = virt_addr;
+ for (i = 0; i < (1<<ipu_buf[cnt].page_shift); i++) {
+ ClearPageReserved(virt_to_page(addr));
+ addr += PAGE_SIZE;
+ }
+
+ if ( cnt == 0 )
+ ipu_del_wired_entry();
+
+ free_pages((unsigned long )virt_addr, ipu_buf[cnt].page_shift);
+
+ ipu_buf[cnt].addr = 0;
+ ipu_buf[cnt].page_shift = 0;
+}
+
+static int tlb_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ show_tlb();
+ return 0;
+}
+
+static int ipu_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ /* read as binary */
+ unsigned int * pint;
+ pint = (unsigned int *) (page+len);
+
+ if ( ipu_buf_cnt >= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */
+ printk("no free buffer.\n");
+ *pint = 0;
+ }
+ else
+ *pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */
+ len += sizeof(unsigned int);
+
+#if defined(DEBUG)
+ show_tlb();
+#endif
+ return len;
+
+}
+
+static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ unsigned int val ;
+ int cnt,i;
+ char buf[12];
+ unsigned long pid, entrylo0, entrylo1, entryhi, pagemask;
+#if defined(DEBUG)
+ printk("ipu write count=%u\n", count);
+#endif
+ if (count == 41) {
+ for (i=0;i<12;i++)
+ buf[i]=0;
+ strncpy(buf, buffer+8*0, 8);
+ pid = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++)
+ buf[i]=0;
+ strncpy(buf, buffer+8*1, 8);
+ entrylo0 = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++)
+ buf[i]=0;
+ strncpy(buf, buffer+8*2, 8);
+ entrylo1 = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++)
+ buf[i]=0;
+ strncpy(buf, buffer+8*3, 8);
+ entryhi = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++)
+ buf[i]=0;
+ strncpy(buf, buffer+8*4, 8);
+ pagemask = simple_strtoul(buf, 0, 16);
+
+#if defined(DEBUG)
+ printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n",
+ pid, entrylo0, entrylo1, entryhi, pagemask);
+#endif
+ ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask);
+ return 41;
+ } else if ( count <= 9 ) {
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer, 8);
+ val = simple_strtoul(buf, 0, 16);
+ } else if (count == 44) {
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer, 10);
+ pid = simple_strtoul(buf, 0, 16);
+
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer + 11, 10);
+ entryhi = simple_strtoul(buf, 0, 16);//vaddr
+
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer + 22, 10);
+ entrylo0 = simple_strtoul(buf, 0, 16);//paddr
+
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer + 33, 10);
+ pagemask = simple_strtoul(buf, 0, 16);
+ pagemask = 0x3ff << 13; /* Fixed to 4MB page size */
+ //pagemask = 0xfff << 13; /* Fixed to 16MB page size */
+
+ ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask);
+ return 44;
+ } else if (count == 12) {
+ printk("\necho release tlb > /proc/jz/ipu\n");
+ ipu_del_wired_entry();
+ return 12;
+ } else {
+ printk("ipu write count error, count=%d\n.", (unsigned int)count);
+ return -1;
+ }
+
+ /* val: 1-9, page_shift, val>= 10: ipu_buf.addr */
+ if ( val == 0 ) { /* debug, print ipu_buf info */
+ for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt)
+ printk("ipu_buf[%d]: addr=0x%08x, page_shift=%d\n",
+ cnt, ipu_buf[cnt].addr, ipu_buf[cnt].page_shift );
+#if defined(DEBUG)
+ show_tlb();
+#endif
+ }
+ else if ( 0< val && val < 10 ) {
+ ipu_buf_get(val);
+ }
+ else if ( val == 0xff ) { /* 255: free all ipu_buf */
+ for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt ) {
+ ipu_buf_free(ipu_buf[cnt].addr);
+ }
+ }
+ else {
+ ipu_buf_free(val);
+ }
+
+ return count;
+}
+
+/*
+ * MMC/SD hotplug
+ */
+
+#ifndef MSC_HOTPLUG_PIN
+#define MSC_HOTPLUG_PIN 90
+#endif
+
+static int mmc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+#if defined(CONFIG_JZ4750_LYRA)
+ if (!(__gpio_get_pin(MSC_HOTPLUG_PIN)))
+#else
+ if (__gpio_get_pin(MSC_HOTPLUG_PIN))
+#endif
+ len += sprintf (page+len, "REMOVE\n");
+ else
+ len += sprintf (page+len, "INSERT\n");
+
+ return len;
+}
+
+/***********************************************************************
+ * IPU memory management (used by mplayer and other apps)
+ *
+ * We reserved 4MB memory for IPU
+ * The memory base address is jz_ipu_framebuf
+ */
+
+/* Usage:
+ *
+ * echo n > /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages
+ * echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx
+ * echo FF > /proc/jz/ipu // FF, free all buffers
+ * od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer
+ */
+
+//#define DEBUG_IMEM 1
+
+#define IMEM_MAX_ORDER 12 /* max 2^12 * 4096 = 16MB */
+
+static unsigned int jz_imem_base; /* physical base address of ipu memory */
+
+static unsigned int allocated_phys_addr = 0;
+
+/*
+ * Allocated buffer list
+ */
+typedef struct imem_list {
+ unsigned int phys_start; /* physical start addr */
+ unsigned int phys_end; /* physical end addr */
+ struct imem_list *next;
+} imem_list_t;
+
+static struct imem_list *imem_list_head = NULL; /* up sorted by phys_start */
+
+#ifdef DEBUG_IMEM
+static void dump_imem_list(void)
+{
+ struct imem_list *imem;
+
+ printk("*** dump_imem_list 0x%x ***\n", (u32)imem_list_head);
+ imem = imem_list_head;
+ while (imem) {
+ printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next);
+ imem = imem->next;
+ }
+}
+#endif
+
+/* allocate 2^order pages inside the 4MB memory */
+static int imem_alloc(unsigned int order)
+{
+ int alloc_ok = 0;
+ unsigned int start, end;
+ unsigned int size = (1 << order) * PAGE_SIZE;
+ struct imem_list *imem, *imemn, *imemp;
+
+ allocated_phys_addr = 0;
+
+ start = jz_imem_base;
+ end = start + (1 << IMEM_MAX_ORDER) * PAGE_SIZE;
+
+ imem = imem_list_head;
+ while (imem) {
+ if ((imem->phys_start - start) >= size) {
+ /* we got a valid address range */
+ alloc_ok = 1;
+ break;
+ }
+
+ start = imem->phys_end + 1;
+ imem = imem->next;
+ }
+
+ if (!alloc_ok) {
+ if ((end - start) >= size)
+ alloc_ok = 1;
+ }
+
+ if (alloc_ok) {
+ end = start + size - 1;
+ allocated_phys_addr = start;
+
+ /* add to imem_list, up sorted by phys_start */
+ imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL);
+ if (!imemn) {
+ return -ENOMEM;
+ }
+ imemn->phys_start = start;
+ imemn->phys_end = end;
+ imemn->next = NULL;
+
+ if (!imem_list_head)
+ imem_list_head = imemn;
+ else {
+ imem = imemp = imem_list_head;
+ while (imem) {
+ if (start < imem->phys_start) {
+ break;
+ }
+
+ imemp = imem;
+ imem = imem->next;
+ }
+
+ if (imem == imem_list_head) {
+ imem_list_head = imemn;
+ imemn->next = imem;
+ }
+ else {
+ imemn->next = imemp->next;
+ imemp->next = imemn;
+ }
+ }
+ }
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+ return 0;
+}
+
+static void imem_free(unsigned int phys_addr)
+{
+ struct imem_list *imem, *imemp;
+
+ imem = imemp = imem_list_head;
+ while (imem) {
+ if (phys_addr == imem->phys_start) {
+ if (imem == imem_list_head) {
+ imem_list_head = imem->next;
+ }
+ else {
+ imemp->next = imem->next;
+ }
+
+ kfree(imem);
+ break;
+ }
+
+ imemp = imem;
+ imem = imem->next;
+ }
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+}
+
+static void imem_free_all(void)
+{
+ struct imem_list *imem;
+
+ imem = imem_list_head;
+ while (imem) {
+ kfree(imem);
+ imem = imem->next;
+ }
+
+ imem_list_head = NULL;
+
+ allocated_phys_addr = 0;
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+}
+
+/*
+ * Return the allocated buffer address and the max order of free buffer
+ */
+static int imem_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned int start_addr, end_addr, max_order, max_size;
+ struct imem_list *imem;
+
+ unsigned int *tmp = (unsigned int *)(page + len);
+
+ start_addr = jz_imem_base;
+ end_addr = start_addr + (1 << IMEM_MAX_ORDER) * PAGE_SIZE;
+
+ if (!imem_list_head)
+ max_size = end_addr - start_addr;
+ else {
+ max_size = 0;
+ imem = imem_list_head;
+ while (imem) {
+ if (max_size < (imem->phys_start - start_addr))
+ max_size = imem->phys_start - start_addr;
+
+ start_addr = imem->phys_end + 1;
+ imem = imem->next;
+ }
+
+ if (max_size < (end_addr - start_addr))
+ max_size = end_addr - start_addr;
+ }
+
+ if (max_size > 0) {
+ max_order = get_order(max_size);
+ if (((1 << max_order) * PAGE_SIZE) > max_size)
+ max_order--;
+ }
+ else {
+ max_order = 0xffffffff; /* No any free buffer */
+ }
+
+ *tmp++ = allocated_phys_addr; /* address allocated by 'echo n > /proc/jz/imem' */
+ *tmp = max_order; /* max order of current free buffers */
+
+ len += 2 * sizeof(unsigned int);
+
+ return len;
+}
+
+static int imem_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ unsigned int val;
+
+ val = simple_strtoul(buffer, 0, 16);
+
+ if (val == 0xff) {
+ /* free all memory */
+ imem_free_all();
+ ipu_del_wired_entry();
+ } else if ((val >= 0) && (val <= IMEM_MAX_ORDER)) {
+ /* allocate 2^val pages */
+ imem_alloc(val);
+ } else {
+ /* free buffer which phys_addr is val */
+ imem_free(val);
+ }
+
+ return count;
+}
+
+/*
+ * /proc/jz/xxx entry
+ *
+ */
+static int __init jz_proc_init(void)
+{
+ struct proc_dir_entry *res;
+ unsigned int virt_addr, i;
+
+ proc_jz_root = proc_mkdir("jz", 0);
+
+ /* External Memory Controller */
+ res = create_proc_entry("emc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = emc_read_proc;
+ res->write_proc = NULL;
+ res->data = NULL;
+ }
+
+ /* Power Management Controller */
+ res = create_proc_entry("pmc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = pmc_read_proc;
+ res->write_proc = pmc_write_proc;
+ res->data = NULL;
+ }
+
+ /* Clock Generation Module */
+ res = create_proc_entry("cgm", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = cgm_read_proc;
+ res->write_proc = cgm_write_proc;
+ res->data = NULL;
+ }
+
+ /* Image process unit */
+ res = create_proc_entry("ipu", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = ipu_read_proc;
+ res->write_proc = ipu_write_proc;
+ res->data = NULL;
+ }
+
+ /* mmc hotplug */
+ res = create_proc_entry("mmc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = mmc_read_proc;
+ res->write_proc = NULL;
+ res->data = NULL;
+ }
+
+ /* show tlb */
+ res = create_proc_entry("tlb", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = tlb_read_proc;
+ res->write_proc = NULL;
+ res->data = NULL;
+ }
+
+#ifdef CONFIG_JZ4750_IPU_MM
+ /*
+ * Reserve a 16MB memory for IPU on JZ4750.
+ */
+ jz_imem_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM_MAX_ORDER);
+ if (jz_imem_base) {
+ /* imem (IPU memory management) */
+ res = create_proc_entry("imem", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = imem_read_proc;
+ res->write_proc = imem_write_proc;
+ res->data = NULL;
+ }
+
+ /* Set page reserved */
+ virt_addr = jz_imem_base;
+ for (i = 0; i < (1 << IMEM_MAX_ORDER); i++) {
+ SetPageReserved(virt_to_page((void *)virt_addr));
+ virt_addr += PAGE_SIZE;
+ }
+
+ /* Convert to physical address */
+ jz_imem_base = virt_to_phys((void *)jz_imem_base);
+
+ printk("Total %dMB memory at 0x%x was reserved for IPU\n",
+ (unsigned int)((1 << IMEM_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem_base);
+ } else
+ printk("NOT enough memory for imem\n");
+#else
+ jz_imem_base = NULL;
+#endif
+
+ return 0;
+}
+
+__initcall(jz_proc_init);
diff --git a/arch/mips/jz4750/prom.c b/arch/mips/jz4750/prom.c
new file mode 100644
index 00000000000..d04bb3e52a3
--- /dev/null
+++ b/arch/mips/jz4750/prom.c
@@ -0,0 +1,198 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * PROM library initialisation code, supports YAMON and U-Boot.
+ *
+ * Copyright 2000, 2001, 2006 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * This file was derived from Carsten Langgaard's
+ * arch/mips/mips-boards/xx files.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/jzsoc.h>
+
+/* #define DEBUG_CMDLINE */
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+char * prom_getcmdline(void)
+{
+ return &(arcs_cmdline[0]);
+}
+
+void prom_init_cmdline(void)
+{
+ char *cp;
+ int actr;
+
+ actr = 1; /* Always ignore argv[0] */
+
+ cp = &(arcs_cmdline[0]);
+ while(actr < prom_argc) {
+ strcpy(cp, prom_argv[actr]);
+ cp += strlen(prom_argv[actr]);
+ *cp++ = ' ';
+ actr++;
+ }
+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+ --cp;
+ if (prom_argc > 1)
+ *cp = '\0';
+
+}
+
+
+char *prom_getenv(char *envname)
+{
+#if 0
+ /*
+ * Return a pointer to the given environment variable.
+ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
+ */
+
+ char **env = prom_envp;
+ int i = strlen(envname);
+ int yamon = (*env && strchr(*env, '=') == NULL);
+
+ while (*env) {
+ if (yamon) {
+ if (strcmp(envname, *env++) == 0)
+ return *env;
+ } else {
+ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
+ return *env + i + 1;
+ }
+ env++;
+ }
+#endif
+ return NULL;
+}
+
+inline unsigned char str2hexnum(unsigned char c)
+{
+ if(c >= '0' && c <= '9')
+ return c - '0';
+ if(c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if(c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return 0; /* foo */
+}
+
+inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+ int i;
+
+ for(i = 0; i < 6; i++) {
+ unsigned char num;
+
+ if((*str == '.') || (*str == ':'))
+ str++;
+ num = str2hexnum(*str++) << 4;
+ num |= (str2hexnum(*str++));
+ ea[i] = num;
+ }
+}
+
+int get_ethernet_addr(char *ethernet_addr)
+{
+ char *ethaddr_str;
+
+ ethaddr_str = prom_getenv("ethaddr");
+ if (!ethaddr_str) {
+ printk("ethaddr not set in boot prom\n");
+ return -1;
+ }
+ str2eaddr(ethernet_addr, ethaddr_str);
+
+#if 0
+ {
+ int i;
+
+ printk("get_ethernet_addr: ");
+ for (i=0; i<5; i++)
+ printk("%02x:", (unsigned char)*(ethernet_addr+i));
+ printk("%02x\n", *(ethernet_addr+i));
+ }
+#endif
+
+ return 0;
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+void __init prom_init(void)
+{
+ unsigned char *memsize_str;
+ unsigned long memsize;
+
+ prom_argc = (int) fw_arg0;
+ prom_argv = (char **) fw_arg1;
+ prom_envp = (char **) fw_arg2;
+
+ mips_machtype = MACH_INGENIC_JZ4750;
+
+ prom_init_cmdline();
+ memsize_str = prom_getenv("memsize");
+ if (!memsize_str) {
+ memsize = 0x04000000;
+ } else {
+ memsize = simple_strtol(memsize_str, NULL, 0);
+ }
+ add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
+/* used by early printk */
+void prom_putchar(char c)
+{
+ volatile u8 *uart_lsr = (volatile u8 *)(UART0_BASE + OFF_LSR);
+ volatile u8 *uart_tdr = (volatile u8 *)(UART0_BASE + OFF_TDR);
+
+ /* Wait for fifo to shift out some bytes */
+ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) );
+
+ *uart_tdr = (u8)c;
+}
+
+const char *get_system_type(void)
+{
+ return "JZ4750";
+}
+
+EXPORT_SYMBOL(prom_getcmdline);
+EXPORT_SYMBOL(get_ethernet_addr);
+EXPORT_SYMBOL(str2eaddr);
diff --git a/arch/mips/jz4750/reset.c b/arch/mips/jz4750/reset.c
new file mode 100644
index 00000000000..baf38aa306a
--- /dev/null
+++ b/arch/mips/jz4750/reset.c
@@ -0,0 +1,42 @@
+/*
+ * linux/arch/mips/jz4750/reset.c
+ *
+ * JZ4750 reset routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <yliu@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+void jz_restart(char *command)
+{
+ printk("Restarting after 4 ms\n");
+ REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN;
+ REG_WDT_TCNT = 0;
+ REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */
+ REG_TCU_TSCR = TCU_TSCR_WDTSC; /* enable wdt clock */
+ REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */
+ while (1);
+}
+
+void jz_halt(void)
+{
+ printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+
+ while (1)
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0");
+}
+
diff --git a/arch/mips/jz4750/setup.c b/arch/mips/jz4750/setup.c
new file mode 100644
index 00000000000..3a54fc21a22
--- /dev/null
+++ b/arch/mips/jz4750/setup.c
@@ -0,0 +1,197 @@
+/*
+ * linux/arch/mips/jz4750/common/setup.c
+ *
+ * JZ4750 common setup routines.
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/ioport.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+#include <asm/pgtable.h>
+#include <asm/time.h>
+#include <asm/jzsoc.h>
+
+#ifdef CONFIG_PC_KEYB
+#include <asm/keyboard.h>
+#endif
+
+jz_clocks_t jz_clocks;
+
+extern char * __init prom_getcmdline(void);
+extern void __init jz_board_setup(void);
+extern void jz_restart(char *);
+extern void jz_pm_hibernate(void);
+extern void jz_halt(void);
+extern void jz_time_init(void);
+
+static void __init sysclocks_setup(void)
+{
+#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */
+ jz_clocks.cclk = __cpm_get_cclk();
+ jz_clocks.hclk = __cpm_get_hclk();
+ jz_clocks.pclk = __cpm_get_pclk();
+ jz_clocks.mclk = __cpm_get_mclk();
+ jz_clocks.lcdclk = __cpm_get_lcdclk();
+ jz_clocks.pixclk = __cpm_get_pixclk();
+ jz_clocks.i2sclk = __cpm_get_i2sclk();
+ jz_clocks.usbclk = __cpm_get_usbclk();
+ jz_clocks.mscclk = __cpm_get_mscclk(0);
+ jz_clocks.extalclk = __cpm_get_extalclk();
+ jz_clocks.rtcclk = __cpm_get_rtcclk();
+#else
+
+#define FPGACLK 8000000
+
+ jz_clocks.cclk = FPGACLK;
+ jz_clocks.hclk = FPGACLK;
+ jz_clocks.pclk = FPGACLK;
+ jz_clocks.mclk = FPGACLK;
+ jz_clocks.lcdclk = FPGACLK;
+ jz_clocks.pixclk = FPGACLK;
+ jz_clocks.i2sclk = FPGACLK;
+ jz_clocks.usbclk = FPGACLK;
+ jz_clocks.mscclk = FPGACLK;
+ jz_clocks.extalclk = FPGACLK;
+ jz_clocks.rtcclk = FPGACLK;
+#endif
+
+ printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n",
+ (jz_clocks.cclk + 500000) / 1000000,
+ (jz_clocks.hclk + 500000) / 1000000,
+ (jz_clocks.pclk + 500000) / 1000000,
+ (jz_clocks.mclk + 500000) / 1000000);
+}
+
+static void __init soc_cpm_setup(void)
+{
+ /* Start all module clocks
+ */
+ __cpm_start_all();
+
+ /* Enable CKO to external memory */
+ __cpm_enable_cko();
+
+ /* CPU enters IDLE mode when executing 'wait' instruction */
+ __cpm_idle_mode();
+
+ /* Setup system clocks */
+ sysclocks_setup();
+}
+
+static void __init soc_harb_setup(void)
+{
+// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */
+// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */
+// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */
+}
+
+static void __init soc_emc_setup(void)
+{
+}
+
+static void __init soc_dmac_setup(void)
+{
+ __dmac_enable_module(0);
+ __dmac_enable_module(1);
+}
+
+static void __init jz_soc_setup(void)
+{
+ soc_cpm_setup();
+ soc_harb_setup();
+ soc_emc_setup();
+ soc_dmac_setup();
+}
+
+static void __init jz_serial_setup(void)
+{
+#ifdef CONFIG_SERIAL_8250
+ struct uart_port s;
+ REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */
+ memset(&s, 0, sizeof(s));
+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
+ s.iotype = SERIAL_IO_MEM;
+ s.regshift = 2;
+ s.uartclk = jz_clocks.extalclk ;
+
+ s.line = 0;
+ s.membase = (u8 *)UART0_BASE;
+ s.irq = IRQ_UART0;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS0 setup failed!\n");
+ }
+
+ s.line = 1;
+ s.membase = (u8 *)UART1_BASE;
+ s.irq = IRQ_UART1;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS1 setup failed!\n");
+ }
+
+ s.line = 2;
+ s.membase = (u8 *)UART2_BASE;
+ s.irq = IRQ_UART2;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS2 setup failed!\n");
+ }
+
+ s.line = 3;
+ s.membase = (u8 *)UART3_BASE;
+ s.irq = IRQ_UART3;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS3 setup failed!\n");
+ }
+#endif
+}
+
+void __init plat_mem_setup(void)
+{
+ char *argptr;
+
+ argptr = prom_getcmdline();
+
+ /* IO/MEM resources. Which will be the addtion value in `inX' and
+ * `outX' macros defined in asm/io.h */
+ set_io_port_base(0);
+ ioport_resource.start = 0x00000000;
+ ioport_resource.end = 0xffffffff;
+ iomem_resource.start = 0x00000000;
+ iomem_resource.end = 0xffffffff;
+
+ _machine_restart = jz_restart;
+ _machine_halt = jz_halt;
+ pm_power_off = jz_pm_hibernate;
+
+ jz_soc_setup();
+ jz_serial_setup();
+ jz_board_setup();
+}
+
diff --git a/arch/mips/jz4750/time.c b/arch/mips/jz4750/time.c
new file mode 100644
index 00000000000..b5167d7ab19
--- /dev/null
+++ b/arch/mips/jz4750/time.c
@@ -0,0 +1,214 @@
+/*
+ * linux/arch/mips/jz4750/time.c
+ *
+ * Setting up the clock on the JZ4750 boards.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/clockchips.h>
+#include <asm/time.h>
+#include <asm/jzsoc.h>
+
+/* This is for machines which generate the exact clock. */
+
+#define JZ_TIMER_TCU_CH 5
+#define JZ_TIMER_IRQ IRQ_TCU1
+#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */
+
+static struct clocksource clocksource_jz; /* Jz clock source */
+static struct clock_event_device jz_clockevent_device; /* Jz clock event */
+
+void (*jz_timer_callback)(void);
+
+static irqreturn_t jz_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd = dev_id;
+ __tcu_clear_full_match_flag(JZ_TIMER_TCU_CH);
+ if (jz_timer_callback)
+ jz_timer_callback();
+
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction jz_irqaction = {
+ .handler = jz_timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+ .name = "jz-timerirq",
+};
+
+static unsigned int current_cycle_high = 0;
+union clycle_type
+{
+ cycle_t cycle64;
+ unsigned int cycle32[2];
+};
+static union clycle_type old_cycle = {0};
+
+cycle_t jz_get_cycles(struct clocksource *cs)
+{
+ /* convert jiffes to jz timer cycles */
+ unsigned int ostcount;
+ unsigned long cpuflags;
+ unsigned int current_cycle;
+
+ local_irq_save(cpuflags);
+ current_cycle = current_cycle_high;
+ ostcount = REG_TCU_OSTCNT;
+ local_irq_restore(cpuflags);
+ if((ostcount < old_cycle.cycle32[0]) && (current_cycle == old_cycle.cycle32[1])){
+ old_cycle.cycle32[0] = ostcount;
+ old_cycle.cycle32[1]++;
+ }else{
+ old_cycle.cycle32[0] = ostcount;
+ old_cycle.cycle32[1] = current_cycle;
+ }
+ return (old_cycle.cycle64);
+}
+
+
+
+static struct clocksource clocksource_jz = {
+ .name = "jz_clocksource",
+ .rating = 300,
+ .read = jz_get_cycles,
+ .mask = 0xFFFFFFFF,
+ .shift = 10,
+ .flags = CLOCK_SOURCE_WATCHDOG,
+};
+
+
+
+static irqreturn_t jzclock_handler(int irq, void *dev_id)
+{
+ REG_TCU_TFCR = TCU_TFCR_OSTFCL; /* ACK timer */
+ current_cycle_high++;
+ return IRQ_HANDLED;
+}
+
+static struct irqaction jz_clockaction = {
+ .handler = jzclock_handler,
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .name = "jz-clockcycle",
+};
+static int __init jz_clocksource_init(void)
+{
+ unsigned int latch;
+
+ /* Init timer */
+ latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ;
+
+ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift);
+ clocksource_register(&clocksource_jz);
+ //---------------------init sys clock -----------------
+
+ REG_TCU_OSTCSR = TCU_OSTCSR_PRESCALE16 | TCU_OSTCSR_EXT_EN;
+
+ REG_TCU_OSTCNT = 0;
+ REG_TCU_OSTDR = 0xffffffff;
+
+ jz_clockaction.dev_id = &clocksource_jz;
+
+ setup_irq(IRQ_TCU0, &jz_clockaction);
+ REG_TCU_TMCR = TCU_TMCR_OSTMCL; /* unmask match irq */
+ REG_TCU_TSCR = TCU_TSCR_OSTSC; /* enable timer clock */
+ REG_TCU_TESR = TCU_TESR_OSTST; /* start counting up */
+
+ //---------------------endif init sys clock -----------------
+ return 0;
+}
+
+static int jz_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ return 0;
+}
+
+static void jz_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static struct clock_event_device jz_clockevent_device = {
+ .name = "jz-clockenvent",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */
+
+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
+ .mult = 1,
+ .rating = 300,
+ .irq = JZ_TIMER_IRQ,
+ .set_mode = jz_set_mode,
+ .set_next_event = jz_set_next_event,
+};
+
+static void __init jz_clockevent_init(void)
+{
+ struct clock_event_device *cd = &jz_clockevent_device;
+ unsigned int cpu = smp_processor_id();
+ cd->cpumask = cpumask_of(cpu);
+ clockevents_register_device(cd);
+}
+
+static void __init jz_timer_setup(void)
+{
+ unsigned int latch;
+
+ jz_clocksource_init(); /* init jz clock source */
+ jz_clockevent_init(); /* init jz clock event */
+ //---------------------init sys tick -----------------
+ /* Init timer */
+ __tcu_stop_counter(JZ_TIMER_TCU_CH);
+ __cpm_start_tcu();
+ latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ;
+
+ REG_TCU_TMSR = ((1 << JZ_TIMER_TCU_CH) | (1 << (JZ_TIMER_TCU_CH + 16)));
+
+ REG_TCU_TCSR(JZ_TIMER_TCU_CH) = TCU_TCSR_PRESCALE16 | TCU_TCSR_EXT_EN;
+ REG_TCU_TDFR(JZ_TIMER_TCU_CH) = latch - 1;
+ REG_TCU_TDHR(JZ_TIMER_TCU_CH) = latch + 1;
+ REG_TCU_TCNT(JZ_TIMER_TCU_CH) = 0;
+ /*
+ * Make irqs happen for the system timer
+ */
+ jz_irqaction.dev_id = &jz_clockevent_device;
+ setup_irq(JZ_TIMER_IRQ, &jz_irqaction);
+ __tcu_clear_full_match_flag(JZ_TIMER_TCU_CH);
+ __tcu_unmask_full_match_irq(JZ_TIMER_TCU_CH);
+ __tcu_start_counter(JZ_TIMER_TCU_CH);
+}
+
+
+void __init plat_time_init(void)
+{
+ jz_timer_setup();
+}
diff --git a/arch/mips/jz4750d/Makefile b/arch/mips/jz4750d/Makefile
new file mode 100644
index 00000000000..a8b22124045
--- /dev/null
+++ b/arch/mips/jz4750d/Makefile
@@ -0,0 +1,23 @@
+#
+# Makefile for the Ingenic JZ4750D.
+#
+
+# Object file lists.
+
+obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
+ platform.o i2c.o
+
+obj-$(CONFIG_PROC_FS) += proc.o
+
+# board specific support
+
+obj-$(CONFIG_JZ4750D_FUWA1) += board-fuwa1.o
+obj-$(CONFIG_JZ4750D_CETUS) += board-cetus.o
+
+# PM support
+
+obj-$(CONFIG_PM) +=pm.o
+
+# CPU Frequency scaling support
+
+obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o
diff --git a/arch/mips/jz4750d/board-cetus.c b/arch/mips/jz4750d/board-cetus.c
new file mode 100644
index 00000000000..0febbd3f0e3
--- /dev/null
+++ b/arch/mips/jz4750d/board-cetus.c
@@ -0,0 +1,72 @@
+/*
+ * linux/arch/mips/jz4750d/board-cetus.c
+ *
+ * JZ4750D CETUS board setup routines.
+ *
+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+
+#include <asm/jzsoc.h>
+
+extern void (*jz_timer_callback)(void);
+
+static void dancing(void)
+{
+ static unsigned char slash[] = "\\|/-";
+// static volatile unsigned char *p = (unsigned char *)0xb6000058;
+ static volatile unsigned char *p = (unsigned char *)0xb6000016;
+ static unsigned int count = 0;
+ *p = slash[count++];
+ count &= 3;
+}
+
+static void cetus_timer_callback(void)
+{
+ static unsigned long count = 0;
+
+ if ((++count) % 50 == 0) {
+ dancing();
+ count = 0;
+ }
+}
+
+static void __init board_cpm_setup(void)
+{
+ /* Stop unused module clocks here.
+ * We have started all module clocks at arch/mips/jz4750d/setup.c.
+ */
+}
+
+static void __init board_gpio_setup(void)
+{
+ /*
+ * Initialize SDRAM pins
+ */
+}
+
+void __init jz_board_setup(void)
+{
+ printk("JZ4750D CETUS board setup\n");
+
+ board_cpm_setup();
+ board_gpio_setup();
+
+ jz_timer_callback = cetus_timer_callback;
+}
diff --git a/arch/mips/jz4750d/board-fuwa1.c b/arch/mips/jz4750d/board-fuwa1.c
new file mode 100644
index 00000000000..e9294c35a5b
--- /dev/null
+++ b/arch/mips/jz4750d/board-fuwa1.c
@@ -0,0 +1,72 @@
+/*
+ * linux/arch/mips/jz4750d/board-fuwa1.c
+ *
+ * JZ4750D FUWA1 board setup routines.
+ *
+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+
+#include <asm/jzsoc.h>
+
+extern void (*jz_timer_callback)(void);
+
+static void dancing(void)
+{
+ static unsigned char slash[] = "\\|/-";
+// static volatile unsigned char *p = (unsigned char *)0xb6000058;
+ static volatile unsigned char *p = (unsigned char *)0xb6000016;
+ static unsigned int count = 0;
+ *p = slash[count++];
+ count &= 3;
+}
+
+static void fuwa1_timer_callback(void)
+{
+ static unsigned long count = 0;
+
+ if ((++count) % 50 == 0) {
+ dancing();
+ count = 0;
+ }
+}
+
+static void __init board_cpm_setup(void)
+{
+ /* Stop unused module clocks here.
+ * We have started all module clocks at arch/mips/jz4750d/setup.c.
+ */
+}
+
+static void __init board_gpio_setup(void)
+{
+ /*
+ * Initialize SDRAM pins
+ */
+}
+
+void __init jz_board_setup(void)
+{
+ printk("JZ4750D FUWA1 board setup\n");
+
+ board_cpm_setup();
+ board_gpio_setup();
+
+ jz_timer_callback = fuwa1_timer_callback;
+}
diff --git a/arch/mips/jz4750d/cpufreq.c b/arch/mips/jz4750d/cpufreq.c
new file mode 100644
index 00000000000..c0d63ace176
--- /dev/null
+++ b/arch/mips/jz4750d/cpufreq.c
@@ -0,0 +1,598 @@
+/*
+ * linux/arch/mips/jz4750d/cpufreq.c
+ *
+ * cpufreq driver for JZ4750D
+ *
+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/cpufreq.h>
+
+#include <asm/jzsoc.h>
+#include <asm/processor.h>
+
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+ "cpufreq-jz4750d", msg)
+
+#undef CHANGE_PLL
+
+#define PLL_UNCHANGED 0
+#define PLL_GOES_UP 1
+#define PLL_GOES_DOWN 2
+
+#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000))
+
+/* Saved the boot-time parameters */
+static struct {
+ /* SDRAM parameters */
+ unsigned int mclk; /* memory clock, KHz */
+ unsigned int tras; /* RAS pulse width, cycles of mclk */
+ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */
+ unsigned int tpc; /* RAS Precharge time, cycles of mclk */
+ unsigned int trwl; /* Write Precharge Time, cycles of mclk */
+ unsigned int trc; /* RAS Cycle Time, cycles of mclk */
+ unsigned int rtcor; /* Refresh Time Constant */
+ unsigned int sdram_initialized;
+
+ /* LCD parameters */
+ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */
+ unsigned int lcd_clks_initialized;
+} boot_config;
+
+struct jz4750d_freq_percpu_info {
+ struct cpufreq_frequency_table table[7];
+};
+
+static struct jz4750d_freq_percpu_info jz4750d_freq_table;
+
+/*
+ * This contains the registers value for an operating point.
+ * If only part of a register needs to change then there is
+ * a mask value for that register.
+ * When going to a new operating point the current register
+ * value is ANDed with the ~mask and ORed with the new value.
+ */
+struct dpm_regs {
+ u32 cpccr; /* Clock Freq Control Register */
+ u32 cpccr_mask; /* Clock Freq Control Register mask */
+ u32 cppcr; /* PLL1 Control Register */
+ u32 cppcr_mask; /* PLL1 Control Register mask */
+ u32 pll_up_flag; /* New PLL freq is higher than current or not */
+};
+
+extern jz_clocks_t jz_clocks;
+
+static void jz_update_clocks(void)
+{
+ /* Next clocks must be updated if we have changed
+ * the PLL or divisors.
+ */
+ jz_clocks.cclk = __cpm_get_cclk();
+ jz_clocks.hclk = __cpm_get_hclk();
+ jz_clocks.mclk = __cpm_get_mclk();
+ jz_clocks.pclk = __cpm_get_pclk();
+ jz_clocks.pixclk = __cpm_get_pixclk();
+ jz_clocks.i2sclk = __cpm_get_i2sclk();
+ jz_clocks.usbclk = __cpm_get_usbclk();
+ jz_clocks.mscclk = __cpm_get_mscclk(0);
+}
+
+static void
+jz_init_boot_config(void)
+{
+ if (!boot_config.lcd_clks_initialized) {
+ /* the first time to scale pll */
+ boot_config.lcdpix_clk = __cpm_get_pixclk();
+ boot_config.lcd_clks_initialized = 1;
+ }
+
+ if (!boot_config.sdram_initialized) {
+ /* the first time to scale frequencies */
+ unsigned int dmcr, rtcor;
+ unsigned int tras, rcd, tpc, trwl, trc;
+
+ dmcr = REG_EMC_DMCR;
+ rtcor = REG_EMC_RTCOR;
+
+ tras = (dmcr >> 13) & 0x7;
+ rcd = (dmcr >> 11) & 0x3;
+ tpc = (dmcr >> 8) & 0x7;
+ trwl = (dmcr >> 5) & 0x3;
+ trc = (dmcr >> 2) & 0x7;
+
+ boot_config.mclk = __cpm_get_mclk() / 1000;
+ boot_config.tras = tras + 4;
+ boot_config.rcd = rcd + 1;
+ boot_config.tpc = tpc + 1;
+ boot_config.trwl = trwl + 1;
+ boot_config.trc = trc * 2 + 1;
+ boot_config.rtcor = rtcor;
+
+ boot_config.sdram_initialized = 1;
+ }
+}
+
+static void jz_update_dram_rtcor(unsigned int new_mclk)
+{
+ unsigned int rtcor;
+
+ new_mclk /= 1000;
+ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk;
+ rtcor--;
+
+ if (rtcor < 1) rtcor = 1;
+ if (rtcor > 255) rtcor = 255;
+
+ REG_EMC_RTCOR = rtcor;
+ REG_EMC_RTCNT = rtcor;
+}
+
+static void jz_update_dram_dmcr(unsigned int new_mclk)
+{
+ unsigned int dmcr;
+ unsigned int tras, rcd, tpc, trwl, trc;
+ unsigned int valid_time, new_time; /* ns */
+
+ new_mclk /= 1000;
+ tras = boot_config.tras * new_mclk / boot_config.mclk;
+ rcd = boot_config.rcd * new_mclk / boot_config.mclk;
+ tpc = boot_config.tpc * new_mclk / boot_config.mclk;
+ trwl = boot_config.trwl * new_mclk / boot_config.mclk;
+ trc = boot_config.trc * new_mclk / boot_config.mclk;
+
+ /* Validation checking */
+ valid_time = (boot_config.tras * 1000000) / boot_config.mclk;
+ new_time = (tras * 1000000) / new_mclk;
+ if (new_time < valid_time) tras += 1;
+
+ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk;
+ new_time = (rcd * 1000000) / new_mclk;
+ if (new_time < valid_time) rcd += 1;
+
+ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk;
+ new_time = (tpc * 1000000) / new_mclk;
+ if (new_time < valid_time) tpc += 1;
+
+ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk;
+ new_time = (trwl * 1000000) / new_mclk;
+ if (new_time < valid_time) trwl += 1;
+
+ valid_time = (boot_config.trc * 1000000) / boot_config.mclk;
+ new_time = (trc * 1000000) / new_mclk;
+ if (new_time < valid_time) trc += 2;
+
+ tras = (tras < 4) ? 4: tras;
+ tras = (tras > 11) ? 11: tras;
+ tras -= 4;
+
+ rcd = (rcd < 1) ? 1: rcd;
+ rcd = (rcd > 4) ? 4: rcd;
+ rcd -= 1;
+
+ tpc = (tpc < 1) ? 1: tpc;
+ tpc = (tpc > 8) ? 8: tpc;
+ tpc -= 1;
+
+ trwl = (trwl < 1) ? 1: trwl;
+ trwl = (trwl > 4) ? 4: trwl;
+ trwl -= 1;
+
+ trc = (trc < 1) ? 1: trc;
+ trc = (trc > 15) ? 15: trc;
+ trc /= 2;
+
+ dmcr = REG_EMC_DMCR;
+
+ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK);
+ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT));
+
+ REG_EMC_DMCR = dmcr;
+}
+
+static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk)
+{
+ /* No risk, no fun: run with interrupts on! */
+ if (new_mclk > cur_mclk) {
+ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL
+ * and TRC of DMCR before changing the frequency.
+ */
+ jz_update_dram_dmcr(new_mclk);
+ } else {
+ /* We're going SLOWER: first update RTCOR value
+ * before changing the frequency.
+ */
+ jz_update_dram_rtcor(new_mclk);
+ }
+}
+
+static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk)
+{
+ /* No risk, no fun: run with interrupts on! */
+ if (new_mclk > cur_mclk) {
+ /* We're going FASTER, so update RTCOR
+ * after changing the frequency
+ */
+ jz_update_dram_rtcor(new_mclk);
+ } else {
+ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL
+ * and TRC of DMCR after changing the frequency.
+ */
+ jz_update_dram_dmcr(new_mclk);
+ }
+}
+
+static void jz_scale_divisors(struct dpm_regs *regs)
+{
+ unsigned int cpccr;
+ unsigned int cur_mclk, new_mclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned int tmp = 0, wait = PLL_WAIT_500NS;
+
+ cpccr = REG_CPM_CPCCR;
+ cpccr &= ~((unsigned long)regs->cpccr_mask);
+ cpccr |= regs->cpccr;
+ cpccr |= CPM_CPCCR_CE; /* update immediately */
+
+ cur_mclk = __cpm_get_mclk();
+ new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT];
+
+ /* Update some DRAM parameters before changing frequency */
+ jz_update_dram_prev(cur_mclk, new_mclk);
+
+ /* update register to change the clocks.
+ * align this code to a cache line.
+ */
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "li %3,0\n\t"
+ "1:\n\t"
+ "bne %3,%2,1b\n\t"
+ "addi %3, 1\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
+
+ /* Update some other DRAM parameters after changing frequency */
+ jz_update_dram_post(cur_mclk, new_mclk);
+}
+
+#ifdef CHANGE_PLL
+/* Maintain the LCD clock and pixel clock */
+static void jz_scale_lcd_divisors(struct dpm_regs *regs)
+{
+ unsigned int new_pll, new_lcd_div, new_lcdpix_div;
+ unsigned int cpccr;
+ unsigned int tmp = 0, wait = PLL_WAIT_500NS;
+
+ if (!boot_config.lcd_clks_initialized) return;
+
+ new_pll = __cpm_get_pllout();
+ new_lcd_div = new_pll / boot_config.lcd_clk;
+ new_lcdpix_div = new_pll / boot_config.lcdpix_clk;
+
+ if (new_lcd_div < 1)
+ new_lcd_div = 1;
+ if (new_lcd_div > 16)
+ new_lcd_div = 16;
+
+ if (new_lcdpix_div < 1)
+ new_lcdpix_div = 1;
+ if (new_lcdpix_div > 512)
+ new_lcdpix_div = 512;
+
+// REG_CPM_CPCCR2 = new_lcdpix_div - 1;
+
+ cpccr = REG_CPM_CPCCR;
+ cpccr &= ~CPM_CPCCR_LDIV_MASK;
+ cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT);
+ cpccr |= CPM_CPCCR_CE; /* update immediately */
+
+ /* update register to change the clocks.
+ * align this code to a cache line.
+ */
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "li %3,0\n\t"
+ "1:\n\t"
+ "bne %3,%2,1b\n\t"
+ "addi %3, 1\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
+}
+
+static void jz_scale_pll(struct dpm_regs *regs)
+{
+ unsigned int cppcr;
+ unsigned int cur_mclk, new_mclk, new_pll;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ int od[] = {1, 2, 2, 4};
+
+ cppcr = REG_CPM_CPPCR;
+ cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK);
+ regs->cppcr &= ~CPM_CPPCR_PLLEN;
+ cppcr |= (regs->cppcr | 0xff);
+
+ /* Update some DRAM parameters before changing frequency */
+ new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]);
+ cur_mclk = __cpm_get_mclk();
+ new_mclk = new_pll / div[(REG_CPM_CPCCR>>16) & 0xf];
+
+ /*
+ * Update some SDRAM parameters
+ */
+ jz_update_dram_prev(cur_mclk, new_mclk);
+
+ /*
+ * Update PLL, align code to cache line.
+ */
+ cppcr |= CPM_CPPCR_PLLEN;
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CPPCR), "r" (cppcr));
+
+ /* Update some other DRAM parameters after changing frequency */
+ jz_update_dram_post(cur_mclk, new_mclk);
+}
+#endif
+
+static void jz4750d_transition(struct dpm_regs *regs)
+{
+ /*
+ * Get and save some boot-time conditions.
+ */
+ jz_init_boot_config();
+
+#ifdef CHANGE_PLL
+ /*
+ * Disable LCD before scaling pll.
+ * LCD and LCD pixel clocks should not be changed even if the PLL
+ * output frequency has been changed.
+ */
+ REG_LCD_CTRL &= ~LCD_CTRL_ENA;
+
+ /*
+ * Stop module clocks before scaling PLL
+ */
+ __cpm_stop_eth();
+ __cpm_stop_aic(1);
+ __cpm_stop_aic(2);
+#endif
+
+ /* ... add more as necessary */
+
+ if (regs->pll_up_flag == PLL_GOES_UP) {
+ /* the pll frequency is going up, so change dividors first */
+ jz_scale_divisors(regs);
+#ifdef CHANGE_PLL
+ jz_scale_pll(regs);
+#endif
+ }
+ else if (regs->pll_up_flag == PLL_GOES_DOWN) {
+ /* the pll frequency is going down, so change pll first */
+#ifdef CHANGE_PLL
+ jz_scale_pll(regs);
+#endif
+ jz_scale_divisors(regs);
+ }
+ else {
+ /* the pll frequency is unchanged, so change divisors only */
+ jz_scale_divisors(regs);
+ }
+
+#ifdef CHANGE_PLL
+ /*
+ * Restart module clocks before scaling PLL
+ */
+ __cpm_start_eth();
+ __cpm_start_aic(1);
+ __cpm_start_aic(2);
+
+ /* ... add more as necessary */
+
+ /* Scale the LCD divisors after scaling pll */
+ if (regs->pll_up_flag != PLL_UNCHANGED) {
+ jz_scale_lcd_divisors(regs);
+ }
+
+ /* Enable LCD controller */
+ REG_LCD_CTRL &= ~LCD_CTRL_DIS;
+ REG_LCD_CTRL |= LCD_CTRL_ENA;
+#endif
+
+ /* Update system clocks */
+ jz_update_clocks();
+}
+
+extern unsigned int idle_times;
+static unsigned int jz4750d_freq_get(unsigned int cpu)
+{
+ return (__cpm_get_cclk() / 1000);
+}
+
+static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs)
+{
+ int n2FR[33] = {
+ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
+ 9
+ };
+ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */
+ unsigned int div_of_cclk, new_freq, i;
+
+ regs->pll_up_flag = PLL_UNCHANGED;
+ regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK;
+
+ new_freq = jz4750d_freq_table.table[index].frequency;
+
+ do {
+ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq);
+ } while (div_of_cclk==0);
+
+ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) {
+ for(i = 1; i<4; i++) {
+ div[i] = 3;
+ }
+ } else {
+ for(i = 1; i<4; i++) {
+ div[i] = 2;
+ }
+ }
+
+ for(i = 0; i<4; i++) {
+ div[i] *= div_of_cclk;
+ }
+
+ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]);
+
+ regs->cpccr =
+ (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
+ (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
+ (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
+ (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT);
+
+ return div_of_cclk;
+}
+
+static void jz4750d_set_cpu_divider_index(unsigned int cpu, unsigned int index)
+{
+ unsigned long divisor, old_divisor;
+ struct cpufreq_freqs freqs;
+ struct dpm_regs regs;
+
+ old_divisor = __cpm_get_pllout() / __cpm_get_cclk();
+ divisor = index_to_divisor(index, &regs);
+
+ freqs.old = __cpm_get_cclk() / 1000;
+ freqs.new = __cpm_get_pllout() / (1000 * divisor);
+ freqs.cpu = cpu;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ if (old_divisor != divisor)
+ jz4750d_transition(&regs);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+}
+
+static int jz4750d_freq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int new_index = 0;
+
+ if (cpufreq_frequency_table_target(policy,
+ &jz4750d_freq_table.table[0],
+ target_freq, relation, &new_index))
+ return -EINVAL;
+
+ jz4750d_set_cpu_divider_index(policy->cpu, new_index);
+
+ dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR);
+
+ return 0;
+}
+
+static int jz4750d_freq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy,
+ &jz4750d_freq_table.table[0]);
+}
+
+static int __init jz4750d_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+
+ struct cpufreq_frequency_table *table = &jz4750d_freq_table.table[0];
+ unsigned int MAX_FREQ;
+
+ dprintk(KERN_INFO "Jz4750d cpufreq driver\n");
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ policy->cpuinfo.min_freq = MAX_FREQ/8;
+ policy->cpuinfo.max_freq = MAX_FREQ;
+ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */
+
+ table[0].index = 0;
+ table[0].frequency = MAX_FREQ/8;
+ table[1].index = 1;
+ table[1].frequency = MAX_FREQ/6;
+ table[2].index = 2;
+ table[2].frequency = MAX_FREQ/4;
+ table[3].index = 3;
+ table[3].frequency = MAX_FREQ/3;
+ table[4].index = 4;
+ table[4].frequency = MAX_FREQ/2;
+ table[5].index = 5;
+ table[5].frequency = MAX_FREQ;
+ table[6].index = 6;
+ table[6].frequency = CPUFREQ_TABLE_END;
+
+#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
+ cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */
+#endif
+
+ return cpufreq_frequency_table_cpuinfo(policy, table);
+}
+
+static struct cpufreq_driver cpufreq_jz4750d_driver = {
+// .flags = CPUFREQ_STICKY,
+ .init = jz4750d_cpufreq_driver_init,
+ .verify = jz4750d_freq_verify,
+ .target = jz4750d_freq_target,
+ .get = jz4750d_freq_get,
+ .name = "jz4750d",
+};
+
+static int __init jz4750d_cpufreq_init(void)
+{
+ return cpufreq_register_driver(&cpufreq_jz4750d_driver);
+}
+
+static void __exit jz4750d_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&cpufreq_jz4750d_driver);
+}
+
+module_init(jz4750d_cpufreq_init);
+module_exit(jz4750d_cpufreq_exit);
+
+MODULE_AUTHOR("Regen <lhhuang@ingenic.cn>");
+MODULE_DESCRIPTION("cpufreq driver for Jz4750d");
+MODULE_LICENSE("GPL");
diff --git a/arch/mips/jz4750d/dma.c b/arch/mips/jz4750d/dma.c
new file mode 100644
index 00000000000..290cc12d5bd
--- /dev/null
+++ b/arch/mips/jz4750d/dma.c
@@ -0,0 +1,822 @@
+/*
+ * linux/arch/mips/jz4750d/dma.c
+ *
+ * Support functions for the JZ4750D internal DMA channels.
+ * No-descriptor transfer only.
+ * Descriptor transfer should also call jz_request_dma() to get a free
+ * channel and call jz_free_dma() to free the channel. And driver should
+ * build the DMA descriptor and setup the DMA channel by itself.
+ *
+ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/soundcard.h>
+
+#include <asm/system.h>
+#include <asm/addrspace.h>
+#include <asm/jzsoc.h>
+
+/*
+ * A note on resource allocation:
+ *
+ * All drivers needing DMA channels, should allocate and release them
+ * through the public routines `jz_request_dma()' and `jz_free_dma()'.
+ *
+ * In order to avoid problems, all processes should allocate resources in
+ * the same sequence and release them in the reverse order.
+ *
+ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ.
+ * When releasing them, first release the IRQ, then release the DMA. The
+ * main reason for this order is that, if you are requesting the DMA buffer
+ * done interrupt, you won't know the irq number until the DMA channel is
+ * returned from jz_request_dma().
+ */
+
+struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = {
+ {dev_id:DMA_ID_BCH_ENC,}, /* DMAC0 channel 0, reserved for BCH */
+ {dev_id:-1,}, /* DMAC0 channel 1 */
+ {dev_id:-1,}, /* DMAC0 channel 2 */
+ {dev_id:-1,}, /* DMAC0 channel 3 */
+ {dev_id:-1,}, /* DMAC1 channel 0 */
+ {dev_id:-1,}, /* DMAC1 channel 1 */
+ {dev_id:-1,}, /* DMAC1 channel 2 */
+ {dev_id:-1,}, /* DMAC1 channel 3 */
+};
+
+// Device FIFO addresses and default DMA modes
+static const struct {
+ unsigned int fifo_addr;
+ unsigned int dma_mode;
+ unsigned int dma_source;
+} dma_dev_table[DMA_ID_MAX] = {
+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_EXT}, /* External request with DREQn */
+ {0x18000000, DMA_AUTOINIT, DMAC_DRSR_RS_NAND}, /* NAND request */
+ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_ENC},
+ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_DEC},
+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO},
+// {CPHYSADDR(TSSI_FIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_TSSIIN},
+ {CPHYSADDR(UART3_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT},
+ {CPHYSADDR(UART3_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART3IN},
+ {CPHYSADDR(UART2_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT},
+ {CPHYSADDR(UART2_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART2IN},
+ {CPHYSADDR(UART1_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT},
+ {CPHYSADDR(UART1_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART1IN},
+ {CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT},
+ {CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN},
+ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI0OUT},
+ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI0IN},
+ {CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT},
+ {CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN},
+ {CPHYSADDR(MSC_TXFIFO(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC0OUT},
+ {CPHYSADDR(MSC_RXFIFO(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC0IN},
+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU},
+ {SADC_TSDAT, DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SADC},/* Touch Screen Data Register */
+ {CPHYSADDR(MSC_TXFIFO(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC1OUT}, /* SSC1 TX */
+ {CPHYSADDR(MSC_RXFIFO(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC1IN}, /* SSC1 RX */
+ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI1OUT},
+ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI1IN},
+ {CPHYSADDR(PCM_DP), DMA_16BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_PMOUT},
+ {CPHYSADDR(PCM_DP), DMA_16BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_PMIN},
+ {},
+};
+
+
+int jz_dma_read_proc(char *buf, char **start, off_t fpos,
+ int length, int *eof, void *data)
+{
+ int i, len = 0;
+ struct jz_dma_chan *chan;
+
+ for (i = 0; i < MAX_DMA_NUM; i++) {
+ if ((chan = get_dma_chan(i)) != NULL) {
+ len += sprintf(buf + len, "%2d: %s\n",
+ i, chan->dev_str);
+ }
+ }
+
+ if (fpos >= len) {
+ *start = buf;
+ *eof = 1;
+ return 0;
+ }
+ *start = buf + fpos;
+ if ((len -= fpos) > length)
+ return length;
+ *eof = 1;
+ return len;
+}
+
+
+void dump_jz_dma_channel(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan;
+
+ if (dmanr > MAX_DMA_NUM)
+ return;
+ chan = &jz_dma_table[dmanr];
+
+ printk("DMA%d Registers:\n", dmanr);
+ printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR(chan->io/HALF_DMA_NUM));
+ printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr));
+ printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr));
+ printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr));
+ printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr));
+ printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr));
+ printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr));
+ printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr));
+ printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR(chan->io/HALF_DMA_NUM));
+}
+
+
+/**
+ * jz_request_dma - dynamically allcate an idle DMA channel to return
+ * @dev_id: the specified dma device id or DMA_ID_RAW_SET
+ * @dev_str: the specified dma device string name
+ * @irqhandler: the irq handler, or NULL
+ * @irqflags: the irq handler flags
+ * @irq_dev_id: the irq handler device id for shared irq
+ *
+ * Finds a free channel, and binds the requested device to it.
+ * Returns the allocated channel number, or negative on error.
+ * Requests the DMA done IRQ if irqhandler != NULL.
+ *
+*/
+/*int jz_request_dma(int dev_id, const char *dev_str,
+ void (*irqhandler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ void *irq_dev_id)
+*/
+
+int jz_request_dma(int dev_id, const char *dev_str,
+ irqreturn_t (*irqhandler)(int, void *),
+ unsigned long irqflags,
+ void *irq_dev_id)
+{
+ struct jz_dma_chan *chan;
+ int i, ret;
+
+ if (dev_id < 0 || dev_id >= DMA_ID_MAX)
+ return -EINVAL;
+
+ for (i = 0; i < MAX_DMA_NUM; i++) {
+ if (jz_dma_table[i].dev_id < 0)
+ break;
+ }
+ if (i == MAX_DMA_NUM) /* no free channel */
+ return -ENODEV;
+
+ /* we got a free channel */
+ chan = &jz_dma_table[i];
+
+ if (irqhandler) {
+ chan->irq = IRQ_DMA_0 + i; // allocate irq number
+ chan->irq_dev = irq_dev_id;
+ if ((ret = request_irq(chan->irq, irqhandler, irqflags,
+ dev_str, chan->irq_dev))) {
+ chan->irq = -1;
+ chan->irq_dev = NULL;
+ return ret;
+ }
+ } else {
+ chan->irq = -1;
+ chan->irq_dev = NULL;
+ }
+
+ // fill it in
+ chan->io = i;
+ chan->dev_id = dev_id;
+ chan->dev_str = dev_str;
+ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
+ chan->mode = dma_dev_table[dev_id].dma_mode;
+ chan->source = dma_dev_table[dev_id].dma_source;
+
+ if (i < HALF_DMA_NUM)
+ REG_DMAC_DMACKE(0) = 1 << i;
+ else
+ REG_DMAC_DMACKE(1) = 1 << (i - HALF_DMA_NUM);
+
+ return i;
+}
+
+void jz_free_dma(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan) {
+ printk("Trying to free DMA%d\n", dmanr);
+ return;
+ }
+
+ disable_dma(dmanr);
+ if (chan->irq)
+ free_irq(chan->irq, chan->irq_dev);
+
+ chan->irq = -1;
+ chan->irq_dev = NULL;
+ chan->dev_id = -1;
+}
+
+void jz_set_dma_dest_width(int dmanr, int nbit)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode &= ~DMAC_DCMD_DWDH_MASK;
+ switch (nbit) {
+ case 8:
+ chan->mode |= DMAC_DCMD_DWDH_8;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCMD_DWDH_16;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCMD_DWDH_32;
+ break;
+ }
+}
+
+void jz_set_dma_src_width(int dmanr, int nbit)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode &= ~DMAC_DCMD_SWDH_MASK;
+ switch (nbit) {
+ case 8:
+ chan->mode |= DMAC_DCMD_SWDH_8;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCMD_SWDH_16;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCMD_SWDH_32;
+ break;
+ }
+}
+
+void jz_set_dma_block_size(int dmanr, int nbyte)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode &= ~DMAC_DCMD_DS_MASK;
+ switch (nbyte) {
+ case 1:
+ chan->mode |= DMAC_DCMD_DS_8BIT;
+ break;
+ case 2:
+ chan->mode |= DMAC_DCMD_DS_16BIT;
+ break;
+ case 4:
+ chan->mode |= DMAC_DCMD_DS_32BIT;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCMD_DS_16BYTE;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCMD_DS_32BYTE;
+ break;
+ }
+}
+
+unsigned int jz_get_dma_command(int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ return chan->mode;
+}
+
+/**
+ * jz_set_dma_mode - do the raw settings for the specified DMA channel
+ * @dmanr: the specified DMA channel
+ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE
+ * @dma_mode: dma raw mode
+ * @dma_source: dma raw request source
+ * @fifo_addr: dma raw device fifo address
+ *
+ * Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call
+ * jz_set_dma_mode() rather than set_dma_mode() if you work with
+ * and external request dma device.
+ *
+ * NOTE: Don not dynamically allocate dma channel if one external request
+ * dma device will occupy this channel.
+*/
+int jz_set_dma_mode(unsigned int dmanr, unsigned int mode,
+ unsigned int dma_mode, unsigned int dma_source,
+ unsigned int fifo_addr)
+{
+ int dev_id, i;
+ struct jz_dma_chan *chan;
+
+ if (dmanr > MAX_DMA_NUM)
+ return -ENODEV;
+ for (i = 0; i < MAX_DMA_NUM; i++) {
+ if (jz_dma_table[i].dev_id < 0)
+ break;
+ }
+ if (i == MAX_DMA_NUM)
+ return -ENODEV;
+
+ chan = &jz_dma_table[dmanr];
+ dev_id = chan->dev_id;
+ if (dev_id > 0) {
+ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n",
+ __FUNCTION__, dmanr);
+ return -ENODEV;
+ }
+
+ /* clone it from the dynamically allocated. */
+ if (i != dmanr) {
+ chan->irq = jz_dma_table[i].irq;
+ chan->irq_dev = jz_dma_table[i].irq_dev;
+ chan->dev_str = jz_dma_table[i].dev_str;
+ jz_dma_table[i].irq = 0;
+ jz_dma_table[i].irq_dev = NULL;
+ jz_dma_table[i].dev_id = -1;
+ }
+ chan->dev_id = DMA_ID_RAW_SET;
+ chan->io = dmanr;
+ chan->fifo_addr = fifo_addr;
+ chan->mode = dma_mode;
+ chan->source = dma_source;
+
+ set_dma_mode(dmanr, dma_mode);
+
+ return dmanr;
+}
+
+void enable_dma(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+ REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */
+ __dmac_enable_channel(dmanr);
+ if (chan->irq)
+ __dmac_channel_enable_irq(dmanr);
+}
+
+#define DMA_DISABLE_POLL 0x10000
+
+void disable_dma(unsigned int dmanr)
+{
+ int i;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ if (!__dmac_channel_enabled(dmanr))
+ return;
+
+ for (i = 0; i < DMA_DISABLE_POLL; i++)
+ if (__dmac_channel_transmit_end_detected(dmanr))
+ break;
+#if 0
+ if (i == DMA_DISABLE_POLL)
+ printk(KERN_INFO "disable_dma: poll expired!\n");
+#endif
+
+ __dmac_disable_channel(dmanr);
+ if (chan->irq)
+ __dmac_channel_disable_irq(dmanr);
+}
+
+/* Note: DMA_MODE_MASK is simulated by sw */
+void set_dma_mode(unsigned int dmanr, unsigned int mode)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ if (mode == DMA_MODE_READ) {
+ chan->mode |= DMAC_DCMD_DAI;
+ chan->mode &= ~DMAC_DCMD_SAI;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode |= DMAC_DCMD_SAI;
+ chan->mode &= ~DMAC_DCMD_DAI;
+ } else {
+ printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+ }
+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+}
+
+void set_dma_addr(unsigned int dmanr, unsigned int phyaddr)
+{
+ unsigned int mode;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ mode = chan->mode & DMA_MODE_MASK;
+ if (mode == DMA_MODE_READ) {
+ REG_DMAC_DSAR(chan->io) = chan->fifo_addr;
+ REG_DMAC_DTAR(chan->io) = phyaddr;
+ } else if (mode == DMA_MODE_WRITE) {
+ REG_DMAC_DSAR(chan->io) = phyaddr;
+ REG_DMAC_DTAR(chan->io) = chan->fifo_addr;
+ } else
+ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n");
+}
+
+void set_dma_count(unsigned int dmanr, unsigned int bytecnt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ int dma_ds[] = {4, 1, 2, 16, 32};
+ unsigned int ds;
+
+ if (!chan)
+ return;
+
+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
+ REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count
+}
+
+unsigned int get_dma_residue(unsigned int dmanr)
+{
+ unsigned int count, ds;
+ int dma_ds[] = {4, 1, 2, 16, 32};
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+
+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
+ count = REG_DMAC_DTCR(chan->io);
+ count = count * dma_ds[ds];
+
+ return count;
+}
+
+void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ switch (audio_fmt) {
+ case AFMT_U8:
+ /* burst mode : 32BIT */
+ break;
+ case AFMT_S16_LE:
+ /* burst mode : 16BYTE */
+ if (mode == DMA_MODE_READ) {
+ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_DAI;
+ chan->mode &= ~DMAC_DCMD_SAI;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ //chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_SAI;
+ chan->mode &= ~DMAC_DCMD_DAI;
+ } else
+ printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+
+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+ break;
+ }
+}
+
+void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ switch (audio_fmt) {
+ case 8:
+ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
+ break;
+ case 16:
+ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
+ if (mode == DMA_MODE_READ) {
+ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_DAI;
+ chan->mode &= ~DMAC_DCMD_SAI;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_SAI;
+ chan->mode &= ~DMAC_DCMD_DAI;
+ } else
+ printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+
+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+ break;
+ }
+}
+
+//#define JZ4750D_DMAC_TEST_ENABLE
+#undef JZ4750D_DMAC_TEST_ENABLE
+
+#ifdef JZ4750D_DMAC_TEST_ENABLE
+
+/*
+ * DMA test: external address <--> external address
+ */
+#define TEST_DMA_SIZE 16*1024
+
+static jz_dma_desc *dma_desc;
+
+static int dma_chan;
+static dma_addr_t dma_desc_phys_addr;
+static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr;
+
+static int dma_check_result(void *src, void *dst, int size)
+{
+ unsigned int addr1, addr2, i, err = 0;
+
+ addr1 = (unsigned int)src;
+ addr2 = (unsigned int)dst;
+
+ for (i = 0; i < size; i += 4) {
+ if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) {
+ err++;
+ printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2);
+ }
+ addr1 += 4;
+ addr2 += 4;
+ }
+ printk("check DMA result err=%d\n", err);
+ return err;
+}
+
+static irqreturn_t jz4750d_dma_irq(int irq, void *dev_id)
+{
+ printk("jz4750d_dma_irq %d\n", irq);
+
+
+ if (__dmac_channel_transmit_halt_detected(dma_chan)) {
+ printk("DMA HALT\n");
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ __dmac_channel_clear_transmit_halt(dma_chan);
+ }
+
+ if (__dmac_channel_address_error_detected(dma_chan)) {
+ printk("DMA ADDR ERROR\n");
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ REG_DMAC_DSAR(dma_chan) = 0; /* clear source address register */
+ REG_DMAC_DTAR(dma_chan) = 0; /* clear target address register */
+ __dmac_channel_clear_address_error(dma_chan);
+ }
+
+ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) {
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ printk("DMA DESC INVALID\n");
+ __dmac_channel_clear_descriptor_invalid(dma_chan);
+ }
+
+ if (__dmac_channel_count_terminated_detected(dma_chan)) {
+ printk("DMA CT\n");
+ __dmac_channel_clear_count_terminated(dma_chan);
+ }
+
+ if (__dmac_channel_transmit_end_detected(dma_chan)) {
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ printk("DMA TT\n");
+ __dmac_channel_clear_transmit_end(dma_chan);
+ dump_jz_dma_channel(dma_chan);
+ dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE);
+ }
+
+ return IRQ_HANDLED;
+}
+
+void dma_nodesc_test(void)
+{
+ unsigned int addr, i;
+
+ printk("dma_nodesc_test\n");
+
+ /* Request DMA channel and setup irq handler */
+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750d_dma_irq,
+ IRQF_DISABLED, NULL);
+ if (dma_chan < 0) {
+ printk("Setup irq failed\n");
+ return;
+ }
+
+ printk("Requested DMA channel = %d\n", dma_chan);
+
+ /* Allocate DMA buffers */
+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+
+ dma_src_phys_addr = CPHYSADDR(dma_src_addr);
+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
+
+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
+
+ /* Prepare data for source buffer */
+ addr = (unsigned int)dma_src_addr;
+ for (i = 0; i < TEST_DMA_SIZE; i += 4) {
+ *(volatile unsigned int *)addr = addr;
+ addr += 4;
+ }
+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
+
+ /* Init target buffer */
+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
+
+ /* Init DMA module */
+ printk("Starting DMA\n");
+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0;
+ REG_DMAC_DCCSR(dma_chan) = 0;
+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr;
+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr;
+ REG_DMAC_DTCR(dma_chan) = 512;
+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE;
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */
+
+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
+
+ /* wait a long time, ensure transfer end */
+ printk("wait 3s...\n");
+ mdelay(3000); /* wait 3s */
+
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ /* free buffers */
+ printk("free DMA buffers\n");
+ free_pages(dma_src_addr, 2);
+ free_pages(dma_dst_addr, 2);
+
+ if (dma_desc)
+ free_pages((unsigned int)dma_desc, 0);
+
+ /* free dma */
+ jz_free_dma(dma_chan);
+}
+
+void dma_desc_test(void)
+{
+ unsigned int next, addr, i;
+ static jz_dma_desc *desc;
+
+ printk("dma_desc_test\n");
+
+ /* Request DMA channel and setup irq handler */
+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750d_dma_irq,
+ IRQF_DISABLED, NULL);
+ if (dma_chan < 0) {
+ printk("Setup irq failed\n");
+ return;
+ }
+
+ printk("Requested DMA channel = %d\n", dma_chan);
+
+ /* Allocate DMA buffers */
+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+
+ dma_src_phys_addr = CPHYSADDR(dma_src_addr);
+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
+
+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
+
+ /* Prepare data for source buffer */
+ addr = (unsigned int)dma_src_addr;
+ for (i = 0; i < TEST_DMA_SIZE; i += 4) {
+ *(volatile unsigned int *)addr = addr;
+ addr += 4;
+ }
+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
+
+ /* Init target buffer */
+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
+
+ /* Allocate DMA descriptors */
+ dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0);
+ dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc);
+
+ printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr);
+
+ /* Setup DMA descriptors */
+ desc = dma_desc;
+ next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
+ desc->dsadr = dma_src_phys_addr; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr; /* DMA target address */
+ desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */
+
+ desc++;
+ next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
+ desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */
+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
+
+ desc++;
+ next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
+ desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */
+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
+
+ desc++;
+ next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE;
+ desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */
+ desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */
+
+ dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc)));
+
+ /* Setup DMA descriptor address */
+ REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr;
+
+ /* Setup request source */
+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
+
+ /* Setup DMA channel control/status register */
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */
+
+ /* Enable DMA */
+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE;
+
+ /* DMA doorbell set -- start DMA now ... */
+ REG_DMAC_DMADBSR(dma_chan/HALF_DMA_NUM) = 1 << dma_chan;
+
+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
+ /* wait a long time, ensure transfer end */
+ printk("wait 3s...\n");
+ mdelay(3000); /* wait 3s */
+
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ /* free buffers */
+ printk("free DMA buffers\n");
+ free_pages(dma_src_addr, 2);
+ free_pages(dma_dst_addr, 2);
+
+ if (dma_desc)
+ free_pages((unsigned int)dma_desc, 0);
+
+ /* free dma */
+ jz_free_dma(dma_chan);
+}
+
+#endif
+
+//EXPORT_SYMBOL_NOVERS(jz_dma_table);
+EXPORT_SYMBOL(jz_dma_table);
+EXPORT_SYMBOL(jz_request_dma);
+EXPORT_SYMBOL(jz_free_dma);
+EXPORT_SYMBOL(jz_set_dma_src_width);
+EXPORT_SYMBOL(jz_set_dma_dest_width);
+EXPORT_SYMBOL(jz_set_dma_block_size);
+EXPORT_SYMBOL(jz_set_dma_mode);
+EXPORT_SYMBOL(set_dma_mode);
+EXPORT_SYMBOL(jz_set_oss_dma);
+EXPORT_SYMBOL(jz_set_alsa_dma);
+EXPORT_SYMBOL(set_dma_addr);
+EXPORT_SYMBOL(set_dma_count);
+EXPORT_SYMBOL(get_dma_residue);
+EXPORT_SYMBOL(enable_dma);
+EXPORT_SYMBOL(disable_dma);
+EXPORT_SYMBOL(dump_jz_dma_channel);
diff --git a/arch/mips/jz4750d/i2c.c b/arch/mips/jz4750d/i2c.c
new file mode 100644
index 00000000000..c12142f02c9
--- /dev/null
+++ b/arch/mips/jz4750d/i2c.c
@@ -0,0 +1,273 @@
+/*
+ * linux/arch/mips/jz4750d/i2c.c
+ *
+ * Jz4750D I2C routines.
+ *
+ * Copyright (C) 2005,2006 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/addrspace.h>
+
+#include <asm/jzsoc.h>
+
+/* I2C protocol */
+#define I2C_READ 1
+#define I2C_WRITE 0
+
+#define TIMEOUT 1000
+
+/*
+ * I2C bus protocol basic routines
+ */
+static int i2c_put_data(unsigned char data)
+{
+ unsigned int timeout = TIMEOUT*10;
+
+ __i2c_write(data);
+ __i2c_set_drf();
+ while (__i2c_check_drf() != 0);
+ while (!__i2c_transmit_ended());
+ while (!__i2c_received_ack() && timeout)
+ timeout--;
+
+ if (timeout)
+ return 0;
+ else
+ return -ETIMEDOUT;
+}
+
+#ifdef CONFIG_JZ_TPANEL_ATA2508
+static int i2c_put_data_nack(unsigned char data)
+{
+ unsigned int timeout = TIMEOUT*10;
+
+ __i2c_write(data);
+ __i2c_set_drf();
+ while (__i2c_check_drf() != 0);
+ while (!__i2c_transmit_ended());
+ while (timeout--);
+ return 0;
+}
+#endif
+
+static int i2c_get_data(unsigned char *data, int ack)
+{
+ int timeout = TIMEOUT*10;
+
+ if (!ack)
+ __i2c_send_nack();
+ else
+ __i2c_send_ack();
+
+ while (__i2c_check_drf() == 0 && timeout)
+ timeout--;
+
+ if (timeout) {
+ if (!ack)
+ __i2c_send_stop();
+ *data = __i2c_read();
+ __i2c_clear_drf();
+ return 0;
+ } else
+ return -ETIMEDOUT;
+}
+
+/*
+ * I2C interface
+ */
+void i2c_open(void)
+{
+ __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */
+ __i2c_enable();
+}
+
+void i2c_close(void)
+{
+ udelay(300); /* wait for STOP goes over. */
+ __i2c_disable();
+}
+
+void i2c_setclk(unsigned int i2cclk)
+{
+ __i2c_set_clk(jz_clocks.extalclk, i2cclk);
+}
+
+int i2c_lseek(unsigned char device, unsigned char offset)
+{
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_err;
+ if (i2c_put_data(offset) < 0)
+ goto address_err;
+ return 0;
+ device_err:
+ printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device);
+ __i2c_send_stop();
+ return -ENODEV;
+ address_err:
+ printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device);
+ __i2c_send_stop();
+ return -EREMOTEIO;
+}
+
+int i2c_read(unsigned char device, unsigned char *buf,
+ unsigned char address, int count)
+{
+ int cnt = count;
+ int timeout = 5;
+
+L_try_again:
+
+ if (timeout < 0)
+ goto L_timeout;
+
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_werr;
+ if (i2c_put_data(address) < 0)
+ goto address_err;
+
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_READ ) < 0)
+ goto device_rerr;
+ __i2c_send_ack(); /* Master sends ACK for continue reading */
+ while (cnt) {
+ if (cnt == 1) {
+ if (i2c_get_data(buf, 0) < 0)
+ break;
+ } else {
+ if (i2c_get_data(buf, 1) < 0)
+ break;
+ }
+ cnt--;
+ buf++;
+ }
+
+ __i2c_send_stop();
+ return count - cnt;
+ device_rerr:
+ device_werr:
+ address_err:
+ timeout --;
+ __i2c_send_stop();
+ goto L_try_again;
+
+L_timeout:
+ __i2c_send_stop();
+ printk("Read I2C device 0x%2x failed.\n", device);
+ return -ENODEV;
+}
+
+int i2c_write(unsigned char device, unsigned char *buf,
+ unsigned char address, int count)
+{
+ int cnt = count;
+ int cnt_in_pg;
+ int timeout = 5;
+ unsigned char *tmpbuf;
+ unsigned char tmpaddr;
+
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+
+ W_try_again:
+ if (timeout < 0)
+ goto W_timeout;
+
+ cnt = count;
+ tmpbuf = (unsigned char *)buf;
+ tmpaddr = address;
+
+ start_write_page:
+ cnt_in_pg = 0;
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_err;
+#ifdef CONFIG_JZ_TPANEL_ATA2508
+ if (address == 0xff) {
+ if (i2c_put_data_nack(tmpaddr) < 0)
+ goto address_err;
+ while (cnt) {
+ if (++cnt_in_pg > 8) {
+ __i2c_send_stop();
+ mdelay(1);
+ tmpaddr += 8;
+ goto start_write_page;
+ }
+ if (i2c_put_data_nack(*tmpbuf) < 0)
+ break;
+ cnt--;
+ tmpbuf++;
+ }
+ }
+ else {
+
+ if (i2c_put_data(tmpaddr) < 0)
+ goto address_err;
+ while (cnt) {
+ if (++cnt_in_pg > 8) {
+ __i2c_send_stop();
+ mdelay(1);
+ tmpaddr += 8;
+ goto start_write_page;
+ }
+ if (i2c_put_data(*tmpbuf) < 0)
+ break;
+ cnt--;
+ tmpbuf++;
+ }
+ }
+#else
+ if (i2c_put_data(tmpaddr) < 0)
+ goto address_err;
+ while (cnt) {
+ if (++cnt_in_pg > 8) {
+ __i2c_send_stop();
+ mdelay(1);
+ tmpaddr += 8;
+ goto start_write_page;
+ }
+ if (i2c_put_data(*tmpbuf) < 0)
+ break;
+ cnt--;
+ tmpbuf++;
+ }
+#endif
+ __i2c_send_stop();
+ return count - cnt;
+ device_err:
+ address_err:
+ timeout--;
+ __i2c_send_stop();
+ goto W_try_again;
+
+ W_timeout:
+ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device);
+ __i2c_send_stop();
+ return -ENODEV;
+}
+
+EXPORT_SYMBOL(i2c_open);
+EXPORT_SYMBOL(i2c_close);
+EXPORT_SYMBOL(i2c_setclk);
+EXPORT_SYMBOL(i2c_read);
+EXPORT_SYMBOL(i2c_write);
diff --git a/arch/mips/jz4750d/irq.c b/arch/mips/jz4750d/irq.c
new file mode 100644
index 00000000000..081170db7fc
--- /dev/null
+++ b/arch/mips/jz4750d/irq.c
@@ -0,0 +1,299 @@
+/*
+ * linux/arch/mips/jz4750d/irq.c
+ *
+ * JZ4750D interrupt routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+/*
+ * INTC irq type
+ */
+
+static void enable_intc_irq(unsigned int irq)
+{
+ __intc_unmask_irq(irq);
+}
+
+static void disable_intc_irq(unsigned int irq)
+{
+ __intc_mask_irq(irq);
+}
+
+static void mask_and_ack_intc_irq(unsigned int irq)
+{
+ __intc_mask_irq(irq);
+ __intc_ack_irq(irq);
+}
+
+static void end_intc_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_intc_irq(irq);
+ }
+}
+
+static unsigned int startup_intc_irq(unsigned int irq)
+{
+ enable_intc_irq(irq);
+ return 0;
+}
+
+static void shutdown_intc_irq(unsigned int irq)
+{
+ disable_intc_irq(irq);
+}
+
+static struct irq_chip intc_irq_type = {
+ .typename = "INTC",
+ .startup = startup_intc_irq,
+ .shutdown = shutdown_intc_irq,
+ .unmask = enable_intc_irq,
+ .mask = disable_intc_irq,
+ .ack = mask_and_ack_intc_irq,
+ .end = end_intc_irq,
+};
+
+/*
+ * GPIO irq type
+ */
+
+static void enable_gpio_irq(unsigned int irq)
+{
+ unsigned int intc_irq;
+
+ if (irq < (IRQ_GPIO_0 + 32)) {
+ intc_irq = IRQ_GPIO0;
+ }
+ else if (irq < (IRQ_GPIO_0 + 64)) {
+ intc_irq = IRQ_GPIO1;
+ }
+ else if (irq < (IRQ_GPIO_0 + 96)) {
+ intc_irq = IRQ_GPIO2;
+ }
+ else if (irq < (IRQ_GPIO_0 + 128)) {
+ intc_irq = IRQ_GPIO3;
+ }
+ else if (irq < (IRQ_GPIO_0 + 160)) {
+ intc_irq = IRQ_GPIO4;
+ }
+ else {
+ intc_irq = IRQ_GPIO5;
+ }
+
+ enable_intc_irq(intc_irq);
+ __gpio_unmask_irq(irq - IRQ_GPIO_0);
+}
+
+static void disable_gpio_irq(unsigned int irq)
+{
+ __gpio_mask_irq(irq - IRQ_GPIO_0);
+}
+
+static void mask_and_ack_gpio_irq(unsigned int irq)
+{
+ __gpio_mask_irq(irq - IRQ_GPIO_0);
+ __gpio_ack_irq(irq - IRQ_GPIO_0);
+}
+
+static void end_gpio_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_gpio_irq(irq);
+ }
+}
+
+static unsigned int startup_gpio_irq(unsigned int irq)
+{
+ enable_gpio_irq(irq);
+ return 0;
+}
+
+static void shutdown_gpio_irq(unsigned int irq)
+{
+ disable_gpio_irq(irq);
+}
+
+static struct irq_chip gpio_irq_type = {
+ .typename = "GPIO",
+ .startup = startup_gpio_irq,
+ .shutdown = shutdown_gpio_irq,
+ .unmask = enable_gpio_irq,
+ .mask = disable_gpio_irq,
+ .ack = mask_and_ack_gpio_irq,
+ .end = end_gpio_irq,
+};
+
+/*
+ * DMA irq type
+ */
+
+static void enable_dma_irq(unsigned int irq)
+{
+ unsigned int intc_irq;
+
+ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */
+ intc_irq = IRQ_DMAC0;
+ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */
+ intc_irq = IRQ_DMAC1;
+ else {
+ printk("%s, unexpected dma irq #%d\n", __FILE__, irq);
+ return;
+ }
+ __intc_unmask_irq(intc_irq);
+ __dmac_channel_enable_irq(irq - IRQ_DMA_0);
+}
+
+static void disable_dma_irq(unsigned int irq)
+{
+ __dmac_channel_disable_irq(irq - IRQ_DMA_0);
+}
+
+static void mask_and_ack_dma_irq(unsigned int irq)
+{
+ unsigned int intc_irq;
+
+ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */
+ intc_irq = IRQ_DMAC0;
+ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */
+ intc_irq = IRQ_DMAC1;
+ else {
+ printk("%s, unexpected dma irq #%d\n", __FILE__, irq);
+ return ;
+ }
+ __intc_ack_irq(intc_irq);
+ __dmac_channel_ack_irq(irq-IRQ_DMA_0); /* needed?? add 20080506, Wolfgang */
+ __dmac_channel_disable_irq(irq - IRQ_DMA_0);
+}
+
+static void end_dma_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_dma_irq(irq);
+ }
+}
+
+static unsigned int startup_dma_irq(unsigned int irq)
+{
+ enable_dma_irq(irq);
+ return 0;
+}
+
+static void shutdown_dma_irq(unsigned int irq)
+{
+ disable_dma_irq(irq);
+}
+
+static struct irq_chip dma_irq_type = {
+ .typename = "DMA",
+ .startup = startup_dma_irq,
+ .shutdown = shutdown_dma_irq,
+ .unmask = enable_dma_irq,
+ .mask = disable_dma_irq,
+ .ack = mask_and_ack_dma_irq,
+ .end = end_dma_irq,
+};
+
+//----------------------------------------------------------------------
+
+void __init arch_init_irq(void)
+{
+ int i;
+
+ clear_c0_status(0xff04); /* clear ERL */
+ set_c0_status(0x0400); /* set IP2 */
+
+ /* Set up INTC irq
+ */
+ for (i = 0; i < 32; i++) {
+ disable_intc_irq(i);
+ set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq);
+ }
+
+ /* Set up DMAC irq
+ */
+ for (i = 0; i < NUM_DMA; i++) {
+ disable_dma_irq(IRQ_DMA_0 + i);
+ set_irq_chip_and_handler(IRQ_DMA_0 + i, &dma_irq_type, handle_level_irq);
+ }
+
+ /* Set up GPIO irq
+ */
+ for (i = 0; i < NUM_GPIO; i++) {
+ disable_gpio_irq(IRQ_GPIO_0 + i);
+ set_irq_chip_and_handler(IRQ_GPIO_0 + i, &gpio_irq_type, handle_level_irq);
+ }
+}
+
+static int plat_real_irq(int irq)
+{
+ switch (irq) {
+ case IRQ_GPIO0:
+ irq = __gpio_group_irq(0) + IRQ_GPIO_0;
+ break;
+ case IRQ_GPIO1:
+ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32;
+ break;
+ case IRQ_GPIO2:
+ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64;
+ break;
+ case IRQ_GPIO3:
+ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96;
+ break;
+ case IRQ_GPIO4:
+ irq = __gpio_group_irq(4) + IRQ_GPIO_0 + 128;
+ break;
+ case IRQ_GPIO5:
+ irq = __gpio_group_irq(5) + IRQ_GPIO_0 + 160;
+ break;
+ case IRQ_DMAC0:
+ case IRQ_DMAC1:
+ irq = __dmac_get_irq() + IRQ_DMA_0;
+ break;
+ }
+
+ return irq;
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ int irq = 0;
+ static unsigned long intc_ipr = 0;
+
+ intc_ipr |= REG_INTC_IPR;
+
+ if (!intc_ipr) return;
+
+ irq = ffs(intc_ipr) - 1;
+ intc_ipr &= ~(1<<irq);
+
+ irq = plat_real_irq(irq);
+ do_IRQ(irq);
+}
diff --git a/arch/mips/jz4750d/platform.c b/arch/mips/jz4750d/platform.c
new file mode 100644
index 00000000000..a725c18a727
--- /dev/null
+++ b/arch/mips/jz4750d/platform.c
@@ -0,0 +1,172 @@
+/*
+ * Platform device support for Jz4740 SoC.
+ *
+ * Copyright 2007, <yliu@ingenic.cn>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/resource.h>
+
+#include <asm/jzsoc.h>
+#if 0
+/* OHCI (USB full speed host controller) */
+static struct resource jz_usb_ohci_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap
+ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_UHC,
+ .end = IRQ_UHC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32)0;
+
+static struct platform_device jz_usb_ohci_device = {
+ .name = "jz-ohci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ohci_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources),
+ .resource = jz_usb_ohci_resources,
+};
+#endif
+/*** LCD controller ***/
+static struct resource jz_lcd_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(LCD_BASE),
+ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_LCD,
+ .end = IRQ_LCD,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 jz_lcd_dmamask = ~(u32)0;
+
+static struct platform_device jz_lcd_device = {
+ .name = "jz-lcd",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_lcd_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_lcd_resources),
+ .resource = jz_lcd_resources,
+};
+
+/* UDC (USB gadget controller) */
+static struct resource jz_usb_gdt_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(UDC_BASE),
+ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_UDC,
+ .end = IRQ_UDC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 udc_dmamask = ~(u32)0;
+
+static struct platform_device jz_usb_gdt_device = {
+ .name = "jz-udc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &udc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources),
+ .resource = jz_usb_gdt_resources,
+};
+
+/** MMC/SD controller **/
+static struct resource jz_mmc_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(MSC_BASE),
+ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_MSC0,
+ .end = IRQ_MSC0,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 jz_mmc_dmamask = ~(u32)0;
+
+static struct platform_device jz_mmc_device = {
+ .name = "jz-mmc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_mmc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_mmc_resources),
+ .resource = jz_mmc_resources,
+};
+
+/** I2C controller **/
+static struct resource jz_i2c_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(I2C_BASE),
+ .end = CPHYSADDR(I2C_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+#if 0
+ [1] = {
+ .start = IRQ_I2C,
+ .end = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ }
+#endif
+};
+
+static u64 jz_i2c_dmamask = ~(u32)0;
+static struct platform_device jz_i2c_device = {
+ .name = "jz_i2c",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_i2c_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_i2c_resources),
+ .resource = jz_i2c_resources,
+};
+
+
+
+/* All */
+static struct platform_device *jz_platform_devices[] __initdata = {
+// &jz_usb_ohci_device,
+ &jz_lcd_device,
+ &jz_usb_gdt_device,
+ &jz_mmc_device,
+ &jz_i2c_device,
+};
+
+static int __init jz_platform_init(void)
+{
+ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
+}
+
+arch_initcall(jz_platform_init);
diff --git a/arch/mips/jz4750d/pm.c b/arch/mips/jz4750d/pm.c
new file mode 100644
index 00000000000..611fcadfebf
--- /dev/null
+++ b/arch/mips/jz4750d/pm.c
@@ -0,0 +1,400 @@
+/*
+ * linux/arch/mips/jz4750d/common/pm.c
+ *
+ * JZ4750D Power Management Routines
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/suspend.h>
+
+#include <asm/cacheops.h>
+#include <asm/jzsoc.h>
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+#define GPIO_PORT_NUM 6
+
+/*
+ * __gpio_as_sleep set all pins to pull-disable, and set all pins as input
+ * except sdram and the pins which can be used as CS1_N to CS4_N for chip select.
+ */
+#define __gpio_as_sleep() \
+do { \
+ REG_GPIO_PXFUNC(1) = ~0x03ff7fff; \
+ REG_GPIO_PXSELC(1) = ~0x03ff7fff; \
+ REG_GPIO_PXDIRC(1) = ~0x03ff7fff; \
+ REG_GPIO_PXPES(1) = 0xffffffff; \
+ REG_GPIO_PXFUNC(2) = ~0x01e00000; \
+ REG_GPIO_PXSELC(2) = ~0x01e00000; \
+ REG_GPIO_PXDIRC(2) = ~0x01e00000; \
+ REG_GPIO_PXPES(2) = 0xffffffff; \
+ REG_GPIO_PXFUNC(3) = 0xffffffff; \
+ REG_GPIO_PXSELC(3) = 0xffffffff; \
+ REG_GPIO_PXDIRC(3) = 0xffffffff; \
+ REG_GPIO_PXPES(3) = 0xffffffff; \
+ REG_GPIO_PXFUNC(4) = 0xffffffff; \
+ REG_GPIO_PXSELC(4) = 0xffffffff; \
+ REG_GPIO_PXDIRC(4) = 0xffffffff; \
+ REG_GPIO_PXPES(4) = 0xffffffff; \
+ REG_GPIO_PXFUNC(5) = 0xffffffff; \
+ REG_GPIO_PXSELC(5) = 0xffffffff; \
+ REG_GPIO_PXDIRC(5) = 0xffffffff; \
+ REG_GPIO_PXPES(5) = 0xffffffff; \
+} while (0)
+
+static int jz_pm_do_hibernate(void)
+{
+ printk("Put CPU into hibernate mode.\n");
+
+ /* Mask all interrupts */
+ REG_INTC_IMSR = 0xffffffff;
+
+ /*
+ * RTC Wakeup or 1Hz interrupt can be enabled or disabled
+ * through RTC driver's ioctl (linux/driver/char/rtc_jz.c).
+ */
+
+ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT);
+
+ /* Set reset pin low-level assertion time after wakeup: must > 60ms */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */
+
+ /* Scratch pad register to be reserved */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HSPR = 0x12345678;
+
+ /* clear wakeup status register */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HWRSR = 0x0;
+
+ /* Put CPU to power down mode */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HCR = RTC_HCR_PD;
+
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ while(1);
+
+ /* We can't get here */
+ return 0;
+}
+
+/* NOTES:
+ * 1: Pins that are floated (NC) should be set as input and pull-enable.
+ * 2: Pins that are pull-up or pull-down by outside should be set as input
+ * and pull-disable.
+ * 3: Pins that are connected to a chip except sdram and nand flash
+ * should be set as input and pull-disable, too.
+ */
+static void jz_board_do_sleep(unsigned long *ptr)
+{
+ unsigned char i;
+
+ /* Print messages of GPIO registers for debug */
+ for(i=0;i<GPIO_PORT_NUM;i++) {
+ dprintk("run dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
+ }
+
+ /* Save GPIO registers */
+ for(i = 1; i < GPIO_PORT_NUM; i++) {
+ *ptr++ = REG_GPIO_PXFUN(i);
+ *ptr++ = REG_GPIO_PXSEL(i);
+ *ptr++ = REG_GPIO_PXDIR(i);
+ *ptr++ = REG_GPIO_PXPE(i);
+ *ptr++ = REG_GPIO_PXIM(i);
+ *ptr++ = REG_GPIO_PXDAT(i);
+ *ptr++ = REG_GPIO_PXTRG(i);
+ }
+
+ /*
+ * Set all pins to pull-disable, and set all pins as input except
+ * sdram and the pins which can be used as CS1_N to CS4_N for chip select.
+ */
+ __gpio_as_sleep();
+
+ /*
+ * Set proper status for GPC21 to GPC24 which can be used as CS1_N to CS4_N.
+ * Keep the pins' function used for chip select(CS) here according to your
+ * system to avoid chip select crashing with sdram when resuming from sleep mode.
+ */
+
+#if defined(CONFIG_JZ4750D_APUS)
+ /* GPB25/CS1_N is used as chip select for nand flash, shouldn't be change. */
+
+ /* GPB26/CS2_N is connected to nand flash, needn't be changed. */
+
+ /* GPB28/CS3_N is used as cs8900's chip select, shouldn't be changed. */
+
+ /* GPB27/CS4_N is used as NOR's chip select, shouldn't be changed. */
+#endif
+
+ /*
+ * Enable pull for NC pins here according to your system
+ */
+
+#if defined(CONFIG_JZ4750D_APUS)
+#endif
+
+ /*
+ * If you must set some GPIOs as output to high level or low level,
+ * you can set them here, using:
+ * __gpio_as_output(n);
+ * __gpio_set_pin(n); or __gpio_clear_pin(n);
+ */
+
+#if defined(CONFIG_JZ4750D_APUS)
+ /* GPC7 which is used as AMPEN_N should be set to high to disable audio amplifier */
+ __gpio_as_output(32*2+7);
+ __gpio_set_pin(32*2+7);
+#endif
+
+#ifdef DEBUG
+ /* Keep uart function for printing debug message */
+ __gpio_as_uart0();
+ __gpio_as_uart1();
+ __gpio_as_uart2();
+ __gpio_as_uart3();
+
+ /* Print messages of GPIO registers for debug */
+ for(i=0;i<GPIO_PORT_NUM;i++) {
+ dprintk("sleep dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
+ }
+#endif
+}
+
+static void jz_board_do_resume(unsigned long *ptr)
+{
+ unsigned char i;
+
+ /* Restore GPIO registers */
+ for(i = 1; i < GPIO_PORT_NUM; i++) {
+ REG_GPIO_PXFUNS(i) = *ptr;
+ REG_GPIO_PXFUNC(i) = ~(*ptr++);
+
+ REG_GPIO_PXSELS(i) = *ptr;
+ REG_GPIO_PXSELC(i) = ~(*ptr++);
+
+ REG_GPIO_PXDIRS(i) = *ptr;
+ REG_GPIO_PXDIRC(i) = ~(*ptr++);
+
+ REG_GPIO_PXPES(i) = *ptr;
+ REG_GPIO_PXPEC(i) = ~(*ptr++);
+
+ REG_GPIO_PXIMS(i)=*ptr;
+ REG_GPIO_PXIMC(i)=~(*ptr++);
+
+ REG_GPIO_PXDATS(i)=*ptr;
+ REG_GPIO_PXDATC(i)=~(*ptr++);
+
+ REG_GPIO_PXTRGS(i)=*ptr;
+ REG_GPIO_PXTRGC(i)=~(*ptr++);
+ }
+
+ /* Print messages of GPIO registers for debug */
+ for(i=0;i<GPIO_PORT_NUM;i++) {
+ dprintk("resume dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
+ }
+}
+
+
+
+static int jz_pm_do_sleep(void)
+{
+ unsigned long delta;
+ unsigned long nfcsr = REG_EMC_NFCSR;
+ unsigned long opcr = REG_CPM_OPCR;
+ unsigned long imr = REG_INTC_IMR;
+ unsigned long sadc = REG_SADC_ENA;
+ unsigned long sleep_gpio_save[7*(GPIO_PORT_NUM-1)];
+
+ printk("Put CPU into sleep mode.\n");
+
+ /* Preserve current time */
+ delta = xtime.tv_sec - REG_RTC_RSR;
+
+ /* Disable nand flash */
+ REG_EMC_NFCSR = ~0xff;
+
+ /* stop sadc */
+ REG_SADC_ENA &= ~0x7;
+ while((REG_SADC_ENA & 0x7) != 0);
+ udelay(100);
+
+ /*stop udc and usb*/
+ __cpm_suspend_uhcphy();
+ __cpm_suspend_udcphy();
+
+ /* Sleep on-board modules */
+ jz_board_do_sleep(sleep_gpio_save);
+
+ /* Mask all interrupts */
+ REG_INTC_IMSR = 0xffffffff;
+
+ /* Just allow following interrupts to wakeup the system.
+ * Note: modify this according to your system.
+ */
+
+ /* enable RTC alarm */
+ __intc_unmask_irq(IRQ_RTC);
+#if 0
+ /* make system wake up after n seconds by RTC alarm */
+ unsigned int v, n;
+ n = 10;
+ while (!__rtc_write_ready());
+ __rtc_enable_alarm();
+ while (!__rtc_write_ready());
+ __rtc_enable_alarm_irq();
+ while (!__rtc_write_ready());
+ v = __rtc_get_second();
+ while (!__rtc_write_ready());
+ __rtc_set_alarm_second(v+n);
+#endif
+
+ /* WAKEUP key */
+ __gpio_as_irq_rise_edge(GPIO_WAKEUP);
+ __gpio_unmask_irq(GPIO_WAKEUP);
+ __intc_unmask_irq(IRQ_GPIO0 - (GPIO_WAKEUP/32)); /* unmask IRQ_GPIOn depends on GPIO_WAKEUP */
+
+ /* disable externel clock Oscillator in sleep mode */
+ __cpm_disable_osc_in_sleep();
+ /* select 32K crystal as RTC clock in sleep mode */
+ __cpm_select_rtcclk_rtc();
+
+ /* Enter SLEEP mode */
+ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
+ REG_CPM_LCR |= CPM_LCR_LPM_SLEEP;
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0");
+
+ /* Restore to IDLE mode */
+ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
+ REG_CPM_LCR |= CPM_LCR_LPM_IDLE;
+
+ /* Restore nand flash control register */
+ REG_EMC_NFCSR = nfcsr;
+
+ /* Restore interrupts */
+ REG_INTC_IMSR = imr;
+ REG_INTC_IMCR = ~imr;
+
+ /* Restore sadc */
+ REG_SADC_ENA = sadc;
+
+ /* Resume on-board modules */
+ jz_board_do_resume(sleep_gpio_save);
+
+ /* Restore Oscillator and Power Control Register */
+ REG_CPM_OPCR = opcr;
+
+ /* Restore current time */
+ xtime.tv_sec = REG_RTC_RSR + delta;
+
+ return 0;
+}
+
+/* Put CPU to HIBERNATE mode */
+int jz_pm_hibernate(void)
+{
+ return jz_pm_do_hibernate();
+}
+
+#ifndef CONFIG_JZ_POWEROFF
+static irqreturn_t pm_irq_handler (int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+#endif
+
+/* Put CPU to SLEEP mode */
+int jz_pm_sleep(void)
+{
+ int retval;
+
+#ifndef CONFIG_JZ_POWEROFF
+ if ((retval = request_irq (IRQ_GPIO_0 + GPIO_WAKEUP, pm_irq_handler, IRQF_DISABLED,
+ "PM", NULL))) {
+ printk ("PM could not get IRQ for GPIO_WAKEUP\n");
+ return retval;
+ }
+#endif
+
+ retval = jz_pm_do_sleep();
+
+#ifndef CONFIG_JZ_POWEROFF
+ free_irq (IRQ_GPIO_0 + GPIO_WAKEUP, NULL);
+#endif
+
+ return retval;
+}
+
+/*
+ * valid states, only support mem(sleep)
+ */
+static int jz_pm_valid(suspend_state_t state)
+{
+ return state == PM_SUSPEND_MEM;
+}
+
+/*
+ * Jz CPU enter save power mode
+ */
+static int jz_pm_enter(suspend_state_t state)
+{
+ return jz_pm_sleep();
+}
+
+static struct platform_suspend_ops jz_pm_ops = {
+ .valid = jz_pm_valid,
+ .enter = jz_pm_enter,
+};
+
+/*
+ * Initialize power interface
+ */
+int __init jz_pm_init(void)
+{
+ printk(JZ_SOC_NAME ": Power Management Interface Registered.\n");
+
+ suspend_set_ops(&jz_pm_ops);
+
+ return 0;
+}
+
+module_init(jz_pm_init);
diff --git a/arch/mips/jz4750d/proc.c b/arch/mips/jz4750d/proc.c
new file mode 100644
index 00000000000..51e4678a442
--- /dev/null
+++ b/arch/mips/jz4750d/proc.c
@@ -0,0 +1,1112 @@
+/*
+ * linux/arch/mips/jz4750d/proc.c
+ *
+ * /proc/jz/ procfs for jz4750d on-chip modules.
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/page-flags.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/jzsoc.h>
+
+//#define DEBUG 1
+#undef DEBUG
+
+
+struct proc_dir_entry *proc_jz_root;
+
+
+/*
+ * EMC Modules
+ */
+static int emc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4);
+ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4);
+ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR);
+ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR);
+ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR);
+ return len;
+}
+
+/*
+ * Power Manager Module
+ */
+static int pmc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long lcr = REG_CPM_LCR;
+ unsigned long clkgr = REG_CPM_CLKGR;
+
+ len += sprintf (page+len, "Low Power Mode : %s\n",
+ ((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ?
+ "IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ?
+ "SLEEP" : "HIBERNATE"));
+ len += sprintf (page+len, "Doze Mode : %s\n",
+ (lcr & CPM_LCR_DOZE_ON) ? "on" : "off");
+ if (lcr & CPM_LCR_DOZE_ON)
+ len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT));
+ len += sprintf (page+len, "AUX_CPU : %s\n",
+ (clkgr & CPM_CLKGR_AUX_CPU) ? "stopped" : "running");
+ len += sprintf (page+len, "AHB1 : %s\n",
+ (clkgr & CPM_CLKGR_AHB1) ? "stopped" : "running");
+ len += sprintf (page+len, "IDCT : %s\n",
+ (clkgr & CPM_CLKGR_IDCT) ? "stopped" : "running");
+ len += sprintf (page+len, "DB : %s\n",
+ (clkgr & CPM_CLKGR_DB) ? "stopped" : "running");
+ len += sprintf (page+len, "ME : %s\n",
+ (clkgr & CPM_CLKGR_ME) ? "stopped" : "running");
+ len += sprintf (page+len, "MC : %s\n",
+ (clkgr & CPM_CLKGR_MC) ? "stopped" : "running");
+ len += sprintf (page+len, "TVE : %s\n",
+ (clkgr & CPM_CLKGR_TVE) ? "stopped" : "running");
+ len += sprintf (page+len, "TSSI : %s\n",
+ (clkgr & CPM_CLKGR_TSSI) ? "stopped" : "running");
+ len += sprintf (page+len, "IPU : %s\n",
+ (clkgr & CPM_CLKGR_IPU) ? "stopped" : "running");
+ len += sprintf (page+len, "DMAC : %s\n",
+ (clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running");
+ len += sprintf (page+len, "UDC : %s\n",
+ (clkgr & CPM_CLKGR_UDC) ? "stopped" : "running");
+ len += sprintf (page+len, "LCD : %s\n",
+ (clkgr & CPM_CLKGR_LCD) ? "stopped" : "running");
+ len += sprintf (page+len, "CIM : %s\n",
+ (clkgr & CPM_CLKGR_CIM) ? "stopped" : "running");
+ len += sprintf (page+len, "SADC : %s\n",
+ (clkgr & CPM_CLKGR_SADC) ? "stopped" : "running");
+ len += sprintf (page+len, "MSC0 : %s\n",
+ (clkgr & CPM_CLKGR_MSC0) ? "stopped" : "running");
+ len += sprintf (page+len, "MSC1 : %s\n",
+ (clkgr & CPM_CLKGR_MSC1) ? "stopped" : "running");
+ len += sprintf (page+len, "SSI : %s\n",
+ (clkgr & CPM_CLKGR_SSI) ? "stopped" : "running");
+ len += sprintf (page+len, "I2C : %s\n",
+ (clkgr & CPM_CLKGR_I2C) ? "stopped" : "running");
+ len += sprintf (page+len, "RTC : %s\n",
+ (clkgr & CPM_CLKGR_RTC) ? "stopped" : "running");
+ len += sprintf (page+len, "TCU : %s\n",
+ (clkgr & CPM_CLKGR_TCU) ? "stopped" : "running");
+ len += sprintf (page+len, "UART1 : %s\n",
+ (clkgr & CPM_CLKGR_UART1) ? "stopped" : "running");
+ len += sprintf (page+len, "UART0 : %s\n",
+ (clkgr & CPM_CLKGR_UART0) ? "stopped" : "running");
+ return len;
+}
+
+static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16);
+ return count;
+}
+
+/*
+ * Clock Generation Module
+ */
+#define TO_MHZ(x) (x/1000000),(x%1000000)/10000
+#define TO_KHZ(x) (x/1000),(x%1000)/10
+
+static int cgm_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */
+ unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */
+ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned int od[4] = {1, 2, 2, 4};
+
+ len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr);
+ len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr);
+ len += sprintf (page+len, "PLL : %s\n",
+ (cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF");
+ len += sprintf (page+len, "m:n:o : %d:%d:%d\n",
+ __cpm_get_pllm() + 2,
+ __cpm_get_plln() + 2,
+ od[__cpm_get_pllod()]
+ );
+ len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n",
+ div[__cpm_get_cdiv()],
+ div[__cpm_get_hdiv()],
+ div[__cpm_get_mdiv()],
+ div[__cpm_get_pdiv()]
+ );
+ len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout()));
+ len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk()));
+ len += sprintf (page+len, "HCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_hclk()));
+ len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk()));
+ len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk()));
+ len += sprintf (page+len, "H1CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_h1clk()));
+ len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk()));
+ len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk()));
+ len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk()));
+ len += sprintf (page+len, "MSC0CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(0)));
+ len += sprintf (page+len, "MSC1CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(1)));
+ len += sprintf (page+len, "EXTALCLK0 : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk0()));
+ len += sprintf (page+len, "EXTALCLK(by CPM): %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk()));
+ len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk()));
+
+ return len;
+}
+
+static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16);
+ return count;
+}
+
+
+/* USAGE:
+ * echo n > /proc/jz/ipu // n = [1,...,9], alloc mem, 2^n pages.
+ * echo FF > /proc/jz/ipu // 255, free all buffer
+ * echo xxxx > /proc/jz/ipu // free buffer which addr is xxxx
+ * echo llll > /proc/jz/ipu // add_wired_entry(l,l,l,l)
+ * echo 0 > /proc/jz/ipu // debug, print ipu_buf
+ * od -X /proc/jz/ipu // read mem addr
+ */
+
+typedef struct _ipu_buf {
+ unsigned int addr; /* phys addr */
+ unsigned int page_shift;
+} ipu_buf_t;
+
+#define IPU_BUF_MAX 4 /* 4 buffers */
+
+static struct _ipu_buf ipu_buf[IPU_BUF_MAX];
+static int ipu_buf_cnt = 0;
+static unsigned char g_asid=0;
+
+extern void local_flush_tlb_all(void);
+
+/* CP0 hazard avoidance. */
+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
+ "nop; nop; nop; nop; nop; nop;\n\t" \
+ ".set reorder\n\t")
+void show_tlb(void)
+{
+#define ASID_MASK 0xFF
+
+ unsigned long flags;
+ unsigned int old_ctx;
+ unsigned int entry;
+ unsigned int entrylo0, entrylo1, entryhi;
+ unsigned int pagemask;
+
+ local_irq_save(flags);
+
+ /* Save old context */
+ old_ctx = (read_c0_entryhi() & 0xff);
+
+ printk("TLB content:\n");
+ entry = 0;
+ while(entry < 32) {
+ write_c0_index(entry);
+ BARRIER;
+ tlb_read();
+ BARRIER;
+ entryhi = read_c0_entryhi();
+ entrylo0 = read_c0_entrylo0();
+ entrylo1 = read_c0_entrylo1();
+ pagemask = read_c0_pagemask();
+ printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK);
+ printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : "");
+ printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : "");
+
+ printk("\t\tpagemask=0x%08x", pagemask);
+ printk("\tentryhi=0x%08x\n", entryhi);
+ printk("\t\tentrylo0=0x%08x", entrylo0);
+ printk("\tentrylo1=0x%08x\n", entrylo1);
+
+ entry++;
+ }
+ BARRIER;
+ write_c0_entryhi(old_ctx);
+
+ local_irq_restore(flags);
+}
+
+static void ipu_add_wired_entry(unsigned long pid,
+ unsigned long entrylo0, unsigned long entrylo1,
+ unsigned long entryhi, unsigned long pagemask)
+{
+ unsigned long flags;
+ unsigned long wired;
+ unsigned long old_pagemask;
+ unsigned long old_ctx;
+ struct task_struct *g, *p;
+
+ /* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */
+ entrylo0 = entrylo0 >> 6;
+ entrylo0 |= 0x6 | (0 << 3);
+
+ do_each_thread(g, p) {
+ if (p->pid == pid )
+ g_asid = p->mm->context[0];
+ } while_each_thread(g, p);
+
+ local_irq_save(flags);
+ /* Save old context and create impossible VPN2 value */
+ old_ctx = read_c0_entryhi() & 0xff;
+ old_pagemask = read_c0_pagemask();
+ wired = read_c0_wired();
+ write_c0_wired(wired + 1);
+ write_c0_index(wired);
+ BARRIER;
+ entryhi &= ~0xff; /* new add, 20070906 */
+ entryhi |= g_asid; /* new add, 20070906 */
+// entryhi |= old_ctx; /* new add, 20070906 */
+ write_c0_pagemask(pagemask);
+ write_c0_entryhi(entryhi);
+ write_c0_entrylo0(entrylo0);
+ write_c0_entrylo1(entrylo1);
+ BARRIER;
+ tlb_write_indexed();
+ BARRIER;
+
+ write_c0_entryhi(old_ctx);
+ BARRIER;
+ write_c0_pagemask(old_pagemask);
+ local_flush_tlb_all();
+ local_irq_restore(flags);
+#if defined(DEBUG)
+ printk("\nold_ctx=%03d\n", old_ctx);
+
+ show_tlb();
+#endif
+}
+
+static void ipu_del_wired_entry( void )
+{
+ unsigned long flags;
+ unsigned long wired;
+
+ local_irq_save(flags);
+ wired = read_c0_wired();
+ if ( wired > 0 ) {
+ write_c0_wired(wired - 1);
+ }
+ local_irq_restore(flags);
+}
+
+static inline void ipu_buf_get( unsigned int page_shift )
+{
+ unsigned char * virt_addr;
+ int i;
+ for ( i=0; i< IPU_BUF_MAX; ++i ) {
+ if ( ipu_buf[i].addr == 0 ) {
+ break;
+ }
+ }
+
+ if ( (ipu_buf_cnt = i) == IPU_BUF_MAX ) {
+ printk("Error, no free ipu buffer.\n");
+ return ;
+ }
+
+ virt_addr = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift);
+
+ if ( virt_addr ) {
+ ipu_buf[ipu_buf_cnt].addr = (unsigned int)virt_to_phys((void *)virt_addr);
+ ipu_buf[ipu_buf_cnt].page_shift = page_shift;
+
+ for (i = 0; i < (1<<page_shift); i++) {
+ SetPageReserved(virt_to_page(virt_addr));
+ virt_addr += PAGE_SIZE;
+ }
+ }
+ else {
+ printk("get memory Failed.\n");
+ }
+}
+
+static inline void ipu_buf_free( unsigned int phys_addr )
+{
+ unsigned char * virt_addr, *addr;
+ int cnt, i;
+
+ if ( phys_addr == 0 )
+ return ;
+
+ for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt )
+ if ( phys_addr == ipu_buf[cnt].addr )
+ break;
+
+ if ( cnt == IPU_BUF_MAX ) { /* addr not in the ipu buffers */
+ printk("Invalid addr:0x%08x\n", (unsigned int)phys_addr);
+ }
+
+ virt_addr = (unsigned char *)phys_to_virt(ipu_buf[cnt].addr);
+ addr = virt_addr;
+ for (i = 0; i < (1<<ipu_buf[cnt].page_shift); i++) {
+ ClearPageReserved(virt_to_page(addr));
+ addr += PAGE_SIZE;
+ }
+
+ if ( cnt == 0 )
+ ipu_del_wired_entry();
+
+ free_pages((unsigned long )virt_addr, ipu_buf[cnt].page_shift);
+
+ ipu_buf[cnt].addr = 0;
+ ipu_buf[cnt].page_shift = 0;
+}
+
+static int ipu_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ /* read as binary */
+ unsigned int * pint;
+ pint = (unsigned int *) (page+len);
+
+ if ( ipu_buf_cnt >= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */
+ printk("no free buffer.\n");
+ *pint = 0;
+ }
+ else
+ *pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */
+ len += sizeof(unsigned int);
+
+#if defined(DEBUG)
+ show_tlb();
+#endif
+ return len;
+
+}
+
+static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ unsigned int val ;
+ int cnt,i;
+ char buf[12];
+ unsigned long pid, entrylo0, entrylo1, entryhi, pagemask;
+#if defined(DEBUG)
+ printk("ipu write count=%u\n", count);
+#endif
+ if (count == 41) {
+ for (i=0;i<12;i++)
+ buf[i]=0;
+ strncpy(buf, buffer+8*0, 8);
+ pid = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++)
+ buf[i]=0;
+ strncpy(buf, buffer+8*1, 8);
+ entrylo0 = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++)
+ buf[i]=0;
+ strncpy(buf, buffer+8*2, 8);
+ entrylo1 = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++)
+ buf[i]=0;
+ strncpy(buf, buffer+8*3, 8);
+ entryhi = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++)
+ buf[i]=0;
+ strncpy(buf, buffer+8*4, 8);
+ pagemask = simple_strtoul(buf, 0, 16);
+
+#if defined(DEBUG)
+ printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n",
+ pid, entrylo0, entrylo1, entryhi, pagemask);
+#endif
+ ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask);
+ return 41;
+ } else if ( count <= 9 ) {
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer, 8);
+ val = simple_strtoul(buf, 0, 16);
+ } else if (count == 44) {
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer, 10);
+ pid = simple_strtoul(buf, 0, 16);
+
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer + 11, 10);
+ entryhi = simple_strtoul(buf, 0, 16);//vaddr
+
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer + 22, 10);
+ entrylo0 = simple_strtoul(buf, 0, 16);//paddr
+
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer + 33, 10);
+ pagemask = simple_strtoul(buf, 0, 16);
+ //pagemask = 0x3ff << 13; /* Fixed to 4MB page size */
+ pagemask = 0xfff << 13; /* Fixed to 16MB page size */
+
+ ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask);
+ return 44;
+ } else if (count == 12) {
+ printk("\necho release tlb > /proc/jz/ipu\n");
+ ipu_del_wired_entry();
+ return 12;
+ } else {
+ printk("ipu write count error, count=%d\n.", (unsigned int)count);
+ return -1;
+ }
+
+ /* val: 1-9, page_shift, val>= 10: ipu_buf.addr */
+ if ( val == 0 ) { /* debug, print ipu_buf info */
+ for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt)
+ printk("ipu_buf[%d]: addr=0x%08x, page_shift=%d\n",
+ cnt, ipu_buf[cnt].addr, ipu_buf[cnt].page_shift );
+#if defined(DEBUG)
+ show_tlb();
+#endif
+ }
+ else if ( 0< val && val < 10 ) {
+ ipu_buf_get(val);
+ }
+ else if ( val == 0xff ) { /* 255: free all ipu_buf */
+ for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt ) {
+ ipu_buf_free(ipu_buf[cnt].addr);
+ }
+ }
+ else {
+ ipu_buf_free(val);
+ }
+
+ return count;
+}
+
+/*
+ * UDC hotplug
+ */
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+extern int jz_udc_active; /* defined in drivers/char/jzchar/jz_udc_hotplug.c */
+#endif
+
+#ifndef GPIO_UDC_HOTPLUG
+#define GPIO_UDC_HOTPLUG 86
+#endif
+
+static int udc_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ if (__gpio_get_pin(GPIO_UDC_HOTPLUG)) {
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+
+ /* Cable has connected, wait for disconnection. */
+ __gpio_as_irq_fall_edge(GPIO_UDC_HOTPLUG);
+
+ if (jz_udc_active)
+ len += sprintf (page+len, "CONNECT_CABLE\n");
+ else
+ len += sprintf (page+len, "CONNECT_POWER\n");
+#else
+ len += sprintf (page+len, "CONNECT\n");
+#endif
+ }
+ else {
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+ /* Cable has disconnected, wait for connection. */
+ __gpio_as_irq_rise_edge(GPIO_UDC_HOTPLUG);
+#endif
+
+ len += sprintf (page+len, "REMOVE\n");
+ }
+
+ return len;
+}
+
+/*
+ * MMC/SD hotplug
+ */
+
+#ifndef MSC_HOTPLUG_PIN
+#define MSC_HOTPLUG_PIN 90
+#endif
+
+static int mmc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ if (__gpio_get_pin(MSC_HOTPLUG_PIN))
+ len += sprintf (page+len, "REMOVE\n");
+ else
+ len += sprintf (page+len, "INSERT\n");
+
+ return len;
+}
+
+/***********************************************************************
+ * IPU memory management (used by mplayer and other apps)
+ *
+ * We reserved 4MB memory for IPU
+ * The memory base address is jz_ipu_framebuf
+ */
+
+/* Usage:
+ *
+ * echo n > /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages
+ * echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx
+ * echo FF > /proc/jz/ipu // FF, free all buffers
+ * od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer
+ */
+
+//#define DEBUG_IMEM 1
+
+#define IMEM0_MAX_ORDER 12 /* max 2^12 * 4096 = 16MB */
+static unsigned int jz_imem0_base; /* physical base address of ipu memory */
+static unsigned int allocated_phys_addr0 = 0;
+
+/*
+ * Allocated buffer list
+ */
+typedef struct imem_list {
+ unsigned int phys_start; /* physical start addr */
+ unsigned int phys_end; /* physical end addr */
+ struct imem_list *next;
+} imem_list_t;
+
+static struct imem_list *imem0_list_head = NULL; /* up sorted by phys_start */
+
+#define IMEM1_MAX_ORDER 11 /* max 2^11 * 4096 = 8MB */
+static unsigned int jz_imem1_base; /* physical base address of ipu memory */
+static unsigned int allocated_phys_addr1 = 0;
+static struct imem_list *imem1_list_head = NULL; /* up sorted by phys_start */
+
+#ifdef DEBUG_IMEM
+static void dump_imem_list(void)
+{
+ struct imem_list *imem;
+
+ printk("*** dump_imem_list 0x%x ***\n", (u32)imem0_list_head);
+ imem = imem0_list_head;
+ while (imem) {
+ printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next);
+ imem = imem->next;
+ }
+
+
+ printk("*** dump_imem_list 0x%x ***\n", (u32)imem1_list_head);
+ imem = imem1_list_head;
+ while (imem) {
+ printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next);
+ imem = imem->next;
+ }
+
+}
+#endif
+
+/* allocate 2^order pages inside the 4MB memory */
+
+static int imem0_alloc(unsigned int order)
+{
+ int alloc_ok = 0;
+ unsigned int start, end;
+ unsigned int size = (1 << order) * PAGE_SIZE;
+ struct imem_list *imem, *imemn, *imemp;
+
+ allocated_phys_addr0 = 0;
+
+ start = jz_imem0_base;
+ end = start + (1 << IMEM0_MAX_ORDER) * PAGE_SIZE;
+
+ imem = imem0_list_head;
+ while (imem) {
+ if ((imem->phys_start - start) >= size) {
+ /* we got a valid address range */
+ alloc_ok = 1;
+ break;
+ }
+
+ start = imem->phys_end + 1;
+ imem = imem->next;
+ }
+
+ if (!alloc_ok) {
+ if ((end - start) >= size)
+ alloc_ok = 1;
+ }
+
+ if (alloc_ok) {
+ end = start + size - 1;
+ allocated_phys_addr0 = start;
+
+ /* add to imem_list, up sorted by phys_start */
+ imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL);
+ if (!imemn) {
+ return -ENOMEM;
+ }
+ imemn->phys_start = start;
+ imemn->phys_end = end;
+ imemn->next = NULL;
+
+ if (!imem0_list_head)
+ imem0_list_head = imemn;
+ else {
+ imem = imemp = imem0_list_head;
+ while (imem) {
+ if (start < imem->phys_start) {
+ break;
+ }
+
+ imemp = imem;
+ imem = imem->next;
+ }
+
+ if (imem == imem0_list_head) {
+ imem0_list_head = imemn;
+ imemn->next = imem;
+ }
+ else {
+ imemn->next = imemp->next;
+ imemp->next = imemn;
+ }
+ }
+ }
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+ return 0;
+}
+
+/* allocate 2^order pages inside the 4MB memory */
+static int imem1_alloc(unsigned int order)
+{
+ int alloc_ok = 0;
+ unsigned int start, end;
+ unsigned int size = (1 << order) * PAGE_SIZE;
+ struct imem_list *imem, *imemn, *imemp;
+
+ allocated_phys_addr1 = 0;
+
+ start = jz_imem1_base;
+ end = start + (1 << IMEM1_MAX_ORDER) * PAGE_SIZE;
+
+ imem = imem1_list_head;
+ while (imem) {
+ if ((imem->phys_start - start) >= size) {
+ /* we got a valid address range */
+ alloc_ok = 1;
+ break;
+ }
+
+ start = imem->phys_end + 1;
+ imem = imem->next;
+ }
+
+ if (!alloc_ok) {
+ if ((end - start) >= size)
+ alloc_ok = 1;
+ }
+
+ if (alloc_ok) {
+ end = start + size - 1;
+ allocated_phys_addr1 = start;
+
+ /* add to imem_list, up sorted by phys_start */
+ imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL);
+ if (!imemn) {
+ return -ENOMEM;
+ }
+ imemn->phys_start = start;
+ imemn->phys_end = end;
+ imemn->next = NULL;
+
+ if (!imem1_list_head)
+ imem1_list_head = imemn;
+ else {
+ imem = imemp = imem1_list_head;
+ while (imem) {
+ if (start < imem->phys_start) {
+ break;
+ }
+
+ imemp = imem;
+ imem = imem->next;
+ }
+
+ if (imem == imem1_list_head) {
+ imem1_list_head = imemn;
+ imemn->next = imem;
+ }
+ else {
+ imemn->next = imemp->next;
+ imemp->next = imemn;
+ }
+ }
+ }
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+ return 0;
+}
+
+
+static void imem_free(unsigned int phys_addr)
+{
+ struct imem_list *imem, *imemp;
+
+ imem = imemp = imem0_list_head;
+ while (imem) {
+ if (phys_addr == imem->phys_start) {
+ if (imem == imem0_list_head) {
+ imem0_list_head = imem->next;
+ }
+ else {
+ imemp->next = imem->next;
+ }
+
+ kfree(imem);
+ break;
+ }
+
+ imemp = imem;
+ imem = imem->next;
+ }
+
+
+ imem = imemp = imem1_list_head;
+ while (imem) {
+ if (phys_addr == imem->phys_start) {
+ if (imem == imem1_list_head) {
+ imem1_list_head = imem->next;
+ }
+ else {
+ imemp->next = imem->next;
+ }
+
+ kfree(imem);
+ break;
+ }
+
+ imemp = imem;
+ imem = imem->next;
+ }
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+}
+
+static void imem_free_all(void)
+{
+ struct imem_list *imem;
+
+ imem = imem0_list_head;
+ while (imem) {
+ kfree(imem);
+ imem = imem->next;
+ }
+
+ imem0_list_head = NULL;
+
+ allocated_phys_addr0 = 0;
+
+
+
+ imem = imem1_list_head;
+ while (imem) {
+ kfree(imem);
+ imem = imem->next;
+ }
+
+ imem1_list_head = NULL;
+
+ allocated_phys_addr1 = 0;
+
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+}
+
+/*
+ * Return the allocated buffer address and the max order of free buffer
+ */
+static int imem0_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned int start_addr, end_addr, max_order, max_size;
+ struct imem_list *imem;
+
+ unsigned int *tmp = (unsigned int *)(page + len);
+
+ start_addr = jz_imem0_base;
+ end_addr = start_addr + (1 << IMEM0_MAX_ORDER) * PAGE_SIZE;
+
+ if (!imem0_list_head)
+ max_size = end_addr - start_addr;
+ else {
+ max_size = 0;
+ imem = imem0_list_head;
+ while (imem) {
+ if (max_size < (imem->phys_start - start_addr))
+ max_size = imem->phys_start - start_addr;
+
+ start_addr = imem->phys_end + 1;
+ imem = imem->next;
+ }
+
+ if (max_size < (end_addr - start_addr))
+ max_size = end_addr - start_addr;
+ }
+
+ if (max_size > 0) {
+ max_order = get_order(max_size);
+ if (((1 << max_order) * PAGE_SIZE) > max_size)
+ max_order--;
+ }
+ else {
+ max_order = 0xffffffff; /* No any free buffer */
+ }
+
+ *tmp++ = allocated_phys_addr0; /* address allocated by 'echo n > /proc/jz/imem' */
+ *tmp = max_order; /* max order of current free buffers */
+
+ len += 2 * sizeof(unsigned int);
+
+ return len;
+}
+
+static int imem0_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ unsigned int val;
+
+ val = simple_strtoul(buffer, 0, 16);
+
+ if (val == 0xff) {
+ /* free all memory */
+ imem_free_all();
+ ipu_del_wired_entry();
+ } else if ((val >= 0) && (val <= IMEM0_MAX_ORDER)) {
+ /* allocate 2^val pages */
+ imem0_alloc(val);
+ } else {
+ /* free buffer which phys_addr is val */
+ imem_free(val);
+ }
+
+ return count;
+}
+
+/*
+ * Return the allocated buffer address and the max order of free buffer
+ */
+static int imem1_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned int start_addr, end_addr, max_order, max_size;
+ struct imem_list *imem;
+
+ unsigned int *tmp = (unsigned int *)(page + len);
+
+ start_addr = jz_imem1_base;
+ end_addr = start_addr + (1 << IMEM1_MAX_ORDER) * PAGE_SIZE;
+
+ if (!imem1_list_head)
+ max_size = end_addr - start_addr;
+ else {
+ max_size = 0;
+ imem = imem1_list_head;
+ while (imem) {
+ if (max_size < (imem->phys_start - start_addr))
+ max_size = imem->phys_start - start_addr;
+
+ start_addr = imem->phys_end + 1;
+ imem = imem->next;
+ }
+
+ if (max_size < (end_addr - start_addr))
+ max_size = end_addr - start_addr;
+ }
+
+ if (max_size > 0) {
+ max_order = get_order(max_size);
+ if (((1 << max_order) * PAGE_SIZE) > max_size)
+ max_order--;
+ }
+ else {
+ max_order = 0xffffffff; /* No any free buffer */
+ }
+
+ *tmp++ = allocated_phys_addr1; /* address allocated by 'echo n > /proc/jz/imem' */
+ *tmp = max_order; /* max order of current free buffers */
+
+ len += 2 * sizeof(unsigned int);
+
+ return len;
+}
+
+static int imem1_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ unsigned int val;
+
+ val = simple_strtoul(buffer, 0, 16);
+
+ if (val == 0xff) {
+ /* free all memory */
+ imem_free_all();
+ ipu_del_wired_entry();
+ } else if ((val >= 0) && (val <= IMEM1_MAX_ORDER)) {
+ /* allocate 2^val pages */
+ imem1_alloc(val);
+ } else {
+ /* free buffer which phys_addr is val */
+ imem_free(val);
+ }
+
+ return count;
+}
+
+/*
+ * /proc/jz/xxx entry
+ *
+ */
+static int __init jz_proc_init(void)
+{
+ struct proc_dir_entry *res;
+ unsigned int virt_addr, i;
+
+ proc_jz_root = proc_mkdir("jz", 0);
+
+ /* External Memory Controller */
+ res = create_proc_entry("emc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = emc_read_proc;
+ res->write_proc = NULL;
+ res->data = NULL;
+ }
+
+ /* Power Management Controller */
+ res = create_proc_entry("pmc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = pmc_read_proc;
+ res->write_proc = pmc_write_proc;
+ res->data = NULL;
+ }
+
+ /* Clock Generation Module */
+ res = create_proc_entry("cgm", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = cgm_read_proc;
+ res->write_proc = cgm_write_proc;
+ res->data = NULL;
+ }
+
+ /* Image process unit */
+ res = create_proc_entry("ipu", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = ipu_read_proc;
+ res->write_proc = ipu_write_proc;
+ res->data = NULL;
+ }
+
+ /* udc hotplug */
+ res = create_proc_entry("udc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = udc_read_proc;
+ res->write_proc = NULL;
+ res->data = NULL;
+ }
+
+ /* mmc hotplug */
+ res = create_proc_entry("mmc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = mmc_read_proc;
+ res->write_proc = NULL;
+ res->data = NULL;
+ }
+
+#ifdef CONFIG_JZ4750_IPU_MM
+ /*
+ * Reserve a 16MB memory for IPU on JZ4750D.
+ */
+ jz_imem0_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM0_MAX_ORDER);
+ if (jz_imem0_base) {
+ /* imem (IPU memory management) */
+ res = create_proc_entry("imem", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = imem0_read_proc;
+ res->write_proc = imem0_write_proc;
+ res->data = NULL;
+ }
+
+ /* Set page reserved */
+ virt_addr = jz_imem0_base;
+ for (i = 0; i < (1 << IMEM0_MAX_ORDER); i++) {
+ SetPageReserved(virt_to_page((void *)virt_addr));
+ virt_addr += PAGE_SIZE;
+ }
+
+ /* Convert to physical address */
+ jz_imem0_base = virt_to_phys((void *)jz_imem0_base);
+
+ printk("Total %dMB memory at 0x%x was reserved for IPU\n",
+ (unsigned int)((1 << IMEM0_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem0_base);
+ } else
+ printk("NOT enough memory for imem\n");
+
+
+ jz_imem1_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM1_MAX_ORDER);
+ if (jz_imem1_base) {
+ /* imem (IPU memory management) */
+ res = create_proc_entry("imem1", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = imem1_read_proc;
+ res->write_proc = imem1_write_proc;
+ res->data = NULL;
+ }
+
+ /* Set page reserved */
+ virt_addr = jz_imem1_base;
+ for (i = 0; i < (1 << IMEM1_MAX_ORDER); i++) {
+ SetPageReserved(virt_to_page((void *)virt_addr));
+ virt_addr += PAGE_SIZE;
+ }
+
+ /* Convert to physical address */
+ jz_imem1_base = virt_to_phys((void *)jz_imem1_base);
+
+ printk("Total %dMB memory1 at 0x%x was reserved for IPU\n",
+ (unsigned int)((1 << IMEM1_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem1_base);
+ } else
+ printk("NOT enough memory for imem1\n");
+#else
+ jz_imem0_base = jz_imem1_base = NULL;
+#endif
+
+ return 0;
+}
+
+__initcall(jz_proc_init);
diff --git a/arch/mips/jz4750d/prom.c b/arch/mips/jz4750d/prom.c
new file mode 100644
index 00000000000..3c173d6ec4a
--- /dev/null
+++ b/arch/mips/jz4750d/prom.c
@@ -0,0 +1,198 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * PROM library initialisation code, supports YAMON and U-Boot.
+ *
+ * Copyright 2000, 2001, 2006 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * This file was derived from Carsten Langgaard's
+ * arch/mips/mips-boards/xx files.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/jzsoc.h>
+
+/* #define DEBUG_CMDLINE */
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+char * prom_getcmdline(void)
+{
+ return &(arcs_cmdline[0]);
+}
+
+void prom_init_cmdline(void)
+{
+ char *cp;
+ int actr;
+
+ actr = 1; /* Always ignore argv[0] */
+
+ cp = &(arcs_cmdline[0]);
+ while(actr < prom_argc) {
+ strcpy(cp, prom_argv[actr]);
+ cp += strlen(prom_argv[actr]);
+ *cp++ = ' ';
+ actr++;
+ }
+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+ --cp;
+ if (prom_argc > 1)
+ *cp = '\0';
+
+}
+
+
+char *prom_getenv(char *envname)
+{
+#if 0
+ /*
+ * Return a pointer to the given environment variable.
+ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
+ */
+
+ char **env = prom_envp;
+ int i = strlen(envname);
+ int yamon = (*env && strchr(*env, '=') == NULL);
+
+ while (*env) {
+ if (yamon) {
+ if (strcmp(envname, *env++) == 0)
+ return *env;
+ } else {
+ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
+ return *env + i + 1;
+ }
+ env++;
+ }
+#endif
+ return NULL;
+}
+
+inline unsigned char str2hexnum(unsigned char c)
+{
+ if(c >= '0' && c <= '9')
+ return c - '0';
+ if(c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if(c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return 0; /* foo */
+}
+
+inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+ int i;
+
+ for(i = 0; i < 6; i++) {
+ unsigned char num;
+
+ if((*str == '.') || (*str == ':'))
+ str++;
+ num = str2hexnum(*str++) << 4;
+ num |= (str2hexnum(*str++));
+ ea[i] = num;
+ }
+}
+
+int get_ethernet_addr(char *ethernet_addr)
+{
+ char *ethaddr_str;
+
+ ethaddr_str = prom_getenv("ethaddr");
+ if (!ethaddr_str) {
+ printk("ethaddr not set in boot prom\n");
+ return -1;
+ }
+ str2eaddr(ethernet_addr, ethaddr_str);
+
+#if 0
+ {
+ int i;
+
+ printk("get_ethernet_addr: ");
+ for (i=0; i<5; i++)
+ printk("%02x:", (unsigned char)*(ethernet_addr+i));
+ printk("%02x\n", *(ethernet_addr+i));
+ }
+#endif
+
+ return 0;
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+void __init prom_init(void)
+{
+ unsigned char *memsize_str;
+ unsigned long memsize;
+
+ prom_argc = (int) fw_arg0;
+ prom_argv = (char **) fw_arg1;
+ prom_envp = (char **) fw_arg2;
+
+ mips_machtype = MACH_INGENIC_JZ4750D;
+
+ prom_init_cmdline();
+ memsize_str = prom_getenv("memsize");
+ if (!memsize_str) {
+ memsize = 0x04000000;
+ } else {
+ memsize = simple_strtol(memsize_str, NULL, 0);
+ }
+ add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
+/* used by early printk */
+void prom_putchar(char c)
+{
+ volatile u8 *uart_lsr = (volatile u8 *)(UART1_BASE + OFF_LSR);
+ volatile u8 *uart_tdr = (volatile u8 *)(UART1_BASE + OFF_TDR);
+
+ /* Wait for fifo to shift out some bytes */
+ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) );
+
+ *uart_tdr = (u8)c;
+}
+
+const char *get_system_type(void)
+{
+ return "JZ4750D";
+}
+
+EXPORT_SYMBOL(prom_getcmdline);
+EXPORT_SYMBOL(get_ethernet_addr);
+EXPORT_SYMBOL(str2eaddr);
diff --git a/arch/mips/jz4750d/reset.c b/arch/mips/jz4750d/reset.c
new file mode 100644
index 00000000000..baf38aa306a
--- /dev/null
+++ b/arch/mips/jz4750d/reset.c
@@ -0,0 +1,42 @@
+/*
+ * linux/arch/mips/jz4750/reset.c
+ *
+ * JZ4750 reset routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <yliu@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+void jz_restart(char *command)
+{
+ printk("Restarting after 4 ms\n");
+ REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN;
+ REG_WDT_TCNT = 0;
+ REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */
+ REG_TCU_TSCR = TCU_TSCR_WDTSC; /* enable wdt clock */
+ REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */
+ while (1);
+}
+
+void jz_halt(void)
+{
+ printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+
+ while (1)
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0");
+}
+
diff --git a/arch/mips/jz4750d/setup.c b/arch/mips/jz4750d/setup.c
new file mode 100644
index 00000000000..eb438035828
--- /dev/null
+++ b/arch/mips/jz4750d/setup.c
@@ -0,0 +1,199 @@
+/*
+ * linux/arch/mips/jz4750d/common/setup.c
+ *
+ * JZ4750D common setup routines.
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/ioport.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+#include <asm/pgtable.h>
+#include <asm/time.h>
+#include <asm/jzsoc.h>
+
+#ifdef CONFIG_PC_KEYB
+#include <asm/keyboard.h>
+#endif
+
+jz_clocks_t jz_clocks;
+
+extern char * __init prom_getcmdline(void);
+extern void __init jz_board_setup(void);
+extern void jz_restart(char *);
+extern void jz_pm_hibernate(void);
+extern void jz_halt(void);
+extern void jz_time_init(void);
+
+static void __init sysclocks_setup(void)
+{
+#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */
+ jz_clocks.cclk = __cpm_get_cclk();
+ jz_clocks.hclk = __cpm_get_hclk();
+ jz_clocks.pclk = __cpm_get_pclk();
+ jz_clocks.mclk = __cpm_get_mclk();
+ jz_clocks.h1clk = __cpm_get_h1clk();
+ jz_clocks.pixclk = __cpm_get_pixclk();
+ jz_clocks.i2sclk = __cpm_get_i2sclk();
+ jz_clocks.usbclk = __cpm_get_usbclk();
+ jz_clocks.mscclk = __cpm_get_mscclk(0);
+ jz_clocks.extalclk = __cpm_get_extalclk();
+ jz_clocks.rtcclk = __cpm_get_rtcclk();
+#else
+
+#define FPGACLK 8000000
+
+ jz_clocks.cclk = FPGACLK;
+ jz_clocks.hclk = FPGACLK;
+ jz_clocks.pclk = FPGACLK;
+ jz_clocks.mclk = FPGACLK;
+ jz_clocks.h1clk = FPGACLK;
+ jz_clocks.pixclk = FPGACLK;
+ jz_clocks.i2sclk = FPGACLK;
+ jz_clocks.usbclk = FPGACLK;
+ jz_clocks.mscclk = FPGACLK;
+ jz_clocks.extalclk = FPGACLK;
+ jz_clocks.rtcclk = FPGACLK;
+#endif
+
+ printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n",
+ (jz_clocks.cclk + 500000) / 1000000,
+ (jz_clocks.hclk + 500000) / 1000000,
+ (jz_clocks.pclk + 500000) / 1000000,
+ (jz_clocks.mclk + 500000) / 1000000);
+}
+
+static void __init soc_cpm_setup(void)
+{
+ /* Start all module clocks
+ */
+ __cpm_start_all();
+
+ /* Enable CKO to external memory */
+ __cpm_enable_cko();
+
+ /* CPU enters IDLE mode when executing 'wait' instruction */
+ __cpm_idle_mode();
+
+ /* Setup system clocks */
+ sysclocks_setup();
+}
+
+static void __init soc_harb_setup(void)
+{
+// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */
+// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */
+// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */
+}
+
+static void __init soc_emc_setup(void)
+{
+}
+
+static void __init soc_dmac_setup(void)
+{
+ __dmac_enable_module(0);
+ __dmac_enable_module(1);
+}
+
+static void __init jz_soc_setup(void)
+{
+ soc_cpm_setup();
+ soc_harb_setup();
+ soc_emc_setup();
+ soc_dmac_setup();
+}
+
+static void __init jz_serial_setup(void)
+{
+#ifdef CONFIG_SERIAL_8250
+ struct uart_port s;
+ REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */
+ memset(&s, 0, sizeof(s));
+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
+ s.iotype = SERIAL_IO_MEM;
+ s.regshift = 2;
+ s.uartclk = jz_clocks.extalclk ;
+
+ s.line = 0;
+ s.membase = (u8 *)UART0_BASE;
+ s.irq = IRQ_UART0;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS0 setup failed!\n");
+ }
+
+ s.line = 1;
+ s.membase = (u8 *)UART1_BASE;
+ s.irq = IRQ_UART1;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS1 setup failed!\n");
+ }
+
+ s.line = 2;
+ s.membase = (u8 *)UART2_BASE;
+ s.irq = IRQ_UART2;
+
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS2 setup failed!\n");
+ }
+/*
+ s.line = 3;
+ s.membase = (u8 *)UART3_BASE;
+ s.irq = IRQ_UART3;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS3 setup failed!\n");
+ }
+*/
+#endif
+}
+
+void __init plat_mem_setup(void)
+{
+ char *argptr;
+
+ argptr = prom_getcmdline();
+
+ /* IO/MEM resources. Which will be the addtion value in `inX' and
+ * `outX' macros defined in asm/io.h */
+ set_io_port_base(0);
+ ioport_resource.start = 0x00000000;
+ ioport_resource.end = 0xffffffff;
+ iomem_resource.start = 0x00000000;
+ iomem_resource.end = 0xffffffff;
+
+ _machine_restart = jz_restart;
+ _machine_halt = jz_halt;
+ pm_power_off = jz_pm_hibernate;
+
+ jz_soc_setup();
+ jz_serial_setup();
+ jz_board_setup();
+}
+
diff --git a/arch/mips/jz4750d/time.c b/arch/mips/jz4750d/time.c
new file mode 100644
index 00000000000..406e63df937
--- /dev/null
+++ b/arch/mips/jz4750d/time.c
@@ -0,0 +1,156 @@
+/*
+ * linux/arch/mips/jz4750d/time.c
+ *
+ * Setting up the clock on the JZ4750D boards.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/clockchips.h>
+
+#include <asm/time.h>
+#include <asm/jzsoc.h>
+
+/* This is for machines which generate the exact clock. */
+
+#define JZ_TIMER_IRQ IRQ_TCU0
+
+#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */
+
+static struct clocksource clocksource_jz; /* Jz clock source */
+static struct clock_event_device jz_clockevent_device; /* Jz clock event */
+
+void (*jz_timer_callback)(void);
+
+static irqreturn_t jz_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd = dev_id;
+
+ REG_TCU_TFCR = TCU_TFCR_OSTFCL; /* ACK timer */
+
+ if (jz_timer_callback)
+ jz_timer_callback();
+
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction jz_irqaction = {
+ .handler = jz_timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+ .name = "jz-timerirq",
+};
+
+
+cycle_t jz_get_cycles(struct clocksource *cs)
+{
+ /* convert jiffes to jz timer cycles */
+ return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_OSTCNT);
+}
+
+static struct clocksource clocksource_jz = {
+ .name = "jz_clocksource",
+ .rating = 300,
+ .read = jz_get_cycles,
+ .mask = 0xFFFFFFFF,
+ .shift = 10,
+ .flags = CLOCK_SOURCE_WATCHDOG,
+};
+
+static int __init jz_clocksource_init(void)
+{
+ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift);
+ clocksource_register(&clocksource_jz);
+ return 0;
+}
+
+static int jz_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ return 0;
+}
+
+static void jz_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static struct clock_event_device jz_clockevent_device = {
+ .name = "jz-clockenvent",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */
+
+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
+ .rating = 300,
+ .irq = JZ_TIMER_IRQ,
+ .set_mode = jz_set_mode,
+ .set_next_event = jz_set_next_event,
+};
+
+static void __init jz_clockevent_init(void)
+{
+ struct clock_event_device *cd = &jz_clockevent_device;
+ unsigned int cpu = smp_processor_id();
+
+ cd->cpumask = cpumask_of(cpu);
+ clockevents_register_device(cd);
+}
+
+static void __init jz_timer_setup(void)
+{
+ jz_clocksource_init(); /* init jz clock source */
+ jz_clockevent_init(); /* init jz clock event */
+
+ /*
+ * Make irqs happen for the system timer
+ */
+ jz_irqaction.dev_id = &jz_clockevent_device;
+ setup_irq(JZ_TIMER_IRQ, &jz_irqaction);
+}
+
+
+void __init plat_time_init(void)
+{
+ unsigned int latch;
+
+ /* Init timer */
+ latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ;
+
+ REG_TCU_OSTCSR = TCU_OSTCSR_PRESCALE16 | TCU_OSTCSR_EXT_EN;
+ REG_TCU_OSTCNT = 0;
+ REG_TCU_OSTDR = latch;
+
+ REG_TCU_TMCR = TCU_TMCR_OSTMCL; /* unmask match irq */
+ REG_TCU_TSCR = TCU_TSCR_OSTSC; /* enable timer clock */
+ REG_TCU_TESR = TCU_TESR_OSTST; /* start counting up */
+
+ jz_timer_setup();
+}
diff --git a/arch/mips/jz4750l/Makefile b/arch/mips/jz4750l/Makefile
new file mode 100644
index 00000000000..883519a6309
--- /dev/null
+++ b/arch/mips/jz4750l/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile for the Ingenic JZ4750L.
+#
+
+# Object file lists.
+
+obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
+ platform.o i2c.o
+
+obj-$(CONFIG_PROC_FS) += proc.o
+
+# board specific support
+
+obj-$(CONFIG_JZ4750L_F4750L) += board-f4750l.o
+
+# PM support
+
+obj-$(CONFIG_PM_LEGACY) +=pm.o
+
+# CPU Frequency scaling support
+
+obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o
diff --git a/arch/mips/jz4750l/board-f4750l.c b/arch/mips/jz4750l/board-f4750l.c
new file mode 100644
index 00000000000..376d0de98f6
--- /dev/null
+++ b/arch/mips/jz4750l/board-f4750l.c
@@ -0,0 +1,72 @@
+/*
+ * linux/arch/mips/jz4750l/board-f4750l.c
+ *
+ * JZ4750L F4750L board setup routines.
+ *
+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+
+#include <asm/jzsoc.h>
+
+extern void (*jz_timer_callback)(void);
+
+static void dancing(void)
+{
+ static unsigned char slash[] = "\\|/-";
+// static volatile unsigned char *p = (unsigned char *)0xb6000058;
+ static volatile unsigned char *p = (unsigned char *)0xb6000016;
+ static unsigned int count = 0;
+ *p = slash[count++];
+ count &= 3;
+}
+
+static void f4750l_timer_callback(void)
+{
+ static unsigned long count = 0;
+
+ if ((++count) % 50 == 0) {
+ dancing();
+ count = 0;
+ }
+}
+
+static void __init board_cpm_setup(void)
+{
+ /* Stop unused module clocks here.
+ * We have started all module clocks at arch/mips/jz4750l/setup.c.
+ */
+}
+
+static void __init board_gpio_setup(void)
+{
+ /*
+ * Initialize SDRAM pins
+ */
+}
+
+void __init jz_board_setup(void)
+{
+ printk("JZ4750L F4750L board setup\n");
+
+ board_cpm_setup();
+ board_gpio_setup();
+
+ jz_timer_callback = f4750l_timer_callback;
+}
diff --git a/arch/mips/jz4750l/cpufreq.c b/arch/mips/jz4750l/cpufreq.c
new file mode 100644
index 00000000000..a0286336586
--- /dev/null
+++ b/arch/mips/jz4750l/cpufreq.c
@@ -0,0 +1,598 @@
+/*
+ * linux/arch/mips/jz4750l/cpufreq.c
+ *
+ * cpufreq driver for JZ4750L
+ *
+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/cpufreq.h>
+
+#include <asm/jzsoc.h>
+#include <asm/processor.h>
+
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
+ "cpufreq-jz4750l", msg)
+
+#undef CHANGE_PLL
+
+#define PLL_UNCHANGED 0
+#define PLL_GOES_UP 1
+#define PLL_GOES_DOWN 2
+
+#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000))
+
+/* Saved the boot-time parameters */
+static struct {
+ /* SDRAM parameters */
+ unsigned int mclk; /* memory clock, KHz */
+ unsigned int tras; /* RAS pulse width, cycles of mclk */
+ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */
+ unsigned int tpc; /* RAS Precharge time, cycles of mclk */
+ unsigned int trwl; /* Write Precharge Time, cycles of mclk */
+ unsigned int trc; /* RAS Cycle Time, cycles of mclk */
+ unsigned int rtcor; /* Refresh Time Constant */
+ unsigned int sdram_initialized;
+
+ /* LCD parameters */
+ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */
+ unsigned int lcd_clks_initialized;
+} boot_config;
+
+struct jz4750l_freq_percpu_info {
+ struct cpufreq_frequency_table table[7];
+};
+
+static struct jz4750l_freq_percpu_info jz4750l_freq_table;
+
+/*
+ * This contains the registers value for an operating point.
+ * If only part of a register needs to change then there is
+ * a mask value for that register.
+ * When going to a new operating point the current register
+ * value is ANDed with the ~mask and ORed with the new value.
+ */
+struct dpm_regs {
+ u32 cpccr; /* Clock Freq Control Register */
+ u32 cpccr_mask; /* Clock Freq Control Register mask */
+ u32 cppcr; /* PLL1 Control Register */
+ u32 cppcr_mask; /* PLL1 Control Register mask */
+ u32 pll_up_flag; /* New PLL freq is higher than current or not */
+};
+
+extern jz_clocks_t jz_clocks;
+
+static void jz_update_clocks(void)
+{
+ /* Next clocks must be updated if we have changed
+ * the PLL or divisors.
+ */
+ jz_clocks.cclk = __cpm_get_cclk();
+ jz_clocks.hclk = __cpm_get_hclk();
+ jz_clocks.mclk = __cpm_get_mclk();
+ jz_clocks.pclk = __cpm_get_pclk();
+ jz_clocks.pixclk = __cpm_get_pixclk();
+ jz_clocks.i2sclk = __cpm_get_i2sclk();
+ jz_clocks.usbclk = __cpm_get_usbclk();
+ jz_clocks.mscclk = __cpm_get_mscclk(0);
+}
+
+static void
+jz_init_boot_config(void)
+{
+ if (!boot_config.lcd_clks_initialized) {
+ /* the first time to scale pll */
+ boot_config.lcdpix_clk = __cpm_get_pixclk();
+ boot_config.lcd_clks_initialized = 1;
+ }
+
+ if (!boot_config.sdram_initialized) {
+ /* the first time to scale frequencies */
+ unsigned int dmcr, rtcor;
+ unsigned int tras, rcd, tpc, trwl, trc;
+
+ dmcr = REG_EMC_DMCR;
+ rtcor = REG_EMC_RTCOR;
+
+ tras = (dmcr >> 13) & 0x7;
+ rcd = (dmcr >> 11) & 0x3;
+ tpc = (dmcr >> 8) & 0x7;
+ trwl = (dmcr >> 5) & 0x3;
+ trc = (dmcr >> 2) & 0x7;
+
+ boot_config.mclk = __cpm_get_mclk() / 1000;
+ boot_config.tras = tras + 4;
+ boot_config.rcd = rcd + 1;
+ boot_config.tpc = tpc + 1;
+ boot_config.trwl = trwl + 1;
+ boot_config.trc = trc * 2 + 1;
+ boot_config.rtcor = rtcor;
+
+ boot_config.sdram_initialized = 1;
+ }
+}
+
+static void jz_update_dram_rtcor(unsigned int new_mclk)
+{
+ unsigned int rtcor;
+
+ new_mclk /= 1000;
+ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk;
+ rtcor--;
+
+ if (rtcor < 1) rtcor = 1;
+ if (rtcor > 255) rtcor = 255;
+
+ REG_EMC_RTCOR = rtcor;
+ REG_EMC_RTCNT = rtcor;
+}
+
+static void jz_update_dram_dmcr(unsigned int new_mclk)
+{
+ unsigned int dmcr;
+ unsigned int tras, rcd, tpc, trwl, trc;
+ unsigned int valid_time, new_time; /* ns */
+
+ new_mclk /= 1000;
+ tras = boot_config.tras * new_mclk / boot_config.mclk;
+ rcd = boot_config.rcd * new_mclk / boot_config.mclk;
+ tpc = boot_config.tpc * new_mclk / boot_config.mclk;
+ trwl = boot_config.trwl * new_mclk / boot_config.mclk;
+ trc = boot_config.trc * new_mclk / boot_config.mclk;
+
+ /* Validation checking */
+ valid_time = (boot_config.tras * 1000000) / boot_config.mclk;
+ new_time = (tras * 1000000) / new_mclk;
+ if (new_time < valid_time) tras += 1;
+
+ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk;
+ new_time = (rcd * 1000000) / new_mclk;
+ if (new_time < valid_time) rcd += 1;
+
+ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk;
+ new_time = (tpc * 1000000) / new_mclk;
+ if (new_time < valid_time) tpc += 1;
+
+ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk;
+ new_time = (trwl * 1000000) / new_mclk;
+ if (new_time < valid_time) trwl += 1;
+
+ valid_time = (boot_config.trc * 1000000) / boot_config.mclk;
+ new_time = (trc * 1000000) / new_mclk;
+ if (new_time < valid_time) trc += 2;
+
+ tras = (tras < 4) ? 4: tras;
+ tras = (tras > 11) ? 11: tras;
+ tras -= 4;
+
+ rcd = (rcd < 1) ? 1: rcd;
+ rcd = (rcd > 4) ? 4: rcd;
+ rcd -= 1;
+
+ tpc = (tpc < 1) ? 1: tpc;
+ tpc = (tpc > 8) ? 8: tpc;
+ tpc -= 1;
+
+ trwl = (trwl < 1) ? 1: trwl;
+ trwl = (trwl > 4) ? 4: trwl;
+ trwl -= 1;
+
+ trc = (trc < 1) ? 1: trc;
+ trc = (trc > 15) ? 15: trc;
+ trc /= 2;
+
+ dmcr = REG_EMC_DMCR;
+
+ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK);
+ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT));
+
+ REG_EMC_DMCR = dmcr;
+}
+
+static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk)
+{
+ /* No risk, no fun: run with interrupts on! */
+ if (new_mclk > cur_mclk) {
+ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL
+ * and TRC of DMCR before changing the frequency.
+ */
+ jz_update_dram_dmcr(new_mclk);
+ } else {
+ /* We're going SLOWER: first update RTCOR value
+ * before changing the frequency.
+ */
+ jz_update_dram_rtcor(new_mclk);
+ }
+}
+
+static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk)
+{
+ /* No risk, no fun: run with interrupts on! */
+ if (new_mclk > cur_mclk) {
+ /* We're going FASTER, so update RTCOR
+ * after changing the frequency
+ */
+ jz_update_dram_rtcor(new_mclk);
+ } else {
+ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL
+ * and TRC of DMCR after changing the frequency.
+ */
+ jz_update_dram_dmcr(new_mclk);
+ }
+}
+
+static void jz_scale_divisors(struct dpm_regs *regs)
+{
+ unsigned int cpccr;
+ unsigned int cur_mclk, new_mclk;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned int tmp = 0, wait = PLL_WAIT_500NS;
+
+ cpccr = REG_CPM_CPCCR;
+ cpccr &= ~((unsigned long)regs->cpccr_mask);
+ cpccr |= regs->cpccr;
+ cpccr |= CPM_CPCCR_CE; /* update immediately */
+
+ cur_mclk = __cpm_get_mclk();
+ new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT];
+
+ /* Update some DRAM parameters before changing frequency */
+ jz_update_dram_prev(cur_mclk, new_mclk);
+
+ /* update register to change the clocks.
+ * align this code to a cache line.
+ */
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "li %3,0\n\t"
+ "1:\n\t"
+ "bne %3,%2,1b\n\t"
+ "addi %3, 1\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
+
+ /* Update some other DRAM parameters after changing frequency */
+ jz_update_dram_post(cur_mclk, new_mclk);
+}
+
+#ifdef CHANGE_PLL
+/* Maintain the LCD clock and pixel clock */
+static void jz_scale_lcd_divisors(struct dpm_regs *regs)
+{
+ unsigned int new_pll, new_lcd_div, new_lcdpix_div;
+ unsigned int cpccr;
+ unsigned int tmp = 0, wait = PLL_WAIT_500NS;
+
+ if (!boot_config.lcd_clks_initialized) return;
+
+ new_pll = __cpm_get_pllout();
+ new_lcd_div = new_pll / boot_config.lcd_clk;
+ new_lcdpix_div = new_pll / boot_config.lcdpix_clk;
+
+ if (new_lcd_div < 1)
+ new_lcd_div = 1;
+ if (new_lcd_div > 16)
+ new_lcd_div = 16;
+
+ if (new_lcdpix_div < 1)
+ new_lcdpix_div = 1;
+ if (new_lcdpix_div > 512)
+ new_lcdpix_div = 512;
+
+// REG_CPM_CPCCR2 = new_lcdpix_div - 1;
+
+ cpccr = REG_CPM_CPCCR;
+ cpccr &= ~CPM_CPCCR_LDIV_MASK;
+ cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT);
+ cpccr |= CPM_CPCCR_CE; /* update immediately */
+
+ /* update register to change the clocks.
+ * align this code to a cache line.
+ */
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "li %3,0\n\t"
+ "1:\n\t"
+ "bne %3,%2,1b\n\t"
+ "addi %3, 1\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
+}
+
+static void jz_scale_pll(struct dpm_regs *regs)
+{
+ unsigned int cppcr;
+ unsigned int cur_mclk, new_mclk, new_pll;
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ int od[] = {1, 2, 2, 4};
+
+ cppcr = REG_CPM_CPPCR;
+ cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK);
+ regs->cppcr &= ~CPM_CPPCR_PLLEN;
+ cppcr |= (regs->cppcr | 0xff);
+
+ /* Update some DRAM parameters before changing frequency */
+ new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]);
+ cur_mclk = __cpm_get_mclk();
+ new_mclk = new_pll / div[(REG_CPM_CPCCR>>16) & 0xf];
+
+ /*
+ * Update some SDRAM parameters
+ */
+ jz_update_dram_prev(cur_mclk, new_mclk);
+
+ /*
+ * Update PLL, align code to cache line.
+ */
+ cppcr |= CPM_CPPCR_PLLEN;
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".align 5\n"
+ "sw %1,0(%0)\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set reorder\n\t"
+ :
+ : "r" (CPM_CPPCR), "r" (cppcr));
+
+ /* Update some other DRAM parameters after changing frequency */
+ jz_update_dram_post(cur_mclk, new_mclk);
+}
+#endif
+
+static void jz4750l_transition(struct dpm_regs *regs)
+{
+ /*
+ * Get and save some boot-time conditions.
+ */
+ jz_init_boot_config();
+
+#ifdef CHANGE_PLL
+ /*
+ * Disable LCD before scaling pll.
+ * LCD and LCD pixel clocks should not be changed even if the PLL
+ * output frequency has been changed.
+ */
+ REG_LCD_CTRL &= ~LCD_CTRL_ENA;
+
+ /*
+ * Stop module clocks before scaling PLL
+ */
+ __cpm_stop_eth();
+ __cpm_stop_aic(1);
+ __cpm_stop_aic(2);
+#endif
+
+ /* ... add more as necessary */
+
+ if (regs->pll_up_flag == PLL_GOES_UP) {
+ /* the pll frequency is going up, so change dividors first */
+ jz_scale_divisors(regs);
+#ifdef CHANGE_PLL
+ jz_scale_pll(regs);
+#endif
+ }
+ else if (regs->pll_up_flag == PLL_GOES_DOWN) {
+ /* the pll frequency is going down, so change pll first */
+#ifdef CHANGE_PLL
+ jz_scale_pll(regs);
+#endif
+ jz_scale_divisors(regs);
+ }
+ else {
+ /* the pll frequency is unchanged, so change divisors only */
+ jz_scale_divisors(regs);
+ }
+
+#ifdef CHANGE_PLL
+ /*
+ * Restart module clocks before scaling PLL
+ */
+ __cpm_start_eth();
+ __cpm_start_aic(1);
+ __cpm_start_aic(2);
+
+ /* ... add more as necessary */
+
+ /* Scale the LCD divisors after scaling pll */
+ if (regs->pll_up_flag != PLL_UNCHANGED) {
+ jz_scale_lcd_divisors(regs);
+ }
+
+ /* Enable LCD controller */
+ REG_LCD_CTRL &= ~LCD_CTRL_DIS;
+ REG_LCD_CTRL |= LCD_CTRL_ENA;
+#endif
+
+ /* Update system clocks */
+ jz_update_clocks();
+}
+
+extern unsigned int idle_times;
+static unsigned int jz4750l_freq_get(unsigned int cpu)
+{
+ return (__cpm_get_cclk() / 1000);
+}
+
+static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs)
+{
+ int n2FR[33] = {
+ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
+ 9
+ };
+ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */
+ unsigned int div_of_cclk, new_freq, i;
+
+ regs->pll_up_flag = PLL_UNCHANGED;
+ regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK;
+
+ new_freq = jz4750l_freq_table.table[index].frequency;
+
+ do {
+ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq);
+ } while (div_of_cclk==0);
+
+ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) {
+ for(i = 1; i<4; i++) {
+ div[i] = 3;
+ }
+ } else {
+ for(i = 1; i<4; i++) {
+ div[i] = 2;
+ }
+ }
+
+ for(i = 0; i<4; i++) {
+ div[i] *= div_of_cclk;
+ }
+
+ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]);
+
+ regs->cpccr =
+ (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
+ (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
+ (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
+ (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT);
+
+ return div_of_cclk;
+}
+
+static void jz4750l_set_cpu_divider_index(unsigned int cpu, unsigned int index)
+{
+ unsigned long divisor, old_divisor;
+ struct cpufreq_freqs freqs;
+ struct dpm_regs regs;
+
+ old_divisor = __cpm_get_pllout() / __cpm_get_cclk();
+ divisor = index_to_divisor(index, &regs);
+
+ freqs.old = __cpm_get_cclk() / 1000;
+ freqs.new = __cpm_get_pllout() / (1000 * divisor);
+ freqs.cpu = cpu;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ if (old_divisor != divisor)
+ jz4750l_transition(&regs);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+}
+
+static int jz4750l_freq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int new_index = 0;
+
+ if (cpufreq_frequency_table_target(policy,
+ &jz4750l_freq_table.table[0],
+ target_freq, relation, &new_index))
+ return -EINVAL;
+
+ jz4750l_set_cpu_divider_index(policy->cpu, new_index);
+
+ dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR);
+
+ return 0;
+}
+
+static int jz4750l_freq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy,
+ &jz4750l_freq_table.table[0]);
+}
+
+static int __init jz4750l_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+
+ struct cpufreq_frequency_table *table = &jz4750l_freq_table.table[0];
+ unsigned int MAX_FREQ;
+
+ dprintk(KERN_INFO "Jz4750l cpufreq driver\n");
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ policy->cpuinfo.min_freq = MAX_FREQ/8;
+ policy->cpuinfo.max_freq = MAX_FREQ;
+ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */
+
+ table[0].index = 0;
+ table[0].frequency = MAX_FREQ/8;
+ table[1].index = 1;
+ table[1].frequency = MAX_FREQ/6;
+ table[2].index = 2;
+ table[2].frequency = MAX_FREQ/4;
+ table[3].index = 3;
+ table[3].frequency = MAX_FREQ/3;
+ table[4].index = 4;
+ table[4].frequency = MAX_FREQ/2;
+ table[5].index = 5;
+ table[5].frequency = MAX_FREQ;
+ table[6].index = 6;
+ table[6].frequency = CPUFREQ_TABLE_END;
+
+#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
+ cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */
+#endif
+
+ return cpufreq_frequency_table_cpuinfo(policy, table);
+}
+
+static struct cpufreq_driver cpufreq_jz4750l_driver = {
+// .flags = CPUFREQ_STICKY,
+ .init = jz4750l_cpufreq_driver_init,
+ .verify = jz4750l_freq_verify,
+ .target = jz4750l_freq_target,
+ .get = jz4750l_freq_get,
+ .name = "jz4750l",
+};
+
+static int __init jz4750l_cpufreq_init(void)
+{
+ return cpufreq_register_driver(&cpufreq_jz4750l_driver);
+}
+
+static void __exit jz4750l_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&cpufreq_jz4750l_driver);
+}
+
+module_init(jz4750l_cpufreq_init);
+module_exit(jz4750l_cpufreq_exit);
+
+MODULE_AUTHOR("Regen <lhhuang@ingenic.cn>");
+MODULE_DESCRIPTION("cpufreq driver for Jz4750l");
+MODULE_LICENSE("GPL");
diff --git a/arch/mips/jz4750l/dma.c b/arch/mips/jz4750l/dma.c
new file mode 100644
index 00000000000..e06a105da00
--- /dev/null
+++ b/arch/mips/jz4750l/dma.c
@@ -0,0 +1,822 @@
+/*
+ * linux/arch/mips/jz4750l/dma.c
+ *
+ * Support functions for the JZ4750L internal DMA channels.
+ * No-descriptor transfer only.
+ * Descriptor transfer should also call jz_request_dma() to get a free
+ * channel and call jz_free_dma() to free the channel. And driver should
+ * build the DMA descriptor and setup the DMA channel by itself.
+ *
+ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/soundcard.h>
+
+#include <asm/system.h>
+#include <asm/addrspace.h>
+#include <asm/jzsoc.h>
+
+/*
+ * A note on resource allocation:
+ *
+ * All drivers needing DMA channels, should allocate and release them
+ * through the public routines `jz_request_dma()' and `jz_free_dma()'.
+ *
+ * In order to avoid problems, all processes should allocate resources in
+ * the same sequence and release them in the reverse order.
+ *
+ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ.
+ * When releasing them, first release the IRQ, then release the DMA. The
+ * main reason for this order is that, if you are requesting the DMA buffer
+ * done interrupt, you won't know the irq number until the DMA channel is
+ * returned from jz_request_dma().
+ */
+
+struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = {
+ {dev_id:DMA_ID_BCH_ENC,}, /* DMAC0 channel 0, reserved for BCH */
+ {dev_id:-1,}, /* DMAC0 channel 1 */
+ {dev_id:-1,}, /* DMAC0 channel 2 */
+ {dev_id:-1,}, /* DMAC0 channel 3 */
+ {dev_id:-1,}, /* DMAC1 channel 0 */
+ {dev_id:-1,}, /* DMAC1 channel 1 */
+ {dev_id:-1,}, /* DMAC1 channel 2 */
+ {dev_id:-1,}, /* DMAC1 channel 3 */
+};
+
+// Device FIFO addresses and default DMA modes
+static const struct {
+ unsigned int fifo_addr;
+ unsigned int dma_mode;
+ unsigned int dma_source;
+} dma_dev_table[DMA_ID_MAX] = {
+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_EXT}, /* External request with DREQn */
+ {0x18000000, DMA_AUTOINIT, DMAC_DRSR_RS_NAND}, /* NAND request */
+ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_ENC},
+ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_DEC},
+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO},
+// {CPHYSADDR(TSSI_FIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_TSSIIN},
+ {CPHYSADDR(UART3_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT},
+ {CPHYSADDR(UART3_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART3IN},
+ {CPHYSADDR(UART2_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT},
+ {CPHYSADDR(UART2_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART2IN},
+ {CPHYSADDR(UART1_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT},
+ {CPHYSADDR(UART1_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART1IN},
+ {CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT},
+ {CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN},
+ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI0OUT},
+ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI0IN},
+ {CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT},
+ {CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN},
+ {CPHYSADDR(MSC_TXFIFO(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC0OUT},
+ {CPHYSADDR(MSC_RXFIFO(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC0IN},
+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU},
+ {SADC_TSDAT, DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SADC},/* Touch Screen Data Register */
+ {CPHYSADDR(MSC_TXFIFO(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC1OUT}, /* SSC1 TX */
+ {CPHYSADDR(MSC_RXFIFO(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC1IN}, /* SSC1 RX */
+ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI1OUT},
+ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI1IN},
+ {CPHYSADDR(PCM_DP), DMA_16BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_PMOUT},
+ {CPHYSADDR(PCM_DP), DMA_16BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_PMIN},
+ {},
+};
+
+
+int jz_dma_read_proc(char *buf, char **start, off_t fpos,
+ int length, int *eof, void *data)
+{
+ int i, len = 0;
+ struct jz_dma_chan *chan;
+
+ for (i = 0; i < MAX_DMA_NUM; i++) {
+ if ((chan = get_dma_chan(i)) != NULL) {
+ len += sprintf(buf + len, "%2d: %s\n",
+ i, chan->dev_str);
+ }
+ }
+
+ if (fpos >= len) {
+ *start = buf;
+ *eof = 1;
+ return 0;
+ }
+ *start = buf + fpos;
+ if ((len -= fpos) > length)
+ return length;
+ *eof = 1;
+ return len;
+}
+
+
+void dump_jz_dma_channel(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan;
+
+ if (dmanr > MAX_DMA_NUM)
+ return;
+ chan = &jz_dma_table[dmanr];
+
+ printk("DMA%d Registers:\n", dmanr);
+ printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR(chan->io/HALF_DMA_NUM));
+ printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr));
+ printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr));
+ printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr));
+ printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr));
+ printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr));
+ printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr));
+ printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr));
+ printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR(chan->io/HALF_DMA_NUM));
+}
+
+
+/**
+ * jz_request_dma - dynamically allcate an idle DMA channel to return
+ * @dev_id: the specified dma device id or DMA_ID_RAW_SET
+ * @dev_str: the specified dma device string name
+ * @irqhandler: the irq handler, or NULL
+ * @irqflags: the irq handler flags
+ * @irq_dev_id: the irq handler device id for shared irq
+ *
+ * Finds a free channel, and binds the requested device to it.
+ * Returns the allocated channel number, or negative on error.
+ * Requests the DMA done IRQ if irqhandler != NULL.
+ *
+*/
+/*int jz_request_dma(int dev_id, const char *dev_str,
+ void (*irqhandler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ void *irq_dev_id)
+*/
+
+int jz_request_dma(int dev_id, const char *dev_str,
+ irqreturn_t (*irqhandler)(int, void *),
+ unsigned long irqflags,
+ void *irq_dev_id)
+{
+ struct jz_dma_chan *chan;
+ int i, ret;
+
+ if (dev_id < 0 || dev_id >= DMA_ID_MAX)
+ return -EINVAL;
+
+ for (i = 0; i < MAX_DMA_NUM; i++) {
+ if (jz_dma_table[i].dev_id < 0)
+ break;
+ }
+ if (i == MAX_DMA_NUM) /* no free channel */
+ return -ENODEV;
+
+ /* we got a free channel */
+ chan = &jz_dma_table[i];
+
+ if (irqhandler) {
+ chan->irq = IRQ_DMA_0 + i; // allocate irq number
+ chan->irq_dev = irq_dev_id;
+ if ((ret = request_irq(chan->irq, irqhandler, irqflags,
+ dev_str, chan->irq_dev))) {
+ chan->irq = -1;
+ chan->irq_dev = NULL;
+ return ret;
+ }
+ } else {
+ chan->irq = -1;
+ chan->irq_dev = NULL;
+ }
+
+ // fill it in
+ chan->io = i;
+ chan->dev_id = dev_id;
+ chan->dev_str = dev_str;
+ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
+ chan->mode = dma_dev_table[dev_id].dma_mode;
+ chan->source = dma_dev_table[dev_id].dma_source;
+
+ if (i < HALF_DMA_NUM)
+ REG_DMAC_DMACKE(0) = 1 << i;
+ else
+ REG_DMAC_DMACKE(1) = 1 << (i - HALF_DMA_NUM);
+
+ return i;
+}
+
+void jz_free_dma(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan) {
+ printk("Trying to free DMA%d\n", dmanr);
+ return;
+ }
+
+ disable_dma(dmanr);
+ if (chan->irq)
+ free_irq(chan->irq, chan->irq_dev);
+
+ chan->irq = -1;
+ chan->irq_dev = NULL;
+ chan->dev_id = -1;
+}
+
+void jz_set_dma_dest_width(int dmanr, int nbit)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode &= ~DMAC_DCMD_DWDH_MASK;
+ switch (nbit) {
+ case 8:
+ chan->mode |= DMAC_DCMD_DWDH_8;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCMD_DWDH_16;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCMD_DWDH_32;
+ break;
+ }
+}
+
+void jz_set_dma_src_width(int dmanr, int nbit)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode &= ~DMAC_DCMD_SWDH_MASK;
+ switch (nbit) {
+ case 8:
+ chan->mode |= DMAC_DCMD_SWDH_8;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCMD_SWDH_16;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCMD_SWDH_32;
+ break;
+ }
+}
+
+void jz_set_dma_block_size(int dmanr, int nbyte)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode &= ~DMAC_DCMD_DS_MASK;
+ switch (nbyte) {
+ case 1:
+ chan->mode |= DMAC_DCMD_DS_8BIT;
+ break;
+ case 2:
+ chan->mode |= DMAC_DCMD_DS_16BIT;
+ break;
+ case 4:
+ chan->mode |= DMAC_DCMD_DS_32BIT;
+ break;
+ case 16:
+ chan->mode |= DMAC_DCMD_DS_16BYTE;
+ break;
+ case 32:
+ chan->mode |= DMAC_DCMD_DS_32BYTE;
+ break;
+ }
+}
+
+unsigned int jz_get_dma_command(int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ return chan->mode;
+}
+
+/**
+ * jz_set_dma_mode - do the raw settings for the specified DMA channel
+ * @dmanr: the specified DMA channel
+ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE
+ * @dma_mode: dma raw mode
+ * @dma_source: dma raw request source
+ * @fifo_addr: dma raw device fifo address
+ *
+ * Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call
+ * jz_set_dma_mode() rather than set_dma_mode() if you work with
+ * and external request dma device.
+ *
+ * NOTE: Don not dynamically allocate dma channel if one external request
+ * dma device will occupy this channel.
+*/
+int jz_set_dma_mode(unsigned int dmanr, unsigned int mode,
+ unsigned int dma_mode, unsigned int dma_source,
+ unsigned int fifo_addr)
+{
+ int dev_id, i;
+ struct jz_dma_chan *chan;
+
+ if (dmanr > MAX_DMA_NUM)
+ return -ENODEV;
+ for (i = 0; i < MAX_DMA_NUM; i++) {
+ if (jz_dma_table[i].dev_id < 0)
+ break;
+ }
+ if (i == MAX_DMA_NUM)
+ return -ENODEV;
+
+ chan = &jz_dma_table[dmanr];
+ dev_id = chan->dev_id;
+ if (dev_id > 0) {
+ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n",
+ __FUNCTION__, dmanr);
+ return -ENODEV;
+ }
+
+ /* clone it from the dynamically allocated. */
+ if (i != dmanr) {
+ chan->irq = jz_dma_table[i].irq;
+ chan->irq_dev = jz_dma_table[i].irq_dev;
+ chan->dev_str = jz_dma_table[i].dev_str;
+ jz_dma_table[i].irq = 0;
+ jz_dma_table[i].irq_dev = NULL;
+ jz_dma_table[i].dev_id = -1;
+ }
+ chan->dev_id = DMA_ID_RAW_SET;
+ chan->io = dmanr;
+ chan->fifo_addr = fifo_addr;
+ chan->mode = dma_mode;
+ chan->source = dma_source;
+
+ set_dma_mode(dmanr, dma_mode);
+
+ return dmanr;
+}
+
+void enable_dma(unsigned int dmanr)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
+ REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */
+ __dmac_enable_channel(dmanr);
+ if (chan->irq)
+ __dmac_channel_enable_irq(dmanr);
+}
+
+#define DMA_DISABLE_POLL 0x10000
+
+void disable_dma(unsigned int dmanr)
+{
+ int i;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ if (!__dmac_channel_enabled(dmanr))
+ return;
+
+ for (i = 0; i < DMA_DISABLE_POLL; i++)
+ if (__dmac_channel_transmit_end_detected(dmanr))
+ break;
+#if 0
+ if (i == DMA_DISABLE_POLL)
+ printk(KERN_INFO "disable_dma: poll expired!\n");
+#endif
+
+ __dmac_disable_channel(dmanr);
+ if (chan->irq)
+ __dmac_channel_disable_irq(dmanr);
+}
+
+/* Note: DMA_MODE_MASK is simulated by sw */
+void set_dma_mode(unsigned int dmanr, unsigned int mode)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ if (mode == DMA_MODE_READ) {
+ chan->mode |= DMAC_DCMD_DAI;
+ chan->mode &= ~DMAC_DCMD_SAI;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode |= DMAC_DCMD_SAI;
+ chan->mode &= ~DMAC_DCMD_DAI;
+ } else {
+ printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+ }
+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+}
+
+void set_dma_addr(unsigned int dmanr, unsigned int phyaddr)
+{
+ unsigned int mode;
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ mode = chan->mode & DMA_MODE_MASK;
+ if (mode == DMA_MODE_READ) {
+ REG_DMAC_DSAR(chan->io) = chan->fifo_addr;
+ REG_DMAC_DTAR(chan->io) = phyaddr;
+ } else if (mode == DMA_MODE_WRITE) {
+ REG_DMAC_DSAR(chan->io) = phyaddr;
+ REG_DMAC_DTAR(chan->io) = chan->fifo_addr;
+ } else
+ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n");
+}
+
+void set_dma_count(unsigned int dmanr, unsigned int bytecnt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ int dma_ds[] = {4, 1, 2, 16, 32};
+ unsigned int ds;
+
+ if (!chan)
+ return;
+
+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
+ REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count
+}
+
+unsigned int get_dma_residue(unsigned int dmanr)
+{
+ unsigned int count, ds;
+ int dma_ds[] = {4, 1, 2, 16, 32};
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+ if (!chan)
+ return 0;
+
+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
+ count = REG_DMAC_DTCR(chan->io);
+ count = count * dma_ds[ds];
+
+ return count;
+}
+
+void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ switch (audio_fmt) {
+ case AFMT_U8:
+ /* burst mode : 32BIT */
+ break;
+ case AFMT_S16_LE:
+ /* burst mode : 16BYTE */
+ if (mode == DMA_MODE_READ) {
+ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_DAI;
+ chan->mode &= ~DMAC_DCMD_SAI;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ //chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_SAI;
+ chan->mode &= ~DMAC_DCMD_DAI;
+ } else
+ printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+
+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+ break;
+ }
+}
+
+void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
+{
+ struct jz_dma_chan *chan = get_dma_chan(dmanr);
+
+ if (!chan)
+ return;
+
+ switch (audio_fmt) {
+ case 8:
+ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
+ break;
+ case 16:
+ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
+ if (mode == DMA_MODE_READ) {
+ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_DAI;
+ chan->mode &= ~DMAC_DCMD_SAI;
+ } else if (mode == DMA_MODE_WRITE) {
+ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
+ mode &= DMA_MODE_MASK;
+ chan->mode |= DMAC_DCMD_SAI;
+ chan->mode &= ~DMAC_DCMD_DAI;
+ } else
+ printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
+
+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
+ REG_DMAC_DRSR(chan->io) = chan->source;
+ break;
+ }
+}
+
+//#define JZ4750L_DMAC_TEST_ENABLE
+#undef JZ4750L_DMAC_TEST_ENABLE
+
+#ifdef JZ4750L_DMAC_TEST_ENABLE
+
+/*
+ * DMA test: external address <--> external address
+ */
+#define TEST_DMA_SIZE 16*1024
+
+static jz_dma_desc *dma_desc;
+
+static int dma_chan;
+static dma_addr_t dma_desc_phys_addr;
+static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr;
+
+static int dma_check_result(void *src, void *dst, int size)
+{
+ unsigned int addr1, addr2, i, err = 0;
+
+ addr1 = (unsigned int)src;
+ addr2 = (unsigned int)dst;
+
+ for (i = 0; i < size; i += 4) {
+ if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) {
+ err++;
+ printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2);
+ }
+ addr1 += 4;
+ addr2 += 4;
+ }
+ printk("check DMA result err=%d\n", err);
+ return err;
+}
+
+static irqreturn_t jz4750l_dma_irq(int irq, void *dev_id)
+{
+ printk("jz4750l_dma_irq %d\n", irq);
+
+
+ if (__dmac_channel_transmit_halt_detected(dma_chan)) {
+ printk("DMA HALT\n");
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ __dmac_channel_clear_transmit_halt(dma_chan);
+ }
+
+ if (__dmac_channel_address_error_detected(dma_chan)) {
+ printk("DMA ADDR ERROR\n");
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ REG_DMAC_DSAR(dma_chan) = 0; /* clear source address register */
+ REG_DMAC_DTAR(dma_chan) = 0; /* clear target address register */
+ __dmac_channel_clear_address_error(dma_chan);
+ }
+
+ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) {
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ printk("DMA DESC INVALID\n");
+ __dmac_channel_clear_descriptor_invalid(dma_chan);
+ }
+
+ if (__dmac_channel_count_terminated_detected(dma_chan)) {
+ printk("DMA CT\n");
+ __dmac_channel_clear_count_terminated(dma_chan);
+ }
+
+ if (__dmac_channel_transmit_end_detected(dma_chan)) {
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ printk("DMA TT\n");
+ __dmac_channel_clear_transmit_end(dma_chan);
+ dump_jz_dma_channel(dma_chan);
+ dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE);
+ }
+
+ return IRQ_HANDLED;
+}
+
+void dma_nodesc_test(void)
+{
+ unsigned int addr, i;
+
+ printk("dma_nodesc_test\n");
+
+ /* Request DMA channel and setup irq handler */
+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750l_dma_irq,
+ IRQF_DISABLED, NULL);
+ if (dma_chan < 0) {
+ printk("Setup irq failed\n");
+ return;
+ }
+
+ printk("Requested DMA channel = %d\n", dma_chan);
+
+ /* Allocate DMA buffers */
+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+
+ dma_src_phys_addr = CPHYSADDR(dma_src_addr);
+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
+
+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
+
+ /* Prepare data for source buffer */
+ addr = (unsigned int)dma_src_addr;
+ for (i = 0; i < TEST_DMA_SIZE; i += 4) {
+ *(volatile unsigned int *)addr = addr;
+ addr += 4;
+ }
+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
+
+ /* Init target buffer */
+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
+
+ /* Init DMA module */
+ printk("Starting DMA\n");
+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0;
+ REG_DMAC_DCCSR(dma_chan) = 0;
+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr;
+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr;
+ REG_DMAC_DTCR(dma_chan) = 512;
+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE;
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */
+
+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
+
+ /* wait a long time, ensure transfer end */
+ printk("wait 3s...\n");
+ mdelay(3000); /* wait 3s */
+
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ /* free buffers */
+ printk("free DMA buffers\n");
+ free_pages(dma_src_addr, 2);
+ free_pages(dma_dst_addr, 2);
+
+ if (dma_desc)
+ free_pages((unsigned int)dma_desc, 0);
+
+ /* free dma */
+ jz_free_dma(dma_chan);
+}
+
+void dma_desc_test(void)
+{
+ unsigned int next, addr, i;
+ static jz_dma_desc *desc;
+
+ printk("dma_desc_test\n");
+
+ /* Request DMA channel and setup irq handler */
+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750l_dma_irq,
+ IRQF_DISABLED, NULL);
+ if (dma_chan < 0) {
+ printk("Setup irq failed\n");
+ return;
+ }
+
+ printk("Requested DMA channel = %d\n", dma_chan);
+
+ /* Allocate DMA buffers */
+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
+
+ dma_src_phys_addr = CPHYSADDR(dma_src_addr);
+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
+
+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
+
+ /* Prepare data for source buffer */
+ addr = (unsigned int)dma_src_addr;
+ for (i = 0; i < TEST_DMA_SIZE; i += 4) {
+ *(volatile unsigned int *)addr = addr;
+ addr += 4;
+ }
+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
+
+ /* Init target buffer */
+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
+
+ /* Allocate DMA descriptors */
+ dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0);
+ dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc);
+
+ printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr);
+
+ /* Setup DMA descriptors */
+ desc = dma_desc;
+ next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
+ desc->dsadr = dma_src_phys_addr; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr; /* DMA target address */
+ desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */
+
+ desc++;
+ next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
+ desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */
+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
+
+ desc++;
+ next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
+ desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */
+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
+
+ desc++;
+ next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4;
+
+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE;
+ desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */
+ desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */
+ desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */
+
+ dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc)));
+
+ /* Setup DMA descriptor address */
+ REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr;
+
+ /* Setup request source */
+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
+
+ /* Setup DMA channel control/status register */
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */
+
+ /* Enable DMA */
+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE;
+
+ /* DMA doorbell set -- start DMA now ... */
+ REG_DMAC_DMADBSR(dma_chan/HALF_DMA_NUM) = 1 << dma_chan;
+
+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
+ /* wait a long time, ensure transfer end */
+ printk("wait 3s...\n");
+ mdelay(3000); /* wait 3s */
+
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ /* free buffers */
+ printk("free DMA buffers\n");
+ free_pages(dma_src_addr, 2);
+ free_pages(dma_dst_addr, 2);
+
+ if (dma_desc)
+ free_pages((unsigned int)dma_desc, 0);
+
+ /* free dma */
+ jz_free_dma(dma_chan);
+}
+
+#endif
+
+//EXPORT_SYMBOL_NOVERS(jz_dma_table);
+EXPORT_SYMBOL(jz_dma_table);
+EXPORT_SYMBOL(jz_request_dma);
+EXPORT_SYMBOL(jz_free_dma);
+EXPORT_SYMBOL(jz_set_dma_src_width);
+EXPORT_SYMBOL(jz_set_dma_dest_width);
+EXPORT_SYMBOL(jz_set_dma_block_size);
+EXPORT_SYMBOL(jz_set_dma_mode);
+EXPORT_SYMBOL(set_dma_mode);
+EXPORT_SYMBOL(jz_set_oss_dma);
+EXPORT_SYMBOL(jz_set_alsa_dma);
+EXPORT_SYMBOL(set_dma_addr);
+EXPORT_SYMBOL(set_dma_count);
+EXPORT_SYMBOL(get_dma_residue);
+EXPORT_SYMBOL(enable_dma);
+EXPORT_SYMBOL(disable_dma);
+EXPORT_SYMBOL(dump_jz_dma_channel);
diff --git a/arch/mips/jz4750l/i2c.c b/arch/mips/jz4750l/i2c.c
new file mode 100644
index 00000000000..7a04def7b75
--- /dev/null
+++ b/arch/mips/jz4750l/i2c.c
@@ -0,0 +1,273 @@
+/*
+ * linux/arch/mips/jz4750l/i2c.c
+ *
+ * Jz4750L I2C routines.
+ *
+ * Copyright (C) 2005,2006 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/addrspace.h>
+
+#include <asm/jzsoc.h>
+
+/* I2C protocol */
+#define I2C_READ 1
+#define I2C_WRITE 0
+
+#define TIMEOUT 1000
+
+/*
+ * I2C bus protocol basic routines
+ */
+static int i2c_put_data(unsigned char data)
+{
+ unsigned int timeout = TIMEOUT*10;
+
+ __i2c_write(data);
+ __i2c_set_drf();
+ while (__i2c_check_drf() != 0);
+ while (!__i2c_transmit_ended());
+ while (!__i2c_received_ack() && timeout)
+ timeout--;
+
+ if (timeout)
+ return 0;
+ else
+ return -ETIMEDOUT;
+}
+
+#ifdef CONFIG_JZ_TPANEL_ATA2508
+static int i2c_put_data_nack(unsigned char data)
+{
+ unsigned int timeout = TIMEOUT*10;
+
+ __i2c_write(data);
+ __i2c_set_drf();
+ while (__i2c_check_drf() != 0);
+ while (!__i2c_transmit_ended());
+ while (timeout--);
+ return 0;
+}
+#endif
+
+static int i2c_get_data(unsigned char *data, int ack)
+{
+ int timeout = TIMEOUT*10;
+
+ if (!ack)
+ __i2c_send_nack();
+ else
+ __i2c_send_ack();
+
+ while (__i2c_check_drf() == 0 && timeout)
+ timeout--;
+
+ if (timeout) {
+ if (!ack)
+ __i2c_send_stop();
+ *data = __i2c_read();
+ __i2c_clear_drf();
+ return 0;
+ } else
+ return -ETIMEDOUT;
+}
+
+/*
+ * I2C interface
+ */
+void i2c_open(void)
+{
+ __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */
+ __i2c_enable();
+}
+
+void i2c_close(void)
+{
+ udelay(300); /* wait for STOP goes over. */
+ __i2c_disable();
+}
+
+void i2c_setclk(unsigned int i2cclk)
+{
+ __i2c_set_clk(jz_clocks.extalclk, i2cclk);
+}
+
+int i2c_lseek(unsigned char device, unsigned char offset)
+{
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_err;
+ if (i2c_put_data(offset) < 0)
+ goto address_err;
+ return 0;
+ device_err:
+ printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device);
+ __i2c_send_stop();
+ return -ENODEV;
+ address_err:
+ printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device);
+ __i2c_send_stop();
+ return -EREMOTEIO;
+}
+
+int i2c_read(unsigned char device, unsigned char *buf,
+ unsigned char address, int count)
+{
+ int cnt = count;
+ int timeout = 5;
+
+L_try_again:
+
+ if (timeout < 0)
+ goto L_timeout;
+
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_werr;
+ if (i2c_put_data(address) < 0)
+ goto address_err;
+
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_READ ) < 0)
+ goto device_rerr;
+ __i2c_send_ack(); /* Master sends ACK for continue reading */
+ while (cnt) {
+ if (cnt == 1) {
+ if (i2c_get_data(buf, 0) < 0)
+ break;
+ } else {
+ if (i2c_get_data(buf, 1) < 0)
+ break;
+ }
+ cnt--;
+ buf++;
+ }
+
+ __i2c_send_stop();
+ return count - cnt;
+ device_rerr:
+ device_werr:
+ address_err:
+ timeout --;
+ __i2c_send_stop();
+ goto L_try_again;
+
+L_timeout:
+ __i2c_send_stop();
+ printk("Read I2C device 0x%2x failed.\n", device);
+ return -ENODEV;
+}
+
+int i2c_write(unsigned char device, unsigned char *buf,
+ unsigned char address, int count)
+{
+ int cnt = count;
+ int cnt_in_pg;
+ int timeout = 5;
+ unsigned char *tmpbuf;
+ unsigned char tmpaddr;
+
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+
+ W_try_again:
+ if (timeout < 0)
+ goto W_timeout;
+
+ cnt = count;
+ tmpbuf = (unsigned char *)buf;
+ tmpaddr = address;
+
+ start_write_page:
+ cnt_in_pg = 0;
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_err;
+#ifdef CONFIG_JZ_TPANEL_ATA2508
+ if (address == 0xff) {
+ if (i2c_put_data_nack(tmpaddr) < 0)
+ goto address_err;
+ while (cnt) {
+ if (++cnt_in_pg > 8) {
+ __i2c_send_stop();
+ mdelay(1);
+ tmpaddr += 8;
+ goto start_write_page;
+ }
+ if (i2c_put_data_nack(*tmpbuf) < 0)
+ break;
+ cnt--;
+ tmpbuf++;
+ }
+ }
+ else {
+
+ if (i2c_put_data(tmpaddr) < 0)
+ goto address_err;
+ while (cnt) {
+ if (++cnt_in_pg > 8) {
+ __i2c_send_stop();
+ mdelay(1);
+ tmpaddr += 8;
+ goto start_write_page;
+ }
+ if (i2c_put_data(*tmpbuf) < 0)
+ break;
+ cnt--;
+ tmpbuf++;
+ }
+ }
+#else
+ if (i2c_put_data(tmpaddr) < 0)
+ goto address_err;
+ while (cnt) {
+ if (++cnt_in_pg > 8) {
+ __i2c_send_stop();
+ mdelay(1);
+ tmpaddr += 8;
+ goto start_write_page;
+ }
+ if (i2c_put_data(*tmpbuf) < 0)
+ break;
+ cnt--;
+ tmpbuf++;
+ }
+#endif
+ __i2c_send_stop();
+ return count - cnt;
+ device_err:
+ address_err:
+ timeout--;
+ __i2c_send_stop();
+ goto W_try_again;
+
+ W_timeout:
+ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device);
+ __i2c_send_stop();
+ return -ENODEV;
+}
+
+EXPORT_SYMBOL(i2c_open);
+EXPORT_SYMBOL(i2c_close);
+EXPORT_SYMBOL(i2c_setclk);
+EXPORT_SYMBOL(i2c_read);
+EXPORT_SYMBOL(i2c_write);
diff --git a/arch/mips/jz4750l/irq.c b/arch/mips/jz4750l/irq.c
new file mode 100644
index 00000000000..af59a1e38a4
--- /dev/null
+++ b/arch/mips/jz4750l/irq.c
@@ -0,0 +1,299 @@
+/*
+ * linux/arch/mips/jz4750l/irq.c
+ *
+ * JZ4750L interrupt routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+/*
+ * INTC irq type
+ */
+
+static void enable_intc_irq(unsigned int irq)
+{
+ __intc_unmask_irq(irq);
+}
+
+static void disable_intc_irq(unsigned int irq)
+{
+ __intc_mask_irq(irq);
+}
+
+static void mask_and_ack_intc_irq(unsigned int irq)
+{
+ __intc_mask_irq(irq);
+ __intc_ack_irq(irq);
+}
+
+static void end_intc_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_intc_irq(irq);
+ }
+}
+
+static unsigned int startup_intc_irq(unsigned int irq)
+{
+ enable_intc_irq(irq);
+ return 0;
+}
+
+static void shutdown_intc_irq(unsigned int irq)
+{
+ disable_intc_irq(irq);
+}
+
+static struct irq_chip intc_irq_type = {
+ .typename = "INTC",
+ .startup = startup_intc_irq,
+ .shutdown = shutdown_intc_irq,
+ .unmask = enable_intc_irq,
+ .mask = disable_intc_irq,
+ .ack = mask_and_ack_intc_irq,
+ .end = end_intc_irq,
+};
+
+/*
+ * GPIO irq type
+ */
+
+static void enable_gpio_irq(unsigned int irq)
+{
+ unsigned int intc_irq;
+
+ if (irq < (IRQ_GPIO_0 + 32)) {
+ intc_irq = IRQ_GPIO0;
+ }
+ else if (irq < (IRQ_GPIO_0 + 64)) {
+ intc_irq = IRQ_GPIO1;
+ }
+ else if (irq < (IRQ_GPIO_0 + 96)) {
+ intc_irq = IRQ_GPIO2;
+ }
+ else if (irq < (IRQ_GPIO_0 + 128)) {
+ intc_irq = IRQ_GPIO3;
+ }
+ else if (irq < (IRQ_GPIO_0 + 160)) {
+ intc_irq = IRQ_GPIO4;
+ }
+ else {
+ intc_irq = IRQ_GPIO5;
+ }
+
+ enable_intc_irq(intc_irq);
+ __gpio_unmask_irq(irq - IRQ_GPIO_0);
+}
+
+static void disable_gpio_irq(unsigned int irq)
+{
+ __gpio_mask_irq(irq - IRQ_GPIO_0);
+}
+
+static void mask_and_ack_gpio_irq(unsigned int irq)
+{
+ __gpio_mask_irq(irq - IRQ_GPIO_0);
+ __gpio_ack_irq(irq - IRQ_GPIO_0);
+}
+
+static void end_gpio_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_gpio_irq(irq);
+ }
+}
+
+static unsigned int startup_gpio_irq(unsigned int irq)
+{
+ enable_gpio_irq(irq);
+ return 0;
+}
+
+static void shutdown_gpio_irq(unsigned int irq)
+{
+ disable_gpio_irq(irq);
+}
+
+static struct irq_chip gpio_irq_type = {
+ .typename = "GPIO",
+ .startup = startup_gpio_irq,
+ .shutdown = shutdown_gpio_irq,
+ .unmask = enable_gpio_irq,
+ .mask = disable_gpio_irq,
+ .ack = mask_and_ack_gpio_irq,
+ .end = end_gpio_irq,
+};
+
+/*
+ * DMA irq type
+ */
+
+static void enable_dma_irq(unsigned int irq)
+{
+ unsigned int intc_irq;
+
+ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */
+ intc_irq = IRQ_DMAC0;
+ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */
+ intc_irq = IRQ_DMAC1;
+ else {
+ printk("%s, unexpected dma irq #%d\n", __FILE__, irq);
+ return;
+ }
+ __intc_unmask_irq(intc_irq);
+ __dmac_channel_enable_irq(irq - IRQ_DMA_0);
+}
+
+static void disable_dma_irq(unsigned int irq)
+{
+ __dmac_channel_disable_irq(irq - IRQ_DMA_0);
+}
+
+static void mask_and_ack_dma_irq(unsigned int irq)
+{
+ unsigned int intc_irq;
+
+ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */
+ intc_irq = IRQ_DMAC0;
+ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */
+ intc_irq = IRQ_DMAC1;
+ else {
+ printk("%s, unexpected dma irq #%d\n", __FILE__, irq);
+ return ;
+ }
+ __intc_ack_irq(intc_irq);
+ __dmac_channel_ack_irq(irq-IRQ_DMA_0); /* needed?? add 20080506, Wolfgang */
+ __dmac_channel_disable_irq(irq - IRQ_DMA_0);
+}
+
+static void end_dma_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ enable_dma_irq(irq);
+ }
+}
+
+static unsigned int startup_dma_irq(unsigned int irq)
+{
+ enable_dma_irq(irq);
+ return 0;
+}
+
+static void shutdown_dma_irq(unsigned int irq)
+{
+ disable_dma_irq(irq);
+}
+
+static struct irq_chip dma_irq_type = {
+ .typename = "DMA",
+ .startup = startup_dma_irq,
+ .shutdown = shutdown_dma_irq,
+ .unmask = enable_dma_irq,
+ .mask = disable_dma_irq,
+ .ack = mask_and_ack_dma_irq,
+ .end = end_dma_irq,
+};
+
+//----------------------------------------------------------------------
+
+void __init arch_init_irq(void)
+{
+ int i;
+
+ clear_c0_status(0xff04); /* clear ERL */
+ set_c0_status(0x0400); /* set IP2 */
+
+ /* Set up INTC irq
+ */
+ for (i = 0; i < 32; i++) {
+ disable_intc_irq(i);
+ set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq);
+ }
+
+ /* Set up DMAC irq
+ */
+ for (i = 0; i < NUM_DMA; i++) {
+ disable_dma_irq(IRQ_DMA_0 + i);
+ set_irq_chip_and_handler(IRQ_DMA_0 + i, &dma_irq_type, handle_level_irq);
+ }
+
+ /* Set up GPIO irq
+ */
+ for (i = 0; i < NUM_GPIO; i++) {
+ disable_gpio_irq(IRQ_GPIO_0 + i);
+ set_irq_chip_and_handler(IRQ_GPIO_0 + i, &gpio_irq_type, handle_level_irq);
+ }
+}
+
+static int plat_real_irq(int irq)
+{
+ switch (irq) {
+ case IRQ_GPIO0:
+ irq = __gpio_group_irq(0) + IRQ_GPIO_0;
+ break;
+ case IRQ_GPIO1:
+ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32;
+ break;
+ case IRQ_GPIO2:
+ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64;
+ break;
+ case IRQ_GPIO3:
+ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96;
+ break;
+ case IRQ_GPIO4:
+ irq = __gpio_group_irq(4) + IRQ_GPIO_0 + 128;
+ break;
+ case IRQ_GPIO5:
+ irq = __gpio_group_irq(5) + IRQ_GPIO_0 + 160;
+ break;
+ case IRQ_DMAC0:
+ case IRQ_DMAC1:
+ irq = __dmac_get_irq() + IRQ_DMA_0;
+ break;
+ }
+
+ return irq;
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ int irq = 0;
+ static unsigned long intc_ipr = 0;
+
+ intc_ipr |= REG_INTC_IPR;
+
+ if (!intc_ipr) return;
+
+ irq = ffs(intc_ipr) - 1;
+ intc_ipr &= ~(1<<irq);
+
+ irq = plat_real_irq(irq);
+ do_IRQ(irq);
+}
diff --git a/arch/mips/jz4750l/platform.c b/arch/mips/jz4750l/platform.c
new file mode 100644
index 00000000000..66373c76e29
--- /dev/null
+++ b/arch/mips/jz4750l/platform.c
@@ -0,0 +1,141 @@
+/*
+ * Platform device support for Jz4740 SoC.
+ *
+ * Copyright 2007, <yliu@ingenic.cn>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/resource.h>
+
+#include <asm/jzsoc.h>
+#if 0
+/* OHCI (USB full speed host controller) */
+static struct resource jz_usb_ohci_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap
+ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_UHC,
+ .end = IRQ_UHC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32)0;
+
+static struct platform_device jz_usb_ohci_device = {
+ .name = "jz-ohci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ohci_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources),
+ .resource = jz_usb_ohci_resources,
+};
+#endif
+/*** LCD controller ***/
+static struct resource jz_lcd_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(LCD_BASE),
+ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_LCD,
+ .end = IRQ_LCD,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 jz_lcd_dmamask = ~(u32)0;
+
+static struct platform_device jz_lcd_device = {
+ .name = "jz-lcd",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_lcd_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_lcd_resources),
+ .resource = jz_lcd_resources,
+};
+
+/* UDC (USB gadget controller) */
+static struct resource jz_usb_gdt_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(UDC_BASE),
+ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_UDC,
+ .end = IRQ_UDC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 udc_dmamask = ~(u32)0;
+
+static struct platform_device jz_usb_gdt_device = {
+ .name = "jz-udc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &udc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources),
+ .resource = jz_usb_gdt_resources,
+};
+
+/** MMC/SD controller **/
+static struct resource jz_mmc_resources[] = {
+ [0] = {
+ .start = CPHYSADDR(MSC_BASE),
+ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_MSC0,
+ .end = IRQ_MSC0,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 jz_mmc_dmamask = ~(u32)0;
+
+static struct platform_device jz_mmc_device = {
+ .name = "jz-mmc",
+ .id = 0,
+ .dev = {
+ .dma_mask = &jz_mmc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(jz_mmc_resources),
+ .resource = jz_mmc_resources,
+};
+
+/* All */
+static struct platform_device *jz_platform_devices[] __initdata = {
+// &jz_usb_ohci_device,
+ &jz_lcd_device,
+ &jz_usb_gdt_device,
+ &jz_mmc_device,
+};
+
+static int __init jz_platform_init(void)
+{
+ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
+}
+
+arch_initcall(jz_platform_init);
diff --git a/arch/mips/jz4750l/pm.c b/arch/mips/jz4750l/pm.c
new file mode 100644
index 00000000000..d666099aea3
--- /dev/null
+++ b/arch/mips/jz4750l/pm.c
@@ -0,0 +1,461 @@
+/*
+ * linux/arch/mips/jz4750l/common/pm.c
+ *
+ * JZ4750L Power Management Routines
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/pm_legacy.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+
+#include <asm/cacheops.h>
+#include <asm/jzsoc.h>
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+#define GPIO_PORT_NUM 6
+
+/*
+ * __gpio_as_sleep set all pins to pull-disable, and set all pins as input
+ * except sdram and the pins which can be used as CS1_N to CS4_N for chip select.
+ */
+#define __gpio_as_sleep() \
+do { \
+ REG_GPIO_PXFUNC(1) = ~0x03ff7fff; \
+ REG_GPIO_PXSELC(1) = ~0x03ff7fff; \
+ REG_GPIO_PXDIRC(1) = ~0x03ff7fff; \
+ REG_GPIO_PXPES(1) = 0xffffffff; \
+ REG_GPIO_PXFUNC(2) = ~0x01e00000; \
+ REG_GPIO_PXSELC(2) = ~0x01e00000; \
+ REG_GPIO_PXDIRC(2) = ~0x01e00000; \
+ REG_GPIO_PXPES(2) = 0xffffffff; \
+ REG_GPIO_PXFUNC(3) = 0xffffffff; \
+ REG_GPIO_PXSELC(3) = 0xffffffff; \
+ REG_GPIO_PXDIRC(3) = 0xffffffff; \
+ REG_GPIO_PXPES(3) = 0xffffffff; \
+ REG_GPIO_PXFUNC(4) = 0xffffffff; \
+ REG_GPIO_PXSELC(4) = 0xffffffff; \
+ REG_GPIO_PXDIRC(4) = 0xffffffff; \
+ REG_GPIO_PXPES(4) = 0xffffffff; \
+ REG_GPIO_PXFUNC(5) = 0xffffffff; \
+ REG_GPIO_PXSELC(5) = 0xffffffff; \
+ REG_GPIO_PXDIRC(5) = 0xffffffff; \
+ REG_GPIO_PXPES(5) = 0xffffffff; \
+} while (0)
+
+static int jz_pm_do_hibernate(void)
+{
+ printk("Put CPU into hibernate mode.\n");
+
+ /* Mask all interrupts */
+ REG_INTC_IMSR = 0xffffffff;
+
+ /*
+ * RTC Wakeup or 1Hz interrupt can be enabled or disabled
+ * through RTC driver's ioctl (linux/driver/char/rtc_jz.c).
+ */
+
+ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT);
+
+ /* Set reset pin low-level assertion time after wakeup: must > 60ms */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */
+
+ /* Scratch pad register to be reserved */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HSPR = 0x12345678;
+
+ /* clear wakeup status register */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HWRSR = 0x0;
+
+ /* Put CPU to power down mode */
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_HCR = RTC_HCR_PD;
+
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ while(1);
+
+ /* We can't get here */
+ return 0;
+}
+
+/* NOTES:
+ * 1: Pins that are floated (NC) should be set as input and pull-enable.
+ * 2: Pins that are pull-up or pull-down by outside should be set as input
+ * and pull-disable.
+ * 3: Pins that are connected to a chip except sdram and nand flash
+ * should be set as input and pull-disable, too.
+ */
+static void jz_board_do_sleep(unsigned long *ptr)
+{
+ unsigned char i;
+
+ /* Print messages of GPIO registers for debug */
+ for(i=0;i<GPIO_PORT_NUM;i++) {
+ dprintk("run dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
+ }
+
+ /* Save GPIO registers */
+ for(i = 1; i < GPIO_PORT_NUM; i++) {
+ *ptr++ = REG_GPIO_PXFUN(i);
+ *ptr++ = REG_GPIO_PXSEL(i);
+ *ptr++ = REG_GPIO_PXDIR(i);
+ *ptr++ = REG_GPIO_PXPE(i);
+ *ptr++ = REG_GPIO_PXIM(i);
+ *ptr++ = REG_GPIO_PXDAT(i);
+ *ptr++ = REG_GPIO_PXTRG(i);
+ }
+
+ /*
+ * Set all pins to pull-disable, and set all pins as input except
+ * sdram and the pins which can be used as CS1_N to CS4_N for chip select.
+ */
+ __gpio_as_sleep();
+
+ /*
+ * Set proper status for GPC21 to GPC24 which can be used as CS1_N to CS4_N.
+ * Keep the pins' function used for chip select(CS) here according to your
+ * system to avoid chip select crashing with sdram when resuming from sleep mode.
+ */
+
+#if defined(CONFIG_JZ4750L_APUS)
+ /* GPB25/CS1_N is used as chip select for nand flash, shouldn't be change. */
+
+ /* GPB26/CS2_N is connected to nand flash, needn't be changed. */
+
+ /* GPB28/CS3_N is used as cs8900's chip select, shouldn't be changed. */
+
+ /* GPB27/CS4_N is used as NOR's chip select, shouldn't be changed. */
+#endif
+
+ /*
+ * Enable pull for NC pins here according to your system
+ */
+
+#if defined(CONFIG_JZ4750L_APUS)
+#endif
+
+ /*
+ * If you must set some GPIOs as output to high level or low level,
+ * you can set them here, using:
+ * __gpio_as_output(n);
+ * __gpio_set_pin(n); or __gpio_clear_pin(n);
+ */
+
+#if defined(CONFIG_JZ4750L_APUS)
+ /* GPC7 which is used as AMPEN_N should be set to high to disable audio amplifier */
+ __gpio_as_output(32*2+7);
+ __gpio_set_pin(32*2+7);
+#endif
+
+#ifdef DEBUG
+ /* Keep uart function for printing debug message */
+ __gpio_as_uart0();
+ __gpio_as_uart1();
+ __gpio_as_uart2();
+ __gpio_as_uart3();
+
+ /* Print messages of GPIO registers for debug */
+ for(i=0;i<GPIO_PORT_NUM;i++) {
+ dprintk("sleep dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
+ }
+#endif
+}
+
+static void jz_board_do_resume(unsigned long *ptr)
+{
+ unsigned char i;
+
+ /* Restore GPIO registers */
+ for(i = 1; i < GPIO_PORT_NUM; i++) {
+ REG_GPIO_PXFUNS(i) = *ptr;
+ REG_GPIO_PXFUNC(i) = ~(*ptr++);
+
+ REG_GPIO_PXSELS(i) = *ptr;
+ REG_GPIO_PXSELC(i) = ~(*ptr++);
+
+ REG_GPIO_PXDIRS(i) = *ptr;
+ REG_GPIO_PXDIRC(i) = ~(*ptr++);
+
+ REG_GPIO_PXPES(i) = *ptr;
+ REG_GPIO_PXPEC(i) = ~(*ptr++);
+
+ REG_GPIO_PXIMS(i)=*ptr;
+ REG_GPIO_PXIMC(i)=~(*ptr++);
+
+ REG_GPIO_PXDATS(i)=*ptr;
+ REG_GPIO_PXDATC(i)=~(*ptr++);
+
+ REG_GPIO_PXTRGS(i)=*ptr;
+ REG_GPIO_PXTRGC(i)=~(*ptr++);
+ }
+
+ /* Print messages of GPIO registers for debug */
+ for(i=0;i<GPIO_PORT_NUM;i++) {
+ dprintk("resume dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \
+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \
+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i));
+ }
+}
+
+
+
+static int jz_pm_do_sleep(void)
+{
+ unsigned long delta;
+ unsigned long nfcsr = REG_EMC_NFCSR;
+ unsigned long opcr = REG_CPM_OPCR;
+ unsigned long imr = REG_INTC_IMR;
+ unsigned long sadc = REG_SADC_ENA;
+ unsigned long sleep_gpio_save[7*(GPIO_PORT_NUM-1)];
+
+ printk("Put CPU into sleep mode.\n");
+
+ /* Preserve current time */
+ delta = xtime.tv_sec - REG_RTC_RSR;
+
+ /* Disable nand flash */
+ REG_EMC_NFCSR = ~0xff;
+
+ /* stop sadc */
+ REG_SADC_ENA &= ~0x7;
+ while((REG_SADC_ENA & 0x7) != 0);
+ udelay(100);
+
+ /*stop udc and usb*/
+ __cpm_suspend_uhcphy();
+ __cpm_suspend_udcphy();
+
+ /* Sleep on-board modules */
+ jz_board_do_sleep(sleep_gpio_save);
+
+ /* Mask all interrupts */
+ REG_INTC_IMSR = 0xffffffff;
+
+ /* Just allow following interrupts to wakeup the system.
+ * Note: modify this according to your system.
+ */
+
+ /* enable RTC alarm */
+ __intc_unmask_irq(IRQ_RTC);
+#if 0
+ /* make system wake up after n seconds by RTC alarm */
+ unsigned int v, n;
+ n = 10;
+ while (!__rtc_write_ready());
+ __rtc_enable_alarm();
+ while (!__rtc_write_ready());
+ __rtc_enable_alarm_irq();
+ while (!__rtc_write_ready());
+ v = __rtc_get_second();
+ while (!__rtc_write_ready());
+ __rtc_set_alarm_second(v+n);
+#endif
+
+ /* WAKEUP key */
+ __gpio_as_irq_rise_edge(GPIO_WAKEUP);
+ __gpio_unmask_irq(GPIO_WAKEUP);
+ __intc_unmask_irq(IRQ_GPIO0 - (GPIO_WAKEUP/32)); /* unmask IRQ_GPIOn depends on GPIO_WAKEUP */
+
+ /* disable externel clock Oscillator in sleep mode */
+ __cpm_disable_osc_in_sleep();
+ /* select 32K crystal as RTC clock in sleep mode */
+ __cpm_select_rtcclk_rtc();
+
+ /* Enter SLEEP mode */
+ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
+ REG_CPM_LCR |= CPM_LCR_LPM_SLEEP;
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0");
+
+ /* Restore to IDLE mode */
+ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK;
+ REG_CPM_LCR |= CPM_LCR_LPM_IDLE;
+
+ /* Restore nand flash control register */
+ REG_EMC_NFCSR = nfcsr;
+
+ /* Restore interrupts */
+ REG_INTC_IMSR = imr;
+ REG_INTC_IMCR = ~imr;
+
+ /* Restore sadc */
+ REG_SADC_ENA = sadc;
+
+ /* Resume on-board modules */
+ jz_board_do_resume(sleep_gpio_save);
+
+ /* Restore Oscillator and Power Control Register */
+ REG_CPM_OPCR = opcr;
+
+ /* Restore current time */
+ xtime.tv_sec = REG_RTC_RSR + delta;
+
+ return 0;
+}
+
+/* Put CPU to HIBERNATE mode */
+int jz_pm_hibernate(void)
+{
+ return jz_pm_do_hibernate();
+}
+
+#ifndef CONFIG_JZ_POWEROFF
+static irqreturn_t pm_irq_handler (int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+#endif
+
+/* Put CPU to SLEEP mode */
+int jz_pm_sleep(void)
+{
+ int retval;
+
+#ifndef CONFIG_JZ_POWEROFF
+ if ((retval = request_irq (IRQ_GPIO_0 + GPIO_WAKEUP, pm_irq_handler, IRQF_DISABLED,
+ "PM", NULL))) {
+ printk ("PM could not get IRQ for GPIO_WAKEUP\n");
+ return retval;
+ }
+#endif
+
+ pm_send_all(PM_SUSPEND, (void *)3);
+ retval = jz_pm_do_sleep();
+ pm_send_all(PM_RESUME, (void *)0);
+
+#ifndef CONFIG_JZ_POWEROFF
+ free_irq (IRQ_GPIO_0 + GPIO_WAKEUP, NULL);
+#endif
+
+ return retval;
+}
+
+#if 0
+/* Deprecated ,was used by dpm */
+void jz_pm_idle(void)
+{
+ local_irq_disable();
+ if (!need_resched()) {
+ local_irq_enable();
+ cpu_wait();
+ }
+}
+#endif
+
+
+#ifdef CONFIG_SYSCTL
+
+/*
+ * Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6
+ * when all the PM interfaces exist nicely.
+ */
+#define CTL_PM_SUSPEND 1
+#define CTL_PM_HIBERNATE 2
+
+/*----------------------------------------------------------------------------
+ * Power Management sleep sysctl proc interface
+ *
+ * A write to /proc/sys/pm/suspend invokes this function
+ * which initiates a sleep.
+ *--------------------------------------------------------------------------*/
+static int sysctl_jz_pm_sleep(void)
+{
+ return jz_pm_sleep();
+}
+
+/*----------------------------------------------------------------------------
+ * Power Management sleep sysctl proc interface
+ *
+ * A write to /proc/sys/pm/hibernate invokes this function
+ * which initiates a poweroff.
+ *--------------------------------------------------------------------------*/
+static int sysctl_jz_pm_hibernate(void)
+{
+ return jz_pm_hibernate();
+}
+
+static struct ctl_table pm_table[] =
+{
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "suspend",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0600,
+ .proc_handler = &sysctl_jz_pm_sleep,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "hibernate",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0600,
+ .proc_handler = &sysctl_jz_pm_hibernate,
+ },
+ { .ctl_name = 0}
+};
+
+static struct ctl_table pm_dir_table[] =
+{
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "pm",
+ .mode = 0555,
+ .child = pm_table,
+ },
+ { .ctl_name = 0}
+};
+
+#endif /* CONFIG_SYSCTL */
+
+/*
+ * Initialize power interface
+ */
+static int __init jz_pm_init(void)
+{
+ printk("Power Management for JZ\n");
+
+#ifdef CONFIG_SYSCTL
+ register_sysctl_table(pm_dir_table);
+#endif
+
+ return 0;
+}
+
+module_init(jz_pm_init);
diff --git a/arch/mips/jz4750l/proc.c b/arch/mips/jz4750l/proc.c
new file mode 100644
index 00000000000..d376210358b
--- /dev/null
+++ b/arch/mips/jz4750l/proc.c
@@ -0,0 +1,885 @@
+/*
+ * linux/arch/mips/jz4750l/proc.c
+ *
+ * /proc/jz/ procfs for jz4750l on-chip modules.
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/page-flags.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/jzsoc.h>
+
+//#define DEBUG 1
+#undef DEBUG
+
+
+struct proc_dir_entry *proc_jz_root;
+
+
+/*
+ * EMC Modules
+ */
+static int emc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4);
+ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4);
+ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR);
+ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR);
+ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR);
+ return len;
+}
+
+/*
+ * Power Manager Module
+ */
+static int pmc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long lcr = REG_CPM_LCR;
+ unsigned long clkgr = REG_CPM_CLKGR;
+
+ len += sprintf (page+len, "Low Power Mode : %s\n",
+ ((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ?
+ "IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ?
+ "SLEEP" : "HIBERNATE"));
+ len += sprintf (page+len, "Doze Mode : %s\n",
+ (lcr & CPM_LCR_DOZE_ON) ? "on" : "off");
+ if (lcr & CPM_LCR_DOZE_ON)
+ len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT));
+ len += sprintf (page+len, "AUX_CPU : %s\n",
+ (clkgr & CPM_CLKGR_AUX_CPU) ? "stopped" : "running");
+ len += sprintf (page+len, "AHB1 : %s\n",
+ (clkgr & CPM_CLKGR_AHB1) ? "stopped" : "running");
+ len += sprintf (page+len, "IDCT : %s\n",
+ (clkgr & CPM_CLKGR_IDCT) ? "stopped" : "running");
+ len += sprintf (page+len, "DB : %s\n",
+ (clkgr & CPM_CLKGR_DB) ? "stopped" : "running");
+ len += sprintf (page+len, "ME : %s\n",
+ (clkgr & CPM_CLKGR_ME) ? "stopped" : "running");
+ len += sprintf (page+len, "MC : %s\n",
+ (clkgr & CPM_CLKGR_MC) ? "stopped" : "running");
+ len += sprintf (page+len, "TVE : %s\n",
+ (clkgr & CPM_CLKGR_TVE) ? "stopped" : "running");
+ len += sprintf (page+len, "TSSI : %s\n",
+ (clkgr & CPM_CLKGR_TSSI) ? "stopped" : "running");
+ len += sprintf (page+len, "IPU : %s\n",
+ (clkgr & CPM_CLKGR_IPU) ? "stopped" : "running");
+ len += sprintf (page+len, "DMAC : %s\n",
+ (clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running");
+ len += sprintf (page+len, "UDC : %s\n",
+ (clkgr & CPM_CLKGR_UDC) ? "stopped" : "running");
+ len += sprintf (page+len, "LCD : %s\n",
+ (clkgr & CPM_CLKGR_LCD) ? "stopped" : "running");
+ len += sprintf (page+len, "CIM : %s\n",
+ (clkgr & CPM_CLKGR_CIM) ? "stopped" : "running");
+ len += sprintf (page+len, "SADC : %s\n",
+ (clkgr & CPM_CLKGR_SADC) ? "stopped" : "running");
+ len += sprintf (page+len, "MSC0 : %s\n",
+ (clkgr & CPM_CLKGR_MSC0) ? "stopped" : "running");
+ len += sprintf (page+len, "MSC1 : %s\n",
+ (clkgr & CPM_CLKGR_MSC1) ? "stopped" : "running");
+ len += sprintf (page+len, "SSI : %s\n",
+ (clkgr & CPM_CLKGR_SSI) ? "stopped" : "running");
+ len += sprintf (page+len, "I2C : %s\n",
+ (clkgr & CPM_CLKGR_I2C) ? "stopped" : "running");
+ len += sprintf (page+len, "RTC : %s\n",
+ (clkgr & CPM_CLKGR_RTC) ? "stopped" : "running");
+ len += sprintf (page+len, "TCU : %s\n",
+ (clkgr & CPM_CLKGR_TCU) ? "stopped" : "running");
+ len += sprintf (page+len, "UART1 : %s\n",
+ (clkgr & CPM_CLKGR_UART1) ? "stopped" : "running");
+ len += sprintf (page+len, "UART0 : %s\n",
+ (clkgr & CPM_CLKGR_UART0) ? "stopped" : "running");
+ return len;
+}
+
+static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16);
+ return count;
+}
+
+/*
+ * Clock Generation Module
+ */
+#define TO_MHZ(x) (x/1000000),(x%1000000)/10000
+#define TO_KHZ(x) (x/1000),(x%1000)/10
+
+static int cgm_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */
+ unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */
+ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+ unsigned int od[4] = {1, 2, 2, 4};
+
+ len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr);
+ len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr);
+ len += sprintf (page+len, "PLL : %s\n",
+ (cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF");
+ len += sprintf (page+len, "m:n:o : %d:%d:%d\n",
+ __cpm_get_pllm() + 2,
+ __cpm_get_plln() + 2,
+ od[__cpm_get_pllod()]
+ );
+ len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n",
+ div[__cpm_get_cdiv()],
+ div[__cpm_get_hdiv()],
+ div[__cpm_get_mdiv()],
+ div[__cpm_get_pdiv()]
+ );
+ len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout()));
+ len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk()));
+ len += sprintf (page+len, "HCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_hclk()));
+ len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk()));
+ len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk()));
+ len += sprintf (page+len, "H1CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_h1clk()));
+ len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk()));
+ len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk()));
+ len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk()));
+ len += sprintf (page+len, "MSC0CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(0)));
+ len += sprintf (page+len, "MSC1CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(1)));
+ len += sprintf (page+len, "EXTALCLK0 : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk0()));
+ len += sprintf (page+len, "EXTALCLK(by CPM): %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk()));
+ len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk()));
+
+ return len;
+}
+
+static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16);
+ return count;
+}
+
+
+/* USAGE:
+ * echo n > /proc/jz/ipu // n = [1,...,9], alloc mem, 2^n pages.
+ * echo FF > /proc/jz/ipu // 255, free all buffer
+ * echo xxxx > /proc/jz/ipu // free buffer which addr is xxxx
+ * echo llll > /proc/jz/ipu // add_wired_entry(l,l,l,l)
+ * echo 0 > /proc/jz/ipu // debug, print ipu_buf
+ * od -X /proc/jz/ipu // read mem addr
+ */
+
+typedef struct _ipu_buf {
+ unsigned int addr; /* phys addr */
+ unsigned int page_shift;
+} ipu_buf_t;
+
+#define IPU_BUF_MAX 4 /* 4 buffers */
+
+static struct _ipu_buf ipu_buf[IPU_BUF_MAX];
+static int ipu_buf_cnt = 0;
+static unsigned char g_asid=0;
+
+extern void local_flush_tlb_all(void);
+
+/* CP0 hazard avoidance. */
+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
+ "nop; nop; nop; nop; nop; nop;\n\t" \
+ ".set reorder\n\t")
+void show_tlb(void)
+{
+#define ASID_MASK 0xFF
+
+ unsigned long flags;
+ unsigned int old_ctx;
+ unsigned int entry;
+ unsigned int entrylo0, entrylo1, entryhi;
+ unsigned int pagemask;
+
+ local_irq_save(flags);
+
+ /* Save old context */
+ old_ctx = (read_c0_entryhi() & 0xff);
+
+ printk("TLB content:\n");
+ entry = 0;
+ while(entry < 32) {
+ write_c0_index(entry);
+ BARRIER;
+ tlb_read();
+ BARRIER;
+ entryhi = read_c0_entryhi();
+ entrylo0 = read_c0_entrylo0();
+ entrylo1 = read_c0_entrylo1();
+ pagemask = read_c0_pagemask();
+ printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK);
+ printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : "");
+ printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : "");
+
+ printk("\t\tpagemask=0x%08x", pagemask);
+ printk("\tentryhi=0x%08x\n", entryhi);
+ printk("\t\tentrylo0=0x%08x", entrylo0);
+ printk("\tentrylo1=0x%08x\n", entrylo1);
+
+ entry++;
+ }
+ BARRIER;
+ write_c0_entryhi(old_ctx);
+
+ local_irq_restore(flags);
+}
+
+static void ipu_add_wired_entry(unsigned long pid,
+ unsigned long entrylo0, unsigned long entrylo1,
+ unsigned long entryhi, unsigned long pagemask)
+{
+ unsigned long flags;
+ unsigned long wired;
+ unsigned long old_pagemask;
+ unsigned long old_ctx;
+ struct task_struct *g, *p;
+
+ /* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */
+ wired = read_c0_wired();
+ if (wired) return;
+
+ do_each_thread(g, p) {
+ if (p->pid == pid )
+ g_asid = p->mm->context[0];
+ } while_each_thread(g, p);
+
+
+ local_irq_save(flags);
+
+ entrylo0 = entrylo0 >> 6; /* PFN */
+ entrylo0 |= 0x6 | (0 << 3); /* Write-through cacheable, dirty, valid */
+
+ /* Save old context and create impossible VPN2 value */
+ old_ctx = read_c0_entryhi() & 0xff;
+ old_pagemask = read_c0_pagemask();
+ wired = read_c0_wired();
+ write_c0_wired(wired + 1);
+ write_c0_index(wired);
+ BARRIER;
+ entryhi &= ~0xff; /* new add, 20070906 */
+ entryhi |= g_asid; /* new add, 20070906 */
+// entryhi |= old_ctx; /* new add, 20070906 */
+ write_c0_pagemask(pagemask);
+ write_c0_entryhi(entryhi);
+ write_c0_entrylo0(entrylo0);
+ write_c0_entrylo1(entrylo1);
+ BARRIER;
+ tlb_write_indexed();
+ BARRIER;
+
+ write_c0_entryhi(old_ctx);
+ BARRIER;
+ write_c0_pagemask(old_pagemask);
+ local_flush_tlb_all();
+ local_irq_restore(flags);
+#if defined(DEBUG)
+ printk("\nold_ctx=%03d\n", old_ctx);
+
+ show_tlb();
+#endif
+}
+
+static void ipu_del_wired_entry( void )
+{
+ unsigned long flags;
+ unsigned long wired;
+
+ local_irq_save(flags);
+ wired = read_c0_wired();
+ if ( wired > 0 ) {
+ write_c0_wired(wired - 1);
+ }
+ local_irq_restore(flags);
+}
+
+static inline void ipu_buf_get( unsigned int page_shift )
+{
+ unsigned char * virt_addr;
+ int i;
+ for ( i=0; i< IPU_BUF_MAX; ++i ) {
+ if ( ipu_buf[i].addr == 0 ) {
+ break;
+ }
+ }
+
+ if ( (ipu_buf_cnt = i) == IPU_BUF_MAX ) {
+ printk("Error, no free ipu buffer.\n");
+ return ;
+ }
+
+ virt_addr = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift);
+
+ if ( virt_addr ) {
+ ipu_buf[ipu_buf_cnt].addr = (unsigned int)virt_to_phys((void *)virt_addr);
+ ipu_buf[ipu_buf_cnt].page_shift = page_shift;
+
+ for (i = 0; i < (1<<page_shift); i++) {
+ SetPageReserved(virt_to_page(virt_addr));
+ virt_addr += PAGE_SIZE;
+ }
+ }
+ else {
+ printk("get memory Failed.\n");
+ }
+}
+
+static inline void ipu_buf_free( unsigned int phys_addr )
+{
+ unsigned char * virt_addr, *addr;
+ int cnt, i;
+
+ if ( phys_addr == 0 )
+ return ;
+
+ for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt )
+ if ( phys_addr == ipu_buf[cnt].addr )
+ break;
+
+ if ( cnt == IPU_BUF_MAX ) { /* addr not in the ipu buffers */
+ printk("Invalid addr:0x%08x\n", (unsigned int)phys_addr);
+ }
+
+ virt_addr = (unsigned char *)phys_to_virt(ipu_buf[cnt].addr);
+ addr = virt_addr;
+ for (i = 0; i < (1<<ipu_buf[cnt].page_shift); i++) {
+ ClearPageReserved(virt_to_page(addr));
+ addr += PAGE_SIZE;
+ }
+
+ if ( cnt == 0 )
+ ipu_del_wired_entry();
+
+ free_pages((unsigned long )virt_addr, ipu_buf[cnt].page_shift);
+
+ ipu_buf[cnt].addr = 0;
+ ipu_buf[cnt].page_shift = 0;
+}
+
+static int ipu_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ /* read as binary */
+ unsigned int * pint;
+ pint = (unsigned int *) (page+len);
+
+ if ( ipu_buf_cnt >= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */
+ printk("no free buffer.\n");
+ *pint = 0;
+ }
+ else
+ *pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */
+ len += sizeof(unsigned int);
+
+#if defined(DEBUG)
+ show_tlb();
+#endif
+ return len;
+
+}
+
+static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ unsigned int val ;
+ int cnt,i;
+ char buf[12];
+ unsigned long pid, entrylo0, entrylo1, entryhi, pagemask;
+#if defined(DEBUG)
+ printk("ipu write count=%u\n", count);
+#endif
+ if (count == (8*5+1)) {
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer+8*0, 8);
+ pid = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer+8*1, 8);
+ entrylo0 = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer+8*2, 8);
+ entrylo1 = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer+8*3, 8);
+ entryhi = simple_strtoul(buf, 0, 16);
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer+8*4, 8);
+ pagemask = simple_strtoul(buf, 0, 16);
+
+#if defined(DEBUG)
+ printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n",
+ pid, entrylo0, entrylo1, entryhi, pagemask);
+#endif
+ ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask);
+ return 41;
+ }
+ else if ( count <= 8+1 ) {
+ for (i=0;i<12;i++) buf[i]=0;
+ strncpy(buf, buffer, 8);
+ val = simple_strtoul(buf, 0, 16);
+ } else if (count == 44) {
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer, 10);
+ pid = simple_strtoul(buf, 0, 16);
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer + 11, 10);
+ entryhi = simple_strtoul(buf, 0, 16);//vaddr
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer + 22, 10);
+ entrylo0 = simple_strtoul(buf, 0, 16);//paddr
+ for (i = 0; i < 12; i++)
+ buf[i] = 0;
+ strncpy(buf, buffer + 33, 10);
+ pagemask = simple_strtoul(buf, 0, 16);
+ pagemask = 0x3ff << 13; /* Fixed to 4MB page size */
+ ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask);
+ return 44;
+ } else {
+ printk("ipu write count error, count=%d\n.", (unsigned int)count);
+ return -1;
+ }
+
+ /* val: 1-9, page_shift, val>= 10: ipu_buf.addr */
+ if ( val == 0 ) { /* debug, print ipu_buf info */
+ for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt)
+ printk("ipu_buf[%d]: addr=0x%08x, page_shift=%d\n",
+ cnt, ipu_buf[cnt].addr, ipu_buf[cnt].page_shift );
+#if defined(DEBUG)
+ show_tlb();
+#endif
+ }
+ else if ( 0< val && val < 10 ) {
+ ipu_buf_get(val);
+ }
+ else if ( val == 0xff ) { /* 255: free all ipu_buf */
+ for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt ) {
+ ipu_buf_free(ipu_buf[cnt].addr);
+ }
+ }
+ else {
+ ipu_buf_free(val);
+ }
+
+ return count;
+}
+
+/*
+ * UDC hotplug
+ */
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+extern int jz_udc_active; /* defined in drivers/char/jzchar/jz_udc_hotplug.c */
+#endif
+
+#ifndef GPIO_UDC_HOTPLUG
+#define GPIO_UDC_HOTPLUG 86
+#endif
+
+static int udc_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ if (__gpio_get_pin(GPIO_UDC_HOTPLUG)) {
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+
+ /* Cable has connected, wait for disconnection. */
+ __gpio_as_irq_fall_edge(GPIO_UDC_HOTPLUG);
+
+ if (jz_udc_active)
+ len += sprintf (page+len, "CONNECT_CABLE\n");
+ else
+ len += sprintf (page+len, "CONNECT_POWER\n");
+#else
+ len += sprintf (page+len, "CONNECT\n");
+#endif
+ }
+ else {
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+ /* Cable has disconnected, wait for connection. */
+ __gpio_as_irq_rise_edge(GPIO_UDC_HOTPLUG);
+#endif
+
+ len += sprintf (page+len, "REMOVE\n");
+ }
+
+ return len;
+}
+
+/*
+ * MMC/SD hotplug
+ */
+
+#ifndef MSC_HOTPLUG_PIN
+#define MSC_HOTPLUG_PIN 90
+#endif
+
+static int mmc_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ if (__gpio_get_pin(MSC_HOTPLUG_PIN))
+ len += sprintf (page+len, "REMOVE\n");
+ else
+ len += sprintf (page+len, "INSERT\n");
+
+ return len;
+}
+
+/***********************************************************************
+ * IPU memory management (used by mplayer and other apps)
+ *
+ * We reserved 4MB memory for IPU
+ * The memory base address is jz_ipu_framebuf
+ */
+
+/* Usage:
+ *
+ * echo n > /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages
+ * echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx
+ * echo FF > /proc/jz/ipu // FF, free all buffers
+ * od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer
+ */
+
+//#define DEBUG_IMEM 1
+
+#define IMEM_MAX_ORDER 10 /* max 2^10 * 4096 = 4MB */
+
+static unsigned int jz_imem_base; /* physical base address of ipu memory */
+
+static unsigned int allocated_phys_addr = 0;
+
+/*
+ * Allocated buffer list
+ */
+typedef struct imem_list {
+ unsigned int phys_start; /* physical start addr */
+ unsigned int phys_end; /* physical end addr */
+ struct imem_list *next;
+} imem_list_t;
+
+static struct imem_list *imem_list_head = NULL; /* up sorted by phys_start */
+
+#ifdef DEBUG_IMEM
+static void dump_imem_list(void)
+{
+ struct imem_list *imem;
+
+ printk("*** dump_imem_list 0x%x ***\n", (u32)imem_list_head);
+ imem = imem_list_head;
+ while (imem) {
+ printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next);
+ imem = imem->next;
+ }
+}
+#endif
+
+/* allocate 2^order pages inside the 4MB memory */
+static int imem_alloc(unsigned int order)
+{
+ int alloc_ok = 0;
+ unsigned int start, end;
+ unsigned int size = (1 << order) * PAGE_SIZE;
+ struct imem_list *imem, *imemn, *imemp;
+
+ allocated_phys_addr = 0;
+
+ start = jz_imem_base;
+ end = start + (1 << IMEM_MAX_ORDER) * PAGE_SIZE;
+
+ imem = imem_list_head;
+ while (imem) {
+ if ((imem->phys_start - start) >= size) {
+ /* we got a valid address range */
+ alloc_ok = 1;
+ break;
+ }
+
+ start = imem->phys_end + 1;
+ imem = imem->next;
+ }
+
+ if (!alloc_ok) {
+ if ((end - start) >= size)
+ alloc_ok = 1;
+ }
+
+ if (alloc_ok) {
+ end = start + size - 1;
+ allocated_phys_addr = start;
+
+ /* add to imem_list, up sorted by phys_start */
+ imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL);
+ if (!imemn) {
+ return -ENOMEM;
+ }
+ imemn->phys_start = start;
+ imemn->phys_end = end;
+ imemn->next = NULL;
+
+ if (!imem_list_head)
+ imem_list_head = imemn;
+ else {
+ imem = imemp = imem_list_head;
+ while (imem) {
+ if (start < imem->phys_start) {
+ break;
+ }
+
+ imemp = imem;
+ imem = imem->next;
+ }
+
+ if (imem == imem_list_head) {
+ imem_list_head = imemn;
+ imemn->next = imem;
+ }
+ else {
+ imemn->next = imemp->next;
+ imemp->next = imemn;
+ }
+ }
+ }
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+ return 0;
+}
+
+static void imem_free(unsigned int phys_addr)
+{
+ struct imem_list *imem, *imemp;
+
+ imem = imemp = imem_list_head;
+ while (imem) {
+ if (phys_addr == imem->phys_start) {
+ if (imem == imem_list_head) {
+ imem_list_head = imem->next;
+ }
+ else {
+ imemp->next = imem->next;
+ }
+
+ kfree(imem);
+ break;
+ }
+
+ imemp = imem;
+ imem = imem->next;
+ }
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+}
+
+static void imem_free_all(void)
+{
+ struct imem_list *imem;
+
+ imem = imem_list_head;
+ while (imem) {
+ kfree(imem);
+ imem = imem->next;
+ }
+
+ imem_list_head = NULL;
+
+ allocated_phys_addr = 0;
+
+#ifdef DEBUG_IMEM
+ dump_imem_list();
+#endif
+}
+
+/*
+ * Return the allocated buffer address and the max order of free buffer
+ */
+static int imem_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned int start_addr, end_addr, max_order, max_size;
+ struct imem_list *imem;
+
+ unsigned int *tmp = (unsigned int *)(page + len);
+
+ start_addr = jz_imem_base;
+ end_addr = start_addr + (1 << IMEM_MAX_ORDER) * PAGE_SIZE;
+
+ if (!imem_list_head)
+ max_size = end_addr - start_addr;
+ else {
+ max_size = 0;
+ imem = imem_list_head;
+ while (imem) {
+ if (max_size < (imem->phys_start - start_addr))
+ max_size = imem->phys_start - start_addr;
+
+ start_addr = imem->phys_end + 1;
+ imem = imem->next;
+ }
+
+ if (max_size < (end_addr - start_addr))
+ max_size = end_addr - start_addr;
+ }
+
+ if (max_size > 0) {
+ max_order = get_order(max_size);
+ if (((1 << max_order) * PAGE_SIZE) > max_size)
+ max_order--;
+ }
+ else {
+ max_order = 0xffffffff; /* No any free buffer */
+ }
+
+ *tmp++ = allocated_phys_addr; /* address allocated by 'echo n > /proc/jz/imem' */
+ *tmp = max_order; /* max order of current free buffers */
+
+ len += 2 * sizeof(unsigned int);
+
+ return len;
+}
+
+static int imem_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ unsigned int val;
+
+ val = simple_strtoul(buffer, 0, 16);
+
+ if (val == 0xff) {
+ /* free all memory */
+ imem_free_all();
+ }
+ else if ((val >= 0) && (val <= IMEM_MAX_ORDER)) {
+ /* allocate 2^val pages */
+ imem_alloc(val);
+ }
+ else {
+ /* free buffer which phys_addr is val */
+ imem_free(val);
+ }
+
+ return count;
+}
+
+/*
+ * /proc/jz/xxx entry
+ *
+ */
+static int __init jz_proc_init(void)
+{
+ struct proc_dir_entry *res;
+ unsigned int virt_addr, i;
+
+ proc_jz_root = proc_mkdir("jz", 0);
+
+ /* External Memory Controller */
+ res = create_proc_entry("emc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = emc_read_proc;
+ res->write_proc = NULL;
+ res->data = NULL;
+ }
+
+ /* Power Management Controller */
+ res = create_proc_entry("pmc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = pmc_read_proc;
+ res->write_proc = pmc_write_proc;
+ res->data = NULL;
+ }
+
+ /* Clock Generation Module */
+ res = create_proc_entry("cgm", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = cgm_read_proc;
+ res->write_proc = cgm_write_proc;
+ res->data = NULL;
+ }
+
+ /* Image process unit */
+ res = create_proc_entry("ipu", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = ipu_read_proc;
+ res->write_proc = ipu_write_proc;
+ res->data = NULL;
+ }
+
+ /* udc hotplug */
+ res = create_proc_entry("udc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = udc_read_proc;
+ res->write_proc = NULL;
+ res->data = NULL;
+ }
+
+ /* mmc hotplug */
+ res = create_proc_entry("mmc", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = mmc_read_proc;
+ res->write_proc = NULL;
+ res->data = NULL;
+ }
+
+ /*
+ * Reserve a 4MB memory for IPU on JZ4750L.
+ */
+ jz_imem_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM_MAX_ORDER);
+ if (jz_imem_base) {
+ /* imem (IPU memory management) */
+ res = create_proc_entry("imem", 0644, proc_jz_root);
+ if (res) {
+ res->read_proc = imem_read_proc;
+ res->write_proc = imem_write_proc;
+ res->data = NULL;
+ }
+
+ /* Set page reserved */
+ virt_addr = jz_imem_base;
+ for (i = 0; i < (1 << IMEM_MAX_ORDER); i++) {
+ SetPageReserved(virt_to_page((void *)virt_addr));
+ virt_addr += PAGE_SIZE;
+ }
+
+ /* Convert to physical address */
+ jz_imem_base = virt_to_phys((void *)jz_imem_base);
+
+ printk("Total %dMB memory at 0x%x was reserved for IPU\n",
+ (unsigned int)((1 << IMEM_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem_base);
+ }
+
+ return 0;
+}
+
+__initcall(jz_proc_init);
diff --git a/arch/mips/jz4750l/prom.c b/arch/mips/jz4750l/prom.c
new file mode 100644
index 00000000000..f1ec324cf46
--- /dev/null
+++ b/arch/mips/jz4750l/prom.c
@@ -0,0 +1,198 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * PROM library initialisation code, supports YAMON and U-Boot.
+ *
+ * Copyright 2000, 2001, 2006 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
+ * This file was derived from Carsten Langgaard's
+ * arch/mips/mips-boards/xx files.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/jzsoc.h>
+
+/* #define DEBUG_CMDLINE */
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+char * prom_getcmdline(void)
+{
+ return &(arcs_cmdline[0]);
+}
+
+void prom_init_cmdline(void)
+{
+ char *cp;
+ int actr;
+
+ actr = 1; /* Always ignore argv[0] */
+
+ cp = &(arcs_cmdline[0]);
+ while(actr < prom_argc) {
+ strcpy(cp, prom_argv[actr]);
+ cp += strlen(prom_argv[actr]);
+ *cp++ = ' ';
+ actr++;
+ }
+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+ --cp;
+ if (prom_argc > 1)
+ *cp = '\0';
+
+}
+
+
+char *prom_getenv(char *envname)
+{
+#if 0
+ /*
+ * Return a pointer to the given environment variable.
+ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
+ */
+
+ char **env = prom_envp;
+ int i = strlen(envname);
+ int yamon = (*env && strchr(*env, '=') == NULL);
+
+ while (*env) {
+ if (yamon) {
+ if (strcmp(envname, *env++) == 0)
+ return *env;
+ } else {
+ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
+ return *env + i + 1;
+ }
+ env++;
+ }
+#endif
+ return NULL;
+}
+
+inline unsigned char str2hexnum(unsigned char c)
+{
+ if(c >= '0' && c <= '9')
+ return c - '0';
+ if(c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if(c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return 0; /* foo */
+}
+
+inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+ int i;
+
+ for(i = 0; i < 6; i++) {
+ unsigned char num;
+
+ if((*str == '.') || (*str == ':'))
+ str++;
+ num = str2hexnum(*str++) << 4;
+ num |= (str2hexnum(*str++));
+ ea[i] = num;
+ }
+}
+
+int get_ethernet_addr(char *ethernet_addr)
+{
+ char *ethaddr_str;
+
+ ethaddr_str = prom_getenv("ethaddr");
+ if (!ethaddr_str) {
+ printk("ethaddr not set in boot prom\n");
+ return -1;
+ }
+ str2eaddr(ethernet_addr, ethaddr_str);
+
+#if 0
+ {
+ int i;
+
+ printk("get_ethernet_addr: ");
+ for (i=0; i<5; i++)
+ printk("%02x:", (unsigned char)*(ethernet_addr+i));
+ printk("%02x\n", *(ethernet_addr+i));
+ }
+#endif
+
+ return 0;
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+void __init prom_init(void)
+{
+ unsigned char *memsize_str;
+ unsigned long memsize;
+
+ prom_argc = (int) fw_arg0;
+ prom_argv = (char **) fw_arg1;
+ prom_envp = (char **) fw_arg2;
+
+ mips_machtype = MACH_INGENIC_JZ4750L;
+
+ prom_init_cmdline();
+ memsize_str = prom_getenv("memsize");
+ if (!memsize_str) {
+ memsize = 0x04000000;
+ } else {
+ memsize = simple_strtol(memsize_str, NULL, 0);
+ }
+ add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
+/* used by early printk */
+void prom_putchar(char c)
+{
+ volatile u8 *uart_lsr = (volatile u8 *)(UART1_BASE + OFF_LSR);
+ volatile u8 *uart_tdr = (volatile u8 *)(UART1_BASE + OFF_TDR);
+
+ /* Wait for fifo to shift out some bytes */
+ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) );
+
+ *uart_tdr = (u8)c;
+}
+
+const char *get_system_type(void)
+{
+ return "JZ4750L";
+}
+
+EXPORT_SYMBOL(prom_getcmdline);
+EXPORT_SYMBOL(get_ethernet_addr);
+EXPORT_SYMBOL(str2eaddr);
diff --git a/arch/mips/jz4750l/reset.c b/arch/mips/jz4750l/reset.c
new file mode 100644
index 00000000000..90b521e100a
--- /dev/null
+++ b/arch/mips/jz4750l/reset.c
@@ -0,0 +1,46 @@
+/*
+ * linux/arch/mips/jz4750/reset.c
+ *
+ * JZ4750 reset routines.
+ *
+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
+ * Author: <yliu@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+void jz_restart(char *command)
+{
+ printk("Restarting after 4 ms\n");
+ REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN;
+ REG_WDT_TCNT = 0;
+ REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */
+ REG_TCU_TSCR = TCU_TSCR_WDTSC; /* enable wdt clock */
+ REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */
+ while (1);
+}
+
+void jz_halt(void)
+{
+ printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+
+ while (1)
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0");
+}
+
+void jz_power_off(void)
+{
+ jz_halt();
+}
diff --git a/arch/mips/jz4750l/setup.c b/arch/mips/jz4750l/setup.c
new file mode 100644
index 00000000000..b2e7e3b6d25
--- /dev/null
+++ b/arch/mips/jz4750l/setup.c
@@ -0,0 +1,199 @@
+/*
+ * linux/arch/mips/jz4750l/common/setup.c
+ *
+ * JZ4750L common setup routines.
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/ioport.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+#include <asm/pgtable.h>
+#include <asm/time.h>
+#include <asm/jzsoc.h>
+
+#ifdef CONFIG_PC_KEYB
+#include <asm/keyboard.h>
+#endif
+
+jz_clocks_t jz_clocks;
+
+extern char * __init prom_getcmdline(void);
+extern void __init jz_board_setup(void);
+extern void jz_restart(char *);
+extern void jz_halt(void);
+extern void jz_power_off(void);
+extern void jz_time_init(void);
+
+static void __init sysclocks_setup(void)
+{
+#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */
+ jz_clocks.cclk = __cpm_get_cclk();
+ jz_clocks.hclk = __cpm_get_hclk();
+ jz_clocks.pclk = __cpm_get_pclk();
+ jz_clocks.mclk = __cpm_get_mclk();
+ jz_clocks.h1clk = __cpm_get_h1clk();
+ jz_clocks.pixclk = __cpm_get_pixclk();
+ jz_clocks.i2sclk = __cpm_get_i2sclk();
+ jz_clocks.usbclk = __cpm_get_usbclk();
+ jz_clocks.mscclk = __cpm_get_mscclk(0);
+ jz_clocks.extalclk = __cpm_get_extalclk();
+ jz_clocks.rtcclk = __cpm_get_rtcclk();
+#else
+
+#define FPGACLK 8000000
+
+ jz_clocks.cclk = FPGACLK;
+ jz_clocks.hclk = FPGACLK;
+ jz_clocks.pclk = FPGACLK;
+ jz_clocks.mclk = FPGACLK;
+ jz_clocks.h1clk = FPGACLK;
+ jz_clocks.pixclk = FPGACLK;
+ jz_clocks.i2sclk = FPGACLK;
+ jz_clocks.usbclk = FPGACLK;
+ jz_clocks.mscclk = FPGACLK;
+ jz_clocks.extalclk = FPGACLK;
+ jz_clocks.rtcclk = FPGACLK;
+#endif
+
+ printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n",
+ (jz_clocks.cclk + 500000) / 1000000,
+ (jz_clocks.hclk + 500000) / 1000000,
+ (jz_clocks.pclk + 500000) / 1000000,
+ (jz_clocks.mclk + 500000) / 1000000);
+}
+
+static void __init soc_cpm_setup(void)
+{
+ /* Start all module clocks
+ */
+ __cpm_start_all();
+
+ /* Enable CKO to external memory */
+ __cpm_enable_cko();
+
+ /* CPU enters IDLE mode when executing 'wait' instruction */
+ __cpm_idle_mode();
+
+ /* Setup system clocks */
+ sysclocks_setup();
+}
+
+static void __init soc_harb_setup(void)
+{
+// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */
+// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */
+// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */
+}
+
+static void __init soc_emc_setup(void)
+{
+}
+
+static void __init soc_dmac_setup(void)
+{
+ __dmac_enable_module(0);
+ __dmac_enable_module(1);
+}
+
+static void __init jz_soc_setup(void)
+{
+ soc_cpm_setup();
+ soc_harb_setup();
+ soc_emc_setup();
+ soc_dmac_setup();
+}
+
+static void __init jz_serial_setup(void)
+{
+#ifdef CONFIG_SERIAL_8250
+ struct uart_port s;
+ REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */
+ memset(&s, 0, sizeof(s));
+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
+ s.iotype = SERIAL_IO_MEM;
+ s.regshift = 2;
+ s.uartclk = jz_clocks.extalclk ;
+
+ s.line = 0;
+ s.membase = (u8 *)UART0_BASE;
+ s.irq = IRQ_UART0;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS0 setup failed!\n");
+ }
+
+ s.line = 1;
+ s.membase = (u8 *)UART1_BASE;
+ s.irq = IRQ_UART1;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS1 setup failed!\n");
+ }
+
+ s.line = 2;
+ s.membase = (u8 *)UART2_BASE;
+ s.irq = IRQ_UART2;
+
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS2 setup failed!\n");
+ }
+/*
+ s.line = 3;
+ s.membase = (u8 *)UART3_BASE;
+ s.irq = IRQ_UART3;
+ if (early_serial_setup(&s) != 0) {
+ printk(KERN_ERR "Serial ttyS3 setup failed!\n");
+ }
+*/
+#endif
+}
+
+void __init plat_mem_setup(void)
+{
+ char *argptr;
+
+ argptr = prom_getcmdline();
+
+ /* IO/MEM resources. Which will be the addtion value in `inX' and
+ * `outX' macros defined in asm/io.h */
+ set_io_port_base(0);
+ ioport_resource.start = 0x00000000;
+ ioport_resource.end = 0xffffffff;
+ iomem_resource.start = 0x00000000;
+ iomem_resource.end = 0xffffffff;
+
+ _machine_restart = jz_restart;
+ _machine_halt = jz_halt;
+ pm_power_off = jz_power_off;
+
+ jz_soc_setup();
+ jz_serial_setup();
+ jz_board_setup();
+}
+
diff --git a/arch/mips/jz4750l/time.c b/arch/mips/jz4750l/time.c
new file mode 100644
index 00000000000..293f0b29785
--- /dev/null
+++ b/arch/mips/jz4750l/time.c
@@ -0,0 +1,156 @@
+/*
+ * linux/arch/mips/jz4750l/time.c
+ *
+ * Setting up the clock on the JZ4750L boards.
+ *
+ * Copyright (C) 2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/clockchips.h>
+
+#include <asm/time.h>
+#include <asm/jzsoc.h>
+
+/* This is for machines which generate the exact clock. */
+
+#define JZ_TIMER_IRQ IRQ_TCU0
+
+#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */
+
+static struct clocksource clocksource_jz; /* Jz clock source */
+static struct clock_event_device jz_clockevent_device; /* Jz clock event */
+
+void (*jz_timer_callback)(void);
+
+static irqreturn_t jz_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd = dev_id;
+
+ REG_TCU_TFCR = TCU_TFCR_OSTFCL; /* ACK timer */
+
+ if (jz_timer_callback)
+ jz_timer_callback();
+
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction jz_irqaction = {
+ .handler = jz_timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
+ .name = "jz-timerirq",
+};
+
+
+cycle_t jz_get_cycles(struct clocksource *cs)
+{
+ /* convert jiffes to jz timer cycles */
+ return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_OSTCNT);
+}
+
+static struct clocksource clocksource_jz = {
+ .name = "jz_clocksource",
+ .rating = 300,
+ .read = jz_get_cycles,
+ .mask = 0xFFFFFFFF,
+ .shift = 10,
+ .flags = CLOCK_SOURCE_WATCHDOG,
+};
+
+static int __init jz_clocksource_init(void)
+{
+ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift);
+ clocksource_register(&clocksource_jz);
+ return 0;
+}
+
+static int jz_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ return 0;
+}
+
+static void jz_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static struct clock_event_device jz_clockevent_device = {
+ .name = "jz-clockenvent",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */
+
+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
+ .rating = 300,
+ .irq = JZ_TIMER_IRQ,
+ .set_mode = jz_set_mode,
+ .set_next_event = jz_set_next_event,
+};
+
+static void __init jz_clockevent_init(void)
+{
+ struct clock_event_device *cd = &jz_clockevent_device;
+ unsigned int cpu = smp_processor_id();
+
+ cd->cpumask = cpumask_of(cpu);
+ clockevents_register_device(cd);
+}
+
+static void __init jz_timer_setup(void)
+{
+ jz_clocksource_init(); /* init jz clock source */
+ jz_clockevent_init(); /* init jz clock event */
+
+ /*
+ * Make irqs happen for the system timer
+ */
+ jz_irqaction.dev_id = &jz_clockevent_device;
+ setup_irq(JZ_TIMER_IRQ, &jz_irqaction);
+}
+
+
+void __init plat_time_init(void)
+{
+ unsigned int latch;
+
+ /* Init timer */
+ latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ;
+
+ REG_TCU_OSTCSR = TCU_OSTCSR_PRESCALE16 | TCU_OSTCSR_EXT_EN;
+ REG_TCU_OSTCNT = 0;
+ REG_TCU_OSTDR = latch;
+
+ REG_TCU_TMCR = TCU_TMCR_OSTMCL; /* unmask match irq */
+ REG_TCU_TSCR = TCU_TSCR_OSTSC; /* enable timer clock */
+ REG_TCU_TESR = TCU_TESR_OSTST; /* start counting up */
+
+ jz_timer_setup();
+}
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 1abe9905c9c..a77732cf7ae 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -160,6 +160,7 @@ void __init check_wait(void)
case CPU_PR4450:
case CPU_BCM3302:
case CPU_CAVIUM_OCTEON:
+ case CPU_JZRISC:
cpu_wait = r4k_wait;
break;
@@ -888,6 +889,25 @@ static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
}
}
+static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
+{
+ decode_configs(c);
+ c->options &= ~MIPS_CPU_COUNTER; /* JZRISC does not implement the CP0 counter. */
+ switch (c->processor_id & 0xff00) {
+ case PRID_IMP_JZRISC:
+ c->cputype = CPU_JZRISC;
+ c->isa_level = MIPS_CPU_ISA_M32R1;
+ c->tlbsize = 32;
+
+ __cpu_name[cpu] = "Ingenic JZRISC";
+
+ break;
+ default:
+ panic("Unknown Ingenic Processor ID!");
+ break;
+ }
+}
+
const char *__cpu_name[NR_CPUS];
__cpuinit void cpu_probe(void)
@@ -925,6 +945,10 @@ __cpuinit void cpu_probe(void)
case PRID_COMP_CAVIUM:
cpu_probe_cavium(c, cpu);
break;
+ case PRID_COMP_INGENIC:
+ case 0xd80000: // used on fpga
+ cpu_probe_ingenic(c, cpu);
+ break;
}
BUG_ON(!__cpu_name[cpu]);
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index ffa331029e0..b8461e1d6ac 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -38,6 +38,11 @@ FEXPORT(ret_from_irq)
FEXPORT(__ret_from_irq)
LONG_L t0, PT_STATUS(sp) # returning to kernel mode?
andi t0, t0, KU_USER
+ bnez t0, resume_userspace
+ nop
+ LONG_L t0, PT_STATUS(sp) # returning to kernel mode?
+ srl t0, t0, 27
+ andi t0, t0, 1
beqz t0, resume_kernel
resume_userspace:
@@ -79,6 +84,11 @@ FEXPORT(syscall_exit)
FEXPORT(restore_all) # restore full frame
#ifdef CONFIG_MIPS_MT_SMTC
+/* Detect and execute deferred IPI "interrupts" */
+ LONG_L s0, TI_REGS($28)
+ LONG_S sp, TI_REGS($28)
+ jal deferred_smtc_ipi
+ LONG_S s0, TI_REGS($28)
#ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP
/* Re-arm any temporarily masked interrupts not explicitly "acked" */
mfc0 v0, CP0_TCSTATUS
@@ -107,11 +117,6 @@ FEXPORT(restore_all) # restore full frame
xor t0, t0, t3
mtc0 t0, CP0_TCCONTEXT
#endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */
-/* Detect and execute deferred IPI "interrupts" */
- LONG_L s0, TI_REGS($28)
- LONG_S sp, TI_REGS($28)
- jal deferred_smtc_ipi
- LONG_S s0, TI_REGS($28)
#endif /* CONFIG_MIPS_MT_SMTC */
.set noat
RESTORE_TEMP
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 6721ee2b1e8..02d1d4077fa 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -928,6 +928,35 @@ static void __cpuinit probe_pcache(void)
c->dcache.waybit = 0;
break;
+ case CPU_JZRISC:
+ config1 = read_c0_config1();
+ config1 = (config1 >> 22) & 0x07;
+ if (config1 == 0x07)
+ config1 = 10;
+ else
+ config1 = config1 + 11;
+ config1 += 2;
+ icache_size = (1 << config1);
+ c->icache.linesz = 32;
+ c->icache.ways = 4;
+ c->icache.waybit = __ffs(icache_size / c->icache.ways);
+
+ config1 = read_c0_config1();
+ config1 = (config1 >> 13) & 0x07;
+ if (config1 == 0x07)
+ config1 = 10;
+ else
+ config1 = config1 + 11;
+ config1 += 2;
+ dcache_size = (1 << config1);
+ c->dcache.linesz = 32;
+ c->dcache.ways = 4;
+ c->dcache.waybit = __ffs(dcache_size / c->dcache.ways);
+
+ c->dcache.flags = 0;
+ c->options |= MIPS_CPU_PREFETCH;
+
+ break;
default:
if (!(config & MIPS_CONF_M))
panic("Don't know how to probe P-caches on this cpu.");
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index 694d51f523d..4b2bc95fb1a 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -52,6 +52,8 @@ void (*_dma_cache_wback)(unsigned long start, unsigned long size);
void (*_dma_cache_inv)(unsigned long start, unsigned long size);
EXPORT_SYMBOL(_dma_cache_wback_inv);
+EXPORT_SYMBOL(_dma_cache_wback);
+EXPORT_SYMBOL(_dma_cache_inv);
#endif /* CONFIG_DMA_NONCOHERENT */
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 9a17bf8395d..9b800534fe3 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -385,6 +385,11 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
tlbw(p);
break;
+ case CPU_JZRISC:
+ tlbw(p);
+ uasm_i_nop(p);
+ break;
+
default:
panic("No TLB refill handler yet (CPU type: %d)",
current_cpu_data.cputype);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 6a06913b01d..b06e2c81006 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -798,6 +798,16 @@ config NVRAM
To compile this driver as a module, choose M here: the
module will be called nvram.
+config RTC_PCF8563
+ bool 'Philips PCF8563 Real Time Clock (I2C Bus)'
+ help
+ Philips PCF8563 Real Time Clock (I2C Bus)
+
+config RTC_JZ
+ bool 'Jz47XX On-Chip Real Time Clock'
+ help
+ Jz47XX On-Chip Real Time Clock
+
#
# These legacy RTC drivers just cause too many conflicts with the generic
# RTC framework ... let's not even try to coexist any more.
@@ -1109,6 +1119,7 @@ config DEVPORT
default y
source "drivers/s390/char/Kconfig"
+source "drivers/char/jzchar/Kconfig"
endmenu
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 66f779ad4f4..ae98c77267d 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -98,6 +98,10 @@ obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o
obj-$(CONFIG_GPIO_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o
+obj-$(CONFIG_RTC_PCF8563) += rtc_pcf8563.o
+obj-$(CONFIG_RTC_JZ) += rtc_jz.o
+obj-$(CONFIG_JZCHAR) += jzchar/
+
obj-$(CONFIG_MWAVE) += mwave/
obj-$(CONFIG_AGP) += agp/
obj-$(CONFIG_PCMCIA) += pcmcia/
diff --git a/drivers/char/jzchar/Kconfig b/drivers/char/jzchar/Kconfig
new file mode 100644
index 00000000000..12116c7396c
--- /dev/null
+++ b/drivers/char/jzchar/Kconfig
@@ -0,0 +1,74 @@
+#
+# JzSOC char devices configuration
+#
+
+menu "JZSOC char device support"
+ depends on SOC_JZ4740 || SOC_JZ4730 || SOC_JZ4750 || SOC_JZ4750D
+
+config JZCHAR
+ tristate 'JzSOC char device support'
+
+config JZ_SIMPLE_I2C
+ tristate 'Ingenic Simple I2C Userspace Driver'
+
+config JZ_CAMERA_SENSOR
+ bool
+
+config JZ_CIM
+ tristate 'JzSOC Camera Interface Module (CIM) support'
+ depends on JZCHAR
+ select JZ_CAMERA_SENSOR
+
+config JZ_TPANEL_ATA2508
+ tristate 'JzSOC MPEG4 TOUCH PANEL ATA2508 support'
+ depends on JZCHAR
+
+#config JZ_TPANEL
+# tristate 'JzSOC touchpanel driver support'
+# depends on JZCHAR
+
+# select JZ_SADC if SOC_JZ4740
+# select JZ_TPANEL_AK4182 if SOC_JZ4730
+
+choice
+ prompt "Touch Panel ADC type"
+ depends on JZ_TPANEL
+ default JZ_SADC if SOC_JZ4740 || SOC_JZ4750 || SOC_JZ4750D
+ default JZ_TPANEL_AK4182 if SOC_JZ4730
+
+config JZ_SADC
+ bool 'Select the JZ47XX internal SADC'
+
+config JZ_TPANEL_AK4182
+ bool 'Select the AK4182 codec'
+
+config JZ_TPANEL_UCB1400
+ bool 'Select the UCB1400 codec'
+
+config JZ_TPANEL_WM9712
+ bool 'Select the WM9712 codec'
+
+endchoice
+
+#config JZ_UDC_HOTPLUG
+# tristate 'JZ UDC hotplug driver support'
+# depends on JZCHAR
+
+config JZ_POWEROFF
+ tristate 'JZ board poweroff support'
+ depends on JZCHAR
+
+config JZ_OW
+ tristate 'JZ One-wire bus support'
+ depends on JZCHAR
+
+config JZ_TCSM
+ tristate 'JZ TCSM support'
+ depends on JZCHAR
+
+config JZ_TSSI
+ tristate 'JZ MPEG2-TS interface support'
+ depends on JZCHAR && (SOC_JZ4750 || SOC_JZ4750D)
+
+endmenu
+
diff --git a/drivers/char/jzchar/Makefile b/drivers/char/jzchar/Makefile
new file mode 100644
index 00000000000..1e4ca0ebbec
--- /dev/null
+++ b/drivers/char/jzchar/Makefile
@@ -0,0 +1,25 @@
+#
+# Makefile for jzchar
+#
+obj-$(CONFIG_JZCHAR) += jzchars.o
+
+obj-$(CONFIG_JZ_SCC) += scc.o
+obj-$(CONFIG_JZ_CIM) += cim.o
+obj-$(CONFIG_JZ_TPANEL_ATA2508) += ata2508.o
+obj-$(CONFIG_JZ_CAMERA_SENSOR) += sensor.o
+obj-$(CONFIG_JZ_I2C_EEPROM) += eeprom.o
+obj-$(CONFIG_JZ_EJTAG) += ejtag.o
+obj-$(CONFIG_JZ_POWEROFF) += poweroff.o
+
+#obj-$(CONFIG_JZ_TPANEL) += jz_ts.o
+obj-$(CONFIG_JZ_TPANEL_UCB1400) += ucb1400.o
+obj-$(CONFIG_JZ_TPANEL_WM9712) += wm9712.o
+obj-$(CONFIG_JZ_TPANEL_AK4182) += ak4182.o
+obj-$(CONFIG_JZ_SADC) += sadc.o
+
+obj-$(CONFIG_JZ_SMART_LCD) += slcd.o
+#obj-$(CONFIG_JZ_UDC_HOTPLUG) += udc_hotplug.o
+obj-$(CONFIG_JZ_OW) += jz_ow.o
+obj-$(CONFIG_JZ_TCSM) += tcsm.o
+obj-$(CONFIG_JZ_TSSI) += jz_tssi.o
+obj-$(CONFIG_JZ_SIMPLE_I2C) += i_i2c.o \ No newline at end of file
diff --git a/drivers/char/jzchar/ak4182.c b/drivers/char/jzchar/ak4182.c
new file mode 100644
index 00000000000..747d3156c9d
--- /dev/null
+++ b/drivers/char/jzchar/ak4182.c
@@ -0,0 +1,657 @@
+/*
+ * ak4182.c using national microwire protocol
+ *
+ * Touch screen driver interface to the AK4182A .
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/pm.h>
+#include <linux/pm_legacy.h>
+
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/jzsoc.h>
+
+#include "jz_ts.h"
+#include "ak4182.h"
+
+#define TS_PIN GPIO_TS_PENIRQ
+#define TS_IRQ (IRQ_GPIO_0 + TS_PIN)
+
+static int samples = 5;
+static int first_time = 0;
+static unsigned long last_x, last_y, last_p;
+
+static int adcsync = 0;
+
+static struct ak4182 *ak;
+
+extern unsigned int (*codec_read_battery)(void);
+
+/*------------------JzSoc SSI configure----------------*/
+static void ak4182_ssi_reset(void)
+{
+ REG_SSI_CR0 = 0x0000;
+ REG_SSI_CR1 = 0x00007960;
+ REG_SSI_SR = 0x00000098;
+ REG_SSI_ITR = 0x0000;
+ REG_SSI_ICR = 0x00;
+ REG_SSI_GR = 0x0000;
+
+ __ssi_disable();
+ __ssi_flush_fifo();
+ __ssi_clear_errors();
+ __ssi_select_ce();
+}
+
+static void ak4182_ssi_enable(void)
+{
+ __ssi_enable();
+}
+
+#ifdef CONFIG_PM
+static void ak4182_ssi_disable(void)
+{
+ __ssi_disable();
+}
+#endif
+
+static void ak4182_ssi_set_trans_mode_format(void)
+{
+ __ssi_microwire_format();
+ __ssi_set_msb();
+ __ssi_set_microwire_command_length(8);
+ __ssi_set_frame_length(12);
+}
+
+static void ak4182_ssi_set_clk_div_ratio(int dev_clk, int ssi_clk)
+{
+ __ssi_set_clk(dev_clk, ssi_clk);
+}
+
+static void ak4182_ssi_set_normal_mode(void)
+{
+ __ssi_normal_mode();
+}
+
+static void ak4182_ssi_set_IRQ(void)
+{
+ __ssi_disable_tx_intr();
+ __ssi_disable_rx_intr();
+}
+
+/*------------------ AK4182 routines ------------------*/
+static inline void ak4182_reg_write(unsigned short val)
+{
+ __ssi_transmit_data(val);
+}
+
+static inline unsigned int ak4182_reg_read(void)
+{
+ unsigned int val;
+ val = __ssi_receive_data();
+ return val;
+}
+
+static unsigned int ak4182_adc_read(int cmd_code, int sync)
+{
+ unsigned int val, timeout = 10000;
+ unsigned int status,valid1,valid2,dataentry;
+
+ ak4182_reg_write(cmd_code);
+ udelay(2);//wait 2 D_CLK
+ for (;;) {
+ status =0;
+ status = REG_SSI_SR;
+ valid1 = (status>>7) & 1;
+ valid2 = (status>>6) & 1;
+ if( valid1==1 && valid2==0 )//SSI transfer is finished
+ {
+ //Receive FIFO data entry number
+ dataentry = val = 0;
+ dataentry = (status>>8) & 0x1F;
+ if( dataentry > 5 )
+ {
+ printk("R-FIFO entry=%d,SSI transfer is wrong!\n",dataentry);
+ while(dataentry > 0)
+ {
+ ak4182_reg_read();
+ dataentry--;
+ }
+ return 0;
+ }
+ while(dataentry > 0)
+ {
+ val = ak4182_reg_read();
+ dataentry--;
+ }
+ return val;
+ }
+
+ if (--timeout == 0)
+ break;
+ udelay(1);
+ }
+ return 0;
+}
+
+
+//enable pen down IRQ
+static void ak4182_enable_irq(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ak->lock, flags);
+ __gpio_unmask_irq(TS_PIN);
+ spin_unlock_irqrestore(&ak->lock, flags);
+}
+
+//disable pen down IRQ
+static void ak4182_disable_irq(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ak->lock, flags);
+ __gpio_mask_irq(TS_PIN);
+// spin_unlock_irqrestore(&ucb->lock, flags);
+ spin_unlock_irqrestore(&ak->lock, flags);
+}
+/*
+ * Switch to X position mode and measure Y plate. We switch the plate
+ * configuration in pressure mode, then switch to position mode. This
+ * gives a faster response time. Even so, we need to wait about 55us
+ * for things to stabilise.
+ */
+static inline unsigned int ak4182_ts_read_xpos(void)
+{
+ return ak4182_adc_read(0xD0, adcsync);//X-axis,0xD0 for 12bit,0xD8 for 8bit
+}
+
+
+/*
+ * Switch to pressure mode, and read pressure. We don't need to wait
+ * here, since both plates are being driven.
+ */
+static inline unsigned int ak4182_ts_read_pressure(void)
+{
+ unsigned int z1,z2,xpos,pressureval=0;//300 Om
+ //Z1 pressure
+ z1 = ak4182_adc_read(0xB0, adcsync);//0xB0 for 12bit,0xB8 for 8bit
+ if(z1>0)
+ {
+ //Z2 pressure
+ z2 = ak4182_adc_read(0xC0, adcsync);//0xC0 for 12bit,0xC8 for 8bit
+ if(z2>z1)
+ {
+ xpos = ak4182_ts_read_xpos();
+ pressureval = (300*xpos*(z2-z1))/(4096*z1);
+ }
+ }
+
+ return pressureval;
+}
+
+
+/*
+ * Switch to Y position mode and measure X plate. We switch the plate
+ * configuration in pressure mode, then switch to position mode. This
+ * gives a faster response time. Even so, we need to wait about 55us
+ * for things to stabilise.
+ */
+static inline unsigned int ak4182_ts_read_ypos(void)
+{
+ return ak4182_adc_read(0x90, adcsync);//Y-axis,0x90 for 12bit,0x98 for 8bit
+}
+
+/*------------------------------------------------------------
+ * Read the battery voltage
+ */
+
+unsigned int ak4182_read_battery(void)
+{
+ unsigned int v;
+ int bat_val[5];
+ int total = 0, max_bat, min_bat;
+
+ v = ak4182_adc_read(0xA7, adcsync);
+ v = ak4182_adc_read(0xA7, adcsync);
+ for(v = 0;v <= 4;v++)
+ bat_val[v] = ak4182_adc_read(0xA7, adcsync);
+
+ ak4182_adc_read(0xA4, adcsync);
+ max_bat = min_bat = bat_val[0];
+ for(v = 0;v <= 4;v++) {
+ total += bat_val[v];
+ if(bat_val[v] > max_bat)
+ max_bat = bat_val[v];
+ if(bat_val[v] < min_bat)
+ min_bat = bat_val[v];
+ }
+ total = total - max_bat - min_bat;
+ v = total / 3;
+ return v;
+}
+
+/*------------------ Calibrate samples -------------------*/
+
+#define DIFF(a,b) ((a>b)?(a-b):(b-a))
+
+static int calibrate_samples(void *xbuf, void *ybuf, void *pbuf, int count)
+{
+ unsigned long *xp = (unsigned long *)xbuf;
+ unsigned long *yp = (unsigned long *)ybuf;
+ unsigned long *pp = (unsigned long *)pbuf;
+ unsigned long x_cal = 0, y_cal = 0, p_cal = 0, tmp;
+ int ignored, i, j;
+ int valid = 0;
+
+ /* throw away the max cases */
+ tmp = xp[0];
+ ignored = 0;
+ for (i = 1; i < count; i++) {
+ if (xp[i] > tmp) {
+ tmp = xp[i];
+ ignored = i;
+ }
+ }//find the max val
+ j = 0;
+ for (i = 0; i < count; i++) {
+ if (i == ignored)
+ continue;
+ xp[j++] = xp[i];
+ }//shift val and delete the max val
+
+ tmp = yp[0];
+ ignored = 0;
+ for (i = 1; i < count; i++) {
+ if (yp[i] > tmp) {
+ tmp = yp[i];
+ ignored = i;
+ }
+ }
+ j = 0;
+ for (i = 0; i < count; i++) {
+ if (i == ignored)
+ continue;
+ yp[j++] = yp[i];
+ }
+
+ tmp = pp[0];
+ ignored = 0;
+ for (i = 1; i < count; i++) {
+ if (pp[i] > tmp) {
+ tmp = pp[i];
+ ignored = i;
+ }
+ }
+ j = 0;
+ for (i = 0; i < count; i++) {
+ if (i == ignored)
+ continue;
+ pp[j++] = pp[i];
+ }
+
+ /* throw away the min cases */
+
+ count -= 1; // decrement by 1
+
+ tmp = xp[0];
+ ignored = 0;
+ for (i = 1; i < count; i++) {
+ if (xp[i] < tmp) {
+ tmp = xp[i];
+ ignored = i;
+ }
+ }
+ j = 0;
+ for (i = 0; i < count; i++) {
+ if (i == ignored)
+ continue;
+ xp[j++] = xp[i];
+ }
+
+ tmp = yp[0];
+ ignored = 0;
+ for (i = 1; i < count; i++) {
+ if (yp[i] < tmp) {
+ tmp = yp[i];
+ ignored = i;
+ }
+ }
+ j = 0;
+ for (i = 0; i < count; i++) {
+ if (i == ignored)
+ continue;
+ yp[j++] = yp[i];
+ }
+
+ tmp = pp[0];
+ ignored = 0;
+ for (i = 1; i < count; i++) {
+ if (pp[i] < tmp) {
+ tmp = pp[i];
+ ignored = i;
+ }
+ }
+ j = 0;
+ for (i = 0; i < count; i++) {
+ if (i == ignored)
+ continue;
+ pp[j++] = pp[i];
+ }
+
+ count -= 1; // decrement by 1
+
+ /* calculate the average of the rest */
+ for (i = 0; i < count; i++) {
+ x_cal += xp[i];
+ y_cal += yp[i];
+ p_cal += pp[i];
+ }
+ x_cal /= count;
+ y_cal /= count;
+ p_cal /= count;
+
+ if (first_time) {
+ first_time = 0;
+ last_x = x_cal;
+ last_y = y_cal;
+ last_p = p_cal;
+ valid = 1;
+ }
+ else {
+ if ((DIFF(x_cal, last_x) > 100) ||
+ (DIFF(y_cal, last_y) > 100))
+ valid = 0;
+ else
+ valid = 1;
+ }
+
+ //printk("x_cal=%d y_cal=%d p_cal=%d valid=%d\n", x_cal, y_cal, p_cal, valid);
+
+ if (valid) {
+ *xp = last_x = x_cal;
+ *yp = last_y = y_cal;
+ *pp = last_p = p_cal;
+ }
+
+ return valid;
+}
+
+
+#define TSMAXX 945
+#define TSMAXY 830
+#define TSMINX 90
+#define TSMINY 105
+
+#define SCREEN_X 480
+#define SCREEN_Y 272
+
+static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x )
+{
+
+ if (ts->minx)
+ {
+ if (x < ts->minx) x = ts->minx;
+ if (x > ts->maxx) x = ts->maxx;
+
+ return (x - ts->minx) * SCREEN_X / (ts->maxx - ts->minx);
+ }
+ else
+ {
+ if (x < TSMINX) x = TSMINX;
+ if (x > TSMAXX) x = TSMAXX;
+
+ return (x - TSMINX) * SCREEN_X / (TSMAXX - TSMINX);
+ }
+}
+
+static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y)
+{
+ if (ts->miny)
+ {
+ if (y < ts->miny) y = ts->miny;
+ if (y > ts->maxy) y = ts->maxy;
+
+ return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny);
+ }
+ else
+ {
+ if (y < TSMINY) y = TSMINY;
+ if (y > TSMAXY) y = TSMAXY;
+
+ return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY);
+ }
+}
+
+/*------------------ Common routines -------------------*/
+
+void ts_enable_irq(void)
+{
+ /* interrupt mode */
+ ak4182_enable_irq();
+ enable_irq(TS_IRQ);
+}
+
+void ts_disable_irq(void)
+{
+ ak4182_disable_irq();
+ disable_irq(TS_IRQ);
+}
+
+int ts_request_irq(u32 *irq,
+ irqreturn_t (*handler)(int, void *),
+ const char *devname,
+ void *dev_id)
+{
+ int retval;
+
+ /* return the irq number */
+ *irq = TS_IRQ;
+ /* initializate ssi for AK4182 */
+ ak4182_ssi_reset();
+ ak4182_ssi_set_trans_mode_format();
+ ak4182_ssi_set_normal_mode();
+ ak4182_ssi_set_clk_div_ratio(JZ_EXTAL, 200*1000);//DCLK is 1.5M Hz max
+ ak4182_ssi_set_IRQ();
+
+ ak4182_enable_irq();
+
+ /* enable gpio irq */
+ __gpio_as_irq_fall_edge(TS_PIN);
+
+ /* register irq handler */
+ retval = request_irq(TS_IRQ, handler, IRQF_DISABLED, devname, dev_id);
+ ak4182_ssi_enable();
+ udelay(10);
+ return retval;
+}
+
+void ts_free_irq(struct jz_ts_t *ts)
+{
+ free_irq(ts->pendown_irq, ts);
+ //Close SSI mode
+ ak4182_ssi_reset();
+}
+
+void ts_irq_callback(void)
+{
+ /* clear interrupt status */
+ __gpio_ack_irq(TS_PIN);
+ first_time = 1; // first time to acquire sample
+}
+
+int PenIsDown(void)
+{
+ unsigned int p;
+ p = ak4182_ts_read_pressure();
+ return (p > 100) ? 1 : 0;
+}
+
+/*
+ * Acquire Raw pen coodinate data and compute touch screen
+ * pressure resistance. Hold spinlock when calling.
+ */
+int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event)
+{
+ unsigned int x_raw[8], y_raw[8], p_raw[8];
+ int valid, i;
+
+ for (i = 0; i < samples; i++) {
+ x_raw[i] = ak4182_ts_read_xpos();
+ }
+ for (i = 0; i < samples; i++) {
+ y_raw[i] = ak4182_ts_read_ypos();
+ }
+ for (i = 0; i < samples; i++) {
+ p_raw[i] = ak4182_ts_read_pressure();
+ }
+
+ valid = calibrate_samples(x_raw, y_raw, p_raw, samples);
+
+ if (valid) {
+ unsigned int x_scr, y_scr;
+
+ if(ts->filter) {
+ x_scr = transform_to_screen_x(ts, x_raw[0]);
+ y_scr = transform_to_screen_y(ts, y_raw[0]);
+
+ if (ts->prints)
+ printk("filter:x_raw:%d,y_raw:%d,x_tran:%d,y_tran:%d\n", x_raw[0], y_raw[0], x_scr, y_scr);
+ }
+ else {
+ x_scr = x_raw[0];
+ y_scr = y_raw[0];
+
+ if (ts->prints)
+ printk("no filter:x_raw=%d y_raw=%d \n", x_raw[0], y_raw[0]);
+ }
+
+ event->x = x_scr;
+ event->y = y_scr;
+ event->pressure = (u16)p_raw[0];
+ event->status = PENDOWN;
+ return 1;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * Suspend the Touch pad.
+ */
+static int ak4182_suspend(struct ak4182 *ak , int state)
+{
+ ak4182_ssi_disable();
+
+ return 0;
+}
+
+/*
+ * Resume the Touch panel.
+ */
+static int ak4182_resume(struct ak4182 *ak)
+{
+ /* initializate ssi for AK4182 */
+ ak4182_ssi_reset();
+ ak4182_ssi_set_trans_mode_format();
+ ak4182_ssi_set_normal_mode();
+ ak4182_ssi_set_clk_div_ratio(JZ_EXTAL, 200*1000);//DCLK is 1.5M Hz max
+ ak4182_ssi_set_IRQ();
+
+ ak4182_enable_irq();
+
+ ak4182_ssi_enable();
+
+ return 0;
+}
+
+static int ak4182_pm_callback(struct pm_dev *pm_dev, pm_request_t rqst, void *data)
+{
+ int ret;
+ struct ak4182 *akinfo = pm_dev->data;
+
+ if (!akinfo)
+ return -EINVAL;
+
+
+ switch (rqst) {
+ case PM_SUSPEND:
+ ret = ak4182_suspend(akinfo, (int)data);
+ break;
+
+ case PM_RESUME:
+ ret = ak4182_resume(akinfo);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_PM */
+
+
+/*
+ * Module init and exit
+ */
+
+int __init ak4182_init(void)
+{
+ ak = kmalloc(sizeof(struct ak4182), GFP_KERNEL);
+ if (!ak) return -ENOMEM;
+
+ memset(ak, 0, sizeof(struct ak4182));
+
+ codec_read_battery = ak4182_read_battery;
+
+ spin_lock_init(&ak->lock);
+ sema_init(&ak->adc_sem, 1);
+
+ //initialize AK4182 register
+ __gpio_clear_pin(73);
+ __gpio_as_output(73);
+ mdelay(2);
+ __gpio_set_pin(73);
+ __gpio_as_ssi();
+
+ ak4182_read_battery();
+
+#ifdef CONFIG_PM
+ ak->pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ak4182_pm_callback);
+ if (ak->pmdev)
+ {
+ ak->pmdev->data = ak;
+ }
+#endif
+
+ printk(JZ_SOC_NAME": AK4182 touch screen driver initialized.\n");
+
+ return 0;
+}
+
+void ak4182_cleanup(void)
+{
+}
+
+module_init(ak4182_init);
+module_exit(ak4182_cleanup);
+
diff --git a/drivers/char/jzchar/ak4182.h b/drivers/char/jzchar/ak4182.h
new file mode 100644
index 00000000000..e8b1bf8e974
--- /dev/null
+++ b/drivers/char/jzchar/ak4182.h
@@ -0,0 +1,16 @@
+#ifndef __AK4182_H__
+#define __AK4182_H__
+
+/* Device data structure */
+
+struct ak4182 {
+ spinlock_t lock;
+ struct pm_dev *pmdev;
+ struct semaphore adc_sem;
+ u16 adc_cr;
+ u16 irq_fal_enbl;
+ u16 irq_ris_enbl;
+ int irq_enabled;
+};
+
+#endif /* __AK4182_H__ */
diff --git a/drivers/char/jzchar/ata2508.c b/drivers/char/jzchar/ata2508.c
new file mode 100644
index 00000000000..9e72cf48ccb
--- /dev/null
+++ b/drivers/char/jzchar/ata2508.c
@@ -0,0 +1,227 @@
+
+#include <linux/autoconf.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+
+#define MP4_KEY_RST (32*3+3)
+#define MP4_KEY_TINT (32*3+2)
+#define MP4_KEY_SCL (32*3+1)
+#define MP4_KEY_SDA (32*3+0)
+#define MP4_TINT_IRQ (IRQ_GPIO_0 + MP4_KEY_TINT)
+
+#define ADDR_WARM_RESET 0xFF
+#define ATA2508_SENSOR_MASK 0x1F
+
+const unsigned char init_data_burst[] = {//Address:0x0D-0x3E
+ 0x04, // BETA
+ 0x27, // AIC_WAIT
+ //0x32, // REF_DELAY
+ 0x16, // REF_DELAY
+ 0x02, // HYSTERESIS01
+ 0x02, // HYSTERESIS1
+ 0x02, // HYSTERESIS2
+ 0x02, // HYSTERESIS3
+ 0x02, // HYSTERESIS4
+ 0x02, // HYSTERESIS51
+ 0x02, // HYSTERESIS61
+ 0x02, // HYSTERESIS7
+ 0x02, // HYSTERESIS8
+ 0x02, // HYSTERESIS9
+ 0x02, // HYSTERESIS10
+ 0x02, // HYSTERESIS11
+ 0x64, // STRENGTH_THRESHOLD0
+ 0x64, // STRENGTH_THRESHOLD1
+ 0x64, // STRENGTH_THRESHOLD2
+ 0x64, // STRENGTH_THRESHOLD3
+ 0x64, // STRENGTH_THRESHOLD4
+ 0x64, // STRENGTH_THRESHOLD5
+ 0x64, // STRENGTH_THRESHOLD6
+ 0x64, // STRENGTH_THRESHOLD7
+ 0x64, // STRENGTH_THRESHOLD8
+ 0x64, // STRENGTH_THRESHOLD9
+ 0x64, // STRENGTH_THRESHOLD10
+ 0x64, // STRENGTH_THRESHOLD11
+ 0x0f, // Sampling Interval
+ 0xC8, // INTEGRATION TIME
+ 0x0f, // IDLE TIME
+ 0x00, // SIF_SETUP(RESERVED)
+ 0x01, // MODE
+ 0x00, // GPIO_REG_L
+ 0x00, // GPIO_REG_H
+ 0x00, // GPIO_CONFIGURATION_L
+ 0x00, // GPIO_CONFIGURATION_H
+ 0x00, // GPIO_DIR_L
+ 0x00, // GPIO_DIR_H
+ 0x0c, // CONTROL
+ 0x38, // INT_MASK
+ 0x00, // INT_CLEAR
+ 0xFF, // INT_edge
+ 0x02, // CONTROL_2
+ 0xAF, // BEEP_TIME
+ 0x7F, // BEEP_FREQUENCY
+ 0x30, // CALIBRATION INTERVAL
+ 0x00, // EINT_ENABLE
+ 0x00, // EINT_POL
+ 0x00, // FILTER_PERIOD
+ 0x00, // FILTER_THRESHOLD
+};
+const unsigned char init_data_alpha[] = {//Address:0x00-0x0C
+ 0x02, // APIS
+ 0x08, // ALPHA0
+ 0x08, // ALPHA1
+ 0x08, // ALPHA2
+ 0x08, // ALPHA3
+ 0x08, // ALPHA4
+ 0x28, // ALPHA5
+ 0x28, // ALPHA6
+ 0x28, // ALPHA7
+ 0x28, // ALPHA8
+ 0x28, // ALPHA9
+ 0x28, // ALPHA10
+ 0x28, // ALPHA11
+};
+static unsigned int i2c_addr = 0x58;
+static unsigned int i2c_clk = 100000;
+
+static void write_reg(u8 reg, u8 val)
+{
+ int ret;
+ i2c_open();
+ i2c_setclk(i2c_clk);
+ ret = i2c_write(i2c_addr, &val, reg, 1);
+ i2c_close();
+}
+
+static u8 read_reg(u8 reg)
+{
+ u8 val;
+
+ i2c_open();
+ i2c_setclk(i2c_clk);
+ i2c_read(i2c_addr, &val, reg, 1);
+ i2c_close();
+ return val;
+}
+
+/*
+ * Interrupt handler
+ */
+static irqreturn_t mp4_tint_irq(int irq, void *dev_id)
+{
+ int key_num = 0;
+ u8 value0, value1;
+
+ __gpio_ack_irq(MP4_KEY_TINT);
+ value0 = read_reg(0x75);
+ value1 = read_reg(0x76);
+ value0 &= ATA2508_SENSOR_MASK;
+ if (value0 == 0) {
+ printk("\nRelease key!\n");
+ return IRQ_HANDLED;
+ }
+ while(value0 >> 1){
+ value0 >>= 1;
+ key_num++;
+ }
+
+ printk("\nPress key %d!\n", key_num);
+ return IRQ_HANDLED;
+}
+
+static int __init init_ata2508(void)
+{
+ int i;
+ unsigned char data1;
+ int retval;
+
+ __gpio_as_output(MP4_KEY_RST);
+ __gpio_set_pin(MP4_KEY_RST);
+ mdelay(100);
+ __gpio_clear_pin(MP4_KEY_RST);
+ mdelay(800);
+ __gpio_set_pin(MP4_KEY_RST);
+ __gpio_mask_irq(MP4_KEY_TINT);
+
+ /*write registers*/
+ for(i=0; i<13; i++)
+ {
+ data1 = init_data_alpha[i];
+ write_reg(i, data1);
+ }
+
+ for(i=13; i<63; i++)
+ {
+ data1 = init_data_burst[i-13];
+ write_reg(i, data1);
+ }
+#if 0
+ for (i = 0; i < 63; i++)
+ {
+ data1 = read_reg(i);
+ printk("REG0x%02x = 0x%02x\n", i, data1);
+ }
+#endif
+
+ /* wait for 1 ms*/
+ mdelay(1);
+#if 0
+ while(1)
+ {
+ data1 = read_reg(0x68);
+ printk("REG0x68 = %d\n", data1);
+ data1 = read_reg(0x75);
+ printk("REG0x75 = 0x%02x\n", data1);
+ data1 = read_reg(0x76);
+ printk("REG0x76 = 0x%02x\n", data1);
+ mdelay(2000);
+ }
+#endif
+ data1 = read_reg(0x68);
+ printk("REG0x68 = %d\n", data1);
+
+ /* to activate all the new settings, give a WARM RESET.*/
+ write_reg(ADDR_WARM_RESET, 0x00); //ADDR_WARM_RESET=0xFF
+
+ //printk("REG0x68 = %d\n", data1);
+
+ /* wait for 1 ~ 10 ms.*/
+ mdelay(10);
+ data1 = read_reg(0x68);
+
+ /* Enable INT that connected to ATA2508's TINT.*/
+ __gpio_as_irq_rise_edge(MP4_KEY_TINT);
+
+ retval = request_irq(MP4_TINT_IRQ, mp4_tint_irq,
+ IRQF_DISABLED, "mp4_key_tint", NULL);
+ if (retval) {
+ printk("Could not get mp4 key irq %d\n", MP4_TINT_IRQ);
+ return retval;
+ }
+
+ printk(JZ_SOC_NAME ": MP4 touch panel register.\n");
+
+ return 0;
+}
+
+static void __exit exit_ata2508(void)
+{
+ free_irq(MP4_TINT_IRQ, NULL);
+}
+
+module_init(init_ata2508);
+module_exit(exit_ata2508);
diff --git a/drivers/char/jzchar/cim.c b/drivers/char/jzchar/cim.c
new file mode 100644
index 00000000000..c320d6798c9
--- /dev/null
+++ b/drivers/char/jzchar/cim.c
@@ -0,0 +1,366 @@
+/*
+ * linux/drivers/char/jzchar/cim.c
+ *
+ * Camera Interface Module (CIM) driver for JzSOC
+ * This driver is independent of the camera sensor
+ *
+ * Copyright (C) 2005 JunZheng semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+
+#include "jzchars.h"
+
+#define CIM_NAME "cim"
+
+MODULE_AUTHOR("Jianli Wei<jlwei@ingenic.cn>");
+MODULE_DESCRIPTION("JzSOC Camera Interface Module driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Define the Max Image Size
+ */
+#define MAX_IMAGE_WIDTH 640
+#define MAX_IMAGE_HEIGHT 480
+#define MAX_IMAGE_BPP 16
+#define MAX_FRAME_SIZE (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP / 8)
+
+typedef struct
+{
+ u32 width;
+ u32 height;
+ u32 bpp;
+} img_param_t;
+
+typedef struct
+{
+ u32 cfg;
+ u32 ctrl;
+ u32 mclk;
+} cim_config_t;
+
+/*
+ * IOCTL_XXX commands
+ */
+#define IOCTL_SET_IMG_PARAM 0 // arg type: img_param_t *
+#define IOCTL_CIM_CONFIG 1 // arg type: cim_config_t *
+
+/* Actual image size, must less than max values */
+static int img_width = MAX_IMAGE_WIDTH, img_height = MAX_IMAGE_HEIGHT, img_bpp = MAX_IMAGE_BPP;
+
+/*
+ * CIM DMA descriptor
+ */
+struct cim_desc {
+ u32 nextdesc; /* Physical address of next desc */
+ u32 framebuf; /* Physical address of frame buffer */
+ u32 frameid; /* Frame ID */
+ u32 dmacmd; /* DMA command */
+};
+
+/*
+ * CIM device structure
+ */
+struct cim_device {
+ unsigned char *framebuf;
+ unsigned int frame_size;
+ unsigned int page_order;
+ wait_queue_head_t wait_queue;
+ struct cim_desc frame_desc __attribute__ ((aligned (16)));
+};
+
+// global
+static struct cim_device *cim_dev;
+
+/*==========================================================================
+ * CIM init routines
+ *========================================================================*/
+
+static void cim_config(cim_config_t *c)
+{
+ REG_CIM_CFG = c->cfg;
+ REG_CIM_CTRL = c->ctrl;
+ // Set the master clock output
+#if defined(CONFIG_SOC_JZ4730)
+ __cim_set_master_clk(__cpm_get_sclk(), c->mclk);
+#elif defined(CONFIG_SOC_JZ4740) || defined(CONFIG_SOC_JZ4750)
+ __cim_set_master_clk(__cpm_get_hclk(), c->mclk);
+#else
+ __cim_set_master_clk(__cpm_get_sclk(), c->mclk);
+#endif
+ // Enable sof, eof and stop interrupts
+ __cim_enable_sof_intr();
+ __cim_enable_eof_intr();
+ __cim_enable_stop_intr();
+}
+
+/*==========================================================================
+ * CIM start/stop operations
+ *========================================================================*/
+
+static int cim_start_dma(char *ubuf)
+{
+ __cim_disable();
+
+ dma_cache_wback((unsigned long)cim_dev->framebuf, (2 ^ (cim_dev->page_order)) * 4096);
+
+ // set the desc addr
+ __cim_set_da(virt_to_phys(&(cim_dev->frame_desc)));
+
+ __cim_clear_state(); // clear state register
+ __cim_reset_rxfifo(); // resetting rxfifo
+ __cim_unreset_rxfifo();
+ __cim_enable_dma(); // enable dma
+
+ // start
+ __cim_enable();
+
+ // wait for interrupts
+ interruptible_sleep_on(&cim_dev->wait_queue);
+
+ // copy frame data to user buffer
+ memcpy(ubuf, cim_dev->framebuf, cim_dev->frame_size);
+
+ return cim_dev->frame_size;
+}
+
+static void cim_stop(void)
+{
+ __cim_disable();
+ __cim_clear_state();
+}
+
+/*==========================================================================
+ * Framebuffer allocation and destroy
+ *========================================================================*/
+
+static void cim_fb_destroy(void)
+{
+ if (cim_dev->framebuf) {
+ free_pages((unsigned long)(cim_dev->framebuf), cim_dev->page_order);
+ cim_dev->framebuf = NULL;
+ }
+}
+
+static int cim_fb_alloc(void)
+{
+ cim_dev->frame_size = img_width * img_height * (img_bpp/8);
+ cim_dev->page_order = get_order(cim_dev->frame_size);
+
+ /* frame buffer */
+ cim_dev->framebuf = (unsigned char *)__get_free_pages(GFP_KERNEL, cim_dev->page_order);
+ if ( !(cim_dev->framebuf) ) {
+ return -ENOMEM;
+ }
+
+ cim_dev->frame_desc.nextdesc = virt_to_phys(&(cim_dev->frame_desc));
+ cim_dev->frame_desc.framebuf = virt_to_phys(cim_dev->framebuf);
+ cim_dev->frame_desc.frameid = 0x52052018;
+ cim_dev->frame_desc.dmacmd = CIM_CMD_EOFINT | CIM_CMD_STOP | (cim_dev->frame_size >> 2); // stop after capturing a frame
+
+ dma_cache_wback((unsigned long)(&(cim_dev->frame_desc)), 16);
+
+ return 0;
+}
+
+/*==========================================================================
+ * File operations
+ *========================================================================*/
+
+static int cim_open(struct inode *inode, struct file *filp);
+static int cim_release(struct inode *inode, struct file *filp);
+static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l);
+static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l);
+static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+
+static struct file_operations cim_fops =
+{
+ open: cim_open,
+ release: cim_release,
+ read: cim_read,
+ write: cim_write,
+ ioctl: cim_ioctl
+};
+
+static int cim_open(struct inode *inode, struct file *filp)
+{
+ try_module_get(THIS_MODULE);
+ return 0;
+}
+
+static int cim_release(struct inode *inode, struct file *filp)
+{
+ cim_stop();
+
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l)
+{
+ if (size < cim_dev->frame_size)
+ return -EINVAL;
+
+ return cim_start_dma(buf);
+}
+
+static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l)
+{
+ printk("cim error: write is not implemented\n");
+ return -1;
+}
+
+static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case IOCTL_SET_IMG_PARAM:
+ {
+ img_param_t i;
+
+ if (copy_from_user((void *)&i, (void *)arg, sizeof(img_param_t)))
+ return -EFAULT;
+
+ img_width = i.width;
+ img_height = i.height;
+ img_bpp = i.bpp;
+
+ if ((img_width * img_height * img_bpp/8) > MAX_FRAME_SIZE) {
+ /* realloc the buffer */
+ cim_fb_destroy();
+ if (cim_fb_alloc() < 0)
+ return -ENOMEM;
+ }
+
+ cim_dev->frame_size = img_width * img_height * (img_bpp/8);
+
+ cim_dev->frame_desc.dmacmd = CIM_CMD_EOFINT | CIM_CMD_STOP | (cim_dev->frame_size >> 2); // stop after capturing a frame
+
+ dma_cache_wback((unsigned long)(&(cim_dev->frame_desc)), 16);
+
+ break;
+ }
+ case IOCTL_CIM_CONFIG:
+ {
+ cim_config_t c;
+
+ if (copy_from_user((void *)&c, (void *)arg, sizeof(cim_config_t)))
+ return -EFAULT;
+
+ cim_config(&c);
+
+ break;
+ }
+ default:
+ printk("Not supported command: 0x%x\n", cmd);
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+/*==========================================================================
+ * Interrupt handler
+ *========================================================================*/
+
+static irqreturn_t cim_irq_handler(int irq, void *dev_id)
+{
+ u32 state = REG_CIM_STATE;
+#if 0
+ if (state & CIM_STATE_DMA_EOF) {
+ wake_up_interruptible(&cim_dev->wait_queue);
+ }
+#endif
+ if (state & CIM_STATE_DMA_STOP) {
+ // Got a frame, wake up wait routine
+ wake_up_interruptible(&cim_dev->wait_queue);
+ }
+
+ // clear status flags
+ REG_CIM_STATE = 0;
+ return IRQ_HANDLED;
+}
+
+/*==========================================================================
+ * Module init and exit
+ *========================================================================*/
+
+static int __init cim_init(void)
+{
+ struct cim_device *dev;
+ int ret;
+
+ /* allocate device */
+ dev = kmalloc(sizeof(struct cim_device), GFP_KERNEL);
+ if (!dev) return -ENOMEM;
+
+ /* record device */
+ cim_dev = dev;
+
+ /* allocate a frame buffer */
+ if (cim_fb_alloc() < 0) {
+ kfree(dev);
+ return -ENOMEM;
+ }
+
+ init_waitqueue_head(&dev->wait_queue);
+
+ ret = jz_register_chrdev(CIM_MINOR, CIM_NAME, &cim_fops, dev);
+ if (ret < 0) {
+ cim_fb_destroy();
+ kfree(dev);
+ return ret;
+ }
+
+ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED,
+ CIM_NAME, dev))) {
+ cim_fb_destroy();
+ kfree(dev);
+ printk(KERN_ERR "CIM could not get IRQ");
+ return ret;
+ }
+
+ printk("JzSOC Camera Interface Module (CIM) driver registered\n");
+
+ return 0;
+}
+
+static void __exit cim_exit(void)
+{
+ free_irq(IRQ_CIM, cim_dev);
+ jz_unregister_chrdev(CIM_MINOR, CIM_NAME);
+ cim_fb_destroy();
+ kfree(cim_dev);
+}
+
+module_init(cim_init);
+module_exit(cim_exit);
diff --git a/drivers/char/jzchar/cim.h b/drivers/char/jzchar/cim.h
new file mode 100644
index 00000000000..c21431bc710
--- /dev/null
+++ b/drivers/char/jzchar/cim.h
@@ -0,0 +1,36 @@
+/*
+ * JzSOC CIM driver
+ *
+ * Copyright (C) 2005 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __CIM_H__
+#define __CIM_H__
+
+typedef struct
+{
+ u32 width;
+ u32 height;
+ u32 bpp;
+} IMG_PARAM;
+
+/*
+ * IOCTL_XXX commands
+ */
+#define IOCTL_SET_IMG_PARAM 0 // arg type: IMG_PARAM *
+
+#endif /* __CIM_H__ */
diff --git a/drivers/char/jzchar/example/i_i2c_tool.c b/drivers/char/jzchar/example/i_i2c_tool.c
new file mode 100644
index 00000000000..62ee2552472
--- /dev/null
+++ b/drivers/char/jzchar/example/i_i2c_tool.c
@@ -0,0 +1,81 @@
+/*
+ * JZ4750 Simple I2C Userspace Example.
+ *
+ * Copyright (c) 2005-2010 Ingenic Semiconductor Inc.
+ * Author: River <zwang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include "../i_i2c_abi.h"
+
+#define I2C_DEV "/dev/i_i2c"
+#define SZ_BUF 2048
+
+int main(int argc, char **argv)
+{
+ struct i_i2c_control control;
+
+ unsigned char buf[SZ_BUF];
+
+ int fd;
+ int count = 64;
+
+ int i;
+ int rv;
+
+ fd = open(I2C_DEV, O_RDWR);
+ if (fd == -1) {
+ perror("open():");
+ exit(EXIT_FAILURE);
+ }
+
+ control.id = I_I2C_ID_AT24C16B;
+ control.offset = 0;
+ control.buf = buf;
+ control.count = count;
+
+ rv = ioctl(fd, I_I2C_IOC_READ_DEV, &control);
+ if (rv) {
+ perror("ioctl():");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < count; i++)
+ fprintf(stderr, "%x ", buf[i]);
+
+ fprintf(stderr, "\n", buf[i]);
+
+ if (argc != 1)
+ for (i = 0; i < count; i++)
+ buf[i] = i;
+ else
+ for (i = 0; i < count; i++)
+ buf[i] = 0;
+
+ control.id = I_I2C_ID_AT24C16B;
+ control.offset = 0;
+ control.buf = buf;
+ control.count = count;
+
+ rv = ioctl(fd, I_I2C_IOC_WRITE_DEV, &control);
+ if (rv) {
+ perror("ioctl():");
+ exit(EXIT_FAILURE);
+ }
+
+ close(fd);
+
+ return 0;
+}
diff --git a/drivers/char/jzchar/i_i2c.c b/drivers/char/jzchar/i_i2c.c
new file mode 100644
index 00000000000..a254851128d
--- /dev/null
+++ b/drivers/char/jzchar/i_i2c.c
@@ -0,0 +1,190 @@
+/*
+ * JZ4750 Simple I2C Userspace Driver.
+ *
+ * Copyright (c) 2005-2010 Ingenic Semiconductor Inc.
+ * Author: River <zwang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+
+#include "i_i2c_abi.h"
+
+/* ------------- CUSTOM: Add your own devices/timings here. -------------*/
+static struct i_i2c_dev i_i2c_devs[] = {
+ {
+ .id = I_I2C_ID_AT24C16B,
+
+ .name = "AT24C16B",
+ .address = 0x50, /* 7 bit device address. */
+ .cap = I_I2C_CAP_SEQ_READ | I_I2C_CAP_SEQ_WRITE, /* Device capabilites. */
+ .size = 16 * 1024, /* The range of offset will be checked when set. */
+ .read_size = 16 * 1024, /* SEQ Read size. */
+ .write_size = 16, /* SEQ Write size. */
+ },
+};
+
+static struct i_i2c_timing i_i2c_timings[] = {
+ {
+ .id = I_I2C_ID_AT24C16B,
+
+ .clk = 100 * 1000, /* I2C Device clock - Default: 100K. */
+ .timeout = 100 * 1000, /* MAX allowed timeout in loops */
+ .t_wr = 5, /* tWR / t(Stop - Next Start) in ms */
+ },
+};
+/*--------------------------------------------------------------------*/
+
+#define DRV_NAME "Simple I2C Userspace Driver"
+#define DRV_VERSION "0.1"
+
+static struct i_i2c_dev *find_dev(int id)
+{
+ struct i_i2c_dev *dev;
+ unsigned int i;
+
+ dev = i_i2c_devs;
+ for (i = 0; i < sizeof(i_i2c_devs) / sizeof(struct i_i2c_dev); i++, dev++)
+ if (dev->id == id)
+ return dev;
+
+ return NULL;
+}
+
+static struct i_i2c_timing *find_timing(int id)
+{
+ struct i_i2c_timing *timing;
+ unsigned int i;
+
+ timing = i_i2c_timings;
+ for (i = 0; i < sizeof(i_i2c_timings) / sizeof(struct i_i2c_timing); i++, timing++)
+ if (timing->id == id)
+ return timing;
+
+ return NULL;
+}
+
+static void prepare_device_and_timing(void)
+{
+ struct i_i2c_dev *dev;
+ struct i_i2c_timing *timing;
+
+ unsigned int i;
+
+ dev = i_i2c_devs;
+
+ for (i = 0; i < sizeof(i_i2c_devs) / sizeof(struct i_i2c_dev); i++, dev++) {
+ if (!dev->timing_id)
+ timing = find_timing(dev->id);
+ else
+ timing = find_timing(dev->timing_id);
+
+ if (!timing) {
+ printk(KERN_ERR "%s(): Cannot find timing for device: %s.\n", __func__, dev->name);
+ continue;
+ }
+
+ dev->timing = timing;
+ dev->timing_id = timing->id;
+
+ i_i2c_init_dev(dev);
+
+ printk("Found I2C Device: %s - Address: 0x%x.\n", dev->name, dev->address);
+ }
+
+ return;
+}
+
+static int i_i2c_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct i_i2c_dev *dev;
+ struct i_i2c_control control;
+
+ if (copy_from_user(&control, (void __user *)arg, sizeof(control))) {
+ return -EFAULT;
+ }
+
+ dev = find_dev(control.id);
+ if (!dev || !dev->timing) {
+ printk(KERN_ERR "%s(): ID %d not found or not timing attached.\n", __func__, control.id);
+ return -ENODEV;
+ }
+
+ if (dev->size && control.offset + control.count > dev->size) {
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case I_I2C_IOC_READ_DEV:
+ if (!access_ok(VERIFY_WRITE, control.buf, control.count)) {
+ return -EFAULT;
+ }
+
+ return i_i2c_read_dev(dev, control.offset, control.buf, control.count);
+
+ case I_I2C_IOC_WRITE_DEV:
+ if (!access_ok(VERIFY_READ, control.buf, control.count)) {
+ return -EFAULT;
+ }
+
+ return i_i2c_write_dev(dev, control.offset, control.buf, control.count);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct file_operations i_i2c_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = i_i2c_ioctl,
+};
+
+static struct miscdevice i_i2c_misc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "i_i2c",
+ .fops = &i_i2c_fops,
+};
+
+static int __init i_i2c_init(void)
+{
+ int rv;
+
+ printk(KERN_INFO JZ_SOC_NAME": %s - %s.\n", DRV_NAME, DRV_VERSION);
+
+ prepare_device_and_timing();
+
+ rv = misc_register(&i_i2c_misc_device);
+ if (rv) {
+ printk(KERN_ERR "%s(): Failed to register misc device.\n", __func__);
+ return rv;
+ }
+
+ printk(KERN_INFO JZ_SOC_NAME": %s Registered.\n", DRV_NAME);
+
+ return 0;
+}
+
+static void __exit i_i2c_exit(void)
+{
+ misc_deregister(&i_i2c_misc_device);
+}
+
+MODULE_AUTHOR("River Wang <zwang@ingenic.cn>");
+MODULE_DESCRIPTION("Ingenic Simple I2C Userspace Driver");
+MODULE_LICENSE("GPL");
+
+module_init(i_i2c_init);
+module_exit(i_i2c_exit);
diff --git a/drivers/char/jzchar/i_i2c_abi.h b/drivers/char/jzchar/i_i2c_abi.h
new file mode 100644
index 00000000000..c54fa1a08e2
--- /dev/null
+++ b/drivers/char/jzchar/i_i2c_abi.h
@@ -0,0 +1,33 @@
+/*
+ * JZ4750 Simple I2C Userspace Driver ABI Definations.
+ *
+ * Copyright (c) 2005-2010 Ingenic Semiconductor Inc.
+ * Author: River <zwang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __I_I2C_ABI_H__
+#define __I_I2C_ABI_H__
+
+/* -------------- CUSTOM: Add your device/timing ID here. --------------*/
+/* Device ID */
+enum {
+ I_I2C_ID_AT24C16B = 1, /* ID must start from 1. */
+};
+/* ---------------------------------------------------------------------*/
+
+struct i_i2c_control {
+ int id; /* Device ID. */
+ off_t offset; /* Offset. */
+ void *buf; /* IO buffer. */
+ size_t count; /* IO count. */
+};
+
+#define I_I2C_IOC_READ_DEV _IOW('I', 1, struct i_i2c_control)
+#define I_I2C_IOC_WRITE_DEV _IOR('I', 2, struct i_i2c_control)
+
+#endif
diff --git a/drivers/char/jzchar/jz_ow.c b/drivers/char/jzchar/jz_ow.c
new file mode 100644
index 00000000000..7ea6fd478af
--- /dev/null
+++ b/drivers/char/jzchar/jz_ow.c
@@ -0,0 +1,497 @@
+/*
+ * linux/drivers/char/jzchar/jz_ow.c
+ *
+ * One Wire Bus test driver
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+#include "jzchars.h"
+
+#define OW_CPU_READ_ROM 1
+#define OW_INTC_READ_ROM 1
+#define OW_CPU_SEARCH_ROM 0
+#define OW_INTC_SEARCH_ROM 0
+
+#define OW_DEBUG 0
+#if OW_DEBUG
+#define OWI_MAX 10
+static char CFG[OWI_MAX];
+static char CTL[OWI_MAX];
+static char STS[OWI_MAX];
+static char DAT[OWI_MAX];
+static char DIV[OWI_MAX];
+static void owi_register_dump(int i)
+{
+ CFG[i]= REG_OWI_CFG;
+ CTL[i]= REG_OWI_CTL;
+ STS[i]= REG_OWI_STS;
+ DAT[i]= REG_OWI_DAT;
+ DIV[i]= REG_OWI_DIV;
+}
+static void owi_register_print(int i)
+{
+ printk(" REG_OWI_CFG: 0x%08x\n", CFG[i]);
+ printk(" REG_OWI_CTL: 0x%08x\n", CTL[i]);
+ printk(" REG_OWI_STS: 0x%08x\n", STS[i]);
+ printk(" REG_OWI_DAT: 0x%08x\n", DAT[i]);
+ printk(" REG_OWI_DIV: 0x%08x\n", DIV[i]);
+}
+#endif
+
+static DECLARE_WAIT_QUEUE_HEAD (ow_wait_queue);
+
+/*
+ * fops routines
+ */
+static int ow_open(struct inode *inode, struct file *filp);
+static int ow_release(struct inode *inode, struct file *filp);
+static ssize_t ow_read(struct file *filp, char *buf, size_t size, loff_t *l);
+static ssize_t ow_write(struct file *filp, const char *buf, size_t size, loff_t *l);
+static int ow_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
+
+static void do_ow_rddata(void);
+static void do_ow_wrdata(void);
+static void do_ow_wr1rd(void);
+static void do_ow_wr0(void);
+static void do_ow_rst(void);
+
+static void do_interrupt_mode_test(void);
+static void do_cpu_mode_test(void);
+
+static struct file_operations ow_fops =
+{
+ open: ow_open,
+ release: ow_release,
+ read: ow_read,
+ write: ow_write,
+ ioctl: ow_ioctl,
+};
+
+static int ow_open(struct inode *inode, struct file *filp)
+{
+ try_module_get(THIS_MODULE);
+ return 0;
+}
+
+static int ow_release(struct inode *inode, struct file *filp)
+{
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static ssize_t ow_read(struct file *filp, char *buf, size_t size, loff_t *l)
+{
+ printk("OW: read is not implemented\n");
+ return -1;
+}
+
+static ssize_t ow_write(struct file *filp, const char *buf, size_t size, loff_t *l)
+{
+ printk("ow: write is not implemented\n");
+ return -1;
+}
+
+static int ow_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ switch (cmd) {
+
+ default:
+ printk("Not supported command: 0x%x\n", cmd);
+ return -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static void do_ow_rddata(void)
+{
+ __owi_clr_sts();
+ __owi_set_rddata();
+ __owi_enable_ow_ops();
+}
+
+static void do_ow_wrdata(void)
+{
+ __owi_clr_sts();
+ __owi_set_wrdata();
+ __owi_enable_ow_ops();
+}
+
+static void do_ow_wr1rd(void)
+{
+ __owi_clr_sts();
+ __owi_set_wr1rd();
+ __owi_enable_ow_ops();
+}
+
+static void do_ow_wr0(void)
+{
+ __owi_clr_sts();
+ __owi_set_wr0();
+ __owi_enable_ow_ops();
+}
+
+static void do_ow_rst(void)
+{
+ __owi_clr_sts();
+ __owi_set_rst();
+ __owi_enable_ow_ops();
+}
+
+static irqreturn_t ow_interrupt(int irq, void *dev_id)
+{
+ __owi_clr_sts();
+ wake_up(&ow_wait_queue);
+
+ return IRQ_HANDLED;
+}
+
+static void ow_intcm_read_rom(char *rom)
+{
+ int i;
+
+ __owi_select_regular_mode();
+ REG_OWI_DIV = 23;
+ __owi_clr_sts();
+ __intc_unmask_irq(IRQ_OWI);
+ __owi_enable_all_interrupts();
+
+ do_ow_rst();
+ sleep_on(&ow_wait_queue);
+
+ REG_OWI_DAT = 0x33;
+ do_ow_wrdata();
+ sleep_on(&ow_wait_queue);
+
+ for(i=0; i<8; i++){
+ do_ow_rddata();
+ sleep_on(&ow_wait_queue);
+ rom[i] = REG_OWI_DAT;
+ }
+ __intc_mask_irq(IRQ_OWI);
+}
+
+static void ow_intcm_search_rom(void)
+{
+ int i, j;
+ int normal, reverse;
+#if 1
+ unsigned char rom[8]={0x01, 0xf9, 0x35, 0x53, 0x11, 0x00, 0x00, 0x3e};
+#else
+ unsigned char rom[8]={0x01, 0xd8, 0x10, 0x02, 0x10, 0x00, 0x00, 0x22};
+#endif
+ __owi_select_regular_mode();
+ REG_OWI_DIV = __cpm_get_extalclk()/1000000 - 1;
+ __owi_clr_sts();
+ __intc_unmask_irq(IRQ_OWI);
+ __owi_enable_all_interrupts();
+
+ /* reset */
+ do_ow_rst();
+ sleep_on(&ow_wait_queue);
+
+ /* send search ROM command */
+ REG_OWI_DAT = 0xf0;
+ do_ow_wrdata();
+ sleep_on(&ow_wait_queue);
+
+ for( i=0; i<8; i++){
+ for (j=0; j<8; j++){
+ do_ow_wr1rd();
+ sleep_on(&ow_wait_queue);
+ normal = ( __owi_get_rdst() !=0);
+ printk("normal: %d\n",normal);
+
+ do_ow_wr1rd();
+ sleep_on(&ow_wait_queue);
+ reverse = ( __owi_get_rdst() !=0);
+ printk("reverse: %d\n",reverse);
+
+ if(normal ==1 && reverse ==1){
+ printk("Search rom INTC mode: 11 NO device found\n");
+ __intc_mask_irq(IRQ_OWI);
+ return;
+ }
+#if 1
+ if ( (rom[i]>>j) & 1 ){
+ printk("write 1\n");
+ do_ow_wr1rd();
+ sleep_on(&ow_wait_queue);
+ }
+ else{
+ printk("write 0\n");
+ do_ow_wr0();
+ sleep_on(&ow_wait_queue);
+ }
+
+#else
+ if(normal ==0 && reverse ==0){
+ if (!((rom[i]>>j) & 1) ){
+ printk("write 1\n");
+ do_ow_wr1rd();
+ sleep_on(&ow_wait_queue);
+ }
+ else{
+ printk("write 0\n");
+ do_ow_wr0();
+ sleep_on(&ow_wait_queue);
+ }
+ }else{
+
+ if(normal ==0){
+ printk("write 0\n");
+ do_ow_wr0();
+ sleep_on(&ow_wait_queue);
+ }
+ if(normal ==1){
+ printk("write 1\n");
+ do_ow_wr1rd();
+ sleep_on(&ow_wait_queue);
+ }
+ }
+#endif
+
+ }
+ printk("\n\n");
+ }
+
+ printk("\nSearch rom INTC mode: device found SUCCESSFULLY\n");
+ __intc_mask_irq(IRQ_OWI);
+
+}
+
+static void ow_cpum_read_rom(char *rom)
+{
+ int i;
+
+ __owi_select_regular_mode();
+ REG_OWI_DIV = __cpm_get_extalclk()/1000000 - 1;
+ __owi_clr_sts();
+ __owi_disable_all_interrupts();
+
+ do_ow_rst();
+ __owi_wait_ops_rdy();
+
+ if(!__owi_get_sts_pst())
+ printk("read rom no device found\n");
+
+ REG_OWI_DAT = 0x33;
+ do_ow_wrdata();
+ __owi_wait_ops_rdy();
+
+ for(i=0; i<8; i++){
+ do_ow_rddata();
+ __owi_wait_ops_rdy();
+ rom[i] = REG_OWI_DAT;
+ }
+}
+
+
+static void ow_comm_bit(unsigned comm)
+{
+ int i;
+ for(i=0; i<8; i++){
+ if ( comm & (1<<i) )
+ do_ow_wr1rd();
+ else
+ do_ow_wr0();
+ while(!__owi_get_sts_bit_rdy());
+ }
+}
+
+static void ow_cpum_search_rom(void)
+{
+ int i, j;
+ int normal, reverse;
+#if 1
+ unsigned char rom[8]={0x01, 0xf9, 0x35, 0x53, 0x11, 0x00, 0x00, 0x3e};
+#else
+ unsigned char rom[8]={0x01, 0xd8, 0x10, 0x02, 0x10, 0x00, 0x00, 0x22};
+#endif
+
+ __owi_select_regular_mode();
+ REG_OWI_DIV = 23;
+ __owi_clr_sts();
+ __owi_disable_all_interrupts();
+
+ do_ow_rst();
+ while(!__owi_get_sts_pst_rdy()) ;
+
+ if(!__owi_get_sts_pst())
+ printk("search rom: no device found\n");
+#if 1
+ REG_OWI_DAT = 0xf0;
+ do_ow_wrdata();
+ while(! __owi_get_sts_byte_rdy()) ;
+#else
+ ow_comm_bit(0xf0);
+#endif
+
+ for( i=0; i<8; i++){
+ for (j=0; j<8; j++){
+ do_ow_wr1rd();
+ while(!__owi_get_sts_bit_rdy()) ;
+ normal = ( __owi_get_rdst() !=0);
+ printk("normal: %d\n",normal);
+
+ do_ow_wr1rd();
+ while(!__owi_get_sts_bit_rdy()) ;
+ reverse = ( __owi_get_rdst() !=0);
+ printk("reverse: %d\n",reverse);
+
+ if(normal ==1 && reverse ==1){
+ printk("Search rom CPU mode: 11 NO device found\n");
+ return;
+ }
+
+#if 1
+ if ( (rom[i]>>j) & 1 ){
+ printk("write 1\n");
+ do_ow_wr1rd();
+ while(!__owi_get_sts_bit_rdy()) ;
+ }
+ else{
+ printk("write 0\n");
+ do_ow_wr0();
+ while(!__owi_get_sts_bit_rdy()) ;
+ }
+
+#else
+ if(normal ==0 && reverse ==0){
+ if (!((rom[i]>>j) & 1) ){
+ printk("write 1\n");
+ do_ow_wr1rd();
+ while(!__owi_get_sts_bit_rdy()) ;
+ }
+ else{
+ printk("write 0\n");
+ do_ow_wr0();
+ while(!__owi_get_sts_bit_rdy()) ;
+ }
+ }else{
+
+ if(normal ==0){
+ printk("write 0\n");
+ do_ow_wr0();
+ while(!__owi_get_sts_bit_rdy()) ;
+ }
+ if(normal ==1){
+ printk("write 1\n");
+ do_ow_wr1rd();
+ while(!__owi_get_sts_bit_rdy()) ;
+ }
+ }
+#endif
+
+ }
+ printk("\n\n");
+ }
+ printk("\nSearch rom CPU mode: device found SUCCESSFULLY\n");
+}
+
+static void do_interrupt_mode_test(void)
+{
+ int ret, i;
+ unsigned char rom[8];
+
+ /* interrupt mode */
+ ret = request_irq(IRQ_OWI, ow_interrupt, IRQF_DISABLED,
+ "JZ_OWI", NULL);
+ if(ret)
+ printk("failed irq \n");
+
+#if OW_INTC_READ_ROM
+ ow_intcm_read_rom(rom);
+ printk("\n\nAfter intc mode read ROM ops: \n");
+ printk("ROM: ");
+ for(i=0; i<8; i++)
+ printk("0x%02x,",rom[i]);
+#endif
+
+#if OW_INTC_SEARCH_ROM
+ ow_intcm_search_rom();
+#endif
+
+}
+
+static void do_cpu_mode_test(void)
+{
+
+#if OW_CPU_READ_ROM
+ int i;
+ unsigned char rom[8];
+
+ ow_cpum_read_rom(rom);
+ printk("\n\nAfter CPU mode read ROM ops: \n");
+ printk("ROM: ");
+ for(i=0; i<8; i++)
+ printk("0x%02x,",rom[i]);
+#endif
+
+#if OW_CPU_SEARCH_ROM
+ ow_cpum_search_rom();
+#endif
+}
+
+/*
+ * Module init and exit
+ */
+static int __init ow_init(void)
+{
+ int ret;
+
+ ret = jz_register_chrdev(OW_MINOR, "ow", &ow_fops, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+ __gpio_as_func1(153);
+
+ REG_OWI_CFG=0;
+ REG_OWI_CTL=0;
+ REG_OWI_STS=0;
+ REG_OWI_DAT=0;
+ REG_OWI_DIV=0;
+
+ do_interrupt_mode_test();
+ do_cpu_mode_test();
+
+ printk(JZ_SOC_NAME": OW driver registered.\n");
+
+ return 0;
+}
+
+static void __exit ow_exit(void)
+{
+ free_irq(IRQ_OWI, NULL);
+ jz_unregister_chrdev(OW_MINOR, "ow");
+}
+
+module_init(ow_init);
+module_exit(ow_exit);
+
+MODULE_AUTHOR("Yurong Tan<yrtan@ingenic.cn>");
+MODULE_DESCRIPTION("One Wire Bus test Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/jzchar/jz_ts.c b/drivers/char/jzchar/jz_ts.c
new file mode 100644
index 00000000000..f889a5c11b6
--- /dev/null
+++ b/drivers/char/jzchar/jz_ts.c
@@ -0,0 +1,443 @@
+/*
+ * jz_ts.c
+ *
+ * Touch screen driver for the Ingenic JZ47XX.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/jzsoc.h>
+
+#include "jz_ts.h"
+
+MODULE_AUTHOR("Peter Wei <jlwei@ingenic.cn>");
+MODULE_DESCRIPTION("Ingenic Touch Screen Driver");
+MODULE_LICENSE("GPL");
+
+#define TS_NAME "jz-ts"
+#define TS_MINOR 16 /* MAJOR: 10, MINOR: 16 */
+#define PFX TS_NAME
+
+//#define JZ_TS_DEBUG
+
+#ifdef JZ_TS_DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
+
+static struct jz_ts_t jz_ts;
+
+unsigned int (*codec_read_battery)(void) = NULL;
+
+// hold the spinlock before calling.
+static void event_add(struct jz_ts_t *ts, struct ts_event *event)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ts->lock, flags);
+
+ // add this event to the event queue
+ ts->event_buf[ts->nextIn] = *event;
+ ts->nextIn = (ts->nextIn + 1) & (EVENT_BUFSIZE - 1);
+ if (ts->event_count < EVENT_BUFSIZE) {
+ ts->event_count++;
+ } else {
+ // throw out the oldest event
+ ts->nextOut = (ts->nextOut + 1) & (EVENT_BUFSIZE - 1);
+ }
+
+ spin_unlock_irqrestore(&ts->lock, flags);
+
+ // async notify
+ if (ts->fasync)
+ kill_fasync(&ts->fasync, SIGIO, POLL_IN);
+ // wake up any read call
+ if (waitqueue_active(&ts->wait))
+ wake_up_interruptible(&ts->wait);
+}
+
+static int event_pull(struct jz_ts_t *ts, struct ts_event *event)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&ts->lock, flags);
+ ret = ts->event_count;
+ if (ts->event_count) {
+ *event = ts->event_buf[ts->nextOut];
+ ts->nextOut = (ts->nextOut + 1) & (EVENT_BUFSIZE - 1);
+ ts->event_count--;
+ }
+ spin_unlock_irqrestore(&ts->lock, flags);
+
+ return ret;
+}
+
+static int pen_is_down = 0;
+
+static irqreturn_t pendown_interrupt(int irq, void * dev_id)
+{
+ struct jz_ts_t* ts = &jz_ts;
+ struct ts_event event;
+
+ dbg("pen down");
+#if defined(CONFIG_SOC_JZ4740)
+ if (ts->sleeping) {
+ ts->sleeping = 0;
+ ts_data_ready();
+ return IRQ_HANDLED;
+ }
+#endif
+ spin_lock(&ts->lock);
+
+ if (ts->irq_enabled) {
+ ts->irq_enabled = 0;
+ }
+ else
+ ts->irq_enabled = 1;
+
+
+ if (pen_is_down)
+ pen_is_down = 0;
+ else
+ pen_is_down = 1;
+
+ // callback routine to clear irq status
+ ts_irq_callback();
+
+ if ( (pen_is_down == 0)){
+ del_timer(&ts->acq_timer);
+ spin_unlock(&ts->lock);
+ event.x = event.y = event.pressure = 0;
+ event.status = PENUP;
+ ts->first_read = 0;
+ event_add(ts, &event);
+ return IRQ_HANDLED;
+ }
+
+ if ( (pen_is_down == 1))
+ {
+ ts->acq_timer.expires = jiffies + HZ / 100;
+ del_timer(&ts->acq_timer);
+ ts->first_read = 1;
+ add_timer(&ts->acq_timer);
+ spin_unlock(&ts->lock);
+ }
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * Raw X,Y,pressure acquisition timer function. It gets scheduled
+ * only while pen is down. Its duration between calls is the polling
+ * rate.
+ */
+static void
+jz_acq_timer(unsigned long data)
+{
+ struct jz_ts_t *ts = (struct jz_ts_t *)data;
+ struct ts_event event;
+ int pen_was_down = ts->pen_is_down;
+
+ spin_lock(&ts->lock);
+
+ if (PenIsDown()) {
+
+ ts->pen_is_down = 1;
+
+ if (AcquireEvent(ts, &event)) // check event is valid or not?
+ event_add(ts, &event);
+
+ // schedule next acquire
+ ts->acq_timer.expires = jiffies + HZ / 100;
+ del_timer(&ts->acq_timer);
+ add_timer(&ts->acq_timer);
+ } else {
+
+ if (!ts->irq_enabled) {
+ ts->irq_enabled = 1;
+ }
+ ts->pen_is_down = 0;
+ if (pen_was_down) {
+ event.x = event.y = event.pressure = 0;
+ event.status = PENUP;
+ event_add(ts, &event);
+ }
+ }
+
+ spin_unlock(&ts->lock);
+}
+
+/* +++++++++++++ Read battery voltage routine ++++++++++++++*/
+
+unsigned int jz_read_battery(void)
+{
+ unsigned int v = 0;
+ struct jz_ts_t *ts = &jz_ts;
+
+ spin_lock(&ts->lock);
+
+ if (codec_read_battery)
+ v = codec_read_battery();
+
+ spin_unlock(&ts->lock);
+
+ return v;
+}
+
+/* +++++++++++++ File operations ++++++++++++++*/
+
+static int
+jz_fasync(int fd, struct file *filp, int mode)
+{
+ struct jz_ts_t *ts = (struct jz_ts_t *)filp->private_data;
+ return fasync_helper(fd, filp, mode, &ts->fasync);
+}
+
+
+static unsigned int
+jz_poll(struct file * filp, poll_table * wait)
+{
+ struct jz_ts_t* ts = (struct jz_ts_t*)filp->private_data;
+ poll_wait(filp, &ts->wait, wait);
+ if (ts->event_count)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static ssize_t
+jz_read(struct file * filp, char * buffer, size_t count, loff_t * ppos)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct jz_ts_t* ts = (struct jz_ts_t*)filp->private_data;
+ char *ptr = buffer;
+ struct ts_event event;
+ int err = 0;
+
+ dbg("jz_read");
+
+ add_wait_queue(&ts->wait, &wait);
+ while (count >= sizeof(struct ts_event)) {
+ err = -ERESTARTSYS;
+ if (signal_pending(current))
+ break;
+
+
+ if (event_pull(ts, &event)) {
+ err = copy_to_user(ptr, &event,
+ sizeof(struct ts_event));
+ if (err)
+ break;
+ ptr += sizeof(struct ts_event);
+ count -= sizeof(struct ts_event);
+ } else {
+ set_current_state(TASK_INTERRUPTIBLE);
+ err = -EAGAIN;
+ if (filp->f_flags & O_NONBLOCK)
+ break;
+ schedule();
+ }
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&ts->wait, &wait);
+
+ return ptr == buffer ? err : ptr - buffer;
+}
+
+
+static int
+jz_open(struct inode * inode, struct file * filp)
+{
+ struct jz_ts_t *ts;
+ int retval;
+
+ dbg("open ts device");
+ filp->private_data = ts = &jz_ts;
+
+ spin_lock(&ts->lock);
+
+ ts->pen_is_down = 0; // start with pen up
+ ts->sleeping = 0;
+ // flush event queue
+ ts->nextIn = ts->nextOut = ts->event_count = 0;
+
+ // Init acquisition timer function
+ init_timer(&ts->acq_timer);
+ ts->acq_timer.function = jz_acq_timer;
+ ts->acq_timer.data = (unsigned long)ts;
+
+ ts->irq_enabled = 1;
+
+ spin_unlock(&ts->lock);
+
+ /* Since ts interrupt can happen immediately after request_irq,
+ * we wait until we've completed init of all relevent driver
+ * state variables. Now we grab the PenDown IRQ
+ */
+ retval = ts_request_irq(&ts->pendown_irq, pendown_interrupt, TS_NAME, ts);
+ if (retval) {
+ err("unable to get PenDown IRQ %d", ts->pendown_irq);
+ return retval;
+ }
+
+ try_module_get(THIS_MODULE);
+ return 0;
+}
+
+static int
+jz_release(struct inode * inode, struct file * filp)
+{
+ struct jz_ts_t* ts = (struct jz_ts_t*)filp->private_data;
+
+ ts_free_irq(ts);
+ jz_fasync(-1, filp, 0);
+ del_timer_sync(&ts->acq_timer);
+
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static int jz_ioctl(struct inode *inode, struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
+{
+ struct txy {
+ int minx;
+ int miny;
+ int maxx;
+ int maxy;
+ };
+
+ struct txy ch;
+
+ /*
+ * Switch according to the ioctl called
+ */
+ switch (ioctl_num)
+ {
+ case IOCTL_SET_MSG:
+ jz_ts.filter=1;
+ break;
+ case IOCTL_SET_NUM:
+ if (copy_from_user((void *)&ch, (void *)ioctl_param, sizeof(ch)))
+ return -EFAULT;
+ jz_ts.minx = ch.minx;
+ jz_ts.miny = ch.miny;
+ jz_ts.maxx = ch.maxx;
+ jz_ts.maxy = ch.maxy;
+ break;
+ }
+
+ return 0;
+}
+
+static struct file_operations ts_fops = {
+ owner: THIS_MODULE,
+ read: jz_read,
+ poll: jz_poll,
+ fasync: jz_fasync,
+ ioctl: jz_ioctl,
+ open: jz_open,
+ release: jz_release,
+};
+
+/* +++++++++++++ End File operations ++++++++++++++*/
+
+static int __init minx_setup(char *str)
+{
+ int i;
+
+ if (get_option(&str,&i)) jz_ts.minx = i;
+ jz_ts.filter=i;
+ return 1;
+}
+
+__setup("ts_minx=", minx_setup);
+
+static int __init miny_setup(char *str)
+{
+ int i;
+ if (get_option(&str,&i)) jz_ts.miny = i;
+ return 1;
+}
+
+__setup("ts_miny=", miny_setup);
+
+static int __init maxx_setup(char *str)
+{
+ int i;
+ if (get_option(&str,&i)) jz_ts.maxx = i;
+ return 1;
+}
+
+__setup("ts_maxx=", maxx_setup);
+
+static int __init maxy_setup(char *str)
+{
+ int i;
+ if (get_option(&str,&i)) jz_ts.maxy = i;
+ return 1;
+}
+
+__setup("ts_maxy=", maxy_setup);
+
+static int __init printraw_setup(char *str)
+{
+ if (str)
+ jz_ts.prints = 1;
+
+ return 0;
+}
+
+__setup("ts_debug", printraw_setup);
+
+
+static struct miscdevice jz_ts_dev = {
+ minor: TS_MINOR,
+ name: TS_NAME,
+ fops: &ts_fops,
+};
+
+static int __init jzts_init_module(void)
+{
+ struct jz_ts_t *ts = &jz_ts;
+ int ret;
+
+ if ((ret = misc_register(&jz_ts_dev)) < 0) {
+ err("can't register misc device");
+ return ret;
+ }
+
+// memset(ts, 0, sizeof(struct jz_ts_t));
+ init_waitqueue_head(&ts->wait);
+ spin_lock_init(&ts->lock);
+
+ printk(JZ_SOC_NAME ": Generic touch screen driver registered.\n");
+
+ return 0;
+}
+
+static void jzts_cleanup_module(void)
+{
+ misc_deregister(&jz_ts_dev);
+}
+
+module_init(jzts_init_module);
+module_exit(jzts_cleanup_module);
diff --git a/drivers/char/jzchar/jz_ts.h b/drivers/char/jzchar/jz_ts.h
new file mode 100644
index 00000000000..4285797dfeb
--- /dev/null
+++ b/drivers/char/jzchar/jz_ts.h
@@ -0,0 +1,54 @@
+#ifndef __JZ_TS_H__
+#define __JZ_TS_H__
+
+/*
+ * IOCTL commands
+ */
+#define IOCTL_SET_MSG 0
+#define IOCTL_SET_NUM 1
+
+
+/*
+ * TS Event type
+ */
+struct ts_event {
+ u16 status;
+ u16 x;
+ u16 y;
+ u16 pressure;
+ u16 pad;
+};
+
+/* TS event status */
+#define PENUP 0x00
+#define PENDOWN 0x01
+
+#define EVENT_BUFSIZE 64 // must be power of two
+
+struct jz_ts_t {
+ int pendown_irq; // IRQ of pendown interrupt
+ int pen_is_down; // 1 = pen is down, 0 = pen is up
+ int irq_enabled;
+ struct ts_event event_buf[EVENT_BUFSIZE];// The event queue
+ int nextIn, nextOut;
+ int event_count;
+ struct fasync_struct *fasync; // asynch notification
+ struct timer_list acq_timer; // Timer for triggering acquisitions
+ wait_queue_head_t wait; // read wait queue
+ spinlock_t lock;
+ int minx, miny, maxx, maxy;
+ int filter, prints;
+ int sleeping;
+ int first_read;
+};
+
+extern void ts_enable_irq(void);
+extern void ts_disable_irq(void);
+extern int ts_request_irq(u32 *irq,irqreturn_t (*handler)(int, void *), const char *devname, void *dev_id);
+extern void ts_free_irq(struct jz_ts_t *ts);
+extern int PenIsDown(void);
+extern int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event);
+extern void ts_irq_callback(void);
+extern void ts_data_ready(void);
+
+#endif /* __JZ_TS_H__ */
diff --git a/drivers/char/jzchar/jz_tssi.c b/drivers/char/jzchar/jz_tssi.c
new file mode 100644
index 00000000000..24f72dcbbe0
--- /dev/null
+++ b/drivers/char/jzchar/jz_tssi.c
@@ -0,0 +1,457 @@
+/*
+ * jz_tssi.c
+ *
+ * MPEG2-TS interface driver for the Ingenic JZ47XX.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/jzsoc.h>
+#include "jzchars.h"
+
+#include "jz_tssi.h"
+
+
+MODULE_AUTHOR("Lucifer Liu <yliu@ingenic.cn>");
+MODULE_DESCRIPTION("Ingenic MPEG2-TS interface Driver");
+MODULE_LICENSE("GPL");
+
+#define TSSI_NAME "JZ MPEG2-TS SI"
+#define TSSI_MINOR 204 /* MAJOR: 10, MINOR: 16 */
+#define TSSI_IRQ IRQ_TSSI
+#define PFX TSSI_NAME
+#define RING_BUF_NUM 100
+
+#define USE_DMA
+#define TRIG_PIN ( 32 * 2 + 15 )
+#define DMA_ID_TSSI 5
+//#define JZ_TSSI_DEBUG
+
+#ifdef JZ_TSSISI_DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
+
+static struct jz_tssi_t jz_tssi_g;
+static struct jz_tssi_buf_ring_t jz_tssi_ring_g;
+static int tssi_dma_reinit(int dma_chan, unsigned char *dma_buf, int size);
+
+static void print_reg( void )
+{
+ printk("REG_TSSI_ENA %8x \n ", REG8( TSSI_ENA ));
+ printk("REG_TSSI_CFG %8x \n ", REG16( TSSI_CFG ));
+ printk("REG_TSSI_CTRL %8x \n ", REG8( TSSI_CTRL ));
+ printk("REG_TSSI_STAT %8x \n ", REG8( TSSI_STAT ));
+ printk("REG_TSSI_FIFO %8x \n ", REG32( TSSI_FIFO ));
+ printk("REG_TSSI_PEN %8x \n ", REG32( TSSI_PEN ));
+ printk("REG_TSSI_PID0 %8x \n ", REG32( TSSI_PID0 ));
+ printk("REG_TSSI_PID1 %8x \n ", REG32( TSSI_PID1 ));
+ printk("REG_TSSI_PID2 %8x \n ", REG32( TSSI_PID2 ));
+ printk("REG_TSSI_PID3 %8x \n ", REG32( TSSI_PID3 ));
+ printk("REG_TSSI_PID4 %8x \n ", REG32( TSSI_PID4 ));
+ printk("REG_TSSI_PID5 %8x \n ", REG32( TSSI_PID5 ));
+ printk("REG_TSSI_PID6 %8x \n ", REG32( TSSI_PID6 ));
+ printk("REG_TSSI_PID7 %8x \n ", REG32( TSSI_PID7 ));
+}
+
+void dump_dma_channel(unsigned int dmanr)
+{
+ printk("DMA%d Registers:\n", dmanr);
+ printk(" DMACR = 0x%8x\n", REG_DMAC_DMACR(0));
+ printk(" DSAR = 0x%8x\n", REG_DMAC_DSAR(dmanr));
+ printk(" DTAR = 0x%8x\n", REG_DMAC_DTAR(dmanr));
+ printk(" DTCR = 0x%8x\n", REG_DMAC_DTCR(dmanr));
+ printk(" DRSR = 0x%8x\n", REG_DMAC_DRSR(dmanr));
+ printk(" DCCSR = 0x%8x\n", REG_DMAC_DCCSR(dmanr));
+ printk(" DCMD = 0x%8x\n", REG_DMAC_DCMD(dmanr));
+ printk(" DDA = 0x%8x\n", REG_DMAC_DDA(dmanr));
+ printk(" DMADBR = 0x%8x\n", REG_DMAC_DMADBR(1));
+}
+
+static int tssi_buf_init( struct jz_tssi_buf_ring_t * ring )
+{
+ int i;
+ struct jz_tssi_buf * bp,* ap, *cp;
+
+ ap = cp = bp = (struct jz_tssi_buf *)kmalloc( sizeof( struct jz_tssi_buf ) ,GFP_KERNEL ); //the first
+ if ( !bp ) {
+ printk("Can not malloc buffer! \n");
+ return -1;
+ }
+
+ for ( i = 0; i < RING_BUF_NUM; i ++ ) {
+ bp = ap;
+ bp->buf = (unsigned int *) kmalloc(MPEG2_TS_PACHAGE_SIZE / 4 * sizeof(unsigned int) ,GFP_KERNEL);
+ if ( !bp->buf ) {
+ printk("Can not malloc buffer! \n");
+ return -1;
+ }
+ bp->index = i;
+ bp->pos = 0;
+ ap = (struct jz_tssi_buf *)kmalloc( sizeof( struct jz_tssi_buf ) ,GFP_KERNEL );
+ if ( !ap ) {
+ printk("Can not malloc buffer! \n");
+ return -1;
+ }
+
+ bp->next = ap; //point to next !
+ }
+
+ bp->next = cp; //point loop to first!
+ ring->front = cp;
+ ring->rear = cp;
+ ring->fu_num = 0;
+ kfree(ap);
+ return 0;
+}
+
+static void tssi_free_buf( struct jz_tssi_buf_ring_t * ring )
+{
+ int i;
+ struct jz_tssi_buf * ap;
+ for ( i = 0; i < RING_BUF_NUM; i ++ )
+ {
+ ap = ring->front;
+ ring->front = ring->front->next;
+ kfree( ap );
+ }
+}
+
+#if 0
+static void tssi_read_fifo(void *dev_id)
+{
+ struct jz_tssi_t* tssi = ( struct jz_tssi_t* )dev_id;
+ struct jz_tssi_buf_ring_t * ring = tssi->cur_buf;
+ struct jz_tssi_buf *buf = ring->rear;
+ int i;
+#if 0
+ if ( ring->fu_num > RING_BUF_NUM )
+ {
+ printk("Ring buffer full ! %d \n",ring->fu_num);
+ return;
+ }
+#endif
+
+ for ( i = 0; i < 8 ; i ++ )
+ {
+ ring->front->buf[ring->front->pos++] = REG_TSSI_FIFO;
+ }
+
+ if ( ring->front->pos >= MPEG2_TS_PACHAGE_SIZE )
+ {
+ ring->fu_num ++;
+ ring->front = ring->front->next;
+ ring->front->pos = 0;
+ }
+}
+#endif
+
+static void tssi_config_filting( void )
+{
+ __tssi_soft_reset();
+ __gpio_as_tssi();
+ __tssi_disable_ovrn_irq(); //use dma ,no need irq
+ __tssi_disable_trig_irq();
+ __tssi_set_tigger_num( 8 ); //trig is 4 word!
+// __tssi_filter_enable();
+ __tssi_clear_state();
+ __tssi_filter_disable();
+ __tssi_state_clear_overrun();
+// __tssi_clear_trig_irq_flag();
+#ifdef USE_DMA
+ __tssi_dma_enable();
+#else
+ __tssi_dma_disable();
+#endif
+
+ __tssi_enable_ovrn_irq();
+// __tssi_enable_trig_irq();
+
+ //set config
+// __tssi_set_bt_1();
+ __tssi_set_wd_1();
+ __tssi_set_data_use_data7();
+ __tssi_set_data_pola_high();
+// __tssi_select_serail_mode();
+ __tssi_select_paral_mode();
+ __tssi_select_clk_fast();
+ __tssi_select_clk_posi_edge();
+ __tssi_select_frm_act_high();
+ __tssi_select_str_act_high();
+ __tssi_select_fail_act_high();
+// __tssi_select_fail_act_low();
+ __tssi_disable_filte_pid0(); //we disable pid0 filter for ever!
+}
+
+static void tssi_add_pid(int pid_num, int pid)
+{
+ unsigned int addr ;
+ int n = pid_num / 2, hl = pid_num % 2;
+ if ( hl ) //use high pid, pid1
+ {
+ addr = TSSI_PID0 + ( n * 4 );
+ REG32( addr ) |= ( (pid & 0x1fff) << 16 ); //13bit
+ REG_TSSI_PEN |= ( 1 << (16 + n) );
+ }
+ else //use low pid, pid0
+ {
+ addr = TSSI_PID0 + ( n * 4 );
+ REG32( addr ) |= pid & 0x1fff; //13bit
+ REG_TSSI_PEN |= ( 1 << n );
+ }
+}
+
+static irqreturn_t tssi_dma_irq(int irq, void * dev_id)
+{
+ struct jz_tssi_t *tssi = (struct jz_tssi_t *)dev_id;
+ struct jz_tssi_buf_ring_t *buf = tssi->cur_buf;
+
+ REG_DMAC_DCCSR(tssi->dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+
+ if (__dmac_channel_transmit_end_detected(tssi->dma_chan)) {
+ __dmac_channel_clear_transmit_end(tssi->dma_chan);
+ if ( buf->fu_num < RING_BUF_NUM )
+ {
+ buf->front = buf->front->next;
+ REG_DMAC_DSAR(tssi->dma_chan) = CPHYSADDR(TSSI_FIFO);
+ REG_DMAC_DTAR(tssi->dma_chan) = CPHYSADDR((unsigned int)buf->front->buf);
+ REG_DMAC_DTCR(tssi->dma_chan) = MPEG2_TS_PACHAGE_SIZE / 32;
+ REG_DMAC_DCCSR(tssi->dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
+ buf->fu_num ++;
+ }
+ __tssi_clear_state();
+ }
+
+ if (__dmac_channel_transmit_halt_detected(tssi->dma_chan)) {
+ printk("DMA HALT\n");
+ __dmac_channel_clear_transmit_halt(tssi->dma_chan);
+ }
+
+ if (__dmac_channel_address_error_detected(tssi->dma_chan)) {
+ printk("DMA ADDR ERROR\n");
+ __dmac_channel_clear_address_error(tssi->dma_chan);
+ }
+
+ if (__dmac_channel_descriptor_invalid_detected(tssi->dma_chan)) {
+ printk("DMA DESC INVALID\n");
+ __dmac_channel_clear_descriptor_invalid(tssi->dma_chan);
+ }
+
+ if (__dmac_channel_count_terminated_detected(tssi->dma_chan)) {
+ printk("DMA CT\n");
+ __dmac_channel_clear_count_terminated(tssi->dma_chan);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t tssi_interrupt(int irq, void * dev_id)
+{
+ __intc_mask_irq(TSSI_IRQ);
+#if 1
+ if ( REG_TSSI_STAT & TSSI_STAT_OVRN )
+ {
+ printk("tssi over run occur! %x\n",REG8( TSSI_STAT ));
+ __tssi_clear_state();
+ printk("clear ! %x\n",REG8( TSSI_STAT ));
+ }
+#endif
+ if ( REG_TSSI_STAT & TSSI_STAT_TRIG )
+ {
+ printk("tssi trig irq occur! \n");
+ tssi_read_fifo( dev_id );
+ }
+
+ __intc_ack_irq(TSSI_IRQ);
+ __intc_unmask_irq(TSSI_IRQ);
+ return IRQ_HANDLED;
+}
+
+static ssize_t jz_read(struct file * filp, char * buffer, size_t count, loff_t * ppos)
+{
+ jz_char_dev_t *adev = (jz_char_dev_t *)filp->private_data;
+ struct jz_tssi_t* tssi = (struct jz_tssi_t*)adev->private;
+ struct jz_tssi_buf_ring_t* ring = tssi->cur_buf;
+
+ int i;
+
+ count /= MPEG2_TS_PACHAGE_SIZE;
+
+ if ( count > ring->fu_num )
+ count = ring->fu_num;
+
+ for ( i = 0; i < count; i ++ )
+ {
+ memcpy( buffer + ( i * MPEG2_TS_PACHAGE_SIZE),
+ ring->rear->buf, MPEG2_TS_PACHAGE_SIZE );
+ ring->rear->pos = 0;
+ ring->rear = ring->rear->next;
+ }
+ ring->fu_num -= count;
+ return count * MPEG2_TS_PACHAGE_SIZE;
+}
+
+static int tssi_dma_reinit(int dma_chan, unsigned char *dma_buf, int size)
+{
+ static unsigned int dma_src_phys_addr, dma_dst_phys_addr;
+ REG_DMAC_DMACKE(0) = 0xff;
+ dma_src_phys_addr = CPHYSADDR(TSSI_FIFO);
+ dma_dst_phys_addr = CPHYSADDR((unsigned int)dma_buf);
+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0;
+ REG_DMAC_DCCSR(dma_chan) = 0;
+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_TSSIIN;
+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr;
+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr;
+ REG_DMAC_DTCR(dma_chan) = size / 32;
+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE;
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */
+ return 0;
+}
+
+static int jz_open(struct inode * inode, struct file * filp)
+{
+ try_module_get(THIS_MODULE);
+
+ __tssi_soft_reset();
+ __intc_mask_irq(TSSI_IRQ);
+ tssi_config_filting();
+
+ return 0;
+}
+
+static int jz_release(struct inode * inode, struct file * filp)
+{
+ __intc_mask_irq(TSSI_IRQ);
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static int jz_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ jz_char_dev_t *adev = (jz_char_dev_t *)file->private_data;
+ struct jz_tssi_t* tssi = (struct jz_tssi_t*)adev->private;
+
+ switch (cmd)
+ {
+ case IOCTL_TSSI_ENABLE :
+ __intc_ack_irq(TSSI_IRQ);
+ __intc_unmask_irq(TSSI_IRQ);
+ __tssi_enable();
+ print_reg();
+
+ break;
+ case IOCTL_TSSI_DISABLE :
+ __tssi_disable();
+
+ break;
+ case IOCTL_TSSI_SOFTRESET :
+ __tssi_soft_reset();
+
+ break;
+ case IOCTL_TSSI_ENFILTER :
+ __tssi_filter_enable();
+ break;
+ case IOCTL_TSSI_DEFILTER :
+ __tssi_filter_disable();
+ break;
+ case IOCTL_TSSI_ADDPID : //add one pid to filter
+ if ( tssi->pid_num < 15 )
+ {
+ tssi_add_pid(tssi->pid_num, arg);
+ tssi->pid_num ++ ;
+ }
+ break;
+
+ case IOCTL_TSSI_FLUSHPID : //set all filting pid to false
+ REG_TSSI_PEN = 0x0;
+ REG_TSSI_PID0 = 0x0;
+ REG_TSSI_PID1 = 0x0;
+ REG_TSSI_PID2 = 0x0;
+ REG_TSSI_PID3 = 0x0;
+ REG_TSSI_PID4 = 0x0;
+ REG_TSSI_PID5 = 0x0;
+ REG_TSSI_PID6 = 0x0;
+ REG_TSSI_PID7 = 0x0;
+ break;
+
+ case IOCTL_TSSI_INIT_DMA:
+ tssi_dma_reinit(tssi->dma_chan, tssi->cur_buf->front->buf, MPEG2_TS_PACHAGE_SIZE);
+ break;
+ case IOCTL_TSSI_DISABLE_DMA:
+ REG_DMAC_DCCSR(tssi->dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ break;
+ }
+
+ return 0;
+}
+
+static struct file_operations tssi_fops = {
+ owner: THIS_MODULE,
+ read: jz_read,
+ poll: NULL,
+ fasync: NULL,
+ ioctl: jz_ioctl,
+ open: jz_open,
+ release: jz_release,
+};
+
+static int __init jztssi_init_module(void)
+{
+ int retval;
+ struct jz_tssi_t *tssi = &jz_tssi_g;
+
+ __cpm_start_tssi();
+ __cpm_start_dmac();
+ tssi_buf_init( &jz_tssi_ring_g );
+ tssi->cur_buf = &jz_tssi_ring_g;
+ tssi->pid_num = 0;
+ retval = request_irq(TSSI_IRQ, tssi_interrupt, IRQF_DISABLED, TSSI_NAME, &jz_tssi_g);
+
+ if (retval) {
+ printk("unable to get IRQ %d",TSSI_IRQ);
+ return retval;
+ }
+
+ tssi->dma_chan = jz_request_dma(DMA_ID_TSSI, "tssi", tssi_dma_irq,
+ IRQF_DISABLED, &jz_tssi_g);
+ if ( tssi->dma_chan < 0 )
+ {
+ printk("MPEG2-TS request irq fail! \n");
+ return -1;
+ }
+
+ jz_register_chrdev(TSSI_MINOR, TSSI_NAME, &tssi_fops, &jz_tssi_g);
+
+ printk(JZ_SOC_NAME": MPEG2-TS interface driver registered %x %d\n",&jz_tssi_g,tssi->dma_chan);
+ return 0;
+}
+
+static void jztssi_cleanup_module(void)
+{
+ free_irq(TSSI_IRQ,0);
+ jz_free_dma(jz_tssi_g.dma_chan);
+ tssi_free_buf( &jz_tssi_ring_g );
+ jz_unregister_chrdev(TSSI_MINOR, TSSI_NAME);
+}
+
+module_init(jztssi_init_module);
+module_exit(jztssi_cleanup_module);
diff --git a/drivers/char/jzchar/jz_tssi.h b/drivers/char/jzchar/jz_tssi.h
new file mode 100644
index 00000000000..7ac424d6fce
--- /dev/null
+++ b/drivers/char/jzchar/jz_tssi.h
@@ -0,0 +1,76 @@
+#ifndef __JZ_TSSI_H__
+#define __JZ_TSSI_H__
+
+/*
+ * IOCTL commands
+ */
+#define IOCTL_TSSI_ENABLE 0x01
+#define IOCTL_TSSI_DISABLE 0x02
+#define IOCTL_TSSI_SOFTRESET 0x03
+#define IOCTL_TSSI_ENFILTER 0x04
+#define IOCTL_TSSI_DEFILTER 0x05
+#define IOCTL_TSSI_ADDPID 0x06
+#define IOCTL_TSSI_FLUSHPID 0x07
+#define IOCTL_TSSI_INIT_DMA 0x08
+#define IOCTL_TSSI_DISABLE_DMA 0x09
+
+#if 0
+#define IOCTL_TSSI_SET_CFG 0x06
+#define IOCTL_TSSI_GET_CFG 0x07
+#define IOCTL_TSSI_ENIRQ_TRIG 0x08
+#define IOCTL_TSSI_DEIRQ_TRIG 0x09
+#define IOCTL_TSSI_ENIRQ_OVRN 0x0a
+#define IOCTL_TSSI_DEIRQ_OVRN 0x0b
+#define IOCTL_TSSI_ENPID0 0x0c
+#define IOCTL_TSSI_DEPID0 0x0d
+#define IOCTL_TSSI_ENPIDN 0x0e
+#define IOCTL_TSSI_DEPIDN 0x0f
+#define IOCTL_TSSI_SETPIDN 0x10
+#define IOCTL_TSSI_SET_TRIG 0x11
+#endif
+
+#define MAX_PID_NUM 15
+#define MPEG2_TS_PACHAGE_SIZE 19200
+
+struct jz_tssi_cfg_t
+{
+ unsigned char wordorder;
+ unsigned char byteorder;
+ unsigned char dataploa;
+ unsigned char use0;
+ unsigned char clkch;
+ unsigned char mode;
+ unsigned char clkpola;
+ unsigned char frmpola;
+ unsigned char strpola;
+ unsigned char failpola;
+ unsigned char trignum;
+
+ unsigned short pid;
+ unsigned char pid_index; //0 to 15
+};
+
+struct jz_tssi_buf
+{
+ unsigned int *buf;
+ unsigned int pos;
+ unsigned int index;
+ struct jz_tssi_buf *next;
+};
+
+struct jz_tssi_buf_ring_t
+{
+ struct jz_tssi_buf *front;
+ struct jz_tssi_buf *rear;
+ unsigned int fu_num;
+};
+
+struct jz_tssi_t
+{
+ struct jz_tssi_cfg_t cur_config;
+ struct jz_tssi_buf_ring_t *cur_buf;
+ struct semaphore tssi_sem;
+ int dma_chan, pid_num;
+};
+
+#endif /* __JZ_TSSI_H__ */
diff --git a/drivers/char/jzchar/jzchars.c b/drivers/char/jzchar/jzchars.c
new file mode 100644
index 00000000000..b321104c714
--- /dev/null
+++ b/drivers/char/jzchar/jzchars.c
@@ -0,0 +1,159 @@
+/*
+ * linux/drivers/char/jzchar/jzchars.c
+ *
+ * JzSOC char device family common layer.
+ */
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#include <asm/jzsoc.h>
+#include "jzchars.h"
+
+LIST_HEAD(jz_char_devs);
+
+int jz_register_chrdev(unsigned char minor, const char *name,
+ struct file_operations *fops, void *private)
+{
+ struct list_head *p;
+ jz_char_dev_t *new;
+ list_for_each(p, &jz_char_devs) {
+ jz_char_dev_t *dev = (jz_char_dev_t *)p;
+ if (minor == dev->dev_minor)
+ return -EBUSY;
+ }
+ new = (jz_char_dev_t *)kmalloc(sizeof(jz_char_dev_t), GFP_KERNEL);
+ new->dev_minor = minor;
+ new->name = (char *)name;
+ new->fops = fops;
+ new->private = private;
+ list_add_tail((struct list_head *)new, &jz_char_devs);
+ return 0;
+}
+
+int jz_unregister_chrdev(unsigned char minor, const char *name)
+{
+ struct list_head *p;
+ jz_char_dev_t *dev = NULL;
+ list_for_each(p, &jz_char_devs) {
+ jz_char_dev_t *one = (jz_char_dev_t *)p;
+ if (minor == one->dev_minor) {
+ dev = one;
+ break;
+ }
+ }
+ if (dev == NULL)
+ return -EINVAL;
+ list_del((struct list_head *)dev);
+ kfree(dev);
+ return 0;
+}
+
+static ssize_t jz_char_read(struct file *, char *, size_t, loff_t *);
+static ssize_t jz_char_write(struct file *, const char *, size_t, loff_t *);
+static int jz_char_open(struct inode *, struct file *);
+static int jz_char_release(struct inode *, struct file *);
+static int jz_char_ioctl(struct inode *, struct file *,
+ unsigned int, unsigned long);
+
+static struct file_operations jz_char_fops =
+{
+ read: jz_char_read,
+ write: jz_char_write,
+ ioctl: jz_char_ioctl,
+ open: jz_char_open,
+ release: jz_char_release
+};
+
+static int __init jz_char_family_init(void)
+{
+ printk(JZ_SOC_NAME": Char device core registered.\n");
+ return register_chrdev(JZ_CHAR_MAJOR, "JzChar", &jz_char_fops);
+}
+
+static void __exit jz_char_family_exit(void)
+{
+ printk(JZ_SOC_NAME": Char device core registered.\n");
+ unregister_chrdev(JZ_CHAR_MAJOR, "JzChar");
+}
+
+module_init(jz_char_family_init);
+module_exit(jz_char_family_exit);
+
+static int jz_char_open(struct inode *inode, struct file *filp)
+{
+ jz_char_dev_t *dev = NULL;
+ unsigned int minor = iminor(inode); //minor extend to 20bit!
+ struct list_head *p;
+ list_for_each(p, &jz_char_devs) {
+ jz_char_dev_t *one = (jz_char_dev_t *)p;
+ if (one->dev_minor == minor) {
+ dev = one;
+ filp->private_data = dev;
+ return dev->fops->open(inode, filp);
+ }
+ }
+ printk("JzChar: No such device\n");
+ return -EINVAL;
+}
+
+static int jz_char_release(struct inode *inode, struct file *filp)
+{
+ jz_char_dev_t *dev = (jz_char_dev_t *)filp->private_data;
+ if (dev->fops->release)
+ return dev->fops->release(inode, filp);
+ return 0;
+}
+
+static int jz_char_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ jz_char_dev_t *dev = (jz_char_dev_t *)filp->private_data;
+ if (dev->fops->ioctl)
+ return dev->fops->ioctl(inode, filp, cmd, arg);
+ return 0;
+}
+
+static ssize_t jz_char_read(struct file *filp, char *buf,
+ size_t count, loff_t *ppos)
+{
+ jz_char_dev_t *dev = (jz_char_dev_t *)filp->private_data;
+ if (dev->fops->read)
+ return dev->fops->read(filp, buf, count, ppos);
+ return 0;
+}
+
+static ssize_t jz_char_write(struct file *filp, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ jz_char_dev_t *dev = (jz_char_dev_t *)filp->private_data;
+ if (dev->fops->write)
+ return dev->fops->write(filp, buf, count, ppos);
+ return 0;
+}
+
+EXPORT_SYMBOL(jz_register_chrdev);
+EXPORT_SYMBOL(jz_unregister_chrdev);
diff --git a/drivers/char/jzchar/jzchars.h b/drivers/char/jzchar/jzchars.h
new file mode 100644
index 00000000000..a76f2ae6215
--- /dev/null
+++ b/drivers/char/jzchar/jzchars.h
@@ -0,0 +1,47 @@
+#ifndef __JZ_CHARS_H__
+#define __JZ_CHARS_H__
+
+#include <linux/list.h>
+#include <linux/fs.h>
+
+#define JZ_CHAR_MAJOR 238
+
+#define UPRT_MINOR 0 // Micro printer
+#define CIM_MINOR 1 // Camera interface module
+#define TPANEL_MINOR 2 // Touchpanel
+#define KEYPAD_MINOR 3 // Keypad
+#define MEMCARD_MINOR 4 // Memory card
+#define MAGCARD_MINOR 5 // Magcard
+#define VFD_MINOR 6 // VFD
+#define POWERFAIL_MINOR 7 // Powerfail
+#define EJTAG_MINOR 8 // EJTAG emulation
+#define REMR0_MINOR 9 // Remote output receive 0
+#define REMR1_MINOR 10 // Remote output receive 1
+#define USPI_MINOR 11 // Ultra-speed SPI device
+#define SADC_MINOR 12 // SAR-ADC
+#define SLCD_MINOR 13 // Smart LCD
+
+// 32 to 47 are reserved for SCC
+#define SCC_MINOR 32
+// 48 to 63 are reserved for Camera sensor
+#define SENSOR_MINOR 48
+// 64 to 71 are for EEPROM
+#define EEPROM_MINOR_BASE 64
+// 72 for OWI
+#define OW_MINOR 72
+// 73 for TCSM_MINOR
+#define TCSM_MINOR 73
+
+typedef struct {
+ struct list_head list;
+ char *name;
+ struct file_operations *fops;
+ void *private;
+ unsigned short dev_minor;
+} jz_char_dev_t;
+
+extern int jz_register_chrdev(unsigned char minor, const char *name,
+ struct file_operations *fops, void * private);
+extern int jz_unregister_chrdev(unsigned char minor, const char *name);
+
+#endif /* __JZ_CHARS_H__ */
diff --git a/drivers/char/jzchar/poweroff.c b/drivers/char/jzchar/poweroff.c
new file mode 100644
index 00000000000..e8d1c24a3df
--- /dev/null
+++ b/drivers/char/jzchar/poweroff.c
@@ -0,0 +1,410 @@
+/*
+ * linux/drivers/char/jzchar/poweroff.c
+ *
+ * Power off handling.
+ *
+ * Copyright (C) 2005-2007 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Porting to Linux-2.6.31.3,
+ * Use platform suspend/resume PM API.
+ * - River <zwang@ingenic.cn>
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+
+#include "jzchars.h"
+
+MODULE_AUTHOR("Jianli Wei <jlwei@ingenic.cn>");
+MODULE_DESCRIPTION("Poweroff handling");
+MODULE_LICENSE("GPL");
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+//#define USE_SUSPEND_HOTPLUG
+
+#ifdef CONFIG_SOC_JZ4730
+#define GPIO_PW_I 97
+#define GPIO_PW_O 66
+#define POWEROFF_PIN_DOWN 1
+#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_rise_edge(POWEROFF_PIN)
+#define DO_SHUTDOWN_SYSTEM __gpio_clear_pin(GPIO_PW_O)
+#define DO_SUSPEND jz_pm_suspend()
+
+#define GPIO_DISP_OFF_N 93
+#define __lcd_set_backlight_level(n) \
+do { \
+ REG_PWM_DUT(0) = n; \
+ REG_PWM_PER(0) = 7; \
+ REG_PWM_CTR(0) = 0x81; \
+} while (0)
+#define __lcd_close_backlight() \
+do { \
+ __lcd_set_backlight_level(0); \
+} while (0)
+#endif
+
+#ifdef CONFIG_SOC_JZ4740
+#define GPIO_PW_I 125
+#define POWEROFF_PIN_DOWN 0
+#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_fall_edge(POWEROFF_PIN)
+#define DO_SHUTDOWN_SYSTEM jz_pm_hibernate()
+#define DO_SUSPEND { \
+ jz_pm_sleep();\
+ suspend_flag = 0;\
+ SET_POWEROFF_PIN_AS_IRQ;\
+ }
+
+#define GPIO_DISP_OFF_N 118
+#define GPIO_PWM 123
+#define __lcd_close_backlight() \
+do { \
+__gpio_as_output(GPIO_PWM); \
+__gpio_clear_pin(GPIO_PWM); \
+} while (0)
+#endif
+
+#ifdef CONFIG_SOC_JZ4750
+#define GPIO_PW_I GPIO_WAKEUP
+#define POWEROFF_PIN_DOWN 0
+#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_fall_edge(POWEROFF_PIN)
+#define DO_SHUTDOWN_SYSTEM jz_pm_hibernate()
+#define DO_SUSPEND { \
+ jz_pm_sleep();\
+ suspend_flag = 0;\
+ SET_POWEROFF_PIN_AS_IRQ;\
+ }
+#endif
+
+#ifdef CONFIG_SOC_JZ4750D
+#define GPIO_PW_I GPIO_WAKEUP
+#define POWEROFF_PIN_DOWN 0
+#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_fall_edge(POWEROFF_PIN)
+#define DO_SHUTDOWN_SYSTEM jz_pm_hibernate()
+#define DO_SUSPEND { \
+ jz_pm_sleep();\
+ suspend_flag = 0;\
+ SET_POWEROFF_PIN_AS_IRQ;\
+ }
+#endif
+
+
+#define POWEROFF_PIN GPIO_PW_I
+#define POWEROFF_IRQ (IRQ_GPIO_0 + POWEROFF_PIN)
+
+#define POWEROFF_PERIOD 1000 /* unit: ms */
+#define POWEROFF_DELAY 100 /* unit: ms */
+
+static struct timer_list poweroff_timer;
+static struct timer_list poweroff_delaytimer;
+static struct work_struct suspend_work;
+
+static int poweroff_flag = 0;
+static int suspend_flag = 0;
+static int num_seconds = 0;
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+extern int jz_udc_active;
+#endif
+
+extern void jz_pm_suspend(void);
+extern int jz_pm_hibernate(void);
+extern int jz_pm_sleep(void);
+
+static void poweroff_timer_routine(unsigned long dummy)
+{
+ if (__gpio_get_pin(POWEROFF_PIN) == POWEROFF_PIN_DOWN) {
+ if (++num_seconds > 3)
+ {
+ printk("\nShutdown system now ..\n");
+
+#ifndef USE_SUSPEND_HOTPLUG
+ /* Turn off LCD to inform user that the system is shutting down.
+ * But the information of shutting down system will be shown
+ * by userspace program if hotplug is used.
+ */
+ __lcd_close_backlight();
+#endif
+
+ /*
+ * Wait until the power key is up, or the system will reset with
+ * power key down after entering hibernate.
+ */
+ while(__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN);
+
+ poweroff_flag = 1;
+ schedule_work(&suspend_work); /* inform user to poweroff */
+ }
+ else {
+ del_timer(&poweroff_timer);
+ init_timer(&poweroff_timer);
+ poweroff_timer.expires = jiffies + POWEROFF_PERIOD/10;
+ poweroff_timer.data = 0;
+ poweroff_timer.function = poweroff_timer_routine;
+ add_timer(&poweroff_timer);
+ }
+ }
+ else
+ {
+ printk("\nSuspend system now ..\n");
+ num_seconds = 0;
+ suspend_flag = 1;
+ poweroff_flag = 0;
+ schedule_work(&suspend_work); /* we are entering suspend */
+ }
+}
+
+static void poweroff_delaytimer_routine(unsigned long dummy)
+{
+ __gpio_as_input(POWEROFF_PIN);
+ if (__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN) {
+ if (suspend_flag) {
+ suspend_flag = 0;
+ del_timer(&poweroff_delaytimer);
+ SET_POWEROFF_PIN_AS_IRQ;
+ __gpio_unmask_irq(POWEROFF_PIN);
+ return;
+ }
+ del_timer(&poweroff_delaytimer);
+ del_timer(&poweroff_timer);
+ init_timer(&poweroff_timer);
+ poweroff_timer.expires = jiffies + POWEROFF_PERIOD/100;
+ poweroff_timer.data = 0;
+ poweroff_timer.function = poweroff_timer_routine;
+ add_timer(&poweroff_timer);
+ }
+ else {
+ del_timer(&poweroff_delaytimer);
+ SET_POWEROFF_PIN_AS_IRQ;
+ __gpio_unmask_irq(POWEROFF_PIN);
+
+ printk("This is a dummy key\n");
+ }
+}
+
+/*
+ * Poweroff pin interrupt handler
+ */
+static irqreturn_t poweroff_irq(int irq, void *dev_id)
+{
+ __gpio_ack_irq(POWEROFF_PIN);
+ __gpio_mask_irq(POWEROFF_PIN);
+ __gpio_as_input(POWEROFF_PIN);
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+ if (__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN && jz_udc_active == 0){
+#else
+ if (__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN){
+#endif
+ del_timer(&poweroff_delaytimer);
+ init_timer(&poweroff_delaytimer);
+ poweroff_delaytimer.expires = jiffies + POWEROFF_DELAY/10;
+ poweroff_delaytimer.data = 0;
+ poweroff_delaytimer.function = poweroff_delaytimer_routine;
+ add_timer(&poweroff_delaytimer);
+ }
+ else {
+
+/*
+ * If it reaches here without jz_udc_active == 0, then it indicates POWEROFF_PIN was
+ * changed to WAKEUP key in pm.c for hand is not able to rise up so quickly, so the
+ * irq handler entered because of WAKEUP key not POWEROFF_PIN.
+ */
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+ if (jz_udc_active == 1)
+ printk("\nUSB is working; Operation is denied\n");
+#endif
+ SET_POWEROFF_PIN_AS_IRQ;
+ __gpio_unmask_irq(POWEROFF_PIN);
+ }
+
+ return IRQ_HANDLED;
+}
+
+#ifdef USE_SUSPEND_HOTPLUG
+static void run_sbin_hotplug(int state)
+{
+ int i;
+ char *argv[3], *envp[8];
+ char media[64], slotnum[16];
+ if (!uevent_helper[0])
+ return;
+
+ i = 0;
+ argv[i++] = uevent_helper;
+ //argv[i++] = "home/lhhuang/hotplug";
+
+ if ( poweroff_flag == 1 )
+ argv[i++] = "poweroff";
+ else
+ argv[i++] = "suspend";
+
+ argv[i] = 0;
+
+ /* minimal command environment */
+ i = 0;
+ envp[i++] = "HOME=/";
+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+
+ /* other stuff we want to pass to /sbin/hotplug */
+ sprintf(slotnum, "SLOT=0");
+
+ if ( poweroff_flag == 1 )
+ sprintf(media, "MEDIA=poweroff");
+ else
+ sprintf(media, "MEDIA=suspend");
+
+ envp[i++] = slotnum;
+ envp[i++] = media;
+
+ if (state)
+ envp[i++] = "ACTION=enter";
+ else
+ envp[i++] = "ACTION=exit";
+
+ envp[i] = 0;
+
+ dprintk("SUSPEND: hotplug path=%s state=%d\n", argv[0], state);
+
+ SET_POWEROFF_PIN_AS_IRQ;
+ __gpio_unmask_irq(POWEROFF_PIN); /* set it because call hotplug with call_usermodehelper() \
+ might failed, especially when using nfsroot */
+
+ call_usermodehelper (argv [0], argv, envp, -1);
+}
+#endif
+
+static void suspend_handler(struct work_struct *work)
+{
+#ifdef USE_SUSPEND_HOTPLUG
+ int state = 1;
+ run_sbin_hotplug(state);
+#else
+ if (poweroff_flag) {
+ dprintk("DO_SHUTDOWN_SYSTEM\n");
+ DO_SHUTDOWN_SYSTEM;
+ } else {
+ dprintk("DO_SUSPEND\n");
+ DO_SUSPEND;
+ }
+#endif
+}
+
+#ifdef CONFIG_PM
+static int poweroff_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ printk("%s(): Called.\n", __func__);
+
+ suspend_flag = 1;
+ poweroff_flag = 0;
+
+ return 0;
+}
+
+static int poweroff_resume(struct platform_device *pdev)
+{
+ printk("%s(): Called.\n", __func__);
+
+ suspend_flag = 0;
+ SET_POWEROFF_PIN_AS_IRQ;
+ __gpio_unmask_irq(POWEROFF_PIN);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static int __devinit poweroff_probe(struct platform_device *pdev)
+{
+ int retval;
+
+ retval = request_irq(POWEROFF_IRQ, poweroff_irq,
+ IRQF_DISABLED, "poweroff", NULL);
+
+ SET_POWEROFF_PIN_AS_IRQ;
+
+ if (retval) {
+ printk("Could not get poweroff irq %d\n", POWEROFF_IRQ);
+ return retval;
+ }
+
+ INIT_WORK(&suspend_work, suspend_handler);
+
+ printk(KERN_INFO JZ_SOC_NAME": Power GPIO Button driver registered.\n");
+ return 0;
+}
+
+static int __devexit poweroff_remove(struct platform_device *pdev)
+{
+ free_irq(POWEROFF_IRQ, NULL);
+
+ return 0;
+}
+
+static void jz_poweroff_release(struct device *dev)
+{
+ return;
+}
+
+static struct platform_device jz_poweroff_device = {
+ .name = "jz-poweroff",
+ .id = -1,
+ .dev = {
+ .release = jz_poweroff_release,
+ },
+};
+
+static struct platform_driver jz_poweroff_driver = {
+ .probe = poweroff_probe,
+ .remove = __devexit_p(poweroff_remove),
+ .suspend = poweroff_suspend,
+ .resume = poweroff_resume,
+ .driver = {
+ .name = "jz-poweroff",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init jz_poweroff_init(void)
+{
+ int rv;
+ rv = platform_driver_register(&jz_poweroff_driver);
+ if (rv)
+ return rv;
+
+ return platform_device_register(&jz_poweroff_device);
+}
+
+static void __exit jz_poweroff_cleanup(void)
+{
+ platform_driver_unregister(&jz_poweroff_driver);
+}
+
+module_init(jz_poweroff_init);
+module_exit(jz_poweroff_cleanup);
+
diff --git a/drivers/char/jzchar/sadc.c b/drivers/char/jzchar/sadc.c
new file mode 100644
index 00000000000..c61dad6edd6
--- /dev/null
+++ b/drivers/char/jzchar/sadc.c
@@ -0,0 +1,580 @@
+/*
+ * linux/drivers/char/jzchar/sadc.c
+ *
+ * SAR-ADC driver for JZ4740.
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/fcntl.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+
+#include "jzchars.h"
+#include "jz_ts.h"
+
+MODULE_AUTHOR("Jianli Wei<jlwei@ingenic.cn>");
+MODULE_DESCRIPTION("JZ4740 SADC driver");
+MODULE_LICENSE("GPL");
+
+#define SADC_NAME "sadc"
+static DECLARE_WAIT_QUEUE_HEAD (sadc_wait_queue);
+
+struct sadc_device {
+ int mode;
+ int dma_chan;
+ char *ts_buf;
+ char *pbat_buf;
+};
+
+static struct sadc_device *sadc_dev;
+
+static int samples = 3; /* we sample 3 every time */
+static int first_time = 0;
+static unsigned long last_x, last_y, last_p;
+
+typedef struct datasource {
+ u16 xbuf;
+ u16 ybuf;
+ u16 zbuf;
+}datasource_t;
+
+static datasource_t data_s;
+static unsigned int p;
+static unsigned int old_x, old_y;
+extern unsigned int (*codec_read_battery)(void);
+
+/*
+ * set adc clock to 12MHz/div. A/D works at freq between 500KHz to 6MHz.
+ */
+static void sadc_init_clock(int div)
+{
+ if (div < 2) div = 2;
+ if (div > 23) div = 23;
+#if defined(CONFIG_SOC_JZ4740)
+ REG_SADC_CFG &= ~SADC_CFG_CLKDIV_MASK;
+ REG_SADC_CFG |= (div - 1) << SADC_CFG_CLKDIV_BIT;
+#endif
+#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D)
+ REG_SADC_ADCLK &= ~SADC_ADCLK_CLKDIV_MASK;
+ REG_SADC_ADCLK |= (div - 1) << SADC_ADCLK_CLKDIV_BIT;
+ REG_SADC_ADCLK &= ~SADC_ADCLK_CLKDIV_BIT;
+ REG_SADC_ADCLK |= 39 << SADC_ADCLK_CLKDIV_10_BIT; /* if div ==3,here is 39 */
+#endif
+}
+
+void start_sadcin(void)
+{
+ REG_SADC_CTRL &= ~SADC_CTRL_SRDYM; /* enable interrupt */
+ REG_SADC_ENA |= SADC_ENA_SADCINEN;
+}
+
+void start_pbat_adc(void)
+{
+ REG_SADC_CFG |= SADC_CFG_PBAT_HIGH ; /* full baterry voltage >= 2.5V */
+// REG_SADC_CFG |= SADC_CFG_PBAT_LOW; /* full baterry voltage < 2.5V */
+
+ REG_SADC_ENA |= SADC_ENA_PBATEN; /* Enable pbat adc */
+}
+
+void start_ts_adc(void)
+{
+ REG_SADC_SAMETIME = 10; /* about 0.1 ms,you can change it */
+ REG_SADC_WAITTIME = 2; /* about 0.02 ms,you can change it */
+
+ REG_SADC_CFG &= ~(SADC_CFG_TS_DMA | SADC_CFG_XYZ_MASK | SADC_CFG_SNUM_MASK);
+ REG_SADC_CFG |= (SADC_CFG_EXIN | SADC_CFG_XYZ | SADC_CFG_SNUM_3);
+ REG_SADC_CTRL |= (SADC_CTRL_TSRDYM|SADC_CTRL_PBATRDYM|SADC_CTRL_PENUM |SADC_CTRL_SRDYM);
+ REG_SADC_CTRL &= ~SADC_CTRL_PENDM;
+ REG_SADC_ENA |= SADC_ENA_TSEN;
+}
+
+static int jz4740_adc_read(struct jz_ts_t *ts)
+{
+ struct datasource *ds = &data_s;
+ u32 xybuf,z;
+
+ if (!(REG_SADC_STATE & SADC_STATE_TSRDY)) {
+ /* sleep */
+ REG_SADC_CTRL &= ~SADC_CTRL_TSRDYM;
+ ts->sleeping = 1;
+ sleep_on(&sadc_wait_queue);
+ }
+ ts->sleeping = 0;
+
+ xybuf = REG_SADC_TSDAT;
+ ds->xbuf = (xybuf>>16) & 0x0fff;
+ ds->ybuf = (xybuf)& 0x0fff;
+ z = REG_SADC_TSDAT;
+ ds->zbuf = z& 0x0fff;
+ REG_SADC_STATE &= ~SADC_STATE_TSRDY;
+ return 0;
+}
+
+/*------------------------------------------------------------
+ * Read the battery voltage
+ */
+unsigned int jz4740_read_battery(void)
+{
+ unsigned int v;
+ unsigned int timeout = 0x3ff;
+ u16 pbat;
+
+ if(!(REG_SADC_STATE & SADC_STATE_PBATRDY) ==1)
+ start_pbat_adc();
+
+ while(!(REG_SADC_STATE & SADC_STATE_PBATRDY) && --timeout)
+ ;
+
+ pbat = REG_SADC_BATDAT;
+ v = pbat & 0x0fff;
+ REG_SADC_STATE = SADC_STATE_PBATRDY;
+ return v;
+}
+
+/*------------------ Calibrate samples -------------------*/
+
+#define DIFF(a,b) (((a)>(b))?((a)-(b)):((b)-(a)))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+#if 0
+#define XM 36 /* XM and YM may be changed for your screen */
+#define YM 20
+static int calibrate_samples(void *xbuf, void *ybuf, void *pbuf, int count)
+{
+ unsigned long usd0,usd1,usd2;
+ int xMaxError = XM,yMaxError = YM;
+ int x_valid = 0,y_valid = 0,valid = 0;
+ unsigned long x_cal = 0, y_cal = 0, p_cal = 0;
+ unsigned long *xp = (unsigned long *)xbuf;
+ unsigned long *yp = (unsigned long *)ybuf;
+ unsigned long *pp = (unsigned long *)pbuf;
+
+ usd0 = (xp[0] > xp[1]) ? (xp[0] - xp[1]) : (xp[1] - xp[0]);
+ usd1 = (xp[1] > xp[2]) ? (xp[1] - xp[2]) : (xp[2] - xp[1]);
+ usd2 = (xp[2] > xp[0]) ? (xp[2] - xp[0]) : (xp[0] - xp[2]);
+
+ if ( usd0 < usd1)
+ x_cal = xp[0] + ((usd2 < usd0) ? xp[2] : xp[1]);
+ else
+ x_cal= xp[2] + ((usd2 < usd1) ? xp[0] : xp[1]);
+ x_cal >>= 1;
+
+ if ( (usd0 < xMaxError) && (usd1 < xMaxError) && (usd2 < xMaxError) )
+ x_valid = 1;
+
+ usd0 = (yp[0] > yp[1]) ? (yp[0] - yp[1]) : (yp[1] - yp[0]);
+ usd1 = (yp[1] > yp[2]) ? (yp[1] - yp[2]) : (yp[2] - yp[1]);
+ usd2 = (yp[2] > yp[0]) ? (yp[2] - yp[0]) : (yp[0] - yp[2]);
+
+ if ( usd0 < usd1)
+ y_cal = yp[0] + ((usd2 < usd0) ? yp[2] : yp[1]);
+ else
+ y_cal = yp[2] + ((usd2 < usd1) ? yp[0] : yp[1]);
+
+ y_cal >>= 1;
+
+ if ( (usd0 < yMaxError) && (usd1 < yMaxError) && (usd2 < yMaxError) )
+ y_valid = 1;
+
+ if( x_valid && y_valid)
+ valid = 1;
+
+ usd0 = (pp[0] > pp[1]) ? (pp[0] - pp[1]) : (pp[1] - pp[0]);
+ usd1 = (pp[1] > pp[2]) ? (pp[1] - pp[2]) : (pp[2] - pp[1]);
+ usd2 = (pp[2] > pp[0]) ? (pp[2] - pp[0]) : (pp[0] - pp[2]);
+
+ if ( usd0 < usd1)
+ p_cal = pp[0] + ((usd2 < usd0) ? pp[2] : pp[1]);
+ else
+ p_cal= pp[2] + ((usd2 < usd1) ? pp[0] : pp[1]);
+
+ p_cal >>= 1;
+
+ if (first_time) {
+ first_time = 0;
+ last_x = x_cal;
+ last_y = y_cal;
+ last_p = p_cal;
+ }
+ else{
+ if ((DIFF(x_cal, last_x) > 50) ||
+ (DIFF(y_cal, last_y) > 50))
+ valid = 0;
+ else
+ valid = 1;
+ }
+ *xp = last_x = x_cal;
+ *yp = last_y = y_cal;
+ *pp = last_p = p_cal;
+
+ return valid;
+}
+#endif
+
+static int calibrate_samples(void *xbuf, void *ybuf, void *pbuf, int count)
+{
+ unsigned long *xp = (unsigned long *)xbuf;
+ unsigned long *yp = (unsigned long *)ybuf;
+ unsigned long *pp = (unsigned long *)pbuf;
+ unsigned long x_cal = 0, y_cal = 0, p_cal = 0;
+ int i;
+ int valid = 1;
+
+ /* calculate the average of the rest */
+ for (i = 0; i < count; i++) {
+ x_cal += xp[i];
+ y_cal += yp[i];
+ p_cal += pp[i];
+ }
+ x_cal /= count;
+ y_cal /= count;
+ p_cal /= count;
+
+ if (first_time) {
+ first_time = 0;
+ last_x = x_cal;
+ last_y = y_cal;
+ last_p = p_cal;
+ }
+ else {
+ if ((DIFF(x_cal, last_x) > 50) ||
+ (DIFF(y_cal, last_y) > 50))
+ valid = 0;
+ else
+ valid = 1;
+ }
+
+ *xp = last_x = x_cal;
+ *yp = last_y = y_cal;
+ *pp = last_p = p_cal;
+
+ return valid;
+}
+
+#define TSMAXX 945
+#define TSMAXY 830
+#define TSMINX 90
+#define TSMINY 105
+
+#define SCREEN_X 480
+#define SCREEN_Y 272
+
+static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x )
+{
+
+ if (ts->minx)
+ {
+ if (x < ts->minx) x = ts->minx;
+ if (x > ts->maxx) x = ts->maxx;
+
+ return (x - ts->minx) * SCREEN_X / (ts->maxx - ts->minx);
+ }
+ else
+ {
+ if (x < TSMINX) x = TSMINX;
+ if (x > TSMAXX) x = TSMAXX;
+
+ return (x - TSMINX) * SCREEN_X / (TSMAXX - TSMINX);
+ }
+}
+
+static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y)
+{
+ if (ts->minx)
+ {
+ if (y < ts->minx) y = ts->miny;
+ if (y > ts->maxx) y = ts->maxy;
+
+ return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny);
+ }
+ else
+ {
+ if (y < TSMINX) y = TSMINY;
+ if (y > TSMAXX) y = TSMAXY;
+
+ return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY);
+ }
+}
+
+/*
+ * File operations
+ */
+static int sadc_open(struct inode *inode, struct file *filp);
+static int sadc_release(struct inode *inode, struct file *filp);
+static ssize_t sadc_read(struct file *filp, char *buf, size_t size, loff_t *l);
+static ssize_t sadc_write(struct file *filp, const char *buf, size_t size, loff_t *l);
+static int sadc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+
+static struct file_operations sadc_fops =
+{
+ open: sadc_open,
+ release: sadc_release,
+ read: sadc_read,
+ write: sadc_write,
+ ioctl: sadc_ioctl
+};
+
+static int sadc_open(struct inode *inode, struct file *filp)
+{
+ try_module_get(THIS_MODULE);
+ return 0;
+}
+
+static int sadc_release(struct inode *inode, struct file *filp)
+{
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static ssize_t sadc_read(struct file *filp, char *buf, size_t size, loff_t *l)
+{
+ return size;
+}
+
+static ssize_t sadc_write(struct file *filp, const char *buf, size_t size, loff_t *l)
+{
+ return size;
+}
+
+static int sadc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ default:
+ printk("Not supported command: 0x%x\n", cmd);
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+/*------------------ Common routines -------------------*/
+
+void ts_enable_irq(void)
+{
+ REG_SADC_CTRL &= ~SADC_CTRL_PENDM;
+}
+
+void ts_disable_irq(void)
+{
+ REG_SADC_CTRL |= (SADC_CTRL_PENDM | SADC_CTRL_PENUM);
+}
+
+void ts_free_irq(struct jz_ts_t *ts)
+{
+ free_irq(ts->pendown_irq, ts);
+}
+
+void ts_data_ready(void)
+{
+ REG_SADC_CTRL |= SADC_CTRL_TSRDYM;
+ wake_up(&sadc_wait_queue);
+}
+
+/*
+ * Interrupt handler
+ */
+void ts_irq_callback(void)
+{
+ u32 state;
+
+ state = REG_SADC_STATE;
+ if (!(REG_SADC_CTRL&SADC_CTRL_PENDM)&&(REG_SADC_STATE & SADC_STATE_PEND)) {
+ REG_SADC_STATE = SADC_STATE_PEND;
+ REG_SADC_STATE = SADC_STATE_PENU;
+ REG_SADC_CTRL |= SADC_CTRL_PENDM;
+ REG_SADC_CTRL &= ~SADC_CTRL_PENUM;
+ p = 1;
+ }
+
+ if (!(REG_SADC_CTRL&SADC_CTRL_PENUM)&&(REG_SADC_STATE & SADC_STATE_PENU)) {
+ REG_SADC_STATE = SADC_STATE_PENU;
+ REG_SADC_CTRL |= SADC_CTRL_PENUM;
+ REG_SADC_CTRL &= ~SADC_CTRL_PENDM;
+ p = 0;
+ }
+
+ first_time = 1; // first time to acquire sample
+}
+
+int PenIsDown(void)
+{
+ return p;
+}
+
+int ts_request_irq(u32 *irq,
+ irqreturn_t (*handler)(int, void *),
+ const char *devname,
+ void *dev_id)
+{
+ int ret;
+
+ /* return the irq number */
+ *irq = IRQ_SADC;
+ ts_disable_irq();
+ /* interrupt mode */
+ ret = request_irq(IRQ_SADC, handler, IRQF_DISABLED,
+ devname, dev_id);
+ if(ret)
+ printk("failed irq \n");
+
+ start_ts_adc();
+ return ret;
+}
+
+/*
+ * Acquire Raw pen coodinate data and compute touch screen
+ * pressure resistance. Hold spinlock when calling.
+ */
+int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event)
+{
+ unsigned int x_raw[8], y_raw[8], p_raw[8];
+ int valid, i;
+ unsigned int avl_x, avl_y, diff_x, diff_y;
+ struct datasource *ds = &data_s;
+ avl_x = avl_y = 0;
+
+ for (i = 0; i < samples; i++) {
+ if (jz4740_adc_read(ts)) {
+ return 0;
+ }
+
+ x_raw[i] = ds->ybuf;
+ y_raw[i] = ds->xbuf;
+ p_raw[i] = ds->zbuf;
+ avl_x += x_raw[i];
+ avl_y += y_raw[i];
+#if 0
+ printk("x_raw=%x y_raw=%x z_raw=%x\n",x_raw[i],y_raw[i],p_raw[i]);
+#endif
+ }
+
+ avl_x /= samples;
+ avl_y /= samples;
+#define MAX_DELTA 20
+ valid = 1;
+
+ for (i = 1; i < samples; i++)
+ {
+ if ((100 * DIFF(x_raw[i],x_raw[i-1])/MIN(x_raw[i],x_raw[i-1])) > MAX_DELTA) {
+ valid = 0;
+ break;
+ }
+
+ if ((100 * DIFF(y_raw[i],y_raw[i-1])/MIN(y_raw[i],y_raw[i-1])) > MAX_DELTA) {
+ valid = 0;
+ break;
+ }
+
+ if ((100 * DIFF(p_raw[i],p_raw[i-1])/MIN(p_raw[i],p_raw[i-1])) > MAX_DELTA) {
+ valid = 0;
+ break;
+ }
+ }
+
+ if (valid) {
+ if (ts->first_read) {
+ ts->first_read = 0;
+ old_x = avl_x;
+ old_y = avl_y;
+ }
+ diff_x = DIFF(old_x, avl_x);
+ diff_y = DIFF(old_y, avl_y);
+ if (diff_x < 100 && diff_y < 100) {
+ old_x = avl_x;
+ old_y = avl_y;
+ } else
+ valid = 0;
+ }
+ if (valid) {
+ valid = calibrate_samples(x_raw, y_raw, p_raw, samples);
+ }
+
+ if (valid) {
+ unsigned int x_scr, y_scr;
+
+ if(ts->filter) {
+ x_scr = transform_to_screen_x(ts, x_raw[0]);
+ y_scr = transform_to_screen_y(ts, y_raw[0]);
+
+ if (ts->prints)
+ printk("x_raw=%d y_raw=%d x_transform=%d y_transform=%d\n", x_raw[0], y_raw[0], x_scr, y_scr);
+ }
+ else {
+ x_scr = x_raw[0];
+ y_scr = y_raw[0];
+
+ if (ts->prints)
+ printk("x_raw=%d y_raw=%d \n", x_raw[0], y_raw[0]);
+ }
+
+ event->x = x_scr;
+ event->y = y_scr;
+ event->pressure = (u16)p_raw[0];
+ event->status = PENDOWN;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Module init and exit
+ */
+static int __init sadc_init(void)
+{
+ struct sadc_device *dev;
+ int ret;
+
+ /* allocate device */
+ dev = kmalloc(sizeof(struct sadc_device), GFP_KERNEL);
+ if (!dev) return -ENOMEM;
+
+ sadc_dev = dev;
+ ret = jz_register_chrdev(SADC_MINOR, SADC_NAME, &sadc_fops, dev);
+ if (ret < 0) {
+ kfree(dev);
+ return ret;
+ }
+
+ codec_read_battery = jz4740_read_battery;
+ sadc_init_clock(3);
+
+ printk(JZ_SOC_NAME": SAR-ADC driver registered.\n");
+ return 0;
+}
+
+static void __exit sadc_exit(void)
+{
+ struct sadc_device *dev = sadc_dev;
+
+ free_irq(IRQ_SADC, dev);
+ jz_unregister_chrdev(SADC_MINOR, SADC_NAME);
+ kfree(dev);
+}
+
+module_init(sadc_init);
+module_exit(sadc_exit);
diff --git a/drivers/char/jzchar/sensor.c b/drivers/char/jzchar/sensor.c
new file mode 100644
index 00000000000..8ad08203cad
--- /dev/null
+++ b/drivers/char/jzchar/sensor.c
@@ -0,0 +1,182 @@
+/*
+ * linux/drivers/char/jzchar/sensor.c
+ *
+ * Common CMOS Camera Sensor Driver
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+
+#include "jzchars.h"
+
+MODULE_AUTHOR("Jianli Wei<jlwei@ingenic.cn>");
+MODULE_DESCRIPTION("Common CMOS Camera Sensor Driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * ioctl commands
+ */
+#define IOCTL_SET_ADDR 0 /* set i2c address */
+#define IOCTL_SET_CLK 1 /* set i2c clock */
+#define IOCTL_WRITE_REG 2 /* write sensor register */
+#define IOCTL_READ_REG 3 /* read sensor register */
+
+/*
+ * i2c related
+ */
+static unsigned int i2c_addr = 0x42;
+static unsigned int i2c_clk = 100000;
+
+static void write_reg(u8 reg, u8 val)
+{
+ i2c_open();
+ i2c_setclk(i2c_clk);
+ i2c_write((i2c_addr >> 1), &val, reg, 1);
+ i2c_close();
+}
+
+static u8 read_reg(u8 reg)
+{
+ u8 val;
+
+ i2c_open();
+ i2c_setclk(i2c_clk);
+ i2c_read((i2c_addr >> 1), &val, reg, 1);
+ i2c_close();
+ return val;
+}
+
+/*
+ * fops routines
+ */
+
+static int sensor_open(struct inode *inode, struct file *filp);
+static int sensor_release(struct inode *inode, struct file *filp);
+static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l);
+static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l);
+static int sensor_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
+
+static struct file_operations sensor_fops =
+{
+ open: sensor_open,
+ release: sensor_release,
+ read: sensor_read,
+ write: sensor_write,
+ ioctl: sensor_ioctl,
+};
+
+static int sensor_open(struct inode *inode, struct file *filp)
+{
+ try_module_get(THIS_MODULE);
+ return 0;
+}
+
+static int sensor_release(struct inode *inode, struct file *filp)
+{
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l)
+{
+ printk("sensor: read is not implemented\n");
+ return -1;
+}
+
+static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l)
+{
+ printk("sensor: write is not implemented\n");
+ return -1;
+}
+
+static int sensor_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case IOCTL_SET_ADDR:
+ if (copy_from_user(&i2c_addr, (void *)arg, 4))
+ return -EFAULT;
+ break;
+ case IOCTL_SET_CLK:
+ if (copy_from_user(&i2c_clk, (void *)arg, 4))
+ return -EFAULT;
+ break;
+ case IOCTL_WRITE_REG:
+ {
+ u8 regval[2];
+
+ if (copy_from_user(regval, (void *)arg, 2))
+ return -EFAULT;
+
+ write_reg(regval[0], regval[1]);
+ break;
+ }
+ case IOCTL_READ_REG:
+ {
+ u8 reg, val;
+
+ if (copy_from_user(&reg, (void *)arg, 1))
+ return -EFAULT;
+
+ val = read_reg(reg);
+
+ if (copy_to_user((void *)(arg + 1), &val, 1))
+ return -EFAULT;
+ break;
+ }
+ default:
+ printk("Not supported command: 0x%x\n", cmd);
+ return -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+/*
+ * Module init and exit
+ */
+
+static int __init sensor_init(void)
+{
+ int ret;
+
+ ret = jz_register_chrdev(SENSOR_MINOR, "sensor", &sensor_fops, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+
+ printk(JZ_SOC_NAME ": Ingenic CMOS camera sensor driver registered\n");
+
+ return 0;
+}
+
+static void __exit sensor_exit(void)
+{
+ jz_unregister_chrdev(SENSOR_MINOR, "sensor");
+}
+
+module_init(sensor_init);
+module_exit(sensor_exit);
diff --git a/drivers/char/jzchar/tcsm.c b/drivers/char/jzchar/tcsm.c
new file mode 100644
index 00000000000..a64972cd63f
--- /dev/null
+++ b/drivers/char/jzchar/tcsm.c
@@ -0,0 +1,123 @@
+/*
+ * linux/drivers/char/jzchar/tcsm.c
+ *
+ * Virtual device driver with tricky appoach to manage TCSM
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+
+#include <asm/mipsregs.h>
+#include <asm/mipsmtregs.h>
+
+#include <asm/irq.h>
+#include <asm/thread_info.h>
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+
+#include "jzchars.h"
+
+MODULE_AUTHOR("Jianli Wei<jlwei@ingenic.cn>");
+MODULE_DESCRIPTION("Virtual Driver of TCSM");
+MODULE_LICENSE("GPL");
+
+/*
+ * fops routines
+ */
+
+static int tcsm_open(struct inode *inode, struct file *filp);
+static int tcsm_release(struct inode *inode, struct file *filp);
+static ssize_t tcsm_read(struct file *filp, char *buf, size_t size, loff_t *l);
+static ssize_t tcsm_write(struct file *filp, const char *buf, size_t size, loff_t *l);
+static int tcsm_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
+
+static struct file_operations tcsm_fops =
+{
+ open: tcsm_open,
+ release: tcsm_release,
+ read: tcsm_read,
+ write: tcsm_write,
+ ioctl: tcsm_ioctl,
+};
+
+static int tcsm_open(struct inode *inode, struct file *filp)
+{
+ struct pt_regs *info = task_pt_regs(current);
+
+ info->cp0_status &= ~0x10;// clear UM bit
+ info->cp0_status |= 0x08000000; // set RP bit a tricky
+
+ return 0;
+}
+
+static int tcsm_release(struct inode *inode, struct file *filp)
+{
+ struct pt_regs *info = task_pt_regs(current);
+
+ info->cp0_status |= 0x10;// set UM bit
+ info->cp0_status &= ~0x08000000; // clear RP bit a tricky
+
+ return 0;
+}
+
+static ssize_t tcsm_read(struct file *filp, char *buf, size_t size, loff_t *l)
+{
+ printk("tcsm: read is not implemented\n");
+ return -1;
+}
+
+static ssize_t tcsm_write(struct file *filp, const char *buf, size_t size, loff_t *l)
+{
+ printk("tcsm: write is not implemented\n");
+ return -1;
+}
+
+static int tcsm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ printk("tcsm: ioctl is not implemented\n");
+ return ret;
+}
+
+/*
+ * Module init and exit
+ */
+
+static int __init tcsm_init(void)
+{
+ int ret;
+
+ ret = jz_register_chrdev(TCSM_MINOR, "tcsm", &tcsm_fops, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+
+ printk(JZ_SOC_NAME": Virtual Driver of TCSM registered.\n");
+ return 0;
+}
+
+static void __exit tcsm_exit(void)
+{
+ jz_unregister_chrdev(TCSM_MINOR, "tcsm");
+}
+
+module_init(tcsm_init);
+module_exit(tcsm_exit);
diff --git a/drivers/char/jzchar/ucb1400.c b/drivers/char/jzchar/ucb1400.c
new file mode 100644
index 00000000000..d5d06f7e553
--- /dev/null
+++ b/drivers/char/jzchar/ucb1400.c
@@ -0,0 +1,585 @@
+/*
+ * ucb1400.c
+ *
+ * Touch screen driver interface to the UCB1400 codec.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/ac97_codec.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/jzsoc.h>
+
+#include "jz_ts.h"
+#include "ucb1400.h"
+
+#ifndef GPIO_TS_PENIRQ
+#define GPIO_TS_PENIRQ 68
+#endif
+
+#define TS_PIN GPIO_TS_PENIRQ
+#define TS_IRQ (IRQ_GPIO_0 + TS_PIN)
+
+static int samples = 5; /* we sample 5 every time, and throw away the max and min cases, then use the average of the other 3 samples */
+static int first_time = 0;
+static unsigned long last_x, last_y, last_p;
+
+static int adcsync = 0;
+
+static unsigned int ucb_id = 0;
+static struct ucb1400 *ucb;
+
+extern struct ac97_codec * find_ac97_codec(void);
+
+extern unsigned int (*codec_read_battery)(void);
+
+/*------------------ UCB1400 routines ------------------*/
+
+static inline void ucb1400_reg_write(unsigned char reg, unsigned short val)
+{
+ struct ac97_codec *codec = find_ac97_codec();
+ if (!codec)
+ return;
+ codec->codec_write(codec, reg, val);
+}
+
+static inline unsigned int ucb1400_reg_read(unsigned char reg)
+{
+ struct ac97_codec *codec = find_ac97_codec();
+ if (!codec)
+ return 0;
+ return codec->codec_read(codec, reg);
+}
+
+static void ucb1400_adc_enable(void)
+{
+ down(&ucb->adc_sem);
+
+ ucb->adc_cr |= UCB_ADC_ENA;
+ ucb1400_reg_write(UCB_ADC_CR, ucb->adc_cr);
+}
+
+static unsigned int ucb1400_adc_read(int adc_channel, int sync)
+{
+ unsigned int val, timeout = 10000;
+
+ if (sync)
+ adc_channel |= UCB_ADC_SYNC_ENA;
+
+ ucb1400_reg_write(UCB_ADC_CR, ucb->adc_cr | adc_channel);
+ ucb1400_reg_write(UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START);
+
+ for (;;) {
+ val = ucb1400_reg_read(UCB_ADC_DATA);
+ if (val & UCB_ADC_DAT_VAL)
+ break;
+ if (--timeout == 0)
+ break;
+ udelay(1);
+ }
+
+ return UCB_ADC_DAT(val);
+}
+
+static void ucb1400_adc_disable(void)
+{
+ ucb->adc_cr &= ~UCB_ADC_ENA;
+ ucb1400_reg_write(UCB_ADC_CR, ucb->adc_cr);
+
+ up(&ucb->adc_sem);
+}
+
+static void ucb1400_enable_irq(unsigned int idx, int edges)
+{
+ unsigned long flags;
+
+ if (idx < 16) {
+ spin_lock_irqsave(&ucb->lock, flags);
+
+ /* This prevents spurious interrupts on the UCB1400 */
+ ucb1400_reg_write(UCB_IE_CLEAR, 1 << idx);
+ ucb1400_reg_write(UCB_IE_CLEAR, 0);
+
+ if (edges & UCB_RISING) {
+ ucb->irq_ris_enbl |= 1 << idx;
+ ucb1400_reg_write(UCB_IE_RIS, ucb->irq_ris_enbl);
+ }
+ if (edges & UCB_FALLING) {
+ ucb->irq_fal_enbl |= 1 << idx;
+ ucb1400_reg_write(UCB_IE_FAL, ucb->irq_fal_enbl);
+ }
+ spin_unlock_irqrestore(&ucb->lock, flags);
+ }
+}
+
+static void ucb1400_disable_irq(unsigned int idx, int edges)
+{
+ unsigned long flags;
+
+ if (idx < 16) {
+ spin_lock_irqsave(&ucb->lock, flags);
+
+ if (edges & UCB_RISING) {
+ ucb->irq_ris_enbl &= ~(1 << idx);
+ ucb1400_reg_write(UCB_IE_RIS, ucb->irq_ris_enbl);
+ }
+ if (edges & UCB_FALLING) {
+ ucb->irq_fal_enbl &= ~(1 << idx);
+ ucb1400_reg_write(UCB_IE_FAL, ucb->irq_fal_enbl);
+ }
+ spin_unlock_irqrestore(&ucb->lock, flags);
+ }
+}
+
+/*
+ * Switch to interrupt mode.
+ */
+static inline void ucb1400_ts_mode_int(void)
+{
+ if (!ucb_id) {
+ ucb_id = ucb1400_reg_read(UCB_ID);
+ }
+
+ if (ucb_id == UCB_ID_1400_BUGGY)
+ ucb1400_reg_write(UCB_TS_CR,
+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+ UCB_TS_CR_MODE_INT);
+ else
+ ucb1400_reg_write(UCB_TS_CR,
+ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+ UCB_TS_CR_MODE_INT);
+}
+
+/*
+ * Switch to pressure mode, and read pressure. We don't need to wait
+ * here, since both plates are being driven.
+ */
+static inline unsigned int ucb1400_ts_read_pressure(void)
+{
+ ucb1400_reg_write(UCB_TS_CR,
+ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+
+ return ucb1400_adc_read(UCB_ADC_INP_TSPY, adcsync);
+}
+
+/*
+ * Switch to X position mode and measure Y plate. We switch the plate
+ * configuration in pressure mode, then switch to position mode. This
+ * gives a faster response time. Even so, we need to wait about 55us
+ * for things to stabilise.
+ */
+static inline unsigned int ucb1400_ts_read_xpos(void)
+{
+ ucb1400_reg_write(UCB_TS_CR,
+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+ ucb1400_reg_write(UCB_TS_CR,
+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+ ucb1400_reg_write(UCB_TS_CR,
+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
+
+ udelay(55);
+
+ return ucb1400_adc_read(UCB_ADC_INP_TSPY, adcsync);
+}
+
+/*
+ * Switch to Y position mode and measure X plate. We switch the plate
+ * configuration in pressure mode, then switch to position mode. This
+ * gives a faster response time. Even so, we need to wait about 55us
+ * for things to stabilise.
+ */
+static inline unsigned int ucb1400_ts_read_ypos(void)
+{
+ ucb1400_reg_write(UCB_TS_CR,
+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+ ucb1400_reg_write(UCB_TS_CR,
+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+ ucb1400_reg_write(UCB_TS_CR,
+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
+
+ udelay(55);
+
+ return ucb1400_adc_read(UCB_ADC_INP_TSPX, adcsync);
+}
+
+/*------------------------------------------------------------
+ * Read the battery voltage
+ */
+
+unsigned int ucb1400_read_battery(void)
+{
+ unsigned int v;
+
+ ucb1400_adc_enable();
+
+ // read twice to reduce fault value
+ v = ucb1400_adc_read(UCB_ADC_INP_AD0, adcsync);
+ v = ucb1400_adc_read(UCB_ADC_INP_AD0, adcsync);
+
+ ucb1400_adc_disable();
+
+// printk("ucb1400_read_battery v=%d\n", v);
+
+ return v;
+}
+
+/*------------------ Calibrate samples -------------------*/
+
+#define DIFF(a,b) ((a>b)?(a-b):(b-a))
+
+static int calibrate_samples(void *xbuf, void *ybuf, void *pbuf, int count)
+{
+ unsigned long *xp = (unsigned long *)xbuf;
+ unsigned long *yp = (unsigned long *)ybuf;
+ unsigned long *pp = (unsigned long *)pbuf;
+ unsigned long x_cal = 0, y_cal = 0, p_cal = 0, tmp;
+ int ignored, i, j;
+ int valid = 0;
+
+ /* throw away the max cases */
+ tmp = xp[0];
+ ignored = 0;
+ for (i = 1; i < count; i++) {
+ if (xp[i] > tmp) {
+ tmp = xp[i];
+ ignored = i;
+ }
+ }
+ j = 0;
+ for (i = 0; i < count; i++) {
+ if (i == ignored)
+ continue;
+ xp[j++] = xp[i];
+ }
+
+ tmp = yp[0];
+ ignored = 0;
+ for (i = 1; i < count; i++) {
+ if (yp[i] > tmp) {
+ tmp = yp[i];
+ ignored = i;
+ }
+ }
+ j = 0;
+ for (i = 0; i < count; i++) {
+ if (i == ignored)
+ continue;
+ yp[j++] = yp[i];
+ }
+
+ tmp = pp[0];
+ ignored = 0;
+ for (i = 1; i < count; i++) {
+ if (pp[i] > tmp) {
+ tmp = pp[i];
+ ignored = i;
+ }
+ }
+ j = 0;
+ for (i = 0; i < count; i++) {
+ if (i == ignored)
+ continue;
+ pp[j++] = pp[i];
+ }
+
+ /* throw away the min cases */
+
+ count -= 1; // decrement by 1
+
+ tmp = xp[0];
+ ignored = 0;
+ for (i = 1; i < count; i++) {
+ if (xp[i] < tmp) {
+ tmp = xp[i];
+ ignored = i;
+ }
+ }
+ j = 0;
+ for (i = 0; i < count; i++) {
+ if (i == ignored)
+ continue;
+ xp[j++] = xp[i];
+ }
+
+ tmp = yp[0];
+ ignored = 0;
+ for (i = 1; i < count; i++) {
+ if (yp[i] < tmp) {
+ tmp = yp[i];
+ ignored = i;
+ }
+ }
+ j = 0;
+ for (i = 0; i < count; i++) {
+ if (i == ignored)
+ continue;
+ yp[j++] = yp[i];
+ }
+
+ tmp = pp[0];
+ ignored = 0;
+ for (i = 1; i < count; i++) {
+ if (pp[i] < tmp) {
+ tmp = pp[i];
+ ignored = i;
+ }
+ }
+ j = 0;
+ for (i = 0; i < count; i++) {
+ if (i == ignored)
+ continue;
+ pp[j++] = pp[i];
+ }
+
+ count -= 1; // decrement by 1
+
+ /* calculate the average of the rest */
+ for (i = 0; i < count; i++) {
+ x_cal += xp[i];
+ y_cal += yp[i];
+ p_cal += pp[i];
+ }
+ x_cal /= count;
+ y_cal /= count;
+ p_cal /= count;
+
+ if (first_time) {
+ first_time = 0;
+ last_x = x_cal;
+ last_y = y_cal;
+ last_p = p_cal;
+ valid = 1;
+ }
+ else {
+ if ((DIFF(x_cal, last_x) > 50) ||
+ (DIFF(y_cal, last_y) > 50))
+ valid = 0;
+ else
+ valid = 1;
+ }
+
+// printk("x_cal=%d y_cal=%d p_cal=%d valid=%d\n", x_cal, y_cal, p_cal, valid);
+
+ if (valid) {
+ *xp = last_x = x_cal;
+ *yp = last_y = y_cal;
+ *pp = last_p = p_cal;
+ }
+
+ return valid;
+}
+
+
+#define TSMAXX 945
+#define TSMAXY 830
+#define TSMINX 90
+#define TSMINY 105
+
+#define SCREEN_X 480
+#define SCREEN_Y 272
+
+static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x )
+{
+
+ if (ts->minx)
+ {
+ if (x < ts->minx) x = ts->minx;
+ if (x > ts->maxx) x = ts->maxx;
+
+ return (x - ts->minx) * SCREEN_X / (ts->maxx - ts->minx);
+ }
+ else
+ {
+ if (x < TSMINX) x = TSMINX;
+ if (x > TSMAXX) x = TSMAXX;
+
+ return (x - TSMINX) * SCREEN_X / (TSMAXX - TSMINX);
+ }
+}
+
+static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y)
+{
+ if (ts->minx)
+ {
+ if (y < ts->minx) y = ts->miny;
+ if (y > ts->maxx) y = ts->maxy;
+
+ return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny);
+ }
+ else
+ {
+ if (y < TSMINX) y = TSMINY;
+ if (y > TSMAXX) y = TSMAXY;
+
+ return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY);
+ }
+}
+
+/*------------------ Common routines -------------------*/
+
+void ts_enable_irq(void)
+{
+ /* interrupt mode */
+ ucb1400_ts_mode_int();
+ ucb1400_enable_irq(UCB_IRQ_TSPX, UCB_FALLING);
+
+ enable_irq(TS_IRQ);
+}
+
+void ts_disable_irq(void)
+{
+ ucb1400_disable_irq(UCB_IRQ_TSPX, UCB_FALLING);
+ disable_irq(TS_IRQ);
+}
+
+int ts_request_irq(u32 *irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ const char *devname,
+ void *dev_id)
+{
+ int retval;
+
+ /* return the irq number */
+ *irq = TS_IRQ;
+
+ /* interrupt mode */
+ ucb1400_ts_mode_int();
+ ucb1400_enable_irq(UCB_IRQ_TSPX, UCB_FALLING);
+
+ /* enable gpio irq */
+ __gpio_as_irq_rise_edge(TS_PIN);
+
+ /* register irq handler */
+ retval = request_irq(TS_IRQ, handler, SA_INTERRUPT, devname, dev_id);
+
+ return retval;
+}
+
+void ts_free_irq(struct jz_ts_t *ts)
+{
+ free_irq(ts->pendown_irq, ts);
+}
+
+void ts_irq_callback(void)
+{
+ /* clear interrupt status */
+ ucb1400_reg_write(UCB_IE_CLEAR, ucb1400_reg_read(UCB_IE_STATUS));
+ __gpio_ack_irq(TS_PIN);
+
+ first_time = 1; // first time to acquire sample
+}
+
+int PenIsDown(void)
+{
+ unsigned int p;
+
+ ucb1400_adc_enable();
+ p = ucb1400_ts_read_pressure();
+ ucb1400_adc_disable();
+
+ return (p > 100) ? 1 : 0;
+}
+
+/*
+ * Acquire Raw pen coodinate data and compute touch screen
+ * pressure resistance. Hold spinlock when calling.
+ */
+int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event)
+{
+ unsigned int x_raw[8], y_raw[8], p_raw[8];
+ int valid, i;
+
+ /* Enable ADC */
+ ucb1400_adc_enable();
+
+ for (i = 0; i < samples; i++) {
+ x_raw[i] = ucb1400_ts_read_xpos();
+ }
+ for (i = 0; i < samples; i++) {
+ y_raw[i] = ucb1400_ts_read_ypos();
+ }
+ for (i = 0; i < samples; i++) {
+ p_raw[i] = ucb1400_ts_read_pressure();
+ }
+
+ /* Disable ADC */
+ ucb1400_adc_disable();
+
+ valid = calibrate_samples(x_raw, y_raw, p_raw, samples);
+
+ if (valid) {
+ unsigned int x_scr, y_scr;
+
+ if(ts->filter) {
+ x_scr = transform_to_screen_x(ts, x_raw[0]);
+ y_scr = transform_to_screen_y(ts, y_raw[0]);
+
+ if (ts->prints)
+ printk("x_raw=%d y_raw=%d x_transform=%d y_transform=%d\n", x_raw[0], y_raw[0], x_scr, y_scr);
+ }
+ else {
+ x_scr = x_raw[0];
+ y_scr = y_raw[0];
+
+ if (ts->prints)
+ printk("x_raw=%d y_raw=%d \n", x_raw[0], y_raw[0]);
+ }
+
+ event->x = x_scr;
+ event->y = y_scr;
+ event->pressure = (u16)p_raw[0];
+ event->status = PENDOWN;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Module init and exit
+ */
+
+int __init ucb1400_init(void)
+{
+ ucb = kmalloc(sizeof(struct ucb1400), GFP_KERNEL);
+ if (!ucb) return -ENOMEM;
+
+ memset(ucb, 0, sizeof(struct ucb1400));
+
+ codec_read_battery = ucb1400_read_battery;
+
+ spin_lock_init(&ucb->lock);
+ sema_init(&ucb->adc_sem, 1);
+
+ return 0;
+}
+
+void ucb1400_cleanup(void)
+{
+ kfree(ucb);
+}
+
+module_init(ucb1400_init);
+module_exit(ucb1400_cleanup);
diff --git a/drivers/char/jzchar/ucb1400.h b/drivers/char/jzchar/ucb1400.h
new file mode 100644
index 00000000000..318c004e3b6
--- /dev/null
+++ b/drivers/char/jzchar/ucb1400.h
@@ -0,0 +1,113 @@
+#ifndef __UCB1400_H__
+#define __UCB1400_H__
+
+/* ucb1400 aclink register mappings */
+
+#define UCB_IO_DATA 0x5a
+#define UCB_IO_DIR 0x5c
+#define UCB_IE_RIS 0x5e
+#define UCB_IE_FAL 0x60
+#define UCB_IE_STATUS 0x62
+#define UCB_IE_CLEAR 0x62
+#define UCB_TS_CR 0x64
+#define UCB_ADC_CR 0x66
+#define UCB_ADC_DATA 0x68
+#define UCB_ID 0x7e /* 7c is mfr id, 7e part id (from aclink spec) */
+
+#define UCB_ADC_DAT(x) ((x) & 0x3ff)
+
+/* register bits */
+
+#define UCB_IO_0 (1 << 0)
+#define UCB_IO_1 (1 << 1)
+#define UCB_IO_2 (1 << 2)
+#define UCB_IO_3 (1 << 3)
+#define UCB_IO_4 (1 << 4)
+#define UCB_IO_5 (1 << 5)
+#define UCB_IO_6 (1 << 6)
+#define UCB_IO_7 (1 << 7)
+#define UCB_IO_8 (1 << 8)
+#define UCB_IO_9 (1 << 9)
+
+#define UCB_IE_ADC (1 << 11)
+#define UCB_IE_TSPX (1 << 12)
+#define UCB_IE_TSMX (1 << 13)
+#define UCB_IE_TCLIP (1 << 14)
+#define UCB_IE_ACLIP (1 << 15)
+
+#define UCB_IRQ_TSPX 12
+
+#define UCB_TC_A_LOOP (1 << 7) /* UCB1200 */
+#define UCB_TC_A_AMPL (1 << 7) /* UCB1300 */
+
+#define UCB_TC_B_VOICE_ENA (1 << 3)
+#define UCB_TC_B_CLIP (1 << 4)
+#define UCB_TC_B_ATT (1 << 6)
+#define UCB_TC_B_SIDE_ENA (1 << 11)
+#define UCB_TC_B_MUTE (1 << 13)
+#define UCB_TC_B_IN_ENA (1 << 14)
+#define UCB_TC_B_OUT_ENA (1 << 15)
+
+#define UCB_AC_B_LOOP (1 << 8)
+#define UCB_AC_B_MUTE (1 << 13)
+#define UCB_AC_B_IN_ENA (1 << 14)
+#define UCB_AC_B_OUT_ENA (1 << 15)
+
+#define UCB_TS_CR_TSMX_POW (1 << 0)
+#define UCB_TS_CR_TSPX_POW (1 << 1)
+#define UCB_TS_CR_TSMY_POW (1 << 2)
+#define UCB_TS_CR_TSPY_POW (1 << 3)
+#define UCB_TS_CR_TSMX_GND (1 << 4)
+#define UCB_TS_CR_TSPX_GND (1 << 5)
+#define UCB_TS_CR_TSMY_GND (1 << 6)
+#define UCB_TS_CR_TSPY_GND (1 << 7)
+#define UCB_TS_CR_MODE_INT (0 << 8)
+#define UCB_TS_CR_MODE_PRES (1 << 8)
+#define UCB_TS_CR_MODE_POS (2 << 8)
+#define UCB_TS_CR_BIAS_ENA (1 << 11)
+#define UCB_TS_CR_TSPX_LOW (1 << 12)
+#define UCB_TS_CR_TSMX_LOW (1 << 13)
+
+#define UCB_ADC_SYNC_ENA (1 << 0)
+#define UCB_ADC_VREFBYP_CON (1 << 1)
+#define UCB_ADC_INP_TSPX (0 << 2)
+#define UCB_ADC_INP_TSMX (1 << 2)
+#define UCB_ADC_INP_TSPY (2 << 2)
+#define UCB_ADC_INP_TSMY (3 << 2)
+#define UCB_ADC_INP_AD0 (4 << 2)
+#define UCB_ADC_INP_AD1 (5 << 2)
+#define UCB_ADC_INP_AD2 (6 << 2)
+#define UCB_ADC_INP_AD3 (7 << 2)
+#define UCB_ADC_EXT_REF (1 << 5)
+#define UCB_ADC_START (1 << 7)
+#define UCB_ADC_ENA (1 << 15)
+
+#define UCB_ADC_DAT_VAL (1 << 15)
+
+#define UCB_ID_1200 0x1004
+#define UCB_ID_1300 0x1005
+#define UCB_ID_1400 0x4304
+#define UCB_ID_1400_BUGGY 0x4303 /* fake ID */
+
+#define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
+#define UCB_MODE_AUD_OFF_CAN (1 << 13)
+
+/*
+ * Which edges of the IRQ do you want to control today?
+ */
+#define UCB_RISING (1 << 0)
+#define UCB_FALLING (1 << 1)
+
+/* Device data structure */
+
+struct ucb1400 {
+ spinlock_t lock;
+ struct pm_dev *pmdev;
+ struct semaphore adc_sem;
+ u16 adc_cr;
+ u16 irq_fal_enbl;
+ u16 irq_ris_enbl;
+ int irq_enabled;
+};
+
+#endif /* __UCB1400_H__ */
diff --git a/drivers/char/jzchar/udc_hotplug.c b/drivers/char/jzchar/udc_hotplug.c
new file mode 100644
index 00000000000..5115033c634
--- /dev/null
+++ b/drivers/char/jzchar/udc_hotplug.c
@@ -0,0 +1,451 @@
+/*
+ * linux/drivers/char/jzchar/udc_hotplug.c
+ *
+ * New UDC hotplug driver.
+ *
+ * Copyright (C) 2007 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/kobject.h>
+#include <linux/miscdevice.h>
+
+#include <asm/jzsoc.h>
+#include "jzchars.h"
+
+#ifndef GPIO_UDC_HOTPLUG
+#define GPIO_UDC_HOTPLUG 86
+#endif
+
+#define UDC_HOTPLUG_PIN GPIO_UDC_HOTPLUG
+#define UDC_HOTPLUG_IRQ (IRQ_GPIO_0 + UDC_HOTPLUG_PIN)
+
+#define dprintk(x,...)
+
+//simple meaning define
+#define NOT_CONNECT 0
+#define YES_CONNECT 1
+#define MAX_GPIO_TIME 50
+
+#define EVENT_USB_ADD 1
+#define EVENT_USB_REMOVE 2
+#define EVENT_POWER_ADD 3
+#define EVENT_POWER_REMOVE 4
+#define EVENT_POWER_TO_USB 5
+#define EVENT_USB_SUSPEND_POWER 6
+
+struct udc_pnp_stat
+{
+ char cable_stat, old_cable_stat;
+ char protl_stat, old_protl_stat;
+ char object_stat1;
+ char object_stat2;
+};
+
+static struct udc_pnp_stat cur_pnp_stat;
+
+static struct file_operations cable_fops = {
+ owner: THIS_MODULE,
+};
+
+static struct miscdevice cable_dev=
+{
+ 231,
+ "udc_cable",
+ &cable_fops
+};
+
+static struct file_operations power_fops = {
+ owner: THIS_MODULE,
+};
+
+static struct miscdevice power_dev=
+{
+ 232,
+ "power_cable",
+ &power_fops
+};
+
+int jz_udc_active = 0; /* 0: Have no actions; 1: Have actions */
+
+static int udc_pin_level;
+static int udc_old_state;
+static int udc_pin_time;
+
+static struct timer_list udc_long_timer, udc_gpio_timer;
+
+/* Kernel thread to deliver event to user space */
+static struct task_struct *kudcd_task;
+
+static void udc_gpio_timer_routine(unsigned long data)
+{
+ wake_up_process(kudcd_task);
+}
+
+static void udc_long_timer_routine(unsigned long data)
+{
+ dprintk("udc_timer\n");
+ if (jz_udc_active)
+ udc_old_state = 1;
+ if (!jz_udc_active && udc_old_state) //udc irq timeout! do suspend
+ {
+ dprintk("udc suspend!\n");
+ udc_old_state = 0;
+ cur_pnp_stat.protl_stat = NOT_CONNECT;
+ del_timer(&udc_long_timer);
+ wake_up_process(kudcd_task);
+ return;
+ }
+ jz_udc_active = 0;
+ udc_long_timer.expires = jiffies + 3 * HZ; /* about 3 s */
+ add_timer(&udc_long_timer);
+}
+
+static int udc_get_pnp_stat(void)
+{
+ udc_pin_level = __gpio_get_pin(UDC_HOTPLUG_PIN);
+ udc_pin_time = 1;
+
+ init_timer(&udc_gpio_timer);
+ del_timer(&udc_gpio_timer);
+ udc_gpio_timer.function = udc_gpio_timer_routine;
+ udc_gpio_timer.expires = jiffies + 1; /* about 10 ms */
+ add_timer(&udc_gpio_timer);
+
+ while(1)
+ {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+
+ if (__gpio_get_pin(UDC_HOTPLUG_PIN) != udc_pin_level)
+ {
+ udc_pin_level = __gpio_get_pin(UDC_HOTPLUG_PIN);
+ udc_pin_time = 1;
+ dprintk("udc gpio detect restart! \n");
+ }
+
+ udc_pin_time ++;
+ if (udc_pin_time > MAX_GPIO_TIME)
+ break;
+
+ del_timer(&udc_gpio_timer);
+ udc_gpio_timer.function = udc_gpio_timer_routine;
+ udc_gpio_timer.expires = jiffies + 1; /* about 10 ms */
+ add_timer(&udc_gpio_timer);
+ }
+
+ del_timer(&udc_gpio_timer);
+ if (__gpio_get_pin(UDC_HOTPLUG_PIN))
+ return YES_CONNECT;
+ else
+ return NOT_CONNECT;
+}
+
+static void udc_get_cable(void)
+{
+ u32 intr_usb;
+
+ __intc_mask_irq(IRQ_UDC);
+
+ /* Now enable PHY to start detect */
+#ifdef CONFIG_SOC_JZ4740
+ REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE;
+#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D)
+ REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE;
+#endif
+ /* Clear IRQs */
+ REG16(USB_REG_INTRINE) = 0;
+ REG16(USB_REG_INTROUTE) = 0;
+ REG8(USB_REG_INTRUSBE) = 0;
+
+ /* disable UDC IRQs first */
+ REG16(USB_REG_INTRINE) = 0;
+ REG16(USB_REG_INTROUTE) = 0;
+ REG8(USB_REG_INTRUSBE) = 0;
+
+ /* Disable DMA */
+ REG32(USB_REG_CNTL1) = 0;
+ REG32(USB_REG_CNTL2) = 0;
+
+ /* Enable HS Mode */
+ REG8(USB_REG_POWER) |= USB_POWER_HSENAB;
+ /* Enable soft connect */
+ REG8(USB_REG_POWER) |= USB_POWER_SOFTCONN;
+
+ dprintk("enable phy! %x %x %x %x %x\n",
+ REG8(USB_REG_POWER),
+ REG_CPM_SCR,
+ REG16(USB_REG_INTRINE),
+ REG16(USB_REG_INTROUTE),
+ REG8(USB_REG_INTRUSBE));
+
+ init_timer(&udc_gpio_timer);
+ del_timer(&udc_gpio_timer);
+ udc_gpio_timer.function = udc_gpio_timer_routine;
+ udc_gpio_timer.expires = jiffies + 11; /* about 100 ms */
+ add_timer(&udc_gpio_timer);
+ /* Sleep a short time to see result */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+
+ del_timer(&udc_gpio_timer);
+ intr_usb = REG8(USB_REG_INTRUSB);
+ if ((intr_usb & USB_INTR_RESET) ||
+ (intr_usb & USB_INTR_RESUME) ||
+ (intr_usb & USB_INTR_SUSPEND))
+ {
+ cur_pnp_stat.protl_stat = YES_CONNECT;
+ dprintk("cable is usb! \n");
+ }
+ else
+ {
+ cur_pnp_stat.protl_stat = NOT_CONNECT;
+ dprintk("cable is power! \n");
+ }
+
+ /* Detect finish ,clean every thing */
+ /* Disconnect from usb */
+ REG8(USB_REG_POWER) &= ~USB_POWER_SOFTCONN;
+ /* Disable the USB PHY */
+#ifdef CONFIG_SOC_JZ4740
+ REG_CPM_SCR &= ~CPM_SCR_USBPHY_ENABLE;
+#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D)
+ REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE;
+#endif
+ /* Clear IRQs */
+ REG16(USB_REG_INTRINE) = 0;
+ REG16(USB_REG_INTROUTE) = 0;
+ REG8(USB_REG_INTRUSBE) = 0;
+ __intc_ack_irq(IRQ_UDC);
+ __intc_unmask_irq(IRQ_UDC);
+}
+
+static void send_event_udev(int event)
+{
+ dprintk("Send udev message: cable=%d old=%d protl=%d old=%d \n",
+ cur_pnp_stat.cable_stat,
+ cur_pnp_stat.old_cable_stat,
+ cur_pnp_stat.protl_stat,
+ cur_pnp_stat.old_protl_stat);
+
+ switch (event)
+ {
+ case EVENT_USB_ADD:
+ printk("usb cable insert! \n");
+ misc_register(&cable_dev);
+ kobject_uevent(&cable_dev.this_device->kobj, KOBJ_ADD);
+ init_timer(&udc_long_timer);
+ del_timer(&udc_long_timer);
+ udc_long_timer.function = udc_long_timer_routine;
+ udc_long_timer.expires = jiffies + 3 * HZ; /* about 3 s */
+ add_timer(&udc_long_timer);
+ break;
+ case EVENT_USB_REMOVE:
+ printk("usb cable remove! \n");
+ kobject_uevent(&cable_dev.this_device->kobj, KOBJ_REMOVE);
+ misc_deregister(&cable_dev);
+ del_timer(&udc_long_timer);
+ break;
+ case EVENT_POWER_ADD:
+ printk("power cable insert! \n");
+ misc_register(&power_dev);
+ kobject_uevent(&power_dev.this_device->kobj, KOBJ_ADD);
+ break;
+ case EVENT_POWER_REMOVE:
+ printk("power cable remove! \n");
+ kobject_uevent(&power_dev.this_device->kobj, KOBJ_REMOVE);
+ misc_deregister(&power_dev);
+ break;
+ case EVENT_POWER_TO_USB:
+ printk("change power cable to usb! \n");
+ kobject_uevent(&power_dev.this_device->kobj, KOBJ_REMOVE);
+ misc_deregister(&power_dev);
+ misc_register(&cable_dev);
+ kobject_uevent(&cable_dev.this_device->kobj, KOBJ_ADD);
+ break;
+ case EVENT_USB_SUSPEND_POWER:
+ printk("usb cable suspend! \n");
+ printk("as power cable insert! \n");
+ kobject_uevent(&cable_dev.this_device->kobj, KOBJ_REMOVE);
+ misc_deregister(&cable_dev);
+ misc_register(&power_dev);
+ kobject_uevent(&power_dev.this_device->kobj, KOBJ_ADD);
+ break;
+ };
+}
+
+static void udc_pnp_detect(void)
+{
+ if (cur_pnp_stat.cable_stat == YES_CONNECT) /* already connected! */
+ {
+ if (udc_get_pnp_stat() == NOT_CONNECT)
+ {
+ dprintk("cable real out! \n");
+ cur_pnp_stat.cable_stat = NOT_CONNECT;
+ cur_pnp_stat.protl_stat = NOT_CONNECT;
+ /* Deliver this event to user space in udev model */
+ if (cur_pnp_stat.old_protl_stat)
+ send_event_udev(EVENT_USB_REMOVE);
+ else
+ send_event_udev(EVENT_POWER_REMOVE);
+ cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat;
+ cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat;
+ }
+ else
+ {
+ if (cur_pnp_stat.old_protl_stat != cur_pnp_stat.protl_stat)
+ {
+ send_event_udev(EVENT_USB_SUSPEND_POWER);
+ cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat;
+ cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat;
+ }
+ else //change power to cable
+ {
+#if 0 //not support yet!
+ udc_get_cable();
+ if (cur_pnp_stat.old_protl_stat != cur_pnp_stat.protl_stat)
+ send_event_udev(EVENT_POWER_TO_USB);
+ cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat;
+ cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat;
+#endif
+ }
+ }
+ }
+ else
+ {
+ if (udc_get_pnp_stat() == YES_CONNECT)
+ {
+ dprintk("cable real in! \n");
+ cur_pnp_stat.cable_stat = YES_CONNECT;
+ udc_get_cable();
+ /* Deliver this event to user space in udev model */
+ if (cur_pnp_stat.protl_stat)
+ send_event_udev(EVENT_USB_ADD);
+ else
+ send_event_udev(EVENT_POWER_ADD);
+ cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat;
+ cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat;
+ }
+ else
+ dprintk("cable false in! \n");
+
+ }
+}
+
+static void udc_pnp_set_gpio(void)
+{
+ if (cur_pnp_stat.cable_stat == YES_CONNECT)
+ __gpio_as_irq_fall_edge(UDC_HOTPLUG_PIN);
+ else
+ __gpio_as_irq_rise_edge(UDC_HOTPLUG_PIN);
+
+ /* clear interrupt pending status */
+ __gpio_ack_irq(UDC_HOTPLUG_PIN);
+ /* unmask interrupt */
+ __gpio_unmask_irq(UDC_HOTPLUG_PIN);
+}
+
+static int udc_pnp_thread(void *unused)
+{
+ printk(KERN_NOTICE "UDC starting pnp monitor thread\n");
+
+ while(1)
+ {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+
+ dprintk("pnp thread wake up! \n");
+ /* wake up here */
+ udc_pnp_detect();
+ /* Reset gpio state last */
+ udc_pnp_set_gpio();
+ }
+}
+
+static irqreturn_t udc_pnp_irq(int irq, void *dev_id)
+{
+ printk("udc_pnp_irq----\n");
+ /* clear interrupt pending status */
+ __gpio_ack_irq(UDC_HOTPLUG_PIN);
+ /* mask interrupt */
+ __gpio_mask_irq(UDC_HOTPLUG_PIN);
+ /* wake up pnp detect thread */
+ wake_up_process(kudcd_task);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Module init and exit
+ */
+static int __init udc_hotplug_init(void)
+{
+ int retval;
+ /* Init pnp stat first */
+ cur_pnp_stat.cable_stat = NOT_CONNECT;
+ cur_pnp_stat.protl_stat = NOT_CONNECT;
+ cur_pnp_stat.old_cable_stat = NOT_CONNECT;
+ cur_pnp_stat.old_protl_stat = NOT_CONNECT;
+ cur_pnp_stat.object_stat1 = NOT_CONNECT;
+ cur_pnp_stat.object_stat2 = NOT_CONNECT;
+ udc_old_state = 0;
+
+ /* create pnp thread and register IRQ */
+ kudcd_task = kthread_run(udc_pnp_thread, NULL, "kudcd");
+ if (IS_ERR(kudcd_task)) {
+ printk(KERN_ERR "jz_udc_hotplug: Failed to create system monitor thread.\n");
+ return PTR_ERR(kudcd_task);
+ }
+
+ retval = request_irq(UDC_HOTPLUG_IRQ, udc_pnp_irq,
+ IRQF_DISABLED, "udc_pnp", NULL);
+ if (retval) {
+ printk("Could not get udc hotplug irq %d\n", UDC_HOTPLUG_IRQ);
+ return retval;
+ }
+
+ /* get current pin level */
+ __gpio_disable_pull(UDC_HOTPLUG_PIN);
+ __gpio_as_input(UDC_HOTPLUG_PIN);
+ udelay(1);
+ udc_pin_level = __gpio_get_pin(UDC_HOTPLUG_PIN);
+
+ if (udc_pin_level) {
+ dprintk("Cable already in! \n");
+ /* Post a event */
+ wake_up_process(kudcd_task);
+ }
+ else {
+ __gpio_as_irq_rise_edge(UDC_HOTPLUG_PIN);
+ dprintk("Cable not in! \n");
+ }
+
+ printk(JZ_SOC_NAME": UDC hotplug driver registered.\n");
+
+ return 0;
+}
+
+static void __exit udc_hotplug_exit(void)
+{
+ free_irq(UDC_HOTPLUG_IRQ, NULL);
+}
+
+module_init(udc_hotplug_init);
+module_exit(udc_hotplug_exit);
+
+EXPORT_SYMBOL(jz_udc_active);
+
+MODULE_AUTHOR("Lucifer <yliu@ingenic.cn>");
+MODULE_DESCRIPTION("JzSOC OnChip udc hotplug driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/jzchar/wm9712.c b/drivers/char/jzchar/wm9712.c
new file mode 100644
index 00000000000..de75435f821
--- /dev/null
+++ b/drivers/char/jzchar/wm9712.c
@@ -0,0 +1,334 @@
+/*
+ * wm9712.c
+ *
+ * Touch screen driver interface to the Wolfson WM9712 codec.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/ac97_codec.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/jzsoc.h>
+
+#include "jz_ts.h"
+#include "wm9712.h"
+
+#define POLL_TIMES 10
+
+static int samples = 1;
+static int inited = 0, started = 0;
+
+extern struct ac97_codec * find_ac97_codec(void);
+extern int PenIsDown(void);
+
+
+static inline void wm9712_reg_write(unsigned int reg, unsigned int val)
+{
+ struct ac97_codec *codec = find_ac97_codec();
+ if (!codec)
+ return;
+ codec->codec_write(codec, reg, val);
+}
+
+static inline unsigned int wm9712_reg_read(unsigned int reg)
+{
+ struct ac97_codec *codec = find_ac97_codec();
+ if (!codec)
+ return 0;
+ return codec->codec_read(codec, reg);
+}
+
+static unsigned int wm9712_adc_read(int adc_channel)
+{
+ unsigned int val;
+
+ if (!PenIsDown())
+ return 0;
+
+ val = wm9712_reg_read(DIGI_REG1);
+ wm9712_reg_write(DIGI_REG1, val|adc_channel|DIGI_REG1_POLL);
+
+ for (;;) {
+ if (wm9712_reg_read(0x54) & (1 << 12)) {
+ val = wm9712_reg_read(DIGI_READBACK);
+ break;
+ }
+ }
+
+ /* stop the measure */
+ wm9712_reg_write(DIGI_REG1, 0);
+
+ return (val & 0x0fff);
+}
+
+static struct timer_list pndn_timer;
+static void (*irq_handler)(int, void *, struct pt_regs *) = NULL;
+
+void ts_irq_callback(void)
+{
+#ifdef TS_IRQ
+ __gpio_ack_irq(TS_IRQ);
+#else
+#endif
+}
+
+void ts_enable_irq(void)
+{
+ if (!inited)
+ return;
+#ifdef TS_IRQ
+ enable_irq(TS_IRQ);
+#else
+ pndn_timer.expires = jiffies + HZ/POLL_TIMES;
+ add_timer(&pndn_timer);
+#endif
+}
+
+void ts_disable_irq(void)
+{
+ if (!inited)
+ return;
+#ifdef TS_IRQ
+ disable_irq(TS_IRQ);
+#endif
+}
+
+#ifndef TS_IRQ
+static void pndn_detect(unsigned long data)
+{
+ if (PenIsDown()) {
+ if (!started)
+ return;
+ if (irq_handler)
+ irq_handler(NULL, data, NULL);
+ } else {
+ pndn_timer.expires = jiffies + HZ/POLL_TIMES;
+ add_timer(&pndn_timer);
+ }
+}
+#endif
+
+void ts_free_irq(struct jz_ts_t *ts)
+{
+#ifdef TS_IRQ
+ free_irq(ts->pendown_irq, ts);
+#else
+ started = 0;
+ del_timer_sync(&pndn_timer);
+#endif
+}
+
+int ts_request_irq(u32 *irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ const char *devname,
+ void *dev_id)
+{
+ /* 4wire, Ip=400uA, Rpu=64Kohm/64, wake-up on pendown without
+ * reset, meassure on pen down. Do not use wait mode.
+ */
+ started = 1;
+ if (!inited) {
+ wm9712_reg_write(DIGI_REG2,
+ DIGI_REG2_WIRE_4 |
+ DIGI_REG2_PIL_200uA |
+ (31 << DIGI_REG2_RPU_BIT) |
+ DIGI_REG2_PRP_ALLON |
+ DIGI_REG2_RPR_NWOR);
+ /* Polling mode and no measurement */
+ wm9712_reg_write(DIGI_REG1, 0);
+ }
+
+#ifdef TS_IRQ
+ /* Generate irq request on PENDOWN pin, pendown cause the level high */
+ wm9712_reg_write(0x56, wm9712_reg_read(0x56) & ~(1 << 3));
+ wm9712_reg_write(0x4c, wm9712_reg_read(0x4c) & ~(1 << 3));
+
+ *irq = TS_IRQ;
+ return request_irq(TS_IRQ, handler, SA_INTERRUPT, devname, dev_id);
+#else
+ if (!inited) {
+ irq_handler = handler;
+ init_timer(&pndn_timer);
+ pndn_timer.function = pndn_detect;
+ pndn_timer.data = (unsigned long)dev_id;
+ pndn_timer.expires = jiffies + HZ/POLL_TIMES;
+ add_timer(&pndn_timer);
+ inited = 1;
+ } else {
+ pndn_timer.expires = jiffies + HZ/POLL_TIMES;
+ add_timer(&pndn_timer);
+ }
+ return 0;
+#endif
+}
+
+int PenIsDown(void)
+{
+ if (wm9712_reg_read(DIGI_READBACK) & DIGI_READBACK_PNDN)
+ return 1;
+ return 0;
+}
+
+#if defined(CONFIG_MIPS_JZ4730_GPS)
+#define adj_data(r1, r2, r3, s) \
+do { \
+ if (r1 < 0x90) \
+ r1 = 0x90; \
+ if (r2 < 0xed) \
+ r2 = 0xed; \
+ r1 = ((r1 - 0x90) * 240) / 3354; \
+ r2 = ((r2 - 0xed) * 320) / 3671; \
+ if (r1 > 239) \
+ r1 = 239; \
+ if (r2 > 319) \
+ r2 = 319; \
+ \
+ *s = r2; \
+ *(s+1) = 239 - r1; \
+ *(s+2) = z_raw; \
+} while (0)
+#endif
+
+#ifndef adj_data
+#define adj_data(r1, r2, r3, s)
+#endif
+
+static int read_adc(unsigned int *sdata)
+{
+ unsigned long x_raw=0, y_raw=0, z_raw=0, t, fail = 0;
+ int i;
+
+ for (i=0; i<samples; i++) {
+ t = wm9712_adc_read(ADCSEL_XPOS);
+ if (t == 0)
+ fail = 1;
+ x_raw += t;
+ t = wm9712_adc_read(ADCSEL_YPOS);
+ if (t == 0)
+ fail = 1;
+ y_raw += t;
+ t = wm9712_adc_read(ADCSEL_PRESSURE);
+ if (t == 0)
+ fail = 1;
+ z_raw += t;
+ }
+
+ if (fail)
+ return 0;
+
+ if (samples > 1) {
+ x_raw = (x_raw + (samples>>1)) / samples;
+ y_raw = (y_raw + (samples>>1)) / samples;
+ z_raw = (z_raw + (samples>>1)) / samples;
+ }
+
+ adj_data (x_raw, y_raw, z_raw, sdata);
+
+ return 1;
+}
+
+
+#define TSMAXX 945
+#define TSMAXY 830
+#define TSMINX 90
+#define TSMINY 105
+
+#define SCREEN_X 480
+#define SCREEN_Y 272
+
+static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x )
+{
+
+ if (ts->minx)
+ {
+ if (x < ts->minx) x = ts->minx;
+ if (x > ts->maxx) x = ts->maxx;
+
+ return (x - ts->minx) * SCREEN_X / (ts->maxx - ts->minx);
+ }
+ else
+ {
+ if (x < TSMINX) x = TSMINX;
+ if (x > TSMAXX) x = TSMAXX;
+
+ return (x - TSMINX) * SCREEN_X / (TSMAXX - TSMINX);
+ }
+}
+
+static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y)
+{
+ if (ts->minx)
+ {
+ if (y < ts->minx) y = ts->miny;
+ if (y > ts->maxx) y = ts->maxy;
+
+ return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny);
+ }
+ else
+ {
+ if (y < TSMINX) y = TSMINY;
+ if (y > TSMAXX) y = TSMAXY;
+
+ return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY);
+ }
+}
+
+
+/*
+ * Acquire Raw pen coodinate data and compute touch screen
+ * pressure resistance. Hold spinlock when calling.
+ */
+int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event)
+{
+ unsigned int s[3];
+ unsigned int x_scr, y_scr;
+ if (!read_adc(s))
+ return 0;
+ if(ts->filter) {
+ x_scr = transform_to_screen_x(ts, s[0]);
+ y_scr = transform_to_screen_y(ts, s[1]);
+
+ if (ts->prints)
+ printk("x_raw=%d y_raw=%d x_transform=%d y_transform=%d\n", s[0], s[1], x_scr, y_scr); }
+ else {
+ x_scr = s[0];
+ y_scr = s[1];
+
+ if (ts->prints)
+ printk("x_raw=%d y_raw=%d \n", s[0], s[1]);
+ }
+ event->x = x_scr;
+ event->y = y_scr;
+ event->pressure = (u16)s[2];
+ event->status = PENDOWN;
+ return 1;
+#if 0
+ do_gettimeofday(&event->stamp);
+#endif
+}
+
+int __init wm9712_init(void)
+{
+ return 0;
+}
+
+void wm9712_cleanup(void)
+{
+}
+
+module_init(wm9712_init);
+module_exit(wm9712_cleanup);
+
diff --git a/drivers/char/jzchar/wm9712.h b/drivers/char/jzchar/wm9712.h
new file mode 100644
index 00000000000..7cd9e5cadad
--- /dev/null
+++ b/drivers/char/jzchar/wm9712.h
@@ -0,0 +1,58 @@
+#ifndef __WM9712_H__
+#define __WM9712_H__
+
+#define DIGI_REG1 0x76
+#define DIGI_REG2 0x78
+#define DIGI_READBACK 0x7A
+
+#define ADCSEL_BIT 12
+#define ADCSEL_MASK (7 << ADCSEL_BIT)
+#define ADCSEL_NONE (0 << ADCSEL_BIT)
+#define ADCSEL_XPOS (1 << ADCSEL_BIT)
+#define ADCSEL_YPOS (2 << ADCSEL_BIT)
+#define ADCSEL_PRESSURE (3 << ADCSEL_BIT)
+#define ADCSEL_COMP1 (4 << ADCSEL_BIT)
+#define ADCSEL_COMP2 (5 << ADCSEL_BIT)
+#define ADCSEL_BMON (6 << ADCSEL_BIT)
+#define ADCSEL_WIPER (7 << ADCSEL_BIT)
+
+#define DIGI_REG1_CTC (1 << 10)
+#define DIGI_REG1_POLL (1 << 15)
+#define DIGI_REG1_CR_BIT 8
+#define DIGI_REG1_CR_MASK (3 << DIGI_REG1_CR_BIT)
+#define DIGI_REG1_COO (1 << 11)
+#define DIGI_REG1_SLEN (1 << 3)
+#define DIGI_REG1_SLT_BIT 0
+#define DIGI_REG1_SLT_MASK (7 << DIGI_REG1_SLT_BIT)
+#define DIGI_REG1_SLT_5 (0 << DIGI_REG1_SLT_BIT)
+#define DIGI_REG1_SLT_6 (1 << DIGI_REG1_SLT_BIT)
+#define DIGI_REG1_SLT_7 (2 << DIGI_REG1_SLT_BIT)
+#define DIGI_REG1_SLT_8 (3 << DIGI_REG1_SLT_BIT)
+#define DIGI_REG1_SLT_9 (4 << DIGI_REG1_SLT_BIT)
+#define DIGI_REG1_SLT_10 (5 << DIGI_REG1_SLT_BIT)
+#define DIGI_REG1_SLT_11 (6 << DIGI_REG1_SLT_BIT)
+#define DIGI_REG1_SLT_RES (7 << DIGI_REG1_SLT_BIT)
+#define DIGI_REG1_DEL_BIT 4
+#define DIGI_REG1_DEL_MASK (0x0f << DIGI_REG1_DEL_BIT)
+
+#define DIGI_REG2_WIRE_5 (1 << 12)
+#define DIGI_REG2_WIRE_4 (0 << 12)
+#define DIGI_REG2_RPU_BIT 0
+#define DIGI_REG2_RPU_MASK (0x3f << DIGI_REG2_RPU_BIT)
+#define DIGI_REG2_PIL_400uA (1 << 8)
+#define DIGI_REG2_PIL_200uA (0 << 8)
+#define DIGI_REG2_PRP_BIT 14
+#define DIGI_REG2_PRP_MASK (3 << DIGI_REG2_PRP_BIT)
+#define DIGI_REG2_PRP_ALLOFF (0 << DIGI_REG2_PRP_BIT)
+#define DIGI_REG2_PRP_WOP (1 << DIGI_REG2_PRP_BIT)
+#define DIGI_REG2_PRP_NWOP (2 << DIGI_REG2_PRP_BIT)
+#define DIGI_REG2_PRP_ALLON (3 << DIGI_REG2_PRP_BIT)
+#define DIGI_REG2_RPR_WOR (0 << 13)
+#define DIGI_REG2_RPR_NWOR (1 << 13)
+#define DIGI_REG2_PDEN (1 << 11)
+#define DIGI_REG2_WAIT (1 << 9)
+
+#define DIGI_READBACK_PNDN (1 << 15)
+
+#endif /* __WM9712_H__ */
+
diff --git a/drivers/char/rtc_jz.c b/drivers/char/rtc_jz.c
new file mode 100644
index 00000000000..afa17ddd089
--- /dev/null
+++ b/drivers/char/rtc_jz.c
@@ -0,0 +1,504 @@
+/*
+ * Jz OnChip Real Time Clock interface for Linux
+ *
+ * NOTE: we need to wait rtc write ready before read or write RTC registers.
+ *
+ */
+
+#include <linux/autoconf.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#include <linux/rtc.h> /* get the user-level API */
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+#include "rtc_jz.h"
+
+
+char sbin_rtc_alarm_handler_path[] = "/sbin/rtcalarm";
+//call_usermodehelper(char *path, char **argv, char **envp, int wait)
+//extern int call_usermodehelper(char *path, char **argv, char **envp);
+
+extern spinlock_t rtc_lock;
+
+static int rtc_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+
+
+static void get_rtc_time (struct rtc_time *rtc_tm);
+static int set_rtc_time (struct rtc_time *rtc_tm);
+static void get_rtc_alm_time (struct rtc_time *alm_tm);
+static int set_rtc_alm_time (struct rtc_time *alm_tm);
+
+static void set_rtc_irq_bit(int bit);
+static void mask_rtc_irq_bit(int bit);
+
+static unsigned int rtc_status = 0;
+static unsigned int epoch = 1900;
+
+static void get_rtc_time(struct rtc_time *rtc_tm)
+{
+ unsigned long lval;
+ struct rtc_time ltm;
+
+ spin_lock_irq(&rtc_lock);
+ while ( !__rtc_write_ready() ) ;
+ lval = REG_RTC_RSR;
+ rtc_time_to_tm(lval, &ltm);
+ if(rtc_valid_tm(&ltm) == 0) {
+ /* is valid */
+ rtc_tm->tm_sec = ltm.tm_sec;
+ rtc_tm->tm_min = ltm.tm_min;
+ rtc_tm->tm_hour = ltm.tm_hour;
+ rtc_tm->tm_mday = ltm.tm_mday;
+ rtc_tm->tm_wday = ltm.tm_wday;
+ rtc_tm->tm_mon = ltm.tm_mon;
+ rtc_tm->tm_year = ltm.tm_year;
+ } else {
+ printk("invlaid data / time!\n");
+ }
+ spin_unlock_irq(&rtc_lock);
+}
+
+static int set_rtc_time(struct rtc_time *rtc_tm)
+{
+ unsigned long lval;
+
+ rtc_tm_to_time(rtc_tm, &lval);
+
+ spin_lock_irq(&rtc_lock);
+ while ( !__rtc_write_ready() ) ;
+ REG_RTC_RSR = lval;
+
+ spin_unlock_irq(&rtc_lock);
+
+ return 0;
+
+}
+
+static void get_rtc_alm_time(struct rtc_time *alm_tm)
+{
+ unsigned long lval;
+ struct rtc_time altm;
+
+ spin_lock_irq(&rtc_lock);
+ while ( !__rtc_write_ready() ) ;
+ lval = REG_RTC_RSAR;
+ rtc_time_to_tm(lval, &altm);
+ if(rtc_valid_tm(&altm) == 0) {
+ /* is valid */
+ alm_tm->tm_sec = altm.tm_sec;
+ alm_tm->tm_min = altm.tm_min;
+ alm_tm->tm_hour = altm.tm_hour;
+ alm_tm->tm_mday = altm.tm_mday;
+ alm_tm->tm_wday = altm.tm_wday;
+ alm_tm->tm_mon = altm.tm_mon;
+ alm_tm->tm_year = altm.tm_year;
+ } else {
+ printk("invlaid data / time in Line:%d!\n",__LINE__);
+ }
+ spin_unlock_irq(&rtc_lock);
+}
+
+static int set_rtc_alm_time(struct rtc_time *alm_tm)
+{
+ unsigned long lval;
+
+ rtc_tm_to_time(alm_tm, &lval);
+
+ spin_lock_irq(&rtc_lock);
+ while ( !__rtc_write_ready() ) ;
+ REG_RTC_RSAR = lval;
+
+ while ( !__rtc_write_ready() ) ; /* set alarm function */
+ if ( !((REG_RTC_RCR>>2) & 0x1) ) {
+ while ( !__rtc_write_ready() ) ;
+ __rtc_enable_alarm();
+ }
+
+ while ( !__rtc_write_ready() ) ;
+ if ( !(REG_RTC_RCR & RTC_RCR_AIE) ) { /* Enable alarm irq */
+ __rtc_enable_alarm_irq();
+ }
+
+ spin_unlock_irq(&rtc_lock);
+
+ return 0;
+}
+
+static void get_rtc_wakeup_alarm(struct rtc_wkalrm *wkalm)
+{
+ int enabled, pending;
+
+ get_rtc_alm_time(&wkalm->time);
+
+ spin_lock_irq(&rtc_lock);
+ while ( !__rtc_write_ready() ) ;
+ enabled = (REG_RTC_HWCR & 0x1);
+ pending = 0;
+ if ( enabled ) {
+ if ( (u32)REG_RTC_RSAR > (u32)REG_RTC_RSR ) /* 32bit val */
+ pending = 1;
+ }
+
+ wkalm->enabled = enabled;
+ wkalm->pending = pending;
+ spin_unlock_irq(&rtc_lock);
+}
+
+static int set_rtc_wakeup_alarm(struct rtc_wkalrm *wkalm)
+{
+ int enabled;
+ //int pending;
+
+ enabled = wkalm->enabled;
+ //pending = wkalm->pending; /* Fix me, what's pending mean??? */
+
+ while ( !__rtc_write_ready() ) ; /* set wakeup alarm enable */
+ if ( enabled != (REG_RTC_HWCR & 0x1) ) {
+ while ( !__rtc_write_ready() ) ;
+ REG_RTC_HWCR = (REG_RTC_HWCR & ~0x1) | enabled;
+ }
+ while ( !__rtc_write_ready() ) ; /* set alarm function */
+ if ( enabled != ((REG_RTC_RCR>>2) & 0x1) ) {
+ while ( !__rtc_write_ready() ) ;
+ REG_RTC_RCR = (REG_RTC_RCR & ~(1<<2)) | (enabled<<2);
+ }
+
+ if ( !enabled ) /* if disabled wkalrm, rturn. */
+ {
+ return 0;
+ }
+
+ while ( !__rtc_write_ready() ) ;
+ if ( !(REG_RTC_RCR & RTC_RCR_AIE) ) { /* Enable alarm irq */
+ __rtc_enable_alarm_irq();
+ }
+
+ set_rtc_alm_time(&wkalm->time);
+
+ return 0;
+}
+
+
+static void set_rtc_irq_bit( int bit )
+{
+ spin_lock_irq(&rtc_lock);
+
+ while ( !__rtc_write_ready() ) ;
+ REG_RTC_RCR |= (1<<bit);
+
+ spin_unlock_irq(&rtc_lock);
+}
+
+static void mask_rtc_irq_bit( int bit )
+{
+ spin_lock_irq(&rtc_lock);
+
+ while ( !__rtc_write_ready() ) ;
+ REG_RTC_RCR &= ~(1<<bit);
+
+
+ spin_unlock_irq(&rtc_lock);
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct rtc_time wtime;
+
+ switch (cmd) {
+ case RTC_AIE_OFF: /* Mask alarm int. enab. bit */
+ {
+ mask_rtc_irq_bit(RTC_AIE);
+ return 0;
+ }
+ case RTC_AIE_ON: /* Allow alarm interrupts. */
+ {
+ __rtc_clear_alarm_flag();
+ set_rtc_irq_bit(RTC_AIE);
+ return 0;
+ }
+ case RTC_1HZIE_OFF: /* Mask 1Hz int. enab. bit */
+ {
+ mask_rtc_irq_bit(RTC_1HZIE);
+ return 0;
+ }
+ case RTC_1HZIE_ON: /* Allow 1Hz interrupts. */
+ {
+ __rtc_clear_1Hz_flag();
+ set_rtc_irq_bit(RTC_1HZIE);
+ return 0;
+ }
+ case RTC_ALM_OFF: /* Disable rtc function, this may not be used any time.*/
+ {
+ mask_rtc_irq_bit(RTC_ALM_EN);
+ return 0;
+ }
+ case RTC_ALM_ON: /* Enable rtc function, this may not be used any time.*/
+ {
+ set_rtc_irq_bit(RTC_ALM_EN);
+ return 0;
+ }
+ case RTC_DISABLED: /* Disable rtc function, this may not be used any time.*/
+ {
+ mask_rtc_irq_bit(RTC_EN);
+ return 0;
+ }
+ case RTC_ENABLED: /* Enable rtc function, this may not be used any time.*/
+ {
+ set_rtc_irq_bit(RTC_EN);
+ return 0;
+ }
+
+ case RTC_ALM_READ: /* Read the present alarm time */
+ /*
+ * This returns a struct rtc_time. Reading >= 0xc0
+ * means "don't care" or "match all". Only the tm_hour,
+ * tm_min, and tm_sec values are filled in.
+ */
+
+ get_rtc_alm_time(&wtime);
+ return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
+
+ case RTC_ALM_SET: /* Store a time into the alarm */
+ {
+ struct rtc_time alm_tm;
+
+ if (copy_from_user(&alm_tm, (struct rtc_time*)arg,
+ sizeof(struct rtc_time)))
+ return -EFAULT;
+ if(rtc_valid_tm(&alm_tm) != 0) {
+ printk("invalid time set in Line:%d! \n",__LINE__);
+ return -EFAULT;
+ }
+
+ return set_rtc_alm_time(&alm_tm);
+ }
+ case RTC_RD_TIME: /* Read the time/date from RTC */
+ get_rtc_time(&wtime);
+ return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
+ case RTC_SET_TIME: /* Set the RTC */
+ {
+ struct rtc_time rtc_tm;
+
+ if (!capable(CAP_SYS_TIME))
+ return -EACCES;
+
+ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+ sizeof(struct rtc_time)))
+ return -EFAULT;
+ if(rtc_valid_tm(&rtc_tm) != 0) {
+ printk("invalid time set in Line:%d! \n",__LINE__);
+ return -EFAULT;
+ }
+
+ return set_rtc_time(&rtc_tm);
+ }
+ case RTC_EPOCH_READ: /* Read the epoch. */
+ return put_user (epoch, (unsigned long *)arg);
+ case RTC_EPOCH_SET: /* Set the epoch. */
+ /*
+ * There were no RTC clocks before 1900.
+ */
+ if (arg < 1900)
+ return -EINVAL;
+
+ if (!capable(CAP_SYS_TIME))
+ return -EACCES;
+
+ epoch = arg;
+ return 0;
+ case RTC_WKALM_SET: /* Wake alarm set. */
+ {
+ struct rtc_wkalrm wkalrm;
+
+ if (copy_from_user(&wkalrm, (struct rtc_wkalrm*)arg,
+ sizeof(struct rtc_wkalrm)))
+ return -EFAULT;
+ return set_rtc_wakeup_alarm(&wkalrm);
+ }
+ case RTC_WKALM_RD: /* Wake alarm read. */
+ {
+ struct rtc_wkalrm wkalrm;
+ get_rtc_wakeup_alarm(&wkalrm);
+ return copy_to_user((void *)arg, &wkalrm, sizeof(struct rtc_wkalrm)) ? -EFAULT : 0;
+ }
+ /* set power down: shut down the machine. */
+ case RTC_POWER_DOWN: /* enter HIBERNATE mode */
+ dprintk("Power down. Bye....\n");
+ while ( !__rtc_write_ready() ) ;
+ REG_RTC_HCR = 0x1;
+ return 0;
+#ifdef DEBUG
+ case RTC_PRINT_REG: /* Print RTC registers */
+ print_rtc_registers();
+ return 0;
+#endif
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * We enforce only one user at a time here with the open/close.
+ * Also clear the previous interrupt data on an open, and clean
+ * up things on a close.
+ */
+
+/* We use rtc_lock to protect against concurrent opens. So the BKL is not
+ * needed here. Or anywhere else in this driver. */
+static int rtc_open(struct inode *inode, struct file *file)
+{
+ spin_lock_irq (&rtc_lock);
+
+ if(rtc_status)
+ goto out_busy;
+
+ rtc_status = 1;
+
+ spin_unlock_irq (&rtc_lock);
+ return 0;
+
+out_busy:
+ spin_unlock_irq (&rtc_lock);
+ return -EBUSY;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+
+ rtc_status = 0;
+ /* No need for locking -- nobody else can do anything until this rmw is
+ * committed, and no timer is running. */
+ return 0;
+}
+
+/*
+ * The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+ owner: THIS_MODULE,
+ llseek: no_llseek,
+ ioctl: rtc_ioctl,
+ open: rtc_open,
+ release: rtc_release,
+};
+
+
+static void run_sbin_rtc_alarm( void )
+{
+ int i;
+ char *argv[2], *envp[3];
+
+ if (!sbin_rtc_alarm_handler_path[0])
+ return;
+
+ print_dbg(": sbin_rtc_alarm_handler_path=%s\n", sbin_rtc_alarm_handler_path);
+
+ i = 0;
+ argv[i++] = sbin_rtc_alarm_handler_path;
+ argv[i] = 0;
+
+ /* minimal command environment */
+ i = 0;
+ envp[i++] = "HOME=/";
+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+
+ /* other stuff we want to pass to /sbin/hotplug */
+
+ envp[i] = 0;
+
+ call_usermodehelper (argv [0], argv, envp, 0);
+}
+
+static void rtc_alarm_task_handler(struct work_struct *work)
+{
+ run_sbin_rtc_alarm();
+}
+
+static struct work_struct rtc_alarm_task;
+
+static irqreturn_t jz_rtc_interrupt(int irq, void *dev_id)
+{
+ REG_RTC_HCR = 0x0;
+ printk("%s:%s:%d\n",__FILE__,__FUNCTION__,__LINE__);
+ spin_lock_irq(&rtc_lock);
+
+ if ( __rtc_get_1Hz_flag() ) {
+ while ( !__rtc_write_ready() ) ;
+ __rtc_clear_1Hz_flag();
+ dprintk("RTC 1Hz interrupt occur.\n");
+ }
+
+ if ( __rtc_get_alarm_flag() ) { /* rtc alarm interrupt */
+ while ( !__rtc_write_ready() ) ;
+ __rtc_clear_alarm_flag();
+ dprintk("RTC alarm interrupt occur.\n");
+ //schedule_task( &rtc_alarm_task );
+ schedule_work( &rtc_alarm_task );
+ }
+ spin_unlock_irq(&rtc_lock);
+
+ return IRQ_HANDLED;
+}
+
+
+#define RTC_MINOR 135
+
+static struct miscdevice rtc_dev=
+{
+ RTC_MINOR,
+ "rtc",
+ &rtc_fops
+};
+
+int __init Jz_rtc_init(void)
+{
+
+ INIT_WORK(&rtc_alarm_task, rtc_alarm_task_handler);
+
+ /* Enabled rtc function, enable rtc alarm function */
+ while ( !__rtc_write_ready() ) ; /* need we wait for WRDY??? */
+ if ( !(REG_RTC_RCR & RTC_RCR_RTCE) || !(REG_RTC_RCR &RTC_RCR_AE) ) {
+ REG_RTC_RCR |= RTC_RCR_AE | RTC_RCR_RTCE;
+ }
+ /* clear irq flags */
+ __rtc_clear_1Hz_flag();
+ /* In a alarm reset, we expect a alarm interrupt.
+ * We can do something in the interrupt handler.
+ * So, do not clear alarm flag.
+ */
+/* __rtc_clear_alarm_flag(); */
+
+ if (request_irq(IRQ_RTC, jz_rtc_interrupt, 0, "rtc", NULL) < 0)
+ return -EBUSY;
+
+ misc_register(&rtc_dev);
+
+ printk("JzSOC onchip RTC installed !!!\n");
+ return 0;
+
+}
+
+void __exit Jz_rtc_exit (void)
+{
+ misc_deregister(&rtc_dev);
+ free_irq (IRQ_RTC, NULL);
+}
+
+module_init(Jz_rtc_init);
+module_exit(Jz_rtc_exit);
+
diff --git a/drivers/char/rtc_jz.h b/drivers/char/rtc_jz.h
new file mode 100644
index 00000000000..6c754d664f0
--- /dev/null
+++ b/drivers/char/rtc_jz.h
@@ -0,0 +1,74 @@
+#ifndef __RTC_JZ_H__
+#define __RTC_JZ_H__
+
+//#define DEBUG 1
+#undef DEBUG
+
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#define print_dbg(f, arg...) \
+ printk("%s, %s[%d]:" f , __FUNCTION__, __FILE__, __LINE__ , ##arg )
+#else
+#define dprintk(x...)
+#define print_dbg(n, arg...)
+#endif
+
+
+#ifdef DEBUG
+
+static void print_rtc_time( struct rtc_time * tm )
+{
+ printk("%02d%02d-%02d:%02d:%02d-%d\n", tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_year);
+ printk("sec:\t%d\n", tm->tm_sec);
+ printk("min:\t%d\n", tm->tm_min);
+ printk("hour:\t%d\n", tm->tm_hour);
+ printk("mday:\t%d\n", tm->tm_mday);
+ printk("mon:\t%d\n", tm->tm_mon);
+ printk("year:\t%d\n", tm->tm_year);
+ printk("wday:\t%d\n", tm->tm_wday);
+ printk("yday:\t%d\n", tm->tm_yday);
+ printk("isdst:\t%d\n", tm->tm_isdst);
+
+}
+
+static void print_rtc_registers( void )
+{
+ while ( !__rtc_write_ready() ) ;
+ printk("REG_RTC_RCR:\t 0x%8.8x\n", REG_RTC_RCR );
+ printk("REG_RTC_RSR:\t 0x%8.8x\n", REG_RTC_RSR );
+ printk("REG_RTC_RSAR:\t 0x%8.8x\n", REG_RTC_RSAR );
+ printk("REG_RTC_RGR:\t 0x%8.8x\n", REG_RTC_RGR );
+ printk("REG_RTC_HCR:\t 0x%8.8x\n", REG_RTC_HCR );
+ printk("REG_RTC_HWFCR:\t 0x%8.8x\n", REG_RTC_HWFCR );
+ printk("REG_RTC_HRCR:\t 0x%8.8x\n", REG_RTC_HRCR );
+ printk("REG_RTC_HWCR:\t 0x%8.8x\n", REG_RTC_HWCR );
+ printk("REG_RTC_HWRSR:\t 0x%8.8x\n", REG_RTC_HWRSR );
+ printk("REG_RTC_HSPR:\t 0x%8.8x\n", REG_RTC_HSPR );
+}
+
+#define RTC_PRINT_REG _IOR('p', 0x12, unsigned long)/* Set power down */
+#endif /* #ifdef DEBUG */
+
+
+/*
+ * JZSOC ioctl calls that are permitted to the /dev/rtc interface
+ */
+
+#define RTC_ENABLED _IO('p', 0x11) /* enable rtc */
+#define RTC_DISABLED _IO('p', 0x12) /* disable rtc */
+#define RTC_ALM_ON _IO('p', 0x13) /* enable rtc */
+#define RTC_ALM_OFF _IO('p', 0x14) /* disable rtc */
+#define RTC_1HZIE_ON _IO('p', 0x15) /* 1Hz int. enable on */
+#define RTC_1HZIE_OFF _IO('p', 0x16) /* ... off */
+
+#define RTC_POWER_DOWN _IOR('p', 0x11, unsigned long)/* Set power down */
+
+/* Registers define */
+/* RTC Control register */
+#define RTC_AIE 3 /* jz4740_06_rtc_spec.pdf, RTC Control Register */
+#define RTC_1HZIE 5 /* ... */
+#define RTC_ALM_EN 2 /* ... */
+#define RTC_EN 0 /* ... */
+
+#endif /* #define __RTC_JZ_H__ */
diff --git a/drivers/char/rtc_pcf8563.c b/drivers/char/rtc_pcf8563.c
new file mode 100644
index 00000000000..08dc30bae03
--- /dev/null
+++ b/drivers/char/rtc_pcf8563.c
@@ -0,0 +1,448 @@
+/*
+ * PCF8563 Real Time Clock interface for Linux
+ *
+ * It only support 24Hour Mode, And the stored values are in BCD format.
+ * The alarm register is start at minute reg, no second alarm register.
+ */
+
+//#include <linux/config.h>
+#include <linux/autoconf.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+
+#include <linux/rtc.h> /* get the user-level API */
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+/**********************************************************************
+ * register summary
+ **********************************************************************/
+#define RTC_SECONDS 2
+#define RTC_MINUTES 3
+#define RTC_HOURS 4
+#define RTC_DAY_OF_MONTH 5
+#define RTC_DAY_OF_WEEK 6
+#define RTC_MONTH 7
+#define RTC_YEAR 8
+
+#define RTC_MINUTES_ALARM 9
+#define RTC_HOURS_ALARM 0x0a
+#define RTC_DAY_ALARM 0x0b
+#define RTC_WEEKDAY_ALARM 0x0c
+
+/* control registers - Moto names
+ */
+#define RTC_CONTROL 0x00
+#define RTC_STATUS 0x01
+#define RTC_CLKOUT 0x0d
+#define RTC_TIMERCTL 0x0e
+#define RTC_TIMERCOUNTDOWN 0x0f
+
+
+/* example: !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
+ * determines if the following two #defines are needed
+ */
+#ifndef BCD2BIN
+#define BCD2BIN(val) (((val) & 0x0f) + ((val) >> 4) * 10)
+#endif
+
+#ifndef BIN2BCD
+#define BIN2BCD(val) ((((val) / 10) << 4) + (val) % 10)
+#endif
+
+extern spinlock_t rtc_lock;
+extern void i2c_open(void);
+extern void i2c_close(void);
+extern int i2c_read(unsigned char device, unsigned char *buf,
+ unsigned char address, int count);
+extern int i2c_write(unsigned char device, unsigned char *buf,
+ unsigned char address, int count);
+/*
+ * We sponge a minor off of the misc major. No need slurping
+ * up another valuable major dev number for this. If you add
+ * an ioctl, make sure you don't conflict with SPARC's RTC
+ * ioctls.
+ */
+
+static int rtc_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+
+
+static void get_rtc_time (struct rtc_time *rtc_tm);
+static void get_rtc_alm_time (struct rtc_time *alm_tm);
+
+/*
+ * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is
+ * protected by the big kernel lock. However, ioctl can still disable the timer
+ * in rtc_status and then with del_timer after the interrupt has read
+ * rtc_status but before mod_timer is called, which would then reenable the
+ * timer (but you would need to have an awful timing before you'd trip on it)
+ */
+static unsigned long rtc_status = 0; /* bitmapped status byte. */
+
+/*
+ * If this driver ever becomes modularised, it will be really nice
+ * to make the epoch retain its value across module reload...
+ */
+static unsigned int epoch = 1900;
+static const unsigned char days_in_mo[] =
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static unsigned char rtcframe[16];
+
+static void read_rtcframe(void)
+{
+ i2c_open();
+ i2c_read(0x51, rtcframe, 0, 16);
+ i2c_close();
+}
+
+static void write_rtcframe(void)
+{
+ i2c_open();
+ i2c_write(0x51, rtcframe, 0, 16);
+ i2c_close();
+}
+
+static void write_rtc(unsigned char addr, unsigned char val)
+{
+ volatile unsigned char v = val;
+ i2c_open();
+ i2c_write(0x51, (unsigned char *)&v, addr, 1);
+ i2c_close();
+}
+
+static unsigned char read_rtc(unsigned char addr)
+{
+ volatile unsigned char v;
+ i2c_open();
+ i2c_read(0x51, (unsigned char *)&v, addr, 1);
+ i2c_close();
+ return v;
+}
+
+static void CMOS_WRITE(unsigned char addr, unsigned char val)
+{
+ rtcframe[addr] = val;
+}
+
+static unsigned char CMOS_READ(unsigned char addr)
+{
+ return rtcframe[addr];
+}
+
+static void get_rtc_time(struct rtc_time *rtc_tm)
+{
+ unsigned char sec,mon,mday,wday,year,hour,min;
+
+ /*
+ * Only the values that we read from the RTC are set. We leave
+ * tm_wday, tm_yday and tm_isdst untouched. Even though the
+ * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+ * by the RTC when initially set to a non-zero value.
+ */
+
+ spin_lock_irq(&rtc_lock);
+ read_rtcframe();
+ sec = CMOS_READ(RTC_SECONDS) & ~0x80;
+ min = CMOS_READ(RTC_MINUTES) & ~0x80;
+ hour = CMOS_READ(RTC_HOURS) & ~0xc0;
+ mday = CMOS_READ(RTC_DAY_OF_MONTH) & ~0xc0;
+ wday = CMOS_READ(RTC_DAY_OF_WEEK) & ~0xf8;
+ mon = CMOS_READ(RTC_MONTH) & ~0xe0;
+ year = CMOS_READ(RTC_YEAR) ;
+
+ rtc_tm->tm_sec = BCD2BIN(sec);
+ rtc_tm->tm_min = BCD2BIN(min);
+ rtc_tm->tm_hour = BCD2BIN(hour);
+ rtc_tm->tm_mday = BCD2BIN(mday);
+ rtc_tm->tm_wday = wday;
+ /* Don't use centry, but start from year 1970 */
+ rtc_tm->tm_mon = BCD2BIN(mon);
+ year = BCD2BIN(year);
+ if ((year += (epoch - 1900)) <= 69)
+ year += 100;
+ rtc_tm->tm_year = year;
+
+ spin_unlock_irq(&rtc_lock);
+
+
+ /*
+ * Account for differences between how the RTC uses the values
+ * and how they are defined in a struct rtc_time;
+ */
+ rtc_tm->tm_mon--;
+}
+
+static void get_rtc_alm_time(struct rtc_time *alm_tm)
+{
+ unsigned char sec, min, hour;
+
+ /*
+ * Only the values that we read from the RTC are set. That
+ * means only tm_hour, tm_min, and tm_sec.
+ */
+ spin_lock_irq(&rtc_lock);
+ read_rtcframe();
+ sec = 0;
+ min = CMOS_READ(RTC_MINUTES_ALARM);
+ hour = CMOS_READ(RTC_HOURS_ALARM);
+
+ alm_tm->tm_sec = sec;//not set sec
+ alm_tm->tm_min = BCD2BIN(min);
+ alm_tm->tm_hour = BCD2BIN(hour);
+
+ spin_unlock_irq(&rtc_lock);
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct rtc_time wtime;
+ switch (cmd) {
+ case RTC_ALM_READ: /* Read the present alarm time */
+ {
+ /*
+ * This returns a struct rtc_time. Reading >= 0xc0
+ * means "don't care" or "match all". Only the tm_hour,
+ * tm_min, and tm_sec values are filled in.
+ */
+
+ get_rtc_alm_time(&wtime);
+ break;
+ }
+ case RTC_ALM_SET: /* Store a time into the alarm */
+ {
+ unsigned char hrs, min, sec;
+ struct rtc_time alm_tm;
+
+ if (copy_from_user(&alm_tm, (struct rtc_time*)arg,
+ sizeof(struct rtc_time)))
+ return -EFAULT;
+
+ hrs = alm_tm.tm_hour;
+ min = alm_tm.tm_min;
+ sec = alm_tm.tm_sec;
+
+
+
+ if (hrs >= 24)
+ return -EINVAL;
+
+ hrs = BIN2BCD(hrs);
+
+ if (min >= 60)
+ return -EINVAL;
+
+ min = BIN2BCD(min);
+
+ if (sec >= 60)
+ return -EINVAL;
+
+ spin_lock_irq(&rtc_lock);
+ read_rtcframe();
+ CMOS_WRITE(RTC_HOURS_ALARM, hrs | 0x80);
+ CMOS_WRITE(RTC_MINUTES_ALARM, min | 0x80);
+
+ CMOS_WRITE(RTC_DAY_ALARM, CMOS_READ(RTC_DAY_ALARM) | 0x80);
+ CMOS_WRITE(RTC_WEEKDAY_ALARM, CMOS_READ(RTC_WEEKDAY_ALARM) | 0x80);
+ CMOS_WRITE(RTC_STATUS, CMOS_READ(RTC_STATUS) | 0x02);/*open alarm int*/
+ write_rtcframe();
+ spin_unlock_irq(&rtc_lock);
+ break;
+ }
+ case RTC_RD_TIME: /* Read the time/date from RTC */
+ {
+ get_rtc_time(&wtime);
+ break;
+ }
+ case RTC_SET_TIME: /* Set the RTC */
+ {
+ struct rtc_time rtc_tm;
+ unsigned char mon, day, hrs, min, sec, leap_yr, date;
+ unsigned int yrs;
+// unsigned char ctr;
+
+ if (!capable(CAP_SYS_TIME))
+ return -EACCES;
+
+ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+ sizeof(struct rtc_time)))
+ return -EFAULT;
+
+
+ yrs = rtc_tm.tm_year + 1900;
+ mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
+ day = rtc_tm.tm_wday;
+ date = rtc_tm.tm_mday;
+ hrs = rtc_tm.tm_hour;
+ min = rtc_tm.tm_min;
+ sec = rtc_tm.tm_sec;
+
+
+ if (yrs < 1970)
+ return -EINVAL;
+
+ leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+ if ((mon > 12) || (date == 0))
+ return -EINVAL;
+
+ if (date > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
+ return -EINVAL;
+
+ if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+ return -EINVAL;
+
+ if ((yrs -= epoch) > 255) /* They are unsigned */
+ return -EINVAL;
+
+ spin_lock_irq(&rtc_lock);
+ /* These limits and adjustments are independant of
+ * whether the chip is in binary mode or not.
+ */
+ if (yrs > 169) {
+ spin_unlock_irq(&rtc_lock);
+ return -EINVAL;
+ }
+
+ if (yrs >= 100)
+ yrs -= 100;
+
+ min = BIN2BCD(min);
+ sec = BIN2BCD(sec);
+ hrs = BIN2BCD(hrs);
+ mon = BIN2BCD(mon);
+ yrs = BIN2BCD(yrs);
+ date = BIN2BCD(date);
+
+ read_rtcframe();
+ CMOS_WRITE(RTC_SECONDS, sec );
+ CMOS_WRITE(RTC_MINUTES, min);
+ CMOS_WRITE(RTC_HOURS, hrs);
+ CMOS_WRITE(RTC_DAY_OF_MONTH, date);
+ CMOS_WRITE(RTC_DAY_OF_WEEK, day);
+ CMOS_WRITE(RTC_MONTH, mon);
+ CMOS_WRITE(RTC_YEAR, yrs);
+ write_rtcframe();
+
+ spin_unlock_irq(&rtc_lock);
+ return 0;
+ }
+ case RTC_EPOCH_READ: /* Read the epoch. */
+ {
+ return put_user (epoch, (unsigned long *)arg);
+ }
+ case RTC_EPOCH_SET: /* Set the epoch. */
+ {
+ /*
+ * There were no RTC clocks before 1900.
+ */
+ if (arg < 1900)
+ return -EINVAL;
+
+ if (!capable(CAP_SYS_TIME))
+ return -EACCES;
+
+ epoch = arg;
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+ return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
+}
+
+/*
+ * We enforce only one user at a time here with the open/close.
+ * Also clear the previous interrupt data on an open, and clean
+ * up things on a close.
+ */
+
+/* We use rtc_lock to protect against concurrent opens. So the BKL is not
+ * needed here. Or anywhere else in this driver. */
+static int rtc_open(struct inode *inode, struct file *file)
+{
+ spin_lock_irq (&rtc_lock);
+
+ if(rtc_status)
+ goto out_busy;
+
+ rtc_status = 1;
+
+ spin_unlock_irq (&rtc_lock);
+ return 0;
+
+out_busy:
+ spin_unlock_irq (&rtc_lock);
+ return -EBUSY;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+
+
+ /* No need for locking -- nobody else can do anything until this rmw is
+ * committed, and no timer is running. */
+ rtc_status = 0;
+ return 0;
+}
+
+/*
+ * The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+ owner: THIS_MODULE,
+ llseek: no_llseek,
+ ioctl: rtc_ioctl,
+ open: rtc_open,
+ release: rtc_release,
+};
+
+#define RTC_MINOR 135
+
+static struct miscdevice rtc_dev=
+{
+ RTC_MINOR,
+ "rtc",
+ &rtc_fops
+};
+
+int __init pcf_rtc_init(void)
+{
+ int r;
+ unsigned char ctr;
+ r = misc_register(&rtc_dev);
+
+ ctr = read_rtc(RTC_CONTROL);
+ write_rtc(RTC_CONTROL,0x00 );
+
+ read_rtcframe();
+ CMOS_WRITE(RTC_STATUS, 0x00);
+ CMOS_WRITE(RTC_CLKOUT, 0x80);
+ /* RTC clock out, 32.768k */
+
+ CMOS_WRITE(RTC_TIMERCTL, 0x00);
+ CMOS_WRITE(RTC_TIMERCOUNTDOWN, 0x00);
+ write_rtcframe();
+
+ printk("PCF8563 RTC installed !!!\n");
+ return 0;
+
+}
+
+void __exit pcf_rtc_exit (void)
+{
+ misc_deregister(&rtc_dev);
+}
+
+module_init(pcf_rtc_init);
+module_exit(pcf_rtc_exit);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 8206442fbab..8e44f4b1f83 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -3,10 +3,17 @@
#
menu "I2C Hardware Bus support"
-
comment "PC SMBus host controller drivers"
depends on PCI
+config I2C_JZ47XX
+ tristate "JZ47XX I2C Interface support"
+ depends on SOC_JZ4730 || SOC_JZ4740 || SOC_JZ4750 || SOC_JZ4760
+ help
+ If you have devices in the Ingenic JZ4730/JZ4740/JZ4750/jJZ4760 I2C bus, say yes to
+ this option. This driver can also be built as a module. If so, the
+ module will be called i2c-jz47xx.
+
config I2C_ALI1535
tristate "ALI 1535"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index e654263bfc0..10649f97366 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -3,6 +3,8 @@
#
# PC SMBus host controller drivers
+#
+obj-$(CONFIG_I2C_JZ47XX) += i2c-jz47xx.o
obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o
obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o
obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o
diff --git a/drivers/i2c/busses/i2c-jz47xx.c b/drivers/i2c/busses/i2c-jz47xx.c
new file mode 100644
index 00000000000..4c936a13300
--- /dev/null
+++ b/drivers/i2c/busses/i2c-jz47xx.c
@@ -0,0 +1,357 @@
+/*
+ * i2c_jz47xx.c for the INGENIC I2C bus access.
+ *
+ * Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc.
+ * Author: <cwjia@ingenic.cn>
+ * The first Modified :<zhzhao@ingenic.cn>
+ * Date:20091027
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <linux/module.h>
+#include <asm/addrspace.h>
+
+#include <asm/jzsoc.h>
+#include "i2c-jz47xx.h"
+
+/* I2C protocol */
+#define I2C_READ 1
+#define I2C_WRITE 0
+
+#define TIMEOUT 1000
+unsigned long sub_addr = 0;
+
+struct jz_i2c {
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ struct i2c_msg *msg;
+ unsigned int msg_num;
+ unsigned int slave_addr;
+ struct i2c_adapter adap;
+ struct clk *clk;
+};
+
+/*
+ * I2C bus protocol basic routines
+ */
+static int i2c_put_data(unsigned char data)
+{
+ unsigned int timeout = TIMEOUT*10;
+ __i2c_write(data);
+ __i2c_set_drf();
+ while (__i2c_check_drf() != 0 && timeout)
+ timeout--;
+ while (!__i2c_transmit_ended());
+
+ timeout = TIMEOUT*10;
+ while (!__i2c_received_ack() && timeout)
+ timeout--;
+ if (timeout){
+ return 0;
+ }
+ else{
+ return -ETIMEDOUT;
+ }
+}
+
+
+static int i2c_get_data(unsigned char *data, int ack)
+{
+ int timeout = TIMEOUT*10;
+ if (!ack)
+ __i2c_send_nack();
+ else
+ __i2c_send_ack();
+
+ while (__i2c_check_drf() == 0 && timeout)
+ timeout--;
+ if (timeout) {
+ if (!ack)
+ __i2c_send_stop();
+ *data = __i2c_read();
+ __i2c_clear_drf();
+ return 0;
+ } else{
+
+ return -ETIMEDOUT;
+ }
+}
+
+/*
+ * I2C interface
+ */
+void i2c_jz_setclk(unsigned int i2cclk)
+{
+ __i2c_set_clk(jz_clocks.extalclk, i2cclk);
+}
+
+
+static int xfer_read(unsigned char device, unsigned char *buf, int length)
+{
+ int cnt = length;
+ int timeout = 5;
+
+ /*eeprom device address transfer*/
+ if(EEPROM_DEVICE_NUMBER == (device & 0xf0)){
+ device = device | ((sub_addr & 0x0700) >> 8);
+ sub_addr = sub_addr & 0xff;
+ }
+
+L_try_again:
+
+ if (timeout < 0)
+ goto L_timeout;
+
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+
+ __i2c_send_start();
+
+
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_werr;
+
+ if (i2c_put_data(sub_addr) < 0)
+ goto address_err;
+
+ __i2c_send_start();
+
+ if (i2c_put_data((device << 1) | I2C_READ ) < 0)
+ goto device_rerr;
+
+
+ __i2c_send_ack(); /* Master sends ACK for continue reading */
+
+
+ while (cnt) {
+
+ if (cnt == 1) {
+
+ if (i2c_get_data(buf, 0) < 0)
+ break;
+ } else {
+
+ if (i2c_get_data(buf, 1) < 0){
+ break;
+ }
+ }
+ cnt--;
+ buf++;
+ }
+ __i2c_send_stop();
+
+ return length - cnt;
+ device_rerr:
+ device_werr:
+ address_err:
+
+ timeout --;
+ __i2c_send_stop();
+ goto L_try_again;
+
+L_timeout:
+ __i2c_send_stop();
+ printk("Read I2C device 0x%2x failed.\n", device);
+ return -ENODEV;
+}
+
+
+static int xfer_write(unsigned char device, unsigned char *buf, int length)
+{
+ int cnt = length;
+ int cnt_in_pg;
+ int timeout = 5;
+ unsigned char *tmpbuf;
+
+ /*eeprom device address transfer*/
+ if(EEPROM_DEVICE_NUMBER == (device & 0xf0)){
+ device = device | ((sub_addr & 0x0700) >> 8);
+ sub_addr = sub_addr & 0xff;
+ }
+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */
+
+ W_try_again:
+ if (timeout < 0)
+ goto W_timeout;
+
+ cnt = length;
+ tmpbuf = (unsigned char *)buf;
+
+ start_write_page:
+ cnt_in_pg = 0;
+ __i2c_send_start();
+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
+ goto device_err;
+
+ if (i2c_put_data(sub_addr) < 0)
+ goto address_err;
+
+
+
+ while (cnt) {
+ if (++cnt_in_pg > 8) {
+ __i2c_send_stop();
+ mdelay(1);
+ sub_addr += 8;
+ mdelay(2);// add 20091027
+ goto start_write_page;
+
+ }
+
+
+ if (i2c_put_data(*tmpbuf) < 0)
+ break;
+ cnt--;
+ tmpbuf++;
+ }
+ __i2c_send_stop();
+ return length - cnt;
+ device_err:
+ address_err:
+ timeout--;
+ __i2c_send_stop();
+ goto W_try_again;
+
+W_timeout:
+ printk( "Write I2C device 0x%2x failed.\n", device);
+ __i2c_send_stop();
+ return -ENODEV;
+}
+
+static int i2c_jz_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
+{
+ int ret, i;
+
+ dev_dbg(&adap->dev, "jz47xx_xfer: processing %d messages:\n", num);
+ for (i = 0; i < num; i++) {
+ dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
+ pmsg->flags & I2C_M_RD ? "read" : "writ",
+ pmsg->len, pmsg->len > 1 ? "s" : "",
+ pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
+ if (pmsg->len && pmsg->buf) { /* sanity check */
+ if (pmsg->flags & I2C_M_RD){
+
+ ret = xfer_read(pmsg->addr, pmsg->buf, pmsg->len);
+ }else{
+
+ ret = xfer_write(pmsg->addr, pmsg->buf, pmsg->len);
+ }
+ if (ret)
+ return ret;
+ /* Wait until transfer is finished */
+ }
+ dev_dbg(&adap->dev, "transfer complete\n");
+ pmsg++; /* next message */
+ }
+ return i;
+}
+
+static u32 i2c_jz_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm i2c_jz_algorithm = {
+ .master_xfer = i2c_jz_xfer,
+ .functionality = i2c_jz_functionality,
+};
+
+static int i2c_jz_probe(struct platform_device *dev)
+{
+
+ struct jz_i2c *i2c;
+ struct i2c_jz_platform_data *plat = dev->dev.platform_data;
+ int ret;
+ __gpio_as_i2c(); // open i2c 20091027
+ __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */
+ __i2c_enable();
+
+ i2c = kzalloc(sizeof(struct jz_i2c), GFP_KERNEL);
+ if (!i2c) {
+ printk("There is no enough memory\n");
+ ret = -ENOMEM;
+ goto emalloc;
+ }
+
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &i2c_jz_algorithm;
+ i2c->adap.retries = 5;
+ spin_lock_init(&i2c->lock);
+ init_waitqueue_head(&i2c->wait);
+ sprintf(i2c->adap.name, "jz_i2c-i2c.%u", dev->id);
+ i2c->adap.algo_data = i2c;
+ i2c->adap.dev.parent = &dev->dev;
+
+ if (plat) {
+ i2c->adap.class = plat->class;
+ }
+
+ /*
+ * If "dev->id" is negative we consider it as zero.
+ * The reason to do so is to avoid sysfs names that only make
+ * sense when there are multiple adapters.
+ */
+ i2c->adap.nr = dev->id != -1 ? dev->id : 0;
+ /* ret = i2c_add_adapter(&i2c->adap); */
+ ret = i2c_add_numbered_adapter(&i2c->adap);
+ if (ret < 0) {
+ printk(KERN_INFO "I2C: Failed to add bus\n");
+ goto eadapt;
+ }
+
+ platform_set_drvdata(dev, i2c);
+ dev_info(&dev->dev, "JZ47xx i2c bus driver.\n");
+ return 0;
+eadapt:
+ __i2c_disable();
+emalloc:
+ return ret;
+}
+
+static int i2c_jz_remove(struct platform_device *dev)
+{
+ struct i2c_adapter *adapter = platform_get_drvdata(dev);
+ int rc;
+
+ rc = i2c_del_adapter(adapter);
+ platform_set_drvdata(dev, NULL);
+ return rc;
+}
+
+static struct platform_driver i2c_jz_driver = {
+ .probe = i2c_jz_probe,
+ .remove = i2c_jz_remove,
+ .driver = {
+ .name = "jz_i2c",
+ },
+};
+
+static int __init i2c_adap_jz_init(void)
+{
+ return platform_driver_register(&i2c_jz_driver);
+}
+
+static void __exit i2c_adap_jz_exit(void)
+{
+ return platform_driver_unregister(&i2c_jz_driver);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(i2c_adap_jz_init);
+module_exit(i2c_adap_jz_exit);
diff --git a/drivers/i2c/busses/i2c-jz47xx.h b/drivers/i2c/busses/i2c-jz47xx.h
new file mode 100644
index 00000000000..eb8611067f9
--- /dev/null
+++ b/drivers/i2c/busses/i2c-jz47xx.h
@@ -0,0 +1,20 @@
+/*
+ * i2c_jz47xx.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _I2C_JZ_H_
+#define _I2C_JZ_H_
+
+struct i2c_slave_client;
+
+struct i2c_jz_platform_data {
+ unsigned int slave_addr;
+ struct i2c_slave_client *slave;
+ unsigned int class;
+};
+
+extern void jz_set_i2c_info(struct i2c_jz_platform_data *info);
+#endif
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 7e13d2df9af..b62d134eaa0 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -37,6 +37,10 @@
#include <linux/smp_lock.h>
#include <linux/jiffies.h>
#include <asm/uaccess.h>
+#include "busses/i2c-jz47xx.h"
+
+
+extern unsigned long sub_addr;
static struct i2c_driver i2cdev_driver;
@@ -62,8 +66,8 @@ static DEFINE_SPINLOCK(i2c_dev_list_lock);
static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
{
struct i2c_dev *i2c_dev;
-
spin_lock(&i2c_dev_list_lock);
+
list_for_each_entry(i2c_dev, &i2c_dev_list, list) {
if (i2c_dev->adap->nr == index)
goto found;
@@ -138,7 +142,6 @@ static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,
{
char *tmp;
int ret;
-
struct i2c_client *client = (struct i2c_client *)file->private_data;
if (count > 8192)
@@ -169,8 +172,10 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c
count = 8192;
tmp = kmalloc(count,GFP_KERNEL);
+
if (tmp==NULL)
return -ENOMEM;
+
if (copy_from_user(tmp,buf,count)) {
kfree(tmp);
return -EFAULT;
@@ -422,12 +427,23 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case I2C_RETRIES:
client->adapter->retries = arg;
break;
+
case I2C_TIMEOUT:
/* For historical reasons, user-space sets the timeout
* value in units of 10 ms.
*/
client->adapter->timeout = msecs_to_jiffies(arg * 10);
break;
+
+ case I2C_SET_SUB_ADDRESS:
+ sub_addr = *(unsigned long *)arg;
+ break;
+
+ case I2C_SET_CLOCK:
+ arg = *(unsigned long *)arg;
+ i2c_jz_setclk(arg);
+ break;
+
default:
/* NOTE: returning a fault code here could cause trouble
* in buggy userspace code. Some old kernel bugs returned
@@ -474,6 +490,7 @@ static int i2cdev_open(struct inode *inode, struct file *file)
goto out;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
+
client->driver = &i2cdev_driver;
client->adapter = adap;
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index a6b989a9dc0..1c3e88389de 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -145,21 +145,6 @@ config KEYBOARD_EP93XX
To compile this driver as a module, choose M here: the
module will be called ep93xx_keypad.
-config KEYBOARD_GPIO
- tristate "GPIO Buttons"
- depends on GENERIC_GPIO
- help
- This driver implements support for buttons connected
- to GPIO pins of various CPUs (and some other chips).
-
- Say Y here if your device has buttons connected
- directly to such GPIO pins. Your board-specific
- setup logic must also provide a platform device,
- with configuration data saying which GPIOs are used.
-
- To compile this driver as a module, choose M here: the
- module will be called gpio_keys.
-
config KEYBOARD_MATRIX
tristate "GPIO driven matrix keypad support"
depends on GENERIC_GPIO
@@ -240,6 +225,39 @@ config KEYBOARD_LOCOMO
To compile this driver as a module, choose M here: the
module will be called locomokbd.
+config KEYBOARD_JZ
+ tristate "JZ keypad support"
+ depends on JZSOC
+ help
+ Enable Y here to support JZ keypad.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jz-keypad.
+
+config 5x5_KEYBOARD_JZ
+ tristate "JZ 5x5 keypad support"
+ depends on JZSOC
+ help
+ Enable Y here to support JZ keypad.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jz-keypad.
+
+config KEYBOARD_GPIO
+ tristate "JZ GPIO Buttons support"
+# depends on GENERIC_GPIO
+ help
+ This driver implements support for buttons connected
+ to GPIO pins of various CPUs (and some other chips).
+
+ Say Y here if your device has buttons connected
+ directly to such GPIO pins. Your board-specific
+ setup logic must also provide a platform device,
+ with configuration data saying which GPIOs are used.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gpio_keys.
+
config KEYBOARD_MAPLE
tristate "Maple bus keyboard"
depends on SH_DREAMCAST && MAPLE
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index b5b5eae9724..75c6ab1c660 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -25,6 +25,8 @@ obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
+obj-$(CONFIG_KEYBOARD_JZ) += jz_keypad.o
+obj-$(CONFIG_5x5_KEYBOARD_JZ) += jz_keypad_5x5.o
obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index efed0c9e242..3a123df1dba 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -1,7 +1,13 @@
/*
- * Driver for keys on GPIO lines capable of generating interrupts.
+ * linux/drivers/input/keyboard/gpio_keys.c
*
- * Copyright 2005 Phil Blundell
+ * JZ GPIO Buttons driver for JZ4740 PAVO
+ *
+ * User applications can access to this device via /dev/input/eventX.
+ *
+ * Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: Richard <cjfeng@ingenic.cn>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -9,6 +15,7 @@
*/
#include <linux/module.h>
+#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
@@ -22,54 +29,133 @@
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
-#include <linux/workqueue.h>
-
#include <asm/gpio.h>
+#include <asm/jzsoc.h>
-struct gpio_button_data {
- struct gpio_keys_button *button;
- struct input_dev *input;
- struct timer_list timer;
- struct work_struct work;
+
+#define SCAN_INTERVAL (10)
+
+/*
+ * GPIO Buttons
+ */
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+static struct gpio_keys_button pavo_buttons[] = {
+ {
+ .gpio = 96,
+ .code = KEY_1,
+ .desc = "Button 0",
+ .active_low = 1,
+ },
+ {
+ .gpio = 97,
+ .code = KEY_2,
+ .desc = "Button 1",
+ .active_low = 1,
+ },
+ {
+ .gpio = 98,
+ .code = KEY_3,
+ .desc = "Button 2",
+ .active_low = 1,
+ },
+ {
+ .gpio = 99,
+ .code = KEY_4,
+ .desc = "Button 3",
+ .active_low = 1,
+ }
};
-struct gpio_keys_drvdata {
- struct input_dev *input;
- struct gpio_button_data data[0];
+static struct timer_list button_timer;
+static spinlock_t gpio_lock;
+static int button_no;
+
+static struct gpio_keys_platform_data pavo_button_data = {
+ .buttons = pavo_buttons,
+ .nbuttons = ARRAY_SIZE(pavo_buttons),
};
-static void gpio_keys_report_event(struct work_struct *work)
+static struct platform_device pavo_button_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &pavo_button_data,
+ }
+};
+
+static void __init pavo_add_device_buttons(void)
{
- struct gpio_button_data *bdata =
- container_of(work, struct gpio_button_data, work);
- struct gpio_keys_button *button = bdata->button;
- struct input_dev *input = bdata->input;
- unsigned int type = button->type ?: EV_KEY;
- int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
-
- input_event(input, type, button->code, !!state);
- input_sync(input);
+ __gpio_as_input(96);
+ __gpio_as_irq_fall_edge(96);
+
+ __gpio_as_input(97);
+ __gpio_as_irq_fall_edge(97);
+
+ __gpio_as_input(98);
+ __gpio_as_irq_fall_edge(98);
+
+ __gpio_as_input(99);
+ __gpio_as_irq_fall_edge(99);
+
+ platform_device_register(&pavo_button_device);
}
+#else
+static void __init pavo_add_device_buttons(void) {}
+#endif
-static void gpio_keys_timer(unsigned long _data)
+static void __init pavo_board_init(void)
{
- struct gpio_button_data *data = (struct gpio_button_data *)_data;
+ /* Push Buttons */
+ pavo_add_device_buttons();
+}
- schedule_work(&data->work);
+static void button_timer_callback(unsigned long data)
+{
+ unsigned long flags;
+ int gpio = pavo_buttons[button_no].gpio;
+ int code = pavo_buttons[button_no].code;
+ struct platform_device *pdev = (struct platform_device *)data;
+ struct input_dev *input = platform_get_drvdata(pdev);
+ int state;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ state = __gpio_get_pin(gpio);
+
+ if (state == 0) {
+ /* press down */
+ input_report_key(input, code, 1);
+ input_sync(input);
+ mod_timer(&button_timer, jiffies + SCAN_INTERVAL);
+ } else {
+ /* up */
+ input_report_key(input, code, 0);
+ input_sync(input);
+ udelay(1000);
+ __gpio_as_irq_fall_edge(gpio);
+ }
+ spin_unlock_irqrestore(&gpio_lock, flags);
}
static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
{
- struct gpio_button_data *bdata = dev_id;
- struct gpio_keys_button *button = bdata->button;
-
- BUG_ON(irq != gpio_to_irq(button->gpio));
+ int i;
+ struct platform_device *pdev = dev_id;
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
- if (button->debounce_interval)
- mod_timer(&bdata->timer,
- jiffies + msecs_to_jiffies(button->debounce_interval));
- else
- schedule_work(&bdata->work);
+ __gpio_ack_irq(irq - IRQ_GPIO_0);
+ for (i = 0; i < pdata->nbuttons; i++) {
+ struct gpio_keys_button *button = &pdata->buttons[i];
+ int gpio = button->gpio;
+
+ if (irq == (gpio + IRQ_GPIO_0) ) {
+ /* start timer */
+ __gpio_as_input(gpio);
+ button_no = i;
+ mod_timer(&button_timer, jiffies + 2 * SCAN_INTERVAL);
+ break;
+ }
+ }
return IRQ_HANDLED;
}
@@ -77,21 +163,17 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
static int __devinit gpio_keys_probe(struct platform_device *pdev)
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
- struct gpio_keys_drvdata *ddata;
struct input_dev *input;
int i, error;
int wakeup = 0;
- ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
- pdata->nbuttons * sizeof(struct gpio_button_data),
- GFP_KERNEL);
input = input_allocate_device();
- if (!ddata || !input) {
- error = -ENOMEM;
- goto fail1;
- }
+ if (!input)
+ return -ENOMEM;
- platform_set_drvdata(pdev, ddata);
+ platform_set_drvdata(pdev, input);
+
+ spin_lock_init(&gpio_lock);
input->name = pdev->name;
input->phys = "gpio-keys/input0";
@@ -101,92 +183,60 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
-
- /* Enable auto repeat feature of Linux input subsystem */
- if (pdata->rep)
- __set_bit(EV_REP, input->evbit);
-
- ddata->input = input;
+ input->evbit[0] = BIT(EV_KEY) | BIT(EV_SYN) | BIT(EV_REP);
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
- struct gpio_button_data *bdata = &ddata->data[i];
int irq;
unsigned int type = button->type ?: EV_KEY;
- bdata->input = input;
- bdata->button = button;
- setup_timer(&bdata->timer,
- gpio_keys_timer, (unsigned long)bdata);
- INIT_WORK(&bdata->work, gpio_keys_report_event);
-
- error = gpio_request(button->gpio, button->desc ?: "gpio_keys");
- if (error < 0) {
- pr_err("gpio-keys: failed to request GPIO %d,"
- " error %d\n", button->gpio, error);
- goto fail2;
- }
-
- error = gpio_direction_input(button->gpio);
- if (error < 0) {
- pr_err("gpio-keys: failed to configure input"
- " direction for GPIO %d, error %d\n",
- button->gpio, error);
- gpio_free(button->gpio);
- goto fail2;
- }
-
- irq = gpio_to_irq(button->gpio);
+ irq = IRQ_GPIO_0 + button->gpio;
if (irq < 0) {
error = irq;
pr_err("gpio-keys: Unable to get irq number"
" for GPIO %d, error %d\n",
button->gpio, error);
- gpio_free(button->gpio);
- goto fail2;
+ goto fail;
}
error = request_irq(irq, gpio_keys_isr,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ IRQF_SAMPLE_RANDOM | IRQF_DISABLED,
button->desc ? button->desc : "gpio_keys",
- bdata);
+ pdev);
if (error) {
pr_err("gpio-keys: Unable to claim irq %d; error %d\n",
irq, error);
- gpio_free(button->gpio);
- goto fail2;
+ goto fail;
}
if (button->wakeup)
wakeup = 1;
-
input_set_capability(input, type, button->code);
}
+ /* Init timer */
+ init_timer(&button_timer);
+ button_timer.data = (unsigned long)&pavo_button_device;
+ button_timer.function = button_timer_callback;
+
error = input_register_device(input);
if (error) {
pr_err("gpio-keys: Unable to register input device, "
"error: %d\n", error);
- goto fail2;
+ goto fail;
}
device_init_wakeup(&pdev->dev, wakeup);
return 0;
- fail2:
+ fail:
while (--i >= 0) {
- free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
- if (pdata->buttons[i].debounce_interval)
- del_timer_sync(&ddata->data[i].timer);
- cancel_work_sync(&ddata->data[i].work);
- gpio_free(pdata->buttons[i].gpio);
+ free_irq(pdata->buttons[i].gpio + IRQ_GPIO_0 , pdev);
}
platform_set_drvdata(pdev, NULL);
- fail1:
input_free_device(input);
- kfree(ddata);
return error;
}
@@ -194,19 +244,14 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
static int __devexit gpio_keys_remove(struct platform_device *pdev)
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
- struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
- struct input_dev *input = ddata->input;
+ struct input_dev *input = platform_get_drvdata(pdev);
int i;
device_init_wakeup(&pdev->dev, 0);
for (i = 0; i < pdata->nbuttons; i++) {
- int irq = gpio_to_irq(pdata->buttons[i].gpio);
- free_irq(irq, &ddata->data[i]);
- if (pdata->buttons[i].debounce_interval)
- del_timer_sync(&ddata->data[i].timer);
- cancel_work_sync(&ddata->data[i].work);
- gpio_free(pdata->buttons[i].gpio);
+ int irq = pdata->buttons[i].gpio + IRQ_GPIO_0;
+ free_irq(irq, pdev);
}
input_unregister_device(input);
@@ -220,12 +265,14 @@ static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
int i;
+
+ printk("%s(): called.\n", __func__);
if (device_may_wakeup(&pdev->dev)) {
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
if (button->wakeup) {
- int irq = gpio_to_irq(button->gpio);
+ int irq = button->gpio + IRQ_GPIO_0;
enable_irq_wake(irq);
}
}
@@ -238,12 +285,14 @@ static int gpio_keys_resume(struct platform_device *pdev)
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
int i;
+
+ printk("%s(): called.\n", __func__);
if (device_may_wakeup(&pdev->dev)) {
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
if (button->wakeup) {
- int irq = gpio_to_irq(button->gpio);
+ int irq = button->gpio + IRQ_GPIO_0;
disable_irq_wake(irq);
}
}
@@ -256,24 +305,25 @@ static int gpio_keys_resume(struct platform_device *pdev)
#define gpio_keys_resume NULL
#endif
-static struct platform_driver gpio_keys_device_driver = {
+struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = __devexit_p(gpio_keys_remove),
.suspend = gpio_keys_suspend,
.resume = gpio_keys_resume,
.driver = {
.name = "gpio-keys",
- .owner = THIS_MODULE,
}
};
static int __init gpio_keys_init(void)
{
+ pavo_board_init();
return platform_driver_register(&gpio_keys_device_driver);
}
static void __exit gpio_keys_exit(void)
{
+ platform_device_unregister(&pavo_button_device);
platform_driver_unregister(&gpio_keys_device_driver);
}
@@ -283,4 +333,3 @@ module_exit(gpio_keys_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
-MODULE_ALIAS("platform:gpio-keys");
diff --git a/drivers/input/keyboard/jz_keypad.c b/drivers/input/keyboard/jz_keypad.c
new file mode 100644
index 00000000000..d02dfc11a02
--- /dev/null
+++ b/drivers/input/keyboard/jz_keypad.c
@@ -0,0 +1,362 @@
+/*
+ * linux/drivers/input/keyboard/jz_keypad.c
+ *
+ * JZ Keypad Driver
+ *
+ * Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: Richard <cjfeng@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+#include <asm/gpio.h>
+
+#include <asm/jzsoc.h>
+
+#define KB_ROWS 3
+#define KB_COLS 3
+
+#define SCAN_INTERVAL (10)
+
+static unsigned short col[KB_COLS] = {85,87,91};
+static unsigned short row[KB_ROWS] = {60,61,62};
+static unsigned short s0[KB_COLS];
+static unsigned short s1[KB_COLS]={7,7,7};
+static unsigned short precol,prerow;
+
+static const unsigned int jz_kbd_keycode[KB_COLS * KB_ROWS] = {
+ KEY_1, KEY_4, KEY_7,
+ KEY_2, KEY_5, 0,
+ KEY_3, KEY_6, 0,
+};
+
+struct jz_kbd {
+ unsigned int keycode[ARRAY_SIZE(jz_kbd_keycode)];
+ struct input_dev *input;
+ char phys[32];
+
+ spinlock_t lock;
+ struct timer_list timer;
+
+ unsigned int suspended;
+ unsigned long suspend_jiffies;
+};
+
+static struct jz_kbd g_jz_kbd;
+
+static inline void jz_scan_kbd(unsigned short *s)
+{
+ int i;
+
+ if (!s)
+ return;
+
+ for (i = 0; i < KB_COLS; i++) {
+
+ __gpio_as_input(85); /* row */
+ __gpio_as_input(87); /* row */
+ __gpio_as_input(91); /* row */
+
+ __gpio_as_input(60); /* col */
+ __gpio_as_input(61); /* col */
+ __gpio_as_input(62); /* col */
+
+ __gpio_clear_pin(col[i]);
+ __gpio_as_output(col[i]);
+
+ udelay(1000);
+ s[i]=(__gpio_get_pin(60) << 0) | (__gpio_get_pin(61) << 1) |
+ (__gpio_get_pin(62) << 2);
+ }
+}
+
+static void jz_kbd_scankeyboard(struct jz_kbd *kbd_data)
+{
+ unsigned int row,col;
+ unsigned long flags;
+ unsigned int num_pressed;
+
+ if (kbd_data->suspended)
+ return;
+
+ spin_lock_irqsave(&kbd_data->lock, flags);
+
+ num_pressed = 0;
+ jz_scan_kbd(s0);
+
+ /* look for key if pressed down on not, col & row */
+ if (s0[0] == 7 && s0[1] == 7 && s0[2] == 7) {
+ if (s1[0] != 7 || s1[1] != 7 || s1[2] != 7) {
+ /* up */
+ input_report_key(kbd_data->input, kbd_data->keycode[prerow * KB_COLS + precol], 0);
+ input_sync(kbd_data->input);
+ }
+ precol = prerow = -1;
+ s1[0] = s1[1] = s1[2] = 7;
+ spin_unlock_irqrestore(&kbd_data->lock, flags);
+ return;
+ }
+
+ if (s0[0] == 6 && s0[1] == 7 && s0[2] == 7) {
+ row = 0;//K7
+ col = 2;
+ goto find_row_col;
+ }
+ if (s0[0] == 7 && s0[1] == 3 && s0[2] == 7) {
+ row = 2;//k6
+ col = 1;
+ goto find_row_col;
+ }
+ if (s0[0] == 7 && s0[1] == 5 && s0[2] == 7) {
+ row = 1;//k5
+ col = 1;
+ goto find_row_col;
+ }
+ if (s0[0] == 7 && s0[1] == 6 && s0[2] == 7) {
+ row = 0;//k4
+ col = 1;
+ goto find_row_col;
+ }
+ if (s0[0] == 7 && s0[1] == 7 && s0[2] == 3) {
+ row = 2;//k3
+ col = 0;
+ goto find_row_col;
+ }
+ if (s0[0] == 7 && s0[1] == 7 && s0[2] == 5) {
+ row = 1;//k2
+ col = 0;
+ goto find_row_col;
+ }
+ if (s0[0] == 7 && s0[1] == 7 && s0[2] == 6) {
+ row = 0;//k1
+ col = 0;
+ goto find_row_col;
+ }
+ /* 2 or 3 buttons are pressed */
+ s0[0] = s0[1] = s0[2] = 7;
+ s1[0] = s1[1] = s1[2] = 7;
+ prerow = precol = -1;
+ spin_unlock_irqrestore(&kbd_data->lock, flags);
+ return;
+find_row_col:
+ if (s1[0] == 7 && s1[1] == 7 && s1[2] == 7) {
+ /* down */
+ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1);
+ input_sync(kbd_data->input);
+ s1[0] = s0[0];
+ s1[1] = s0[1];
+ s1[2] = s0[2];
+
+ precol = col;
+ prerow = row;
+ spin_unlock_irqrestore(&kbd_data->lock, flags);
+ return;
+ }
+ if (s1[0] != 7 || s1[1] != 7 || s1[2] != 7) {
+ /* is the same as the preview key */
+ if (s0[0] == s1[0] && s0[1] == s1[1] && s0[2] == s1[2]) {
+ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1);
+ input_sync(kbd_data->input);
+ s1[0] = s0[0];
+ s1[1] = s0[1];
+ s1[2] = s0[2];
+
+ precol = col;
+ prerow = row;
+ spin_unlock_irqrestore(&kbd_data->lock, flags);
+ return;
+ } else {
+ /* the preview key is up and other key is down */
+ if (s0[0] != s1[0] || s0[1] != s1[1] || s0[2] != s1[2]) {
+ input_report_key(kbd_data->input, kbd_data->keycode[prerow * KB_COLS + precol], 0);
+ input_sync(kbd_data->input);
+ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1);
+ input_sync(kbd_data->input);
+ s1[0] = s0[0];
+ s1[1] = s0[1];
+ s1[2] = s0[2];
+ precol = col;
+ prerow = row;
+ spin_unlock_irqrestore(&kbd_data->lock, flags);
+ return;
+ }
+ }
+ }
+}
+
+static void jz_kbd_timer_callback(unsigned long data)
+{
+ jz_kbd_scankeyboard(&g_jz_kbd);
+ mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL);
+}
+
+#ifdef CONFIG_PM
+static int jz_kbd_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct jz_kbd *jz_kbd = platform_get_drvdata(dev);
+
+ printk("%s(): called.\n", __func__);
+
+ jz_kbd->suspended = 1;
+
+ return 0;
+}
+
+static int jz_kbd_resume(struct platform_device *dev)
+{
+ struct jz_kbd *jz_kbd = platform_get_drvdata(dev);
+
+ printk("%s(): called.\n", __func__);
+
+ jz_kbd->suspend_jiffies = jiffies;
+ jz_kbd->suspended = 0;
+
+ return 0;
+}
+#else
+#define jz_kbd_suspend NULL
+#define jz_kbd_resume NULL
+#endif
+
+static int __init jz_kbd_probe(struct platform_device *dev)
+{
+ struct input_dev *input_dev;
+ int i, error;
+
+ input_dev = input_allocate_device();
+ if (!input_dev)
+ return -ENOMEM;
+
+ platform_set_drvdata(dev, &g_jz_kbd);
+
+ strcpy(g_jz_kbd.phys, "input/kbd0");
+
+ spin_lock_init(&g_jz_kbd.lock);
+
+ g_jz_kbd.suspend_jiffies = jiffies;
+ g_jz_kbd.input = input_dev;
+
+ input_dev->private = &g_jz_kbd;
+ input_dev->name = "JZ Keypad";
+ input_dev->phys = g_jz_kbd.phys;
+ input_dev->cdev.dev = &dev->dev;
+
+ input_dev->id.bustype = BUS_PARPORT;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_SYN);
+ input_dev->keycode = g_jz_kbd.keycode; /* keycode array address */
+ input_dev->keycodesize = sizeof(unsigned int);
+ input_dev->keycodemax = ARRAY_SIZE(jz_kbd_keycode);
+
+ memcpy(g_jz_kbd.keycode, jz_kbd_keycode, sizeof(g_jz_kbd.keycode));
+
+ for (i = 0; i < ARRAY_SIZE(jz_kbd_keycode); i++)
+ set_bit(g_jz_kbd.keycode[i], input_dev->keybit);
+
+ //clear_bit(0, input_dev->keybit);
+
+ __gpio_as_input(85);
+ __gpio_as_input(87);
+ __gpio_as_input(91);
+
+#if 0
+ __gpio_as_input(60);
+ __gpio_as_input(61);
+ __gpio_as_input(62);
+#endif
+
+ /* Init Keyboard rescan timer */
+ init_timer(&g_jz_kbd.timer);
+ g_jz_kbd.timer.function = jz_kbd_timer_callback;
+ g_jz_kbd.timer.data = (unsigned long)&g_jz_kbd;
+ mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL);
+
+ error = input_register_device(input_dev);
+ if (error) {
+ pr_err("gpio-keys: Unable to register input device, "
+ "error: %d\n", error);
+ }
+ printk("input: %s Keypad Registered.\n", JZ_SOC_NAME);
+
+ return 0;
+}
+
+static int jz_kbd_remove(struct platform_device *dev)
+{
+ struct jz_kbd *jz_kbd = platform_get_drvdata(dev);
+
+ del_timer_sync(&jz_kbd->timer);
+
+ __gpio_as_input(85);
+ __gpio_as_input(87);
+ __gpio_as_input(91);
+
+ /* These pins is conficting with cs8900a's CS RD WE pins on JZ4740-PAVO board */
+ __gpio_as_input(60);
+ __gpio_as_input(61);
+ __gpio_as_input(62);
+
+ input_unregister_device(jz_kbd->input);
+
+ return 0;
+}
+
+static struct platform_driver jz_kbd_driver = {
+ .probe = jz_kbd_probe,
+ .remove = jz_kbd_remove,
+ .suspend = jz_kbd_suspend,
+ .resume = jz_kbd_resume,
+ .driver = {
+ .name = "jz-keypad",
+ },
+};
+
+/*
+ * Jz Keyboard Device
+ */
+static struct platform_device jzkbd_device = {
+ .name = "jz-keypad",
+ .id = -1,
+};
+
+static int __init jz_kbd_init(void)
+{
+ platform_device_register(&jzkbd_device);
+ return platform_driver_register(&jz_kbd_driver);
+}
+
+static void __exit jz_kbd_exit(void)
+{
+ platform_device_unregister(&jzkbd_device);
+ platform_driver_unregister(&jz_kbd_driver);
+}
+
+module_init(jz_kbd_init);
+module_exit(jz_kbd_exit);
+
+MODULE_AUTHOR("Richard");
+MODULE_DESCRIPTION("JZ keypad driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/jz_keypad_5x5.c b/drivers/input/keyboard/jz_keypad_5x5.c
new file mode 100644
index 00000000000..08f1d4b353e
--- /dev/null
+++ b/drivers/input/keyboard/jz_keypad_5x5.c
@@ -0,0 +1,334 @@
+/*
+ * JZ Keypad ( 5 x 5 ) Driver
+ *
+ * Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc.
+ *
+ * Author: Jason <xwang@ingenic.cn> 20090210
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+#include <asm/gpio.h>
+#include <asm/jzsoc.h>
+
+#define KB_ROWS 5
+#define KB_COLS 5
+
+#define SCAN_INTERVAL (10)
+
+#define ROW_KEYBIT_MASK 0xFFE0
+
+#define SET_GPIOS_AS_INPUT() \
+do { \
+ unsigned short i; \
+ \
+ for (i = 0; i < KB_ROWS; i++) { \
+ __gpio_as_input(jz_row_gpios[i]); \
+ __gpio_as_input(jz_col_gpios[i]); \
+ } \
+} while (0)
+
+
+#define GET_ROW_GPIO_PINS() \
+({ \
+ unsigned short _pins = 0, i; \
+ for (i = 0; \
+ i < KB_ROWS; \
+ _pins |= __gpio_get_pin(jz_row_gpios[i]) << i, i++) \
+ ; \
+ _pins; \
+})
+
+#define CHECK_IF_KEY_PRESSED(s) \
+({ \
+ unsigned short i; \
+ for (i = 0; i < KB_COLS && s[i] == 0x1F ; i++) \
+ ; \
+ i != KB_ROWS; \
+})
+
+#define CLEAN_SCAN_RESULT(s) \
+do { \
+ unsigned short i; \
+ for (i = 0; i < KB_COLS; s[i++] = 0x1F) \
+ ; \
+} while (0)
+
+
+static const unsigned short jz_col_gpios[KB_ROWS] = {76, 75, 74, 73, 72};
+static const unsigned short jz_row_gpios[KB_COLS] = {181, 182, 79, 78, 77};
+
+static const unsigned int jz_kbd_keycode[KB_ROWS * KB_COLS] = {
+ KEY_A, KEY_B, KEY_C, KEY_D, KEY_E,
+ KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
+ KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
+ KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
+ KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_SPACE, KEY_BACKSPACE, KEY_Y
+};
+
+struct jz_kbd {
+ unsigned int keycode[ARRAY_SIZE(jz_kbd_keycode)];
+ struct input_dev *input;
+ char phys[32];
+
+ spinlock_t lock;
+ struct timer_list timer;
+
+ unsigned int suspended;
+ unsigned long suspend_jiffies;
+};
+static struct jz_kbd g_jz_kbd;
+
+static unsigned short scan_result[KB_COLS];
+static unsigned short pre_scan_result[KB_COLS] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F};
+static unsigned short pre_col, pre_row;
+
+/**
+ * Scan keypad by reading GPIO pins.
+ */
+static inline void jz_do_scan(unsigned short *s)
+{
+ unsigned short i;
+
+ if (!s)
+ return ;
+
+ for (i = 0; i < KB_COLS; i++) {
+
+ SET_GPIOS_AS_INPUT();
+ __gpio_clear_pin(jz_col_gpios[i]);
+ __gpio_as_output(jz_col_gpios[i]);
+
+ udelay(1000);
+
+ s[i] = GET_ROW_GPIO_PINS();
+ }
+}
+
+/**
+ * Call scan function and handle 'GPIO event'(like key down, key up),
+ * and report it to upper layer of input subsystem ... if necessary
+ */
+static void jz_kbd_scan(struct jz_kbd *kbd_data)
+{
+ unsigned short row, col, i;
+ unsigned long flags;
+
+ if (kbd_data->suspended)
+ return;
+
+ spin_lock_irqsave(&kbd_data->lock, flags);
+
+ jz_do_scan(scan_result);
+
+ /* check if any key was pressed or not */
+ if (!CHECK_IF_KEY_PRESSED(scan_result)) {
+
+ /* key up */
+ if (CHECK_IF_KEY_PRESSED(pre_scan_result)) {
+ input_report_key(kbd_data->input, kbd_data->keycode[pre_row * KB_COLS + pre_col], 0);
+ input_sync(kbd_data->input);
+ }
+ pre_col = pre_row = 0xFFFF;
+ CLEAN_SCAN_RESULT(pre_scan_result);
+
+ spin_unlock_irqrestore(&kbd_data->lock, flags);
+ return;
+ }
+
+ /* find the key */
+ for (row = 0; row < KB_ROWS; row++) {
+ for (i = scan_result[row], col = 0; col < KB_COLS; col++) {
+ if ( !(i & 0x01) )
+ break;
+ i >>= 1;
+ }
+ if (col != KB_COLS)
+ break;
+ }
+
+ //printk("[DRIVER] row = %d, col = %d, key code: 0x%02X\n", row, col, kbd_data->keycode[row * KB_COLS + col]);
+
+ /* the same as the preview one || new key */
+ if ( (col == pre_col && row == pre_row)
+ || (pre_col == 0xFFFF && pre_row == 0xFFFF) ) {
+
+ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1);
+ input_sync(kbd_data->input);
+
+ } else {
+ /* the preview key is up and other key is down */
+ input_report_key(kbd_data->input, kbd_data->keycode[pre_row * KB_COLS + col], 0);
+ input_sync(kbd_data->input);
+ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1);
+ input_sync(kbd_data->input);
+ }
+
+ for (i = 0; i < KB_ROWS; i++) {
+ pre_scan_result[i] = scan_result[i];
+ }
+
+ pre_col = col;
+ pre_row = row;
+
+ spin_unlock_irqrestore(&kbd_data->lock, flags);
+
+ return;
+}
+
+static void jz_kbd_timer_callback(unsigned long data)
+{
+ jz_kbd_scan(&g_jz_kbd);
+ mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL);
+}
+
+#ifdef CONFIG_PM
+static int jz_kbd_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct jz_kbd *jz_kbd = platform_get_drvdata(dev);
+
+ printk("%s(): called.\n", __func__);
+
+ jz_kbd->suspended = 1;
+
+ return 0;
+}
+
+static int jz_kbd_resume(struct platform_device *dev)
+{
+ struct jz_kbd *jz_kbd = platform_get_drvdata(dev);
+
+ printk("%s(): called.\n", __func__);
+
+ jz_kbd->suspend_jiffies = jiffies;
+ jz_kbd->suspended = 0;
+
+ return 0;
+}
+
+#else
+#define jz_kbd_suspend NULL
+#define jz_kbd_resume NULL
+#endif
+
+/**
+ * Driver init
+ */
+static int __init jz_kbd_probe(struct platform_device *dev)
+{
+ struct input_dev *input_dev;
+ int i, error;
+
+ input_dev = input_allocate_device();
+ if (!input_dev)
+ return -ENOMEM;
+
+ platform_set_drvdata(dev, &g_jz_kbd);
+
+ strcpy(g_jz_kbd.phys, "input/kbd0");
+
+ spin_lock_init(&g_jz_kbd.lock);
+
+ g_jz_kbd.suspend_jiffies = jiffies;
+ g_jz_kbd.input = input_dev;
+
+ input_dev->private = &g_jz_kbd;
+ input_dev->name = "JZ 5x5 Keypad";
+ input_dev->phys = g_jz_kbd.phys;
+ input_dev->cdev.dev = &dev->dev;
+
+ input_dev->id.bustype = BUS_PARPORT;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_SYN);
+ input_dev->keycode = g_jz_kbd.keycode;
+ input_dev->keycodesize = sizeof(unsigned int);
+ input_dev->keycodemax = ARRAY_SIZE(jz_kbd_keycode);
+
+ memcpy(g_jz_kbd.keycode, jz_kbd_keycode, sizeof(g_jz_kbd.keycode));
+
+ for ( i = 0; i < ARRAY_SIZE(jz_kbd_keycode); i++)
+ set_bit(g_jz_kbd.keycode[i], input_dev->keybit);
+
+ init_timer(&g_jz_kbd.timer);
+ g_jz_kbd.timer.function = jz_kbd_timer_callback;
+ g_jz_kbd.timer.data = (unsigned long)&g_jz_kbd;
+ mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL);
+
+ error = input_register_device(input_dev);
+ if (error) {
+ pr_err("gpio-keys: Unable to register input device, "
+ "error: %d\n", error);
+ }
+ printk("input: JZ 5x5 Keypad Registered.\n");
+
+ return 0;
+}
+
+static int jz_kbd_remove(struct platform_device *dev)
+{
+ struct jz_kbd *kbd = platform_get_drvdata(dev);
+
+ del_timer_sync(&kbd->timer);
+
+ SET_GPIOS_AS_INPUT();
+
+ input_unregister_device(kbd->input);
+
+ return 0;
+}
+
+static struct platform_driver jz_kbd_driver = {
+ .probe = jz_kbd_probe,
+ .remove = jz_kbd_remove,
+ .suspend= jz_kbd_suspend,
+ .resume = jz_kbd_resume,
+ .driver = {
+ .name = "jz-5x5-keypad",
+ },
+};
+
+static struct platform_device jzkbd_device = {
+ .name = "jz-5x5-keypad",
+ .id = -1,
+};
+
+static int __init jz_kbd_init(void)
+{
+ platform_device_register(&jzkbd_device);
+ return platform_driver_register(&jz_kbd_driver);
+}
+
+static void __exit jz_kbd_exit(void)
+{
+ platform_device_unregister(&jzkbd_device);
+ platform_driver_unregister(&jz_kbd_driver);
+}
+
+module_init(jz_kbd_init);
+module_exit(jz_kbd_exit);
+
+MODULE_AUTHOR("Jason <xwang@ingenic.cn>");
+MODULE_DESCRIPTION("JZ 5x5 keypad driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 72e2712c7e2..cd07ee4317b 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig INPUT_TOUCHSCREEN
bool "Touchscreens"
- help
+ help
Say Y here, and a list of supported touchscreens will be displayed.
This option doesn't affect the kernel.
@@ -29,6 +29,27 @@ config TOUCHSCREEN_ADS7846
To compile this driver as a module, choose M here: the
module will be called ads7846.
+
+
+config TOUCHSCREEN_JZ
+ tristate "JZ touchscreen"
+ default y
+ help
+ Say Y here to enable JZ SAR A/D controller if you use touchscreen
+ on JZ platform.
+
+ To compile this driver as a module, choose M here, and the
+ module jz_ts should be called.
+
+config JZ_ADKEY
+ bool "JZ ADKEY"
+ depends on TOUCHSCREEN_JZ
+ help
+ The AD value of the key is get by JZ SAR A/D controller when any ad key
+ is pressed down.
+
+
+
config TOUCHSCREEN_AD7877
tristate "AD7877 based touchscreens"
depends on SPI_MASTER
@@ -194,6 +215,7 @@ config TOUCHSCREEN_INEXIO
To compile this driver as a module, choose M here: the
module will be called inexio.
+
config TOUCHSCREEN_MK712
tristate "ICS MicroClock MK712 touchscreen"
help
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 3e1c5e0b952..54c27f19e1b 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
+obj-$(CONFIG_TOUCHSCREEN_JZ) += jz_ts.o
obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
diff --git a/drivers/input/touchscreen/jz_ts.c b/drivers/input/touchscreen/jz_ts.c
new file mode 100644
index 00000000000..928dcaa26b0
--- /dev/null
+++ b/drivers/input/touchscreen/jz_ts.c
@@ -0,0 +1,892 @@
+/*
+ * JZ Touch Screen Driver
+ *
+ * Copyright (c) 2005 - 2009 Ingenic Semiconductor Inc.
+ *
+ * Author: Jason <xwang@ingenic.cn> 20090219
+ * Regen <lhhuang@ingenic.cn> 20090324 add adkey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <asm/irq.h>
+#include <asm/gpio.h>
+#include <asm/jzsoc.h>
+
+#if 1
+#define DBG printk("%s(%d) \n",__FUNCTION__,__LINE__);
+#else
+#define DBG
+#endif
+
+#define TS_NAME "jz-ts"
+
+#define KEY_SCAN_INTERVAL 5
+#define TS_SCAN_INTERVAL 0
+
+/* from qwerty.kl of android */
+#define DPAD_CENTER 232
+#define DPAD_DOWN 108
+#define DPAD_UP 103
+#define DPAD_LEFT 105
+#define DPAD_RIGHT 106
+
+/* TS event status */
+#define PENUP 0x00
+#define PENDOWN 0x01
+
+/* Sample times in one sample process */
+//#define SAMPLE_TIMES 3
+
+#define SAMPLE_TIMES 5
+#define DROP_SAMPLE_TIMES 1 /* min drop 1 sample */
+#define CAL_SAMPLE_TIMES (SAMPLE_TIMES - DROP_SAMPLE_TIMES)
+#define VIRTUAL_SAMPLE 3 /* min >= 2 */
+/* Min pressure value. If less than it, filt the point.
+ * Mask it if it is not useful for you
+ */
+//#define MIN_PRESSURE 0x100
+
+/* Max delta x distance between current point and last point. */
+#define MAX_DELTA_X_OF_2_POINTS 200
+/* Max delta x distance between current point and last point. */
+#define MAX_DELTA_Y_OF_2_POINTS 120
+
+/* Max delta between points in one sample process
+ * Verify method :
+ * (diff value / min value) * 100 <= MAX_DELTA_OF_SAMPLING
+ */
+#define MAX_DELTA_OF_SAMPLING 20
+
+
+#define TS_ABS(x) ((x) > 0 ? (x): -(x))
+#define DIFF(a,b) (((a)>(b))?((a)-(b)):((b)-(a)))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+
+/************************************************************************/
+/* SAR ADC OPS */
+/************************************************************************/
+
+typedef struct datasource {
+ u16 xbuf;
+ u16 ybuf;
+ u16 zbuf;
+ u16 reserve;
+}datasource_t;
+struct ts_event {
+ u16 status;
+ u16 x;
+ u16 y;
+ u16 pressure;
+ u16 pad;
+};
+#define TOUCH_TYPE 1
+#define BAT_TYPE 2
+#define SADC_TYPE 4
+
+
+//sadc touch fifo size 2 * 32bit
+#define FIFO_MAX_SIZE 2
+
+/*
+ * TS deriver
+ */
+struct jz_ts_t {
+ int touch_cal_count;
+
+ unsigned int ts_fifo[FIFO_MAX_SIZE][CAL_SAMPLE_TIMES];
+ datasource_t data_s;
+ struct ts_event event;
+ int event_valid;
+
+
+ int cal_type; /* current calibrate type */
+ int oldbat_value;
+ //struct timer_list acq_timer; // Timer for triggering acquisitions
+#ifdef CONFIG_JZ_ADKEY
+ struct timer_list key_timer; // for adkey
+ int active_low; // for adkey's interrupt pin
+#endif
+ wait_queue_head_t wait; // read wait queue
+ spinlock_t lock;
+
+ /* Following 4 members use to pass arguments from u-boot to tell us the ts data.
+ * But in Android we do not use them.
+ */
+/*
+ int minx, miny, maxx, maxy;
+*/
+ int first_read;
+
+ char phys[32];
+ struct input_dev *input_dev;
+};
+
+static struct jz_ts_t *jz_ts;
+
+/*
+ * TS Event type
+ */
+
+#ifdef CONFIG_JZ_ADKEY
+struct ad_keys_button {
+ int code; /* input event code */
+ int val; /* the ad value of the key */
+ int fuzz; /* the error(+-fuzz) allowed of the ad value of the key */
+};
+static struct ad_keys_button ad_buttons[] = {
+ {
+ .code = DPAD_LEFT,
+ .val = DPAD_LEFT_LEVEL,
+ .fuzz = 40,
+ },
+ {
+ .code = DPAD_DOWN,
+ .val = DPAD_DOWN_LEVEL,
+ .fuzz = 40,
+ },
+ {
+ .code = DPAD_UP,
+ .val = DPAD_UP_LEVEL,
+ .fuzz = 40,
+ },
+ {
+ .code = DPAD_CENTER,
+ .val = DPAD_CENTER_LEVEL,
+ .fuzz = 40,
+ },
+ {
+ .code = DPAD_RIGHT,
+ .val = DPAD_RIGHT_LEVEL,
+ .fuzz = 40,
+ },
+};
+#define KEY_NUM (sizeof(ad_buttons) / sizeof(struct ad_keys_button))
+#endif
+
+
+//static unsigned int p;
+
+static DECLARE_WAIT_QUEUE_HEAD (sadc_wait_queue);
+
+extern unsigned int (*codec_read_battery)(void);
+#if 0
+static void reg_debug(void)
+{
+ printk("\t####CTRL####################################################\n");
+ printk("\tPEND %s, ", REG_SADC_CTRL & SADC_CTRL_PENDM ? "masked" : "enabled");
+ printk("PENU %s, ", REG_SADC_CTRL & SADC_CTRL_PENUM ? "masked" : "enabled");
+ printk("TSRDY %s\n", REG_SADC_CTRL & SADC_CTRL_TSRDYM ? "masked" : "enabled");
+ printk("\t----STATE---------------------------------------------------\n");
+ printk("\tIRQ actived: %s, %s, %s\n",
+ REG_SADC_STATE & SADC_STATE_PEND ? "pen down" : " ",
+ REG_SADC_STATE & SADC_STATE_PENU ? "pen up " : " ",
+ REG_SADC_STATE & SADC_STATE_TSRDY ? "sample " : " ");
+ printk("\t############################################################\n");
+}
+#endif
+/*
+ * set adc clock to 24MHz/div. A/D works at freq between 500KHz to 8MHz.
+ */
+static void sadc_init_clock(int div)
+{
+
+ REG_CPM_CLKGR &= ~CPM_CLKGR_SADC;
+
+ if (div < 2) div = 2;
+ if (div > 23) div = 23;
+#if defined(CONFIG_SOC_JZ4740)
+ REG_SADC_CFG &= ~SADC_CFG_CLKDIV_MASK;
+ REG_SADC_CFG |= (div - 1) << SADC_CFG_CLKDIV_BIT;
+#endif
+#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D)
+ div = 48;
+
+ REG_SADC_ADCLK &= ~SADC_ADCLK_CLKDIV_MASK;
+ REG_SADC_ADCLK |= (div - 1) << SADC_ADCLK_CLKDIV_BIT;
+ REG_SADC_ADCLK &= ~SADC_ADCLK_CLKDIV_BIT;
+// REG_SADC_ADCLK |= 39 << SADC_ADCLK_CLKDIV_10_BIT; /* if div ==3,here is 39 */
+
+ REG_SADC_ADCLK |= 4 << SADC_ADCLK_CLKDIV_10_BIT; /* if div ==48,here is 4 */
+
+ // if(SADC_STATE_SLEEPND & REG_SADC_STATE)
+ if( REG_SADC_STATE)
+ {
+ REG_SADC_ENA |= SADC_ENA_EXIT_SLP;
+ while(REG_SADC_ENA & SADC_ENA_EXIT_SLP);
+ // REG_SADC_STATE = SADC_STATE_SLEEPND;
+ }
+
+ #endif
+}
+
+static inline void sadc_start_sadcin(void)
+{
+ REG_SADC_ENA |= SADC_ENA_SADCINEN;
+}
+
+static inline void sadc_start_pbat(void)
+{
+ REG_SADC_ENA |= SADC_ENA_PBATEN; /* Enable pbat adc */
+}
+
+static inline void ts_enable_pendown_irq(void)
+{
+ REG_SADC_CTRL &= ~SADC_CTRL_PENDM;
+}
+
+static inline void ts_enable_penup_irq(void)
+{
+ REG_SADC_CTRL &= ~SADC_CTRL_PENUM;
+}
+
+static inline void ts_disable_pendown_irq(void)
+{
+ REG_SADC_CTRL |= SADC_CTRL_PENDM;
+}
+
+static inline void ts_disable_penup_irq(void)
+{
+ REG_SADC_CTRL |= SADC_CTRL_PENUM;
+}
+
+static inline void sadc_enable_ts(void)
+{
+ REG_SADC_ENA |= SADC_ENA_TSEN;
+}
+
+static inline void sadc_disable_ts(void)
+{
+ REG_SADC_ENA &= ~SADC_ENA_TSEN;
+}
+
+static inline void sadc_start_ts(void)
+{
+ REG_SADC_SAMETIME = 10; /* about 0.02 ms,you can change it */
+ REG_SADC_WAITTIME = 2; /* about 3.33 ms,you can change it */
+
+ REG_SADC_CFG &= ~(SADC_CFG_TS_DMA | SADC_CFG_XYZ_MASK | SADC_CFG_SNUM_MASK |SADC_CFG_EXIN | SADC_CFG_CLKOUT_NUM_MASK);
+ REG_SADC_CFG |= (SADC_CFG_XYZ1Z2 | SADC_CFG_SNUM(SAMPLE_TIMES) | SADC_CFG_SPZZ | SADC_CFG_DNUM(VIRTUAL_SAMPLE));
+
+ if (CFG_PBAT_DIV == 1)
+ REG_SADC_CFG |= SADC_CFG_PBAT_HIGH; /* full baterry voltage >= 2.5V */
+ else
+ REG_SADC_CFG |= SADC_CFG_PBAT_LOW; /* full baterry voltage < 2.5V */
+
+// REG_SADC_CTRL = (SADC_STATE_SLEEPND | SADC_CTRL_TSRDYM | SADC_CTRL_PBATRDYM | SADC_CTRL_PENUM |SADC_CTRL_SRDYM);
+ REG_SADC_CTRL = ( SADC_CTRL_TSRDYM | SADC_CTRL_PBATRDYM | SADC_CTRL_PENUM |SADC_CTRL_SRDYM);
+ REG_SADC_STATE = REG_SADC_STATE;
+
+ REG_SADC_ENA |= SADC_ENA_TSEN;
+}
+
+/**
+ * Read the battery voltage
+ */
+unsigned int jz_read_battery(void)
+{
+ unsigned int v;
+ unsigned int timeout = 0x3fff;
+ u16 pbat;
+ spin_lock_irq(&jz_ts->lock);
+ if(jz_ts->oldbat_value == 0xffffffff)
+ {
+ //printk("==========================\n");
+ sadc_start_pbat();
+ while(!(REG_SADC_STATE & SADC_STATE_PBATRDY) && --timeout) ;
+ pbat = REG_SADC_BATDAT;
+ v = pbat & 0x0fff;
+ jz_ts->oldbat_value = v;
+ REG_SADC_STATE = SADC_STATE_PBATRDY; //
+ REG_SADC_CTRL &= ~SADC_CTRL_PBATRDYM;
+
+ //printk("==========================\n");
+ }
+ if(!(jz_ts->cal_type & BAT_TYPE))
+ {
+ jz_ts->cal_type |= BAT_TYPE;
+ sadc_start_pbat();
+ //printk("start next pbat\n");
+ }
+
+ v = jz_ts->oldbat_value;
+ //printk("pbat = %d\n",v);
+ spin_unlock_irq(&jz_ts->lock);
+ return v;
+}
+
+static inline void ts_data_ready(void)
+{
+ REG_SADC_CTRL |= SADC_CTRL_TSRDYM;
+}
+
+#ifdef CONFIG_JZ_ADKEY
+/**
+ * Read the battery voltage
+ */
+static unsigned int read_sadcin(void)
+{
+ unsigned int v;
+ unsigned int timeout = 0x3ff;
+ u16 val;
+ jz_ts->cal_type |= SADC_TYPE;
+ if(!(REG_SADC_STATE & SADC_STATE_SRDY))
+ sadc_start_sadcin();
+
+ while(!(REG_SADC_STATE & SADC_STATE_SRDY) && --timeout)
+ ;
+
+ val = REG_SADC_SADDAT;
+ v = val & 0x0fff;
+ REG_SADC_STATE = SADC_STATE_SRDY;
+ jz_ts->cal_type &= ~SADC_TYPE;
+ return v;
+}
+
+static unsigned int key_scan(int ad_val)
+{
+ int i;
+
+ for(i = 0; i<KEY_NUM; i++) {
+ if((ad_buttons[i].val + ad_buttons[i].fuzz >= ad_val) &&
+ (ad_val >=ad_buttons[i].val - ad_buttons[i].fuzz)) {
+ return ad_buttons[i].code;
+ }
+ }
+ return -1;
+}
+
+static void key_timer_callback(unsigned long data)
+{
+ struct jz_ts_t *ts = (struct jz_ts_t *)data;
+ int state;
+ int active_low = ts->active_low;
+ int ad_val, code;
+ static int old_code;
+
+ state = __gpio_get_pin(GPIO_ADKEY_INT);
+ ad_val = read_sadcin();
+
+ if (active_low) {
+ if (state == 0) {
+ /* press down */
+ code = key_scan(ad_val);
+ old_code = code;
+ input_report_key(ts->input_dev, code, 1);
+ //emily input_sync(ts->input_dev);
+ mod_timer(&ts->key_timer, jiffies + KEY_SCAN_INTERVAL);
+ } else {
+ /* up */
+ input_report_key(ts->input_dev, old_code, 0);
+ //emily input_sync(ts->input_dev);
+ udelay(1000);
+ __gpio_as_irq_fall_edge(GPIO_ADKEY_INT);
+ }
+ } else {
+ if (state == 1) {
+ /* press down */
+ code = key_scan(ad_val);
+ old_code = code;
+ input_report_key(ts->input_dev, code, 1);
+ //emily input_sync(ts->input_dev);
+ mod_timer(&ts->key_timer, jiffies + KEY_SCAN_INTERVAL);
+ } else {
+ /* up */
+ input_report_key(ts->input_dev, old_code, 0);
+ //emily input_sync(ts->input_dev);
+ udelay(1000);
+ __gpio_as_irq_rise_edge(GPIO_ADKEY_INT);
+ }
+ }
+}
+
+static irqreturn_t key_interrupt(int irq, void * dev_id)
+{
+ struct jz_ts_t *ts = dev_id;
+ DBG;
+ __gpio_ack_irq(GPIO_ADKEY_INT);
+ __gpio_as_input(GPIO_ADKEY_INT);
+ sadc_start_sadcin();
+ mod_timer(&ts->key_timer, jiffies + KEY_SCAN_INTERVAL);
+ return IRQ_HANDLED;
+}
+#endif
+
+/************************************************************************/
+/* Touch Screen module */
+/************************************************************************/
+
+#define TSMAXX 3920
+#define TSMAXY 3700
+#define TSMAXZ (1024) /* measure data */
+
+#define TSMINX 150
+#define TSMINY 270
+#define TSMINZ 0
+
+
+#define SCREEN_MAXX 1023
+#define SCREEN_MAXY 1023
+#define PRESS_MAXZ 256
+
+static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x )
+{
+/* Now we don't need u-boot to tell us the ts data. */
+/*
+ if (ts->minx)
+ {
+ if (x < ts->minx) x = ts->minx;
+ if (x > ts->maxx) x = ts->maxx;
+
+ return (x - ts->minx) * SCREEN_MAXX / (ts->maxx - ts->minx);
+ }
+ else
+ {
+*/
+ if (x < TSMINX) x = TSMINX;
+ if (x > TSMAXX) x = TSMAXX;
+
+ return (x - TSMINX) * SCREEN_MAXX / (TSMAXX - TSMINX);
+/*
+ }
+*/
+}
+
+static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y)
+{
+/* Now we don't need u-boot to tell us the ts data. */
+/*
+ if (ts->miny)
+ {
+ if (y < ts->miny) y = ts->miny;
+ if (y > ts->maxy) y = ts->maxy;
+
+ return (ts->maxy - y) * SCREEN_MAXY / (ts->maxy - ts->miny);
+ }
+ else
+ {
+*/
+ if (y < TSMINY) y = TSMINY;
+ if (y > TSMAXY) y = TSMAXY;
+
+ return (TSMAXY - y) * SCREEN_MAXY / (TSMAXY - TSMINY);
+/*
+ }
+*/
+}
+static unsigned long transform_to_screen_z(struct jz_ts_t *ts, unsigned long z){
+ if(z < TSMINZ) z = TSMINZ;
+ if (z > TSMAXY) z = TSMAXY;
+ return (TSMAXZ - z) * PRESS_MAXZ / (TSMAXZ - TSMINZ);
+}
+ /* R plane calibrate,please look up spec 11th page*/
+
+#define Yr_PLANE 272
+#define Xr_PLANE 480
+
+#define Touch_Formula_One(z1,z2,ref,r) ({ \
+ int z; \
+ if((z1) > 0){ \
+ z = ((ref) * (z2)) / (z1); \
+ if((z2) > (z1)) z = (z * r - (ref) * r) / (4096); \
+ else z = 0; \
+ }else \
+ z = 4095; \
+ z; \
+ })
+
+
+static int ts_data_filter(struct jz_ts_t *ts){
+ int i,xt = 0,yt = 0,zt1 = 0,zt2 = 0,zt3 = 0,zt4 = 0,t1_count = 0,t2_count = 0,z;
+
+ datasource_t *ds = &ts->data_s;
+ int t,xmin = 0x0fff,ymin = 0x0fff,xmax = 0,ymax = 0;//,z1min = 0xfff,z1max = 0,z2min = 0xfff,z2max = 0;
+
+ /* fifo high 16 bit = y,fifo low 16 bit = x */
+
+ for(i = 0;i < CAL_SAMPLE_TIMES;i++){
+
+ t = (ts->ts_fifo[0][i] & 0x0fff);
+#if (CAL_SAMPLE_TIMES >= 3)
+ if(t > xmax) xmax = t;
+ if(t < xmin) xmin = t;
+#endif
+ xt += t;
+ t = (ts->ts_fifo[0][i] >> 16) & 0x0fff;
+#if (CAL_SAMPLE_TIMES >= 3)
+ if(t > ymax) ymax = t;
+ if(t < ymin) ymin = t;
+#endif
+
+ yt += t;
+ if(ts->ts_fifo[1][i] & 0x8000)
+ {
+ t = (ts->ts_fifo[1][i] & 0x0fff);
+ zt1 += t;
+
+ t = (ts->ts_fifo[1][i] >> 16) & 0x0fff;
+ zt2 += t;
+
+ t1_count++;
+ }else
+ {
+ t = (ts->ts_fifo[1][i] & 0x0fff);
+ zt3 += t;
+
+ t = (ts->ts_fifo[1][i] >> 16) & 0x0fff;
+ zt4 += t;
+
+ t2_count++;
+ }
+ }
+#if (CAL_SAMPLE_TIMES >= 3)
+ xt = xt - xmin - xmax;
+ yt = yt - ymin - ymax;
+#endif
+
+ xt /= (CAL_SAMPLE_TIMES - 2);
+ yt /= (CAL_SAMPLE_TIMES - 2);
+ if(t1_count > 0)
+ {
+ zt1 /= t1_count;
+ zt2 /= t1_count;
+ zt1 = Touch_Formula_One(zt1,zt2,xt,Xr_PLANE);
+ }
+ if(t2_count)
+ {
+ zt3 /= t2_count;
+ zt4 /= t2_count;
+ zt3 = Touch_Formula_One(zt3,zt4,yt,Yr_PLANE);
+ }
+ if((t1_count) && (t2_count))
+ z = (zt1 + zt3) / 2;
+ else if(t1_count)
+ z = zt1;
+ else if(t2_count)
+ z = zt3;
+ else
+ z = 0;
+
+ ds->xbuf = xt;
+ ds->ybuf = yt;
+ ds->zbuf = z;
+ return 1;
+
+}
+static void ts_transform_data(struct jz_ts_t *ts){
+
+ struct ts_event *event = &ts->event;
+ // event->x = transform_to_screen_x(ts,ts->data_s.xbuf);
+ // event->y = transform_to_screen_y(ts,ts->data_s.ybuf);
+ // event->pressure = transform_to_screen_z(ts,ts->data_s.zbuf);
+ event->x =ts->data_s.xbuf;
+ event->y =ts->data_s.ybuf;
+ event->pressure =ts->data_s.zbuf;
+
+ if(event->pressure == 0) event->pressure = 1;
+}
+static void handle_ts_event(struct jz_ts_t *ts){
+ struct ts_event *event = &ts->event;
+
+ input_report_abs(ts->input_dev, ABS_X, event->x);
+ input_report_abs(ts->input_dev, ABS_Y, event->y);
+ input_report_abs(ts->input_dev, ABS_PRESSURE, event->pressure);
+
+// printk("event->x = %d,event->y = %d event->pressure = %d\n",event->x,event->y,event->pressure);
+
+ /* Android need it ... */
+ input_report_key(ts->input_dev, BTN_TOUCH, 1);
+
+ input_sync(ts->input_dev);
+
+}
+
+static void handle_touch(struct jz_ts_t *ts,unsigned int *data,int size){
+ /* drop no touch calibrate points */
+ if(ts->cal_type & (~TOUCH_TYPE))
+ ts->cal_type |= ~TOUCH_TYPE;
+ if(ts->event_valid){
+ handle_ts_event(ts);
+ ts->event_valid = 0;
+ }
+
+ if(ts->touch_cal_count >= DROP_SAMPLE_TIMES)
+ {
+ if(ts->touch_cal_count < SAMPLE_TIMES){
+ ts->ts_fifo[0][ts->touch_cal_count - DROP_SAMPLE_TIMES] = data[0];
+ ts->ts_fifo[1][ts->touch_cal_count - DROP_SAMPLE_TIMES] = data[1];
+ }else
+ {
+ /* drop sample*/
+ if(ts->cal_type & TOUCH_TYPE){
+ if(ts_data_filter(ts)){
+ ts->event_valid = 1;
+ ts_transform_data(ts);
+ }
+
+ }
+ ts->touch_cal_count = 0;
+ }
+ }
+ ts->touch_cal_count++;
+}
+
+static void handle_pbat(struct jz_ts_t *ts,unsigned int *fifo,int size){
+ ts->oldbat_value = (*fifo) & 0xfff; // max data = 4096
+ jz_ts->cal_type &= ~BAT_TYPE;
+ //printk("interrupt pbat v = %d\n",ts->oldbat_value);
+ REG_SADC_ENA &= ~SADC_ENA_PBATEN;
+}
+static void handle_sadc(struct jz_ts_t *ts,unsigned int *fifo,int size){
+
+}
+
+static irqreturn_t sadc_interrupt(int irq, void * dev_id)
+{
+ struct jz_ts_t *ts = dev_id;
+ unsigned int state;
+ unsigned int fifo[FIFO_MAX_SIZE];
+ static int pen_is_down = 0;
+
+ spin_lock_irq(&ts->lock);
+
+ state = REG_SADC_STATE & (~REG_SADC_CTRL);
+ /* first handle pen up interrupt */
+ if(state & SADC_STATE_PENU){
+ /* REG_SADC_CTRL used in pendown & penup mutex */
+
+ REG_SADC_CTRL |= SADC_CTRL_PENUM;
+ REG_SADC_CTRL &= ~SADC_CTRL_PENDM;
+
+ if(pen_is_down == 1)
+ {
+ /* mask pen up and wait pen down */
+ REG_SADC_CTRL |= SADC_CTRL_TSRDYM;
+ {
+ input_report_abs(ts->input_dev, ABS_PRESSURE, 0);
+ /* Android need it ... */
+ input_report_key(ts->input_dev, BTN_TOUCH, 0);
+ input_sync(ts->input_dev);
+ ts->cal_type &= ~TOUCH_TYPE;
+ ts->event_valid = 0;
+ }
+
+ }
+ pen_is_down = 0;
+ }else if(state & SADC_CTRL_PENDM){
+ /* REG_SADC_CTRL used in pendown & penup mutex */
+ REG_SADC_CTRL |= SADC_CTRL_PENDM;
+ REG_SADC_CTRL &= ~SADC_CTRL_PENUM;
+ REG_SADC_CTRL &= ~SADC_CTRL_TSRDYM;
+
+ if(pen_is_down == 0){
+ /* mask pen down and wait pen up */
+ pen_is_down = 1;
+ ts->event_valid = 0;
+ ts->cal_type |= TOUCH_TYPE;
+ ts->touch_cal_count = 0;
+ }
+ state |= SADC_STATE_PENU;
+ // state |= SADC_STATE_SLEEPND;
+ }else if(state & SADC_STATE_TSRDY){
+
+ fifo[0] = REG_SADC_TSDAT;
+ fifo[1] = REG_SADC_TSDAT;
+
+ /* alone here clear state */
+ REG_SADC_STATE = SADC_STATE_TSRDY;
+
+ if(pen_is_down)
+ handle_touch(ts,fifo,2);
+
+ }else if(state & SADC_STATE_PBATRDY){
+
+
+ fifo[0] = REG_SADC_BATDAT;
+ handle_pbat(ts,fifo,1);
+
+ }else if(state & SADC_STATE_SRDY){
+ /* no use */
+ fifo[0] = REG_SADC_SADDAT;
+ handle_sadc(ts,fifo,1);
+
+ }//else if(state & SADC_STATE_SLEEPND){
+ else if(state){
+ //after power will use
+ //REG_SADC_CTRL |= SADC_STATE_SLEEPND;
+
+ }
+ //when data count not is set_count penup is not clear;
+ if(!(state & SADC_STATE_TSRDY))
+ REG_SADC_STATE = state;
+ spin_unlock_irq(&ts->lock);
+
+ return IRQ_HANDLED;
+}
+
+#if 0
+static void jz_acq_timer(unsigned long data)
+{
+ struct jz_ts_t *ts = (struct jz_ts_t *)data;
+ spin_lock_irq(&ts->lock);
+ //printk("REG_SADC_CTRL = %x REG_SADC_ENA = %x REG_SADC_CFG = %x\n",REG_SADC_CTRL,REG_SADC_ENA,REG_SADC_CFG);
+ //printk("REG_SADC_STATE = %x REG_CPM_CLKGR = %x\n",REG_SADC_STATE,REG_CPM_CLKGR);
+ // schedule next acquire
+ ts->acq_timer.expires = jiffies + 100;//TS_SCAN_INTERVAL;
+ del_timer(&ts->acq_timer);
+ add_timer(&ts->acq_timer);
+ REG_CPM_CLKGR &= ~CPM_CLKGR_SADC;
+ spin_unlock_irq(&ts->lock);
+
+}
+#endif
+
+static int __init jz_ts_init(void)
+{
+ struct input_dev *input_dev;
+ struct jz_ts_t *ts;
+ int error;
+
+ DBG;
+ ts = jz_ts = kzalloc(sizeof(struct jz_ts_t), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ts || !input_dev)
+ return -ENOMEM;
+
+ input_dev->name = "qwerty"; /* Set to 'qwerty' to load /system/usr/keychars/qwerty.kcm.bin by Android */
+ input_dev->phys = ts->phys;
+
+
+
+/*
+ old:
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+*/
+
+ /* For Android */
+ set_bit(EV_ABS, input_dev->evbit);
+ set_bit(ABS_X, input_dev->absbit);
+ set_bit(ABS_Y, input_dev->absbit);
+ set_bit(ABS_PRESSURE, input_dev->absbit);
+ set_bit(EV_KEY, input_dev->evbit);
+ set_bit(BTN_TOUCH, input_dev->keybit);
+
+#ifdef CONFIG_JZ_ADKEY
+ set_bit(DPAD_CENTER, input_dev->keybit);
+ set_bit(DPAD_DOWN, input_dev->keybit);
+ set_bit(DPAD_UP, input_dev->keybit);
+ set_bit(DPAD_LEFT, input_dev->keybit);
+ set_bit(DPAD_RIGHT, input_dev->keybit);
+#endif
+ input_set_abs_params(input_dev, ABS_X, 0, SCREEN_MAXX + 1, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_MAXY + 1, 0, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, PRESS_MAXZ + 1, 0, 0);
+ input_set_drvdata(input_dev, ts);
+ error = input_register_device(input_dev);
+
+ strcpy(ts->phys, "input/ts0");
+ spin_lock_init(&ts->lock);
+
+ ts->input_dev = input_dev;
+#if 0
+ // Init ts acquisition timer function
+
+ init_timer(&ts->acq_timer);
+ ts->acq_timer.function = jz_acq_timer;
+ ts->acq_timer.data = (unsigned long)ts;
+ ts->irq_enabled = 1;
+ ts->acq_timer.expires = jiffies + 100;
+ add_timer(&ts->acq_timer);
+#endif
+ if (error) {
+ printk("Input device register failed !\n");
+ goto err_free_dev;
+ }
+
+ sadc_init_clock(6);
+ //ts_disable_pendown_irq();
+ //ts_disable_penup_irq();
+ REG_SADC_CTRL = 0x3f;
+
+ error = request_irq(IRQ_SADC, sadc_interrupt, IRQF_DISABLED, TS_NAME, ts);
+ if (error) {
+ pr_err("unable to get PenDown IRQ %d", IRQ_SADC);
+ goto err_free_irq;
+ }
+ ts->cal_type = 0;
+
+ ts->oldbat_value = 0xffffffff; //battery cal data first is invalid
+
+ DBG;
+#ifdef CONFIG_JZ_ADKEY
+ // Init key acquisition timer function
+ init_timer(&ts->key_timer);
+ ts->key_timer.function = key_timer_callback;
+ ts->key_timer.data = (unsigned long)ts;
+ ts->active_low = ACTIVE_LOW_ADKEY;
+
+ error = request_irq(IRQ_GPIO_0 + GPIO_ADKEY_INT, key_interrupt, IRQF_DISABLED, TS_NAME, ts);
+ if (error) {
+ pr_err("unable to get AD KEY IRQ %d", IRQ_GPIO_0 + GPIO_ADKEY_INT);
+ goto err_free_irq;
+ }
+
+ __gpio_disable_pull(GPIO_ADKEY_INT);
+ if(ts->active_low)
+ __gpio_as_irq_fall_edge(GPIO_ADKEY_INT);
+ else
+ __gpio_as_irq_rise_edge(GPIO_ADKEY_INT);
+
+#endif
+ sadc_start_ts();
+
+ printk("input: JZ Touch Screen registered.\n");
+
+ return 0;
+
+err_free_irq:
+ free_irq(IRQ_SADC, ts);
+#ifdef CONFIG_JZ_ADKEY
+ free_irq(IRQ_GPIO_0 + GPIO_ADKEY_INT, ts);
+#endif
+err_free_dev:
+ input_free_device(ts->input_dev);
+ kfree(ts);
+ return 0;
+}
+
+static void __exit jz_ts_exit(void)
+{
+
+ ts_disable_pendown_irq();
+ ts_disable_penup_irq();
+ sadc_disable_ts();
+ free_irq(IRQ_SADC, jz_ts);
+ input_unregister_device(jz_ts->input_dev);
+
+}
+
+module_init(jz_ts_init);
+module_exit(jz_ts_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("JZ TouchScreen Driver");
+MODULE_AUTHOR("Jason <xwang@ingenic.com>");
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index dcf9fa9264b..93a74b9292f 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -615,6 +615,24 @@ config VIDEO_VINO
Say Y here to build in support for the Vino video input system found
on SGI Indy machines.
+config VIDEO_JZ4730_CIM
+ tristate 'JzSOC Camera Interface Module (CIM) support'
+ depends on VIDEO_V4L2 && FB_JZSOC && SOC_JZ4730
+ select VIDEO_JZ_SENSOR
+
+config VIDEO_JZ4740_CIM
+ tristate 'JzSOC Camera Interface Module (CIM) support'
+ depends on VIDEO_V4L2 && FB_JZSOC && SOC_JZ4740
+ select VIDEO_JZ_SENSOR
+
+config VIDEO_JZ4750_CIM
+ tristate 'JzSOC Camera Interface Module (CIM) support'
+ depends on VIDEO_V4L2 && FB_JZSOC && (SOC_JZ4750 || SOC_JZ4750D)
+ select VIDEO_JZ_SENSOR
+
+config VIDEO_JZ_SENSOR
+ tristate "Jz generic camera sensor driver"
+
config VIDEO_STRADIS
tristate "Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)"
depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 9f2e3214a48..77a294482e8 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -80,6 +80,11 @@ obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
# And now the v4l2 drivers:
+obj-$(CONFIG_VIDEO_JZ4730_CIM) += jz4730_cim.o
+obj-$(CONFIG_VIDEO_JZ4740_CIM) += jz4740_cim.o
+obj-$(CONFIG_VIDEO_JZ4750_CIM) += jz4750_cim.o
+obj-$(CONFIG_VIDEO_JZ_SENSOR) += jz_sensor.o
+
obj-$(CONFIG_VIDEO_BT848) += bt8xx/
obj-$(CONFIG_VIDEO_ZORAN) += zoran/
obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
diff --git a/drivers/media/video/jz4730_cim.c b/drivers/media/video/jz4730_cim.c
new file mode 100644
index 00000000000..4ea05944783
--- /dev/null
+++ b/drivers/media/video/jz4730_cim.c
@@ -0,0 +1,622 @@
+/*
+ * linux/drivers/char/jzchar/cim.c
+ *
+ * Camera Interface Module (CIM) driver for JzSOC
+ * This driver is independent of the camera sensor
+ *
+ * Copyright (C) 2005 JunZheng semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+//#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+#include <asm/cacheflush.h>
+
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <linux/video_decoder.h>
+
+#define CIM_NAME "cim"
+
+MODULE_AUTHOR("Jianli Wei<jlwei@ingenic.cn>");
+MODULE_DESCRIPTION("JzSOC Camera Interface Module driver");
+MODULE_LICENSE("GPL");
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+/*
+ * Define the Max Image Size
+ */
+#define MAX_IMAGE_WIDTH 2048
+#define MAX_IMAGE_HEIGHT 2048
+#define MAX_IMAGE_BPP 16
+#define MAX_FRAME_SIZE (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP / 8)
+#define CIM_RAM_ADDR (CIM_BASE + 0x1000)
+
+typedef struct
+{
+ u32 width;
+ u32 height;
+ u32 bpp;
+} img_param_t;
+
+typedef struct
+{
+ u32 cfg;
+ u32 ctrl;
+ u32 mclk;
+} cim_config_t;
+
+/*
+ * IOCTL_XXX commands
+ */
+#define IOCTL_SET_IMG_PARAM 0 // arg type: img_param_t *
+#define IOCTL_CIM_CONFIG 1 // arg type: cim_config_t *
+#define IOCTL_STOP_CIM 2 // arg type: void
+#define IOCTL_GET_IMG_PARAM 3 // arg type: img_param_t *
+#define IOCTL_GET_CIM_CONFIG 4 // arg type: cim_config_t *
+#define IOCTL_TEST_CIM_RAM 5 // no arg type *
+
+/*
+ * CIM DMA descriptor
+ */
+struct cim_desc {
+ u32 nextdesc; /* Physical address of next desc */
+ u32 framebuf; /* Physical address of frame buffer */
+ u32 frameid; /* Frame ID */
+ u32 dmacmd; /* DMA command */
+ u32 pagenum;
+};
+
+/*
+ * CIM device structure
+ */
+struct cim_device {
+ struct video_device *jz_cim;
+ unsigned char *framebuf;
+ unsigned int frame_size;
+ unsigned int page_order;
+ wait_queue_head_t wait_queue;
+ struct cim_desc *frame_desc __attribute__ ((aligned (16)));
+};
+
+/* global*/
+static struct cim_device *cim_dev;
+
+/*==========================================================================
+ * CIM init routines
+ *========================================================================*/
+#if defined(CONFIG_SOC_JZ4750)
+static void cim_image_area(img_param_t *c) {
+ /*set the image data area start 0, 0, lines_per_frame and pixels_per_line*/
+ REG_CIM_SIZE = 0;
+ REG_CIM_OFFSET = 0;
+ if (REG_CIM_CTRL & CIM_CTRL_SIZEEN_MASK) {
+ REG_CIM_SIZE = (c->height << CIM_SIZE_LPF_BIT) | (c->width << CIM_SIZE_PPL_BIT);
+ REG_CIM_OFFSET = (0 << CIM_OFFSET_V_BIT) | (0 << CIM_OFFSET_H_BIT);
+// REG_CIM_OFFSET = (100 << CIM_OFFSET_V_BIT) | (50 << CIM_OFFSET_H_BIT);
+ }
+}
+#endif
+
+static void cim_config(cim_config_t *c)
+{
+ REG_CIM_CFG = c->cfg;
+ REG_CIM_CTRL = c->ctrl;
+
+ /*Set the master clock output*/
+#if defined(CONFIG_SOC_JZ4730)
+ __cim_set_master_clk(__cpm_get_sclk(), c->mclk);
+#elif defined(CONFIG_SOC_JZ4740)
+ __cim_set_master_clk(__cpm_get_hclk(), c->mclk);
+#elif defined(CONFIG_SOC_JZ4750)
+ __cim_set_master_clk(__cpm_get_hclk(), c->mclk);
+#else
+ __cim_set_master_clk(__cpm_get_hclk(), c->mclk);
+#endif
+ /* Enable sof, eof and stop interrupts*/
+ __cim_enable_sof_intr();
+ __cim_enable_eof_intr();
+ __cim_enable_stop_intr();
+}
+
+/*==========================================================================
+ * CIM start/stop operations
+ *========================================================================*/
+static int cim_start_dma(char *ubuf)
+{
+ struct cim_desc *jz_frame_desc;
+ int cim_frame_size = 0;
+ jz_frame_desc = cim_dev->frame_desc;
+ dprintk("framedesc = %x\n", (u32) jz_frame_desc);
+ __cim_disable();
+ dprintk("__cim_disable\n");
+ __cim_set_da(virt_to_phys(cim_dev->frame_desc));
+ __cim_clear_state(); // clear state register
+ __cim_reset_rxfifo(); // resetting rxfifo
+ __cim_unreset_rxfifo();
+ __cim_enable_dma(); // enable dma
+ __cim_enable();
+
+ dprintk("__cim_enable\n");
+// while(1) {
+// mdelay(10);
+// dprintk("REG_CIM_DA = 0x%08x\n", REG_CIM_DA);
+// dprintk("REG_CIM_FA = 0x%08x\n", REG_CIM_FA);
+// dprintk("REG_CIM_FID = 0x%08x\n", REG_CIM_FID);
+// dprintk("REG_CIM_CMD = 0x%08x\n", REG_CIM_CMD);
+// dprintk("REG_CIM_CFG = 0x%08x\n", REG_CIM_CFG);
+// dprintk("REG_CIM_STATE = 0x%08x\n", REG_CIM_STATE);
+// dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL);
+// dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE);
+// dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET);
+// mdelay(100);
+// }
+ // wait for interrupts
+ interruptible_sleep_on(&cim_dev->wait_queue);
+ dprintk("interruptible_sleep_on\n");
+ dprintk("REG_CIM_DA = 0x%08x\n", REG_CIM_DA);
+ dprintk("REG_CIM_FA = 0x%08x\n", REG_CIM_FA);
+ dprintk("REG_CIM_FID = 0x%08x\n", REG_CIM_FID);
+ dprintk("REG_CIM_CMD = 0x%08x\n", REG_CIM_CMD);
+ dprintk("REG_CIM_CFG = 0x%08x\n", REG_CIM_CFG);
+ dprintk("REG_CIM_STATE = 0x%08x\n", REG_CIM_STATE);
+ dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL);
+ dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE);
+ dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET);
+ dprintk("REG_CIM_CMD_3 = %x\n", REG_CIM_CMD);
+ dprintk("REG_CIM_FA = %x\n", REG_CIM_FA);
+ /* copy frame data to user buffer */
+ jz_frame_desc = cim_dev->frame_desc;
+
+ while(jz_frame_desc != NULL)
+ {
+ dprintk("ubuf = %x, framebuf = %x,frame_size= %d\n", (u32)ubuf,(u32) jz_frame_desc->framebuf, jz_frame_desc->dmacmd & 0xffffff);
+ memcpy(ubuf, phys_to_virt(jz_frame_desc->framebuf), ((jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4));
+ ubuf += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4;
+ cim_frame_size += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4;
+ jz_frame_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc);
+ }
+ return cim_dev->frame_size;
+}
+static void cim_stop(void)
+{
+ __cim_disable();
+ __cim_clear_state();
+}
+
+/*==========================================================================
+ * Framebuffer allocation and destroy
+ *========================================================================*/
+static void cim_fb_destroy(void)
+{
+ int pages;
+ struct cim_desc *jz_frame_desc, *p_desc;
+ if (cim_dev->frame_desc == NULL) {
+ printk("Original memory is NULL\n");
+ return;
+ }
+ jz_frame_desc = cim_dev->frame_desc;
+ while (jz_frame_desc != NULL) {
+ dprintk("framebuf = %x,thisdesc = %x,frame_size= %d\n", (u32) jz_frame_desc->framebuf, (unsigned int)jz_frame_desc, (jz_frame_desc->dmacmd & 0xffffff) * 4);
+ p_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc);
+ pages = jz_frame_desc->pagenum;
+ dprintk("page_order = %d\n", pages);
+ free_pages((unsigned long)phys_to_virt(jz_frame_desc->framebuf), pages);
+ kfree(jz_frame_desc);
+ jz_frame_desc = p_desc;
+ }
+ cim_dev->frame_desc = NULL;
+}
+
+static struct cim_desc *get_desc_list(int page_order)
+{
+ int num, page_nums = 0;
+ unsigned char *p_buf;
+ struct cim_desc *desc_list_head __attribute__ ((aligned (16)));
+ struct cim_desc *desc_list_tail __attribute__ ((aligned (16)));
+ struct cim_desc *p_desc;
+// num = page_order - 1;
+ num = page_order;
+ desc_list_head = desc_list_tail = NULL;
+
+ while(page_nums < (1 << page_order)) {
+ p_desc = (struct cim_desc *)kmalloc(sizeof(struct cim_desc), GFP_KERNEL);
+ if (NULL == p_desc)
+ return NULL;
+ //return -ENOMEM;
+ cim_realloc_pages:
+ p_buf = (unsigned char *)__get_free_pages(GFP_KERNEL, num);
+ if ( !(p_buf) && num != 0) {
+ num --;
+ goto cim_realloc_pages;
+ }
+ else if ( !(p_buf) && num == 0) {
+ printk("No memory can be alloc!\n");
+ //return -ENOMEM;
+ return NULL;
+ }
+ else {
+ if (desc_list_head == NULL) {
+ dprintk("Page_list_head\n");
+ desc_list_head = p_desc;
+ }
+
+ else
+ desc_list_tail->nextdesc = virt_to_phys(p_desc);
+
+ desc_list_tail = p_desc;
+ desc_list_tail->framebuf = virt_to_phys(p_buf);
+ dprintk("framebuf addr is 0x%08x\n", (u32)desc_list_tail->framebuf);
+ dprintk("frame_desc addr is 0x%08x\n",(u32)virt_to_phys(desc_list_tail));
+
+ desc_list_tail->frameid = 0x52052018;
+ desc_list_tail->pagenum = num;
+ if ((page_nums + (1<< num)) < (1 << page_order)) {
+ desc_list_tail->dmacmd = ((1 << num) * 4096) >> 2 ;
+ }
+ else
+ desc_list_tail->dmacmd =
+ (cim_dev->frame_size - page_nums * 4096) >> 2 ;
+ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd);
+ page_nums += (1 << num);
+ dprintk("the pages_num is %d\n", page_nums);
+ }
+ }
+
+ desc_list_tail->nextdesc = virt_to_phys(NULL);
+ /* stop after capturing a frame */
+ desc_list_tail->dmacmd |= (CIM_CMD_STOP | CIM_CMD_EOFINT);
+ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd);
+
+ return desc_list_head;
+}
+
+static int cim_fb_alloc(int img_width, int img_height, int img_bpp)
+{
+#if defined(CONFIG_SOC_JZ4750)
+ if ((REG_CIM_CFG & (CIM_CFG_DF_MASK | CIM_CFG_BYPASS_MASK)) == 0)
+ cim_dev->frame_size = img_width * (img_height-1) * (img_bpp/8);
+ else
+ cim_dev->frame_size = img_width * img_height * (img_bpp/8);
+#else
+ cim_dev->frame_size = img_width * img_height * (img_bpp/8);
+#endif
+ cim_dev->page_order = get_order(cim_dev->frame_size);
+ dprintk("cim_dev->page_order=%d\n", cim_dev->page_order);
+ /* frame buffer ?? need large mem ??*/
+ cim_dev->frame_desc = get_desc_list(cim_dev->page_order);
+ if (cim_dev->frame_desc == NULL)
+ return -ENOMEM;
+ dma_cache_wback((unsigned long)(cim_dev->frame_desc), 16);
+ return 0;
+}
+
+/*==========================================================================
+ * File operations
+ *========================================================================*/
+
+static int cim_open(struct inode *inode, struct file *filp);
+static int cim_release(struct inode *inode, struct file *filp);
+static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l);
+static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l);
+static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int cim_mmap(struct file *file, struct vm_area_struct *vma);
+
+static struct file_operations cim_fops =
+{
+ open: cim_open,
+ release: cim_release,
+ read: cim_read,
+ write: cim_write,
+ ioctl: cim_ioctl,
+ compat_ioctl: v4l_compat_ioctl32,
+ mmap: cim_mmap
+};
+
+static struct video_device jz_v4l_device = {
+ .name = "jz cim",
+ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE |
+ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY
+ .fops = &cim_fops,
+ .minor = -1,
+ .owner = THIS_MODULE,
+ .release = video_device_release,
+};
+
+static int cim_open(struct inode *inode, struct file *filp)
+{
+
+ try_module_get(THIS_MODULE);
+ return 0;
+}
+
+static int cim_release(struct inode *inode, struct file *filp)
+{
+ cim_fb_destroy();
+ cim_stop();
+
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l)
+{
+ if (size < cim_dev->frame_size)
+ return -EINVAL;
+ dprintk("read cim\n");
+ return cim_start_dma(buf);
+}
+
+static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l)
+{
+ printk("cim error: write is not implemented\n");
+ return -1;
+}
+
+static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ switch (cmd) {
+ case IOCTL_GET_IMG_PARAM:
+ {
+ img_param_t i;
+ return copy_to_user(argp, &i, sizeof(img_param_t)) ? -EFAULT : 0;
+ }
+ case IOCTL_SET_IMG_PARAM:
+ {
+ img_param_t i;
+ int img_width, img_height, img_bpp;
+ if (copy_from_user((void *)&i, (void *)arg, sizeof(img_param_t)))
+ return -EFAULT;
+#if defined(CONFIG_SOC_JZ4750)
+ cim_image_area(&i);
+#endif
+ img_width = i.width;
+ img_height = i.height;
+ img_bpp = i.bpp;
+ dprintk("ioctl_set_cim_param\n");
+ if ((img_width * img_height * img_bpp/8) > MAX_FRAME_SIZE){
+ printk("ERROR! Image is too large!\n");
+ return -EINVAL;
+ }
+ /* allocate frame buffers */
+ if (cim_dev->frame_desc == NULL){
+ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){
+ printk("ERROR! Init & alloc cim fail!\n");
+ return -ENOMEM;
+ }
+ }
+ else
+ if ((img_width * img_height * img_bpp/8) > cim_dev->frame_size){
+ /* realloc the buffer */
+ cim_fb_destroy();
+ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){
+ printk("ERRROR! Init & alloc cim fail!\n");
+ return -ENOMEM;
+ }
+ }
+ break;
+ }
+ case IOCTL_CIM_CONFIG:
+ {
+ cim_config_t c;
+
+ if (copy_from_user((void *)&c, (void *)arg, sizeof(cim_config_t)))
+ return -EFAULT;
+
+ cim_config(&c);
+
+ break;
+ }
+ case IOCTL_TEST_CIM_RAM:
+ {
+
+ int i;
+ volatile unsigned int *ptr;
+ ptr = (volatile unsigned int *)(CIM_RAM_ADDR);
+ printk("RAM test!\n");
+ printk("CIM_RAM_ADDR = 0x%08x\n", CIM_RAM_ADDR);
+ for (i = 0; i < 1024; ptr++, i++)
+ *ptr = i;
+ ptr = (volatile unsigned int *)(CIM_RAM_ADDR);
+ dma_cache_wback((unsigned long)CIM_RAM_ADDR,0xffc);
+
+ for (i = 0; i < 1024; i++) {
+ if (i != *ptr)
+ printk("*ptr!=i, *ptr=%d, i=%d\n", *ptr, i);
+ if (i%32 == 0) {
+ if (i%128 == 0)
+ printk("\n");
+ printk("*ptr=%04d, i=%04d | ", *ptr, i);
+ }
+ ptr++;
+ }
+ printk("\n");
+ break;
+ }
+ default:
+ printk("Not supported command: 0x%x\n", cmd);
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */
+static int cim_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ unsigned long start;
+ unsigned long off;
+ u32 len;
+
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
+
+ /* frame buffer memory */
+ start = cim_dev->frame_desc->framebuf;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + (cim_dev->frame_desc->dmacmd & CIM_CMD_LEN_MASK));
+ start &= PAGE_MASK;
+
+ if ((vma->vm_end - vma->vm_start + off) > len)
+ return -EINVAL;
+ off += start;
+
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ vma->vm_flags |= VM_IO;
+
+#if defined(CONFIG_MIPS32)
+ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
+// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NO_WA; /* WT cachable */
+ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
+#endif
+
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ vma->vm_flags |= VM_IO;
+ return -EAGAIN;
+
+ return 0;
+}
+/*==========================================================================
+ * Interrupt handler
+ *========================================================================*/
+
+static irqreturn_t cim_irq_handler(int irq, void *dev_id)
+{
+ u32 state = REG_CIM_STATE;
+ dprintk("REG_CIM_STATE = %x\n", REG_CIM_STATE);
+ dprintk("REG_CIM_CTRL = %x\n", REG_CIM_CTRL);
+#if 1
+ if (state & CIM_STATE_RXF_OF) {
+ dprintk("OverFlow interrupt!\n");
+ }
+#endif
+ if (state & CIM_STATE_DMA_EOF) {
+ dprintk("EOF interrupt!\n");
+ __cim_disable_dma();
+ __cim_disable();
+ wake_up_interruptible(&cim_dev->wait_queue);
+ dprintk("EOF interrupt wake up!\n");
+ }
+
+ if (state & CIM_STATE_DMA_STOP) {
+ // Got a frame, wake up wait routine
+ __cim_disable_dma();
+ __cim_disable();
+ dprintk("Stop interrupt!\n");
+ wake_up_interruptible(&cim_dev->wait_queue);
+ }
+#if 1
+ if (state & CIM_STATE_RXF_TRIG) {
+ dprintk("Trig!\n");
+ }
+#endif
+
+ /* clear status flags*/
+ REG_CIM_STATE = 0;
+ return IRQ_HANDLED;
+}
+
+static int v4l_device_init(void)
+{
+ cim_dev = kzalloc(sizeof(struct cim_device), GFP_KERNEL);
+ if (!cim_dev) return -ENOMEM;
+ cim_dev->jz_cim = video_device_alloc();
+ if (!cim_dev->jz_cim) {
+ return -ENOMEM;
+ }
+ memcpy(cim_dev->jz_cim, &jz_v4l_device, sizeof(struct video_device));
+ cim_dev->frame_desc = NULL;
+ cim_dev->frame_size = 0;
+ cim_dev->page_order = 0;
+ return 0;
+}
+/*==========================================================================
+ * Module init and exit
+ *========================================================================*/
+
+static int __init jz_cim_init(void)
+{
+ struct cim_device *dev;
+ int ret;
+ /* allocate device */
+ ret = v4l_device_init();
+ if (ret)
+ return ret;
+ /* record device */
+ dev = cim_dev;
+ init_waitqueue_head(&dev->wait_queue);
+
+ ret = video_register_device(dev->jz_cim, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ printk(KERN_ERR "CIM Video4Linux-device "
+ "registration failed\n");
+ return -EINVAL;
+ }
+
+ if (ret < 0) {
+ cim_fb_destroy();
+ kfree(dev);
+ return ret;
+ }
+
+ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED,
+ CIM_NAME, dev))) {
+ printk(KERN_ERR "request_irq return error, ret=%d\n", ret);
+ cim_fb_destroy();
+ kfree(dev);
+ printk(KERN_ERR "CIM could not get IRQ\n");
+ return ret;
+ }
+
+ printk("JzSOC Camera Interface Module (CIM) driver registered\n");
+
+ return 0;
+}
+
+static void __exit jz_cim_exit(void)
+{
+ free_irq(IRQ_CIM, cim_dev);
+ kfree(cim_dev);
+ video_unregister_device(cim_dev->jz_cim);
+}
+
+module_init(jz_cim_init);
+module_exit(jz_cim_exit);
diff --git a/drivers/media/video/jz4740_cim.c b/drivers/media/video/jz4740_cim.c
new file mode 100644
index 00000000000..4ea05944783
--- /dev/null
+++ b/drivers/media/video/jz4740_cim.c
@@ -0,0 +1,622 @@
+/*
+ * linux/drivers/char/jzchar/cim.c
+ *
+ * Camera Interface Module (CIM) driver for JzSOC
+ * This driver is independent of the camera sensor
+ *
+ * Copyright (C) 2005 JunZheng semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+//#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+#include <asm/cacheflush.h>
+
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <linux/video_decoder.h>
+
+#define CIM_NAME "cim"
+
+MODULE_AUTHOR("Jianli Wei<jlwei@ingenic.cn>");
+MODULE_DESCRIPTION("JzSOC Camera Interface Module driver");
+MODULE_LICENSE("GPL");
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+/*
+ * Define the Max Image Size
+ */
+#define MAX_IMAGE_WIDTH 2048
+#define MAX_IMAGE_HEIGHT 2048
+#define MAX_IMAGE_BPP 16
+#define MAX_FRAME_SIZE (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP / 8)
+#define CIM_RAM_ADDR (CIM_BASE + 0x1000)
+
+typedef struct
+{
+ u32 width;
+ u32 height;
+ u32 bpp;
+} img_param_t;
+
+typedef struct
+{
+ u32 cfg;
+ u32 ctrl;
+ u32 mclk;
+} cim_config_t;
+
+/*
+ * IOCTL_XXX commands
+ */
+#define IOCTL_SET_IMG_PARAM 0 // arg type: img_param_t *
+#define IOCTL_CIM_CONFIG 1 // arg type: cim_config_t *
+#define IOCTL_STOP_CIM 2 // arg type: void
+#define IOCTL_GET_IMG_PARAM 3 // arg type: img_param_t *
+#define IOCTL_GET_CIM_CONFIG 4 // arg type: cim_config_t *
+#define IOCTL_TEST_CIM_RAM 5 // no arg type *
+
+/*
+ * CIM DMA descriptor
+ */
+struct cim_desc {
+ u32 nextdesc; /* Physical address of next desc */
+ u32 framebuf; /* Physical address of frame buffer */
+ u32 frameid; /* Frame ID */
+ u32 dmacmd; /* DMA command */
+ u32 pagenum;
+};
+
+/*
+ * CIM device structure
+ */
+struct cim_device {
+ struct video_device *jz_cim;
+ unsigned char *framebuf;
+ unsigned int frame_size;
+ unsigned int page_order;
+ wait_queue_head_t wait_queue;
+ struct cim_desc *frame_desc __attribute__ ((aligned (16)));
+};
+
+/* global*/
+static struct cim_device *cim_dev;
+
+/*==========================================================================
+ * CIM init routines
+ *========================================================================*/
+#if defined(CONFIG_SOC_JZ4750)
+static void cim_image_area(img_param_t *c) {
+ /*set the image data area start 0, 0, lines_per_frame and pixels_per_line*/
+ REG_CIM_SIZE = 0;
+ REG_CIM_OFFSET = 0;
+ if (REG_CIM_CTRL & CIM_CTRL_SIZEEN_MASK) {
+ REG_CIM_SIZE = (c->height << CIM_SIZE_LPF_BIT) | (c->width << CIM_SIZE_PPL_BIT);
+ REG_CIM_OFFSET = (0 << CIM_OFFSET_V_BIT) | (0 << CIM_OFFSET_H_BIT);
+// REG_CIM_OFFSET = (100 << CIM_OFFSET_V_BIT) | (50 << CIM_OFFSET_H_BIT);
+ }
+}
+#endif
+
+static void cim_config(cim_config_t *c)
+{
+ REG_CIM_CFG = c->cfg;
+ REG_CIM_CTRL = c->ctrl;
+
+ /*Set the master clock output*/
+#if defined(CONFIG_SOC_JZ4730)
+ __cim_set_master_clk(__cpm_get_sclk(), c->mclk);
+#elif defined(CONFIG_SOC_JZ4740)
+ __cim_set_master_clk(__cpm_get_hclk(), c->mclk);
+#elif defined(CONFIG_SOC_JZ4750)
+ __cim_set_master_clk(__cpm_get_hclk(), c->mclk);
+#else
+ __cim_set_master_clk(__cpm_get_hclk(), c->mclk);
+#endif
+ /* Enable sof, eof and stop interrupts*/
+ __cim_enable_sof_intr();
+ __cim_enable_eof_intr();
+ __cim_enable_stop_intr();
+}
+
+/*==========================================================================
+ * CIM start/stop operations
+ *========================================================================*/
+static int cim_start_dma(char *ubuf)
+{
+ struct cim_desc *jz_frame_desc;
+ int cim_frame_size = 0;
+ jz_frame_desc = cim_dev->frame_desc;
+ dprintk("framedesc = %x\n", (u32) jz_frame_desc);
+ __cim_disable();
+ dprintk("__cim_disable\n");
+ __cim_set_da(virt_to_phys(cim_dev->frame_desc));
+ __cim_clear_state(); // clear state register
+ __cim_reset_rxfifo(); // resetting rxfifo
+ __cim_unreset_rxfifo();
+ __cim_enable_dma(); // enable dma
+ __cim_enable();
+
+ dprintk("__cim_enable\n");
+// while(1) {
+// mdelay(10);
+// dprintk("REG_CIM_DA = 0x%08x\n", REG_CIM_DA);
+// dprintk("REG_CIM_FA = 0x%08x\n", REG_CIM_FA);
+// dprintk("REG_CIM_FID = 0x%08x\n", REG_CIM_FID);
+// dprintk("REG_CIM_CMD = 0x%08x\n", REG_CIM_CMD);
+// dprintk("REG_CIM_CFG = 0x%08x\n", REG_CIM_CFG);
+// dprintk("REG_CIM_STATE = 0x%08x\n", REG_CIM_STATE);
+// dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL);
+// dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE);
+// dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET);
+// mdelay(100);
+// }
+ // wait for interrupts
+ interruptible_sleep_on(&cim_dev->wait_queue);
+ dprintk("interruptible_sleep_on\n");
+ dprintk("REG_CIM_DA = 0x%08x\n", REG_CIM_DA);
+ dprintk("REG_CIM_FA = 0x%08x\n", REG_CIM_FA);
+ dprintk("REG_CIM_FID = 0x%08x\n", REG_CIM_FID);
+ dprintk("REG_CIM_CMD = 0x%08x\n", REG_CIM_CMD);
+ dprintk("REG_CIM_CFG = 0x%08x\n", REG_CIM_CFG);
+ dprintk("REG_CIM_STATE = 0x%08x\n", REG_CIM_STATE);
+ dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL);
+ dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE);
+ dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET);
+ dprintk("REG_CIM_CMD_3 = %x\n", REG_CIM_CMD);
+ dprintk("REG_CIM_FA = %x\n", REG_CIM_FA);
+ /* copy frame data to user buffer */
+ jz_frame_desc = cim_dev->frame_desc;
+
+ while(jz_frame_desc != NULL)
+ {
+ dprintk("ubuf = %x, framebuf = %x,frame_size= %d\n", (u32)ubuf,(u32) jz_frame_desc->framebuf, jz_frame_desc->dmacmd & 0xffffff);
+ memcpy(ubuf, phys_to_virt(jz_frame_desc->framebuf), ((jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4));
+ ubuf += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4;
+ cim_frame_size += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4;
+ jz_frame_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc);
+ }
+ return cim_dev->frame_size;
+}
+static void cim_stop(void)
+{
+ __cim_disable();
+ __cim_clear_state();
+}
+
+/*==========================================================================
+ * Framebuffer allocation and destroy
+ *========================================================================*/
+static void cim_fb_destroy(void)
+{
+ int pages;
+ struct cim_desc *jz_frame_desc, *p_desc;
+ if (cim_dev->frame_desc == NULL) {
+ printk("Original memory is NULL\n");
+ return;
+ }
+ jz_frame_desc = cim_dev->frame_desc;
+ while (jz_frame_desc != NULL) {
+ dprintk("framebuf = %x,thisdesc = %x,frame_size= %d\n", (u32) jz_frame_desc->framebuf, (unsigned int)jz_frame_desc, (jz_frame_desc->dmacmd & 0xffffff) * 4);
+ p_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc);
+ pages = jz_frame_desc->pagenum;
+ dprintk("page_order = %d\n", pages);
+ free_pages((unsigned long)phys_to_virt(jz_frame_desc->framebuf), pages);
+ kfree(jz_frame_desc);
+ jz_frame_desc = p_desc;
+ }
+ cim_dev->frame_desc = NULL;
+}
+
+static struct cim_desc *get_desc_list(int page_order)
+{
+ int num, page_nums = 0;
+ unsigned char *p_buf;
+ struct cim_desc *desc_list_head __attribute__ ((aligned (16)));
+ struct cim_desc *desc_list_tail __attribute__ ((aligned (16)));
+ struct cim_desc *p_desc;
+// num = page_order - 1;
+ num = page_order;
+ desc_list_head = desc_list_tail = NULL;
+
+ while(page_nums < (1 << page_order)) {
+ p_desc = (struct cim_desc *)kmalloc(sizeof(struct cim_desc), GFP_KERNEL);
+ if (NULL == p_desc)
+ return NULL;
+ //return -ENOMEM;
+ cim_realloc_pages:
+ p_buf = (unsigned char *)__get_free_pages(GFP_KERNEL, num);
+ if ( !(p_buf) && num != 0) {
+ num --;
+ goto cim_realloc_pages;
+ }
+ else if ( !(p_buf) && num == 0) {
+ printk("No memory can be alloc!\n");
+ //return -ENOMEM;
+ return NULL;
+ }
+ else {
+ if (desc_list_head == NULL) {
+ dprintk("Page_list_head\n");
+ desc_list_head = p_desc;
+ }
+
+ else
+ desc_list_tail->nextdesc = virt_to_phys(p_desc);
+
+ desc_list_tail = p_desc;
+ desc_list_tail->framebuf = virt_to_phys(p_buf);
+ dprintk("framebuf addr is 0x%08x\n", (u32)desc_list_tail->framebuf);
+ dprintk("frame_desc addr is 0x%08x\n",(u32)virt_to_phys(desc_list_tail));
+
+ desc_list_tail->frameid = 0x52052018;
+ desc_list_tail->pagenum = num;
+ if ((page_nums + (1<< num)) < (1 << page_order)) {
+ desc_list_tail->dmacmd = ((1 << num) * 4096) >> 2 ;
+ }
+ else
+ desc_list_tail->dmacmd =
+ (cim_dev->frame_size - page_nums * 4096) >> 2 ;
+ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd);
+ page_nums += (1 << num);
+ dprintk("the pages_num is %d\n", page_nums);
+ }
+ }
+
+ desc_list_tail->nextdesc = virt_to_phys(NULL);
+ /* stop after capturing a frame */
+ desc_list_tail->dmacmd |= (CIM_CMD_STOP | CIM_CMD_EOFINT);
+ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd);
+
+ return desc_list_head;
+}
+
+static int cim_fb_alloc(int img_width, int img_height, int img_bpp)
+{
+#if defined(CONFIG_SOC_JZ4750)
+ if ((REG_CIM_CFG & (CIM_CFG_DF_MASK | CIM_CFG_BYPASS_MASK)) == 0)
+ cim_dev->frame_size = img_width * (img_height-1) * (img_bpp/8);
+ else
+ cim_dev->frame_size = img_width * img_height * (img_bpp/8);
+#else
+ cim_dev->frame_size = img_width * img_height * (img_bpp/8);
+#endif
+ cim_dev->page_order = get_order(cim_dev->frame_size);
+ dprintk("cim_dev->page_order=%d\n", cim_dev->page_order);
+ /* frame buffer ?? need large mem ??*/
+ cim_dev->frame_desc = get_desc_list(cim_dev->page_order);
+ if (cim_dev->frame_desc == NULL)
+ return -ENOMEM;
+ dma_cache_wback((unsigned long)(cim_dev->frame_desc), 16);
+ return 0;
+}
+
+/*==========================================================================
+ * File operations
+ *========================================================================*/
+
+static int cim_open(struct inode *inode, struct file *filp);
+static int cim_release(struct inode *inode, struct file *filp);
+static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l);
+static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l);
+static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int cim_mmap(struct file *file, struct vm_area_struct *vma);
+
+static struct file_operations cim_fops =
+{
+ open: cim_open,
+ release: cim_release,
+ read: cim_read,
+ write: cim_write,
+ ioctl: cim_ioctl,
+ compat_ioctl: v4l_compat_ioctl32,
+ mmap: cim_mmap
+};
+
+static struct video_device jz_v4l_device = {
+ .name = "jz cim",
+ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE |
+ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY
+ .fops = &cim_fops,
+ .minor = -1,
+ .owner = THIS_MODULE,
+ .release = video_device_release,
+};
+
+static int cim_open(struct inode *inode, struct file *filp)
+{
+
+ try_module_get(THIS_MODULE);
+ return 0;
+}
+
+static int cim_release(struct inode *inode, struct file *filp)
+{
+ cim_fb_destroy();
+ cim_stop();
+
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l)
+{
+ if (size < cim_dev->frame_size)
+ return -EINVAL;
+ dprintk("read cim\n");
+ return cim_start_dma(buf);
+}
+
+static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l)
+{
+ printk("cim error: write is not implemented\n");
+ return -1;
+}
+
+static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ switch (cmd) {
+ case IOCTL_GET_IMG_PARAM:
+ {
+ img_param_t i;
+ return copy_to_user(argp, &i, sizeof(img_param_t)) ? -EFAULT : 0;
+ }
+ case IOCTL_SET_IMG_PARAM:
+ {
+ img_param_t i;
+ int img_width, img_height, img_bpp;
+ if (copy_from_user((void *)&i, (void *)arg, sizeof(img_param_t)))
+ return -EFAULT;
+#if defined(CONFIG_SOC_JZ4750)
+ cim_image_area(&i);
+#endif
+ img_width = i.width;
+ img_height = i.height;
+ img_bpp = i.bpp;
+ dprintk("ioctl_set_cim_param\n");
+ if ((img_width * img_height * img_bpp/8) > MAX_FRAME_SIZE){
+ printk("ERROR! Image is too large!\n");
+ return -EINVAL;
+ }
+ /* allocate frame buffers */
+ if (cim_dev->frame_desc == NULL){
+ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){
+ printk("ERROR! Init & alloc cim fail!\n");
+ return -ENOMEM;
+ }
+ }
+ else
+ if ((img_width * img_height * img_bpp/8) > cim_dev->frame_size){
+ /* realloc the buffer */
+ cim_fb_destroy();
+ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){
+ printk("ERRROR! Init & alloc cim fail!\n");
+ return -ENOMEM;
+ }
+ }
+ break;
+ }
+ case IOCTL_CIM_CONFIG:
+ {
+ cim_config_t c;
+
+ if (copy_from_user((void *)&c, (void *)arg, sizeof(cim_config_t)))
+ return -EFAULT;
+
+ cim_config(&c);
+
+ break;
+ }
+ case IOCTL_TEST_CIM_RAM:
+ {
+
+ int i;
+ volatile unsigned int *ptr;
+ ptr = (volatile unsigned int *)(CIM_RAM_ADDR);
+ printk("RAM test!\n");
+ printk("CIM_RAM_ADDR = 0x%08x\n", CIM_RAM_ADDR);
+ for (i = 0; i < 1024; ptr++, i++)
+ *ptr = i;
+ ptr = (volatile unsigned int *)(CIM_RAM_ADDR);
+ dma_cache_wback((unsigned long)CIM_RAM_ADDR,0xffc);
+
+ for (i = 0; i < 1024; i++) {
+ if (i != *ptr)
+ printk("*ptr!=i, *ptr=%d, i=%d\n", *ptr, i);
+ if (i%32 == 0) {
+ if (i%128 == 0)
+ printk("\n");
+ printk("*ptr=%04d, i=%04d | ", *ptr, i);
+ }
+ ptr++;
+ }
+ printk("\n");
+ break;
+ }
+ default:
+ printk("Not supported command: 0x%x\n", cmd);
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */
+static int cim_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ unsigned long start;
+ unsigned long off;
+ u32 len;
+
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
+
+ /* frame buffer memory */
+ start = cim_dev->frame_desc->framebuf;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + (cim_dev->frame_desc->dmacmd & CIM_CMD_LEN_MASK));
+ start &= PAGE_MASK;
+
+ if ((vma->vm_end - vma->vm_start + off) > len)
+ return -EINVAL;
+ off += start;
+
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ vma->vm_flags |= VM_IO;
+
+#if defined(CONFIG_MIPS32)
+ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
+// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NO_WA; /* WT cachable */
+ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
+#endif
+
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ vma->vm_flags |= VM_IO;
+ return -EAGAIN;
+
+ return 0;
+}
+/*==========================================================================
+ * Interrupt handler
+ *========================================================================*/
+
+static irqreturn_t cim_irq_handler(int irq, void *dev_id)
+{
+ u32 state = REG_CIM_STATE;
+ dprintk("REG_CIM_STATE = %x\n", REG_CIM_STATE);
+ dprintk("REG_CIM_CTRL = %x\n", REG_CIM_CTRL);
+#if 1
+ if (state & CIM_STATE_RXF_OF) {
+ dprintk("OverFlow interrupt!\n");
+ }
+#endif
+ if (state & CIM_STATE_DMA_EOF) {
+ dprintk("EOF interrupt!\n");
+ __cim_disable_dma();
+ __cim_disable();
+ wake_up_interruptible(&cim_dev->wait_queue);
+ dprintk("EOF interrupt wake up!\n");
+ }
+
+ if (state & CIM_STATE_DMA_STOP) {
+ // Got a frame, wake up wait routine
+ __cim_disable_dma();
+ __cim_disable();
+ dprintk("Stop interrupt!\n");
+ wake_up_interruptible(&cim_dev->wait_queue);
+ }
+#if 1
+ if (state & CIM_STATE_RXF_TRIG) {
+ dprintk("Trig!\n");
+ }
+#endif
+
+ /* clear status flags*/
+ REG_CIM_STATE = 0;
+ return IRQ_HANDLED;
+}
+
+static int v4l_device_init(void)
+{
+ cim_dev = kzalloc(sizeof(struct cim_device), GFP_KERNEL);
+ if (!cim_dev) return -ENOMEM;
+ cim_dev->jz_cim = video_device_alloc();
+ if (!cim_dev->jz_cim) {
+ return -ENOMEM;
+ }
+ memcpy(cim_dev->jz_cim, &jz_v4l_device, sizeof(struct video_device));
+ cim_dev->frame_desc = NULL;
+ cim_dev->frame_size = 0;
+ cim_dev->page_order = 0;
+ return 0;
+}
+/*==========================================================================
+ * Module init and exit
+ *========================================================================*/
+
+static int __init jz_cim_init(void)
+{
+ struct cim_device *dev;
+ int ret;
+ /* allocate device */
+ ret = v4l_device_init();
+ if (ret)
+ return ret;
+ /* record device */
+ dev = cim_dev;
+ init_waitqueue_head(&dev->wait_queue);
+
+ ret = video_register_device(dev->jz_cim, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ printk(KERN_ERR "CIM Video4Linux-device "
+ "registration failed\n");
+ return -EINVAL;
+ }
+
+ if (ret < 0) {
+ cim_fb_destroy();
+ kfree(dev);
+ return ret;
+ }
+
+ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED,
+ CIM_NAME, dev))) {
+ printk(KERN_ERR "request_irq return error, ret=%d\n", ret);
+ cim_fb_destroy();
+ kfree(dev);
+ printk(KERN_ERR "CIM could not get IRQ\n");
+ return ret;
+ }
+
+ printk("JzSOC Camera Interface Module (CIM) driver registered\n");
+
+ return 0;
+}
+
+static void __exit jz_cim_exit(void)
+{
+ free_irq(IRQ_CIM, cim_dev);
+ kfree(cim_dev);
+ video_unregister_device(cim_dev->jz_cim);
+}
+
+module_init(jz_cim_init);
+module_exit(jz_cim_exit);
diff --git a/drivers/media/video/jz4750_cim.c b/drivers/media/video/jz4750_cim.c
new file mode 100644
index 00000000000..7edf285b0ca
--- /dev/null
+++ b/drivers/media/video/jz4750_cim.c
@@ -0,0 +1,734 @@
+/*
+ * linux/drivers/char/jzchar/cim.c
+ *
+ * Camera Interface Module (CIM) driver for JzSOC
+ * This driver is independent of the camera sensor
+ *
+ * Copyright (C) 2005 JunZheng semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+//#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+#include <asm/cacheflush.h>
+
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <linux/video_decoder.h>
+
+#include "jz4750_cim.h"
+
+#define CIM_NAME "cim"
+
+MODULE_AUTHOR("Jianli Wei<jlwei@ingenic.cn>");
+MODULE_DESCRIPTION("JzSOC Camera Interface Module driver");
+MODULE_LICENSE("GPL");
+
+#if defined(CONFIG_SOC_JZ4750D)
+//#define USE_CIM_OFRCV 1 /* Test overflow recovery */
+#define USE_CIM_DMA_SYNC 1 //set da every time
+#endif
+
+//#define CIM_DEBUG
+#undef CIM_DEBUG
+#ifdef CIM_DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+/*
+ * Define the Max Image Size
+ */
+#define MAX_IMAGE_WIDTH 2048
+#define MAX_IMAGE_HEIGHT 2048
+#define MAX_IMAGE_BPP 16
+#define MAX_FRAME_SIZE (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP / 8)
+#define CIM_RAM_ADDR (CIM_BASE + 0x1000)
+
+typedef struct
+{
+ u32 width;
+ u32 height;
+ u32 bpp;
+} img_param_t;
+
+typedef struct
+{
+ u32 cfg;
+ u32 ctrl;
+ u32 mclk;
+ u32 size;
+ u32 offs;
+} cim_config_t;
+
+/*
+ * IOCTL_XXX commands
+ */
+#define IOCTL_SET_IMG_PARAM 0 // arg type: img_param_t *
+#define IOCTL_CIM_CONFIG 1 // arg type: cim_config_t *
+#define IOCTL_STOP_CIM 2 // arg type: void
+#define IOCTL_GET_IMG_PARAM 3 // arg type: img_param_t *
+#define IOCTL_GET_CIM_CONFIG 4 // arg type: cim_config_t *
+#define IOCTL_TEST_CIM_RAM 5 // no arg type *
+#define IOCTL_START_CIM 6 // arg type: void
+
+/*
+ * CIM DMA descriptor
+ */
+struct cim_desc {
+ u32 nextdesc; /* Physical address of next desc */
+ u32 framebuf; /* Physical address of frame buffer */
+ u32 frameid; /* Frame ID */
+ u32 dmacmd; /* DMA command */
+ u32 pagenum;
+};
+
+/*
+ * CIM device structure
+ */
+struct cim_device {
+ struct video_device *jz_cim;
+ unsigned char *framebuf;
+ unsigned int frame_size;
+ unsigned int page_order;
+ wait_queue_head_t wait_queue;
+ struct cim_desc *frame_desc __attribute__ ((aligned (16)));
+};
+
+/* global*/
+static struct cim_device *cim_dev;
+static int start_init = 1;
+static int irq_sleep;
+/*==========================================================================
+ * CIM init routines
+ *========================================================================*/
+
+static void cim_image_area(img_param_t *c) {
+ /*set the image data area start 0, 0, lines_per_frame and pixels_per_line*/
+ REG_CIM_SIZE = 0;
+ REG_CIM_OFFSET = 0;
+#if defined(CONFIG_SOC_JZ4750D)
+ if (REG_CIM_CTRL & CIM_CTRL_WIN_EN) {
+ REG_CIM_SIZE = (c->height << CIM_SIZE_LPF_BIT) | (c->width << CIM_SIZE_PPL_BIT);
+// REG_CIM_OFFSET = (0 << CIM_OFFSET_V_BIT) | (0 << CIM_OFFSET_H_BIT);
+// REG_CIM_OFFSET = (100 << CIM_OFFSET_V_BIT) | (50 << CIM_OFFSET_H_BIT);
+ REG_CIM_OFFSET = (200 << CIM_OFFSET_V_BIT) | (300 << CIM_OFFSET_H_BIT);
+ }
+#endif
+}
+
+
+static void cim_config(cim_config_t *c)
+{
+ REG_CIM_CFG = c->cfg;
+ REG_CIM_CTRL = c->ctrl;
+ REG_CIM_SIZE = c->size;
+ REG_CIM_OFFSET = c->offs;
+
+ dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE);
+ dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET);
+ /* Set the master clock output */
+ /* If use pll clock, enable it */
+// __cim_set_master_clk(__cpm_get_hclk(), c->mclk);
+
+ /* Enable sof, eof and stop interrupts*/
+
+// __cim_enable_sof_intr();
+ __cim_enable_eof_intr();
+#if defined(USE_CIM_EEOFINT)
+ __cim_enable_eeof_intr();
+#endif
+// __cim_enable_stop_intr();
+// __cim_enable_trig_intr();
+// __cim_enable_rxfifo_overflow_intr();
+// __cim_enable_vdd_intr();
+// printk("hclk=%d, mclk = %d\n", __cpm_get_hclk(),c->mclk);
+ dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL);
+}
+
+/*==========================================================================
+ * CIM start/stop operations
+ *========================================================================*/
+static int cim_start_dma(char *ubuf)
+{
+
+ struct cim_desc *jz_frame_desc;
+ int cim_frame_size = 0;
+ dprintk("==========start_init = %d\n", start_init);
+ __cim_disable();
+ __cim_set_da(virt_to_phys(cim_dev->frame_desc));
+ __cim_clear_state(); // clear state register
+ __cim_reset_rxfifo(); // resetting rxfifo
+ __cim_unreset_rxfifo();
+ __cim_enable_dma(); // enable dma
+ __cim_enable();
+ interruptible_sleep_on(&cim_dev->wait_queue);
+
+#if 1
+ dprintk("interruptible_sleep_on\n");
+ dprintk("REG_CIM_DA = 0x%08x\n", REG_CIM_DA);
+ dprintk("REG_CIM_FA = 0x%08x\n", REG_CIM_FA);
+ dprintk("REG_CIM_FID = 0x%08x\n", REG_CIM_FID);
+ dprintk("REG_CIM_CMD = 0x%08x\n", REG_CIM_CMD);
+ dprintk("REG_CIM_CFG = 0x%08x\n", REG_CIM_CFG);
+ dprintk("REG_CIM_STATE = 0x%08x\n", REG_CIM_STATE);
+ dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL);
+ dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE);
+ dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET);
+ dprintk("REG_CIM_CMD_3 = %x\n", REG_CIM_CMD);
+ dprintk("REG_CIM_FA = %x\n", REG_CIM_FA);
+#endif
+ /* copy frame data to user buffer */
+#if 0
+ jz_frame_desc = cim_dev->frame_desc;
+
+ while (jz_frame_desc != NULL)
+ {
+ dprintk("ubuf = %x, framebuf = %x,frame_size= %d\n", (u32)ubuf,(u32) jz_frame_desc->framebuf, jz_frame_desc->dmacmd & 0xffffff);
+ memcpy(ubuf, phys_to_virt(jz_frame_desc->framebuf), ((jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4));
+ ubuf += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4;
+ cim_frame_size += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4;
+ jz_frame_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc);
+ }
+#endif
+ dprintk("---------**********-----\n");
+ return cim_dev->frame_size;
+}
+static void cim_stop(void)
+{
+ __cim_disable();
+ __cim_clear_state();
+}
+
+/*==========================================================================
+ * Framebuffer allocation and destroy
+ *========================================================================*/
+static void cim_fb_destroy(void)
+{
+ int pages;
+ struct cim_desc *jz_frame_desc, *p_desc;
+ __cim_disable_dma();
+ __cim_disable();
+
+ dprintk("cim_dev->frame_desc = %x\n", (u32)cim_dev->frame_desc);
+ if (cim_dev->frame_desc == NULL) {
+ printk("Original memory is NULL\n");
+ return;
+ }
+ jz_frame_desc = cim_dev->frame_desc;
+// while (jz_frame_desc != NULL) {
+// while (jz_frame_desc != cim_dev->frame_desc) {
+ dprintk("framebuf = %x,thisdesc = %x,frame_size= %d\n", (u32) jz_frame_desc->framebuf, (unsigned int)jz_frame_desc, (jz_frame_desc->dmacmd & 0xffffff) * 4);
+ p_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc);
+ pages = jz_frame_desc->pagenum;
+ dprintk("page_order = %d\n", pages);
+ free_pages((unsigned long)phys_to_virt(jz_frame_desc->framebuf), pages);
+ kfree(jz_frame_desc);
+ jz_frame_desc = p_desc;
+// }
+ cim_dev->frame_desc = NULL;
+ start_init = 1;
+}
+
+static struct cim_desc *get_desc_list(int page_order)
+{
+ int num, page_nums = 0;
+ unsigned char *p_buf;
+ struct cim_desc *desc_list_head __attribute__ ((aligned (16)));
+ struct cim_desc *desc_list_tail __attribute__ ((aligned (16)));
+ struct cim_desc *p_desc;
+// num = page_order - 1;
+ num = page_order;
+ desc_list_head = desc_list_tail = NULL;
+
+ while(page_nums < (1 << page_order)) {
+ p_desc = (struct cim_desc *)kmalloc(sizeof(struct cim_desc), GFP_KERNEL);
+ if (NULL == p_desc)
+ return NULL;
+ //return -ENOMEM;
+ cim_realloc_pages:
+ p_buf = (unsigned char *)__get_free_pages(GFP_KERNEL, num);
+ if ( !(p_buf) && num != 0) {
+ num --;
+ goto cim_realloc_pages;
+ }
+ else if ( !(p_buf) && num == 0) {
+ printk("No memory can be alloc!\n");
+ //return -ENOMEM;
+ return NULL;
+ }
+ else {
+ if (desc_list_head == NULL) {
+ dprintk("Page_list_head\n");
+ desc_list_head = p_desc;
+ }
+
+ else
+ desc_list_tail->nextdesc = virt_to_phys(p_desc);
+
+ desc_list_tail = p_desc;
+ desc_list_tail->framebuf = virt_to_phys(p_buf);
+ dprintk("framebuf addr is 0x%08x\n", (u32)desc_list_tail->framebuf);
+ dprintk("frame_desc addr is 0x%08x\n",(u32)virt_to_phys(desc_list_tail));
+
+ desc_list_tail->frameid = 0x52052018;
+ desc_list_tail->pagenum = num;
+ if ((page_nums + (1<< num)) < (1 << page_order)) {
+ desc_list_tail->dmacmd = ((1 << num) * 4096) >> 2 ;
+ }
+ else
+ desc_list_tail->dmacmd =
+ (cim_dev->frame_size - page_nums * 4096) >> 2 ;
+ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd);
+ page_nums += (1 << num);
+ dprintk("the pages_num is %d\n", page_nums);
+ dma_cache_wback((unsigned long)(desc_list_tail), 16);
+ }
+ }
+
+// desc_list_tail->nextdesc = virt_to_phys(NULL);
+ desc_list_tail->nextdesc = virt_to_phys(desc_list_head);
+ desc_list_tail->dmacmd |= CIM_CMD_EOFINT;
+#if defined(CONFIG_SOC_JZ4750D)
+#if defined(USE_CIM_OFRCV)
+ desc_list_tail->dmacmd |= (CIM_CMD_EOFINT | CIM_CMD_OFRCV);
+#endif
+#if defined(USE_CIM_DMA_SYNC) /* wake ervry time */
+ desc_list_tail->nextdesc = virt_to_phys(NULL);
+ desc_list_tail->dmacmd |= (CIM_CMD_STOP | CIM_CMD_EOFINT | CIM_CMD_OFRCV);
+#endif
+#if defined(USE_CIM_EEOFINT)
+// desc_list_tail->dmacmd |= CIM_CMD_EEOFINT;
+ desc_list_tail->dmacmd |= (CIM_CMD_STOP | CIM_CMD_EOFINT | CIM_CMD_EEOFINT);
+#endif
+#endif
+ /* stop after capturing a frame */
+// desc_list_tail->dmacmd |= (CIM_CMD_STOP | CIM_CMD_EOFINT | CIM_CMD_SOFINT);
+
+
+
+
+ dma_cache_wback((unsigned long)(desc_list_tail), 16);
+ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd);
+
+ return desc_list_head;
+}
+
+static int cim_fb_alloc(int img_width, int img_height, int img_bpp)
+{
+ if ((REG_CIM_CFG & (CIM_CFG_DF_MASK | CIM_CFG_BYPASS_MASK)) == 0)
+ cim_dev->frame_size = img_width * (img_height-1) * (img_bpp/8);
+ else
+ cim_dev->frame_size = img_width * img_height * (img_bpp/8);
+
+ cim_dev->page_order = get_order(cim_dev->frame_size);
+ dprintk("cim_dev->page_order=%d\n", cim_dev->page_order);
+ /* frame buffer ?? need large mem ??*/
+ cim_dev->frame_desc = get_desc_list(cim_dev->page_order);
+ if (cim_dev->frame_desc == NULL)
+ return -ENOMEM;
+ dma_cache_wback((unsigned long)(cim_dev->frame_desc), 16);
+ return 0;
+}
+
+/*==========================================================================
+ * File operations
+ *========================================================================*/
+
+static int cim_open(struct inode *inode, struct file *filp);
+static int cim_release(struct inode *inode, struct file *filp);
+static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l);
+static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l);
+static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int cim_mmap(struct file *file, struct vm_area_struct *vma);
+
+static struct file_operations cim_fops =
+{
+ open: cim_open,
+ release: cim_release,
+ read: cim_read,
+ write: cim_write,
+ ioctl: cim_ioctl,
+ compat_ioctl: v4l_compat_ioctl32,
+ mmap: cim_mmap
+};
+
+static struct video_device jz_v4l_device = {
+ .name = "jz cim",
+ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE |
+ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY
+ .fops = &cim_fops,
+ .minor = -1,
+ .owner = THIS_MODULE,
+ .release = video_device_release,
+};
+
+static int cim_open(struct inode *inode, struct file *filp)
+{
+
+ try_module_get(THIS_MODULE);
+ return 0;
+}
+
+static int cim_release(struct inode *inode, struct file *filp)
+{
+ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
+ cim_fb_destroy();
+ cim_stop();
+
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l)
+{
+ printk("============cim error: write is not implemented\n");
+ if (size < cim_dev->frame_size)
+ return -EINVAL;
+ return cim_start_dma(buf);
+}
+
+static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l)
+{
+ printk("cim error: write is not implemented\n");
+ return -1;
+}
+
+static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ switch (cmd) {
+ case IOCTL_GET_IMG_PARAM:
+ {
+ unsigned int i;
+ i = cim_dev->frame_desc->framebuf;
+// printk("cim_dev->frame_desc->framebuf = 0x%08x\n", cim_dev->frame_desc->framebuf);
+ dprintk("&&cim_dev->frame_desc->framebuf = 0x%08x\n", i);
+
+ return copy_to_user(argp, &i, sizeof(unsigned int)) ? -EFAULT : 0;
+ }
+ case IOCTL_STOP_CIM:
+ {
+ __cim_disable_dma(); // enable dma
+ __cim_disable();
+
+// cim_fb_destroy();
+ return 0;
+ }
+ case IOCTL_START_CIM:
+ {
+ __cim_set_da(virt_to_phys(cim_dev->frame_desc));
+ __cim_clear_state(); // clear state register
+ __cim_reset_rxfifo(); // resetting rxfifo
+ __cim_unreset_rxfifo();
+ __cim_enable_dma(); // enable dma
+ __cim_enable();
+ return 0;
+ }
+ case IOCTL_SET_IMG_PARAM:
+ {
+ img_param_t i;
+ int img_width, img_height, img_bpp;
+ if (copy_from_user((void *)&i, (void *)arg, sizeof(img_param_t)))
+ return -EFAULT;
+ img_width = i.width;
+ img_height = i.height;
+ img_bpp = i.bpp;
+ printk("ALLOC =========\n");
+ if ((img_width * img_height * img_bpp/8) > MAX_FRAME_SIZE){
+ printk("ERROR! Image is too large!\n");
+ return -EINVAL;
+ }
+ /* allocate frame buffers */
+ if (cim_dev->frame_desc == NULL){
+ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){
+ printk("ERROR! Init & alloc cim fail!\n");
+ return -ENOMEM;
+ }
+ }
+ else
+ if ((img_width * img_height * img_bpp/8) > cim_dev->frame_size){
+ /* realloc the buffer */
+ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
+ cim_fb_destroy();
+ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){
+ printk("ERRROR! Init & alloc cim fail!\n");
+ return -ENOMEM;
+ }
+ }
+ break;
+ }
+ case IOCTL_CIM_CONFIG:
+ {
+ cim_config_t c;
+
+ if (copy_from_user((void *)&c, (void *)arg, sizeof(cim_config_t)))
+ return -EFAULT;
+ cim_config(&c);
+
+ break;
+ }
+ case IOCTL_TEST_CIM_RAM:
+ {
+
+ int i;
+ volatile unsigned int *ptr;
+ ptr = (volatile unsigned int *)(CIM_RAM_ADDR);
+ dprintk("RAM test!\n");
+ dprintk("CIM_RAM_ADDR = 0x%08x\n", CIM_RAM_ADDR);
+ for (i = 0; i < 1024; ptr++, i++)
+ *ptr = i;
+ ptr = (volatile unsigned int *)(CIM_RAM_ADDR);
+ dma_cache_wback((unsigned long)CIM_RAM_ADDR,0xffc);
+
+ for (i = 0; i < 1024; i++) {
+ if (i != *ptr)
+ dprintk("*ptr!=i, *ptr=%d, i=%d\n", *ptr, i);
+ if (i%32 == 0) {
+ if (i%128 == 0)
+ dprintk("\n");
+ dprintk("*ptr=%04d, i=%04d | ", *ptr, i);
+ }
+ ptr++;
+ }
+ dprintk("\n");
+ break;
+ }
+ default:
+ printk("Not supported command: 0x%x\n", cmd);
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */
+static int cim_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ unsigned long start;
+ unsigned long off;
+ u32 len;
+
+ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
+ off = vma->vm_pgoff << PAGE_SHIFT;
+
+ /* frame buffer memory */
+ start = cim_dev->frame_desc->framebuf;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + (cim_dev->frame_desc->dmacmd & CIM_CMD_LEN_MASK)*4);
+ start &= PAGE_MASK;
+ printk("vma->vm_end = 0x%08lx,\nvma->vm_start = 0x%08lx,\noff = 0x%08lx,\n len = 0x%08x\n\n", vma->vm_end, vma->vm_start, off, len);
+ if ((vma->vm_end - vma->vm_start + off) > len) {
+ printk("Error: vma is larger than memory length\n");
+ return -EINVAL;
+ }
+ off += start;
+
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ vma->vm_flags |= VM_IO;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Uncacheable */
+
+#if defined(CONFIG_MIPS32)
+ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
+ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; /* Uncacheable */
+#endif
+
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ return -EAGAIN;
+ }
+ return 0;
+}
+/*==========================================================================
+ * Interrupt handler
+ *========================================================================*/
+
+static irqreturn_t cim_irq_handler(int irq, void *dev_id)
+{
+ u32 state = REG_CIM_STATE;
+ dprintk("REG_CIM_STATE = %x\n", REG_CIM_STATE);
+ dprintk("IRQ:REG_CIM_CTRL = %x\n", REG_CIM_CTRL);
+
+#if 0 //sof
+ /* recommed don't open it */
+ if ((REG_CIM_CTRL & CIM_CTRL_DMA_SOFM) && (state & CIM_STATE_DMA_SOF)) {
+ dprintk("SOF interrupt!\n");
+ REG_CIM_STATE &= ~CIM_STATE_DMA_SOF;
+ }
+#endif
+#if 0 //eeof
+ if ((REG_CIM_CTRL & CIM_CTRL_DMA_EEOFM) && (state & CIM_STATE_DMA_EEOF)) {
+ dprintk("EEOF interrupt!\n");
+ __cim_disable_dma();
+ __cim_disable();
+ wake_up_interruptible(&cim_dev->wait_queue);
+ REG_CIM_STATE &= ~CIM_STATE_DMA_EEOF;
+ }
+#endif
+
+#if 1 //eof
+ if ((REG_CIM_CTRL & CIM_CTRL_DMA_EOFM) && (state & CIM_STATE_DMA_EOF)) {
+// if (state & CIM_STATE_DMA_EOF) {
+ dprintk("EOF interrupt!\n");
+
+#if defined(USE_CIM_DMA_SYNC) /* wake ervry time */
+// __cim_disable_dma();
+// __cim_disable();
+ wake_up_interruptible(&cim_dev->wait_queue);
+#else
+// if(irq_sleep == 1)
+ wake_up_interruptible(&cim_dev->wait_queue);
+#endif
+ REG_CIM_STATE &= ~CIM_STATE_DMA_EOF;
+ return IRQ_HANDLED;
+ }
+#endif
+#if 0 //overflow
+ if (state & CIM_STATE_RXF_OF) {
+ printk("OverFlow interrupt!\n");
+ REG_CIM_STATE &= ~CIM_STATE_RXF_OF;
+// dprintk("REG_CIM_STATE = %x\n", REG_CIM_STATE);
+ return IRQ_HANDLED;
+ }
+#endif
+#if 1 // stop
+ if ((REG_CIM_CTRL & CIM_CTRL_DMA_STOPM) && (state & CIM_STATE_DMA_STOP)) {
+ // Got a frame, wake up wait routine
+//#if defined(USE_CIM_DMA_SYNC) /* wake ervry time */
+ __cim_disable_dma();
+// __cim_disable();
+
+ dprintk("Stop interrupt!\n");
+// wake_up_interruptible(&cim_dev->wait_queue);
+ REG_CIM_STATE &= ~CIM_STATE_DMA_STOP;
+ }
+#endif
+
+#if 0 //trig
+ if ((REG_CIM_CTRL & CIM_CTRL_RXF_TRIGM) && (state & CIM_STATE_RXF_TRIG)) {
+ REG_CIM_STATE &= ~CIM_STATE_RXF_TRIG;
+ dprintk("Trig interrupt!\n");
+ }
+#endif
+
+#if 0 //vdd
+ /* only happen disable cim during DMA transfer*/
+ if ((REG_CIM_CTRL & CIM_CTRL_VDDM) && (state & CIM_STATE_VDD)) {
+ dprintk(">>CIM Disable Done Interrupt!\n");
+ REG_CIM_STATE &= ~CIM_STATE_VDD;
+ }
+#endif
+ /* clear status flags*/
+ dprintk("before clear REG_CIM_STATE = %x\n", REG_CIM_STATE);
+// REG_CIM_STATE = 0;
+
+ return IRQ_HANDLED;
+}
+
+/*Camera gpio init, different operationg according sensor*/
+static void camera_gpio_init(void) {
+
+ __gpio_as_cim();
+ __gpio_as_i2c();
+ __sensor_gpio_init();
+}
+
+static int v4l_device_init(void)
+{
+ camera_gpio_init();
+ cim_dev = kzalloc(sizeof(struct cim_device), GFP_KERNEL);
+ if (!cim_dev) return -ENOMEM;
+ cim_dev->jz_cim = video_device_alloc();
+ if (!cim_dev->jz_cim) {
+ return -ENOMEM;
+ }
+ memcpy(cim_dev->jz_cim, &jz_v4l_device, sizeof(struct video_device));
+ cim_dev->frame_desc = NULL;
+ cim_dev->frame_size = 0;
+ cim_dev->page_order = 0;
+ return 0;
+}
+/*==========================================================================
+ * Module init and exit
+ *========================================================================*/
+
+static int __init jz4750_cim_init(void)
+{
+ struct cim_device *dev;
+ int ret;
+ /* allocate device */
+ ret = v4l_device_init();
+ if (ret)
+ return ret;
+ /* record device */
+ dev = cim_dev;
+ init_waitqueue_head(&dev->wait_queue);
+
+ ret = video_register_device(dev->jz_cim, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ printk(KERN_ERR "CIM Video4Linux-device "
+ "registration failed\n");
+ return -EINVAL;
+ }
+
+ if (ret < 0) {
+ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
+ cim_fb_destroy();
+ kfree(dev);
+ return ret;
+ }
+
+ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED,
+ CIM_NAME, dev))) {
+ printk(KERN_ERR "request_irq return error, ret=%d\n", ret);
+ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
+ cim_fb_destroy();
+ kfree(dev);
+ printk(KERN_ERR "CIM could not get IRQ\n");
+ return ret;
+ }
+
+ printk("JzSOC Camera Interface Module (CIM) driver registered\n");
+
+ return 0;
+}
+
+static void __exit jz4750_cim_exit(void)
+{
+ free_irq(IRQ_CIM, cim_dev);
+ kfree(cim_dev);
+ video_unregister_device(cim_dev->jz_cim);
+}
+
+module_init(jz4750_cim_init);
+module_exit(jz4750_cim_exit);
diff --git a/drivers/media/video/jz4750_cim.h b/drivers/media/video/jz4750_cim.h
new file mode 100644
index 00000000000..7e73c7cc291
--- /dev/null
+++ b/drivers/media/video/jz4750_cim.h
@@ -0,0 +1,49 @@
+/*
+ * linux/drivers/media/video/jz4750_cim.h -- Ingenic Jz4750 On-Chip CIM driver
+ *
+ * Copyright (C) 2005-2008, Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __JZ4750_CIM_H__
+#define __JZ4750_CIM_H__
+
+/* gpio init */
+#if defined(CONFIG_JZ4750_APUS) || defined(CONFIG_JZ4750D_FUWA1) /* board pavo */
+#define GPIO_CAMERA_RST (32*4+8) /* CIM_MCLK as reset */
+#else
+#error "driver/video/Jzlcd.h, please define SPI pins on your board."
+#endif
+
+#define CONFIG_OV9650 1
+
+#if defined(CONFIG_OV9650) || defined(CONFIG_OV2640)
+#if defined(CONFIG_JZ4750_APUS) /* board pavo */
+#define __sensor_gpio_init() \
+do {\
+ __gpio_as_output(GPIO_CAMERA_RST); \
+ __gpio_set_pin(GPIO_CAMERA_RST); \
+ mdelay(50); \
+ __gpio_clear_pin(GPIO_CAMERA_RST);\
+} while(0)
+
+#elif defined(CONFIG_JZ4750D_FUWA1) /* board pavo */
+#define __sensor_gpio_init() \
+do {\
+ __gpio_as_output(GPIO_CAMERA_RST); \
+ __gpio_set_pin(GPIO_CAMERA_RST); \
+ mdelay(50); \
+ __gpio_clear_pin(GPIO_CAMERA_RST);\
+} while(0)
+#endif
+#endif
+
+#ifndef __sensor_gpio_init
+#define __sensor_gpio_init()
+#endif
+#endif /* __JZ4750_CIM_H__ */
+
diff --git a/drivers/media/video/jz_cim.h b/drivers/media/video/jz_cim.h
new file mode 100644
index 00000000000..f72cfa498d5
--- /dev/null
+++ b/drivers/media/video/jz_cim.h
@@ -0,0 +1,36 @@
+/*
+ * JzSOC CIM driver
+ *
+ * Copyright (C) 2005 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __JZ_CIM_H__
+#define __JZ_CIM_H__
+
+typedef struct
+{
+ u32 width;
+ u32 height;
+ u32 bpp;
+} IMG_PARAM;
+
+/*
+ * IOCTL_XXX commands
+ */
+#define IOCTL_SET_IMG_PARAM 0 // arg type: IMG_PARAM *
+
+#endif /* __JZ__CIM_H__ */
diff --git a/drivers/media/video/jz_sensor.c b/drivers/media/video/jz_sensor.c
new file mode 100644
index 00000000000..2d6005fb57c
--- /dev/null
+++ b/drivers/media/video/jz_sensor.c
@@ -0,0 +1,202 @@
+/*
+ * linux/drivers/char/jzchar/sensor.c
+ *
+ * Common CMOS Camera Sensor Driver
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+//#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+//#include <linux/jz-chars.h>
+//#include "jz-chars.h"
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/jzsoc.h>
+
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <linux/video_decoder.h>
+
+MODULE_AUTHOR("Jianli Wei<jlwei@ingenic.cn>");
+MODULE_DESCRIPTION("Common CMOS Camera Sensor Driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * ioctl commands
+ */
+#define IOCTL_SET_ADDR 0 /* set i2c address */
+#define IOCTL_SET_CLK 1 /* set i2c clock */
+#define IOCTL_WRITE_REG 2 /* write sensor register */
+#define IOCTL_READ_REG 3 /* read sensor register */
+
+/*
+ * i2c related
+ */
+static unsigned int i2c_addr = 0x42;
+static unsigned int i2c_clk = 100000;
+
+struct video_device *jz_sensor;
+
+static void write_reg(u8 reg, u8 val)
+{
+ i2c_open();
+ i2c_setclk(i2c_clk);
+ i2c_write((i2c_addr >> 1), &val, reg, 1);
+ i2c_close();
+}
+
+static u8 read_reg(u8 reg)
+{
+ u8 val;
+
+ i2c_open();
+ i2c_setclk(i2c_clk);
+ i2c_read((i2c_addr >> 1), &val, reg, 1);
+ i2c_close();
+ return val;
+}
+
+/*
+ * fops routines
+ */
+
+static int sensor_open(struct inode *inode, struct file *filp);
+static int sensor_release(struct inode *inode, struct file *filp);
+static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l);
+static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l);
+static int sensor_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
+
+static struct file_operations sensor_fops =
+{
+ open: sensor_open,
+ release: sensor_release,
+ read: sensor_read,
+ write: sensor_write,
+ ioctl: sensor_ioctl,
+};
+
+static int sensor_open(struct inode *inode, struct file *filp)
+{
+ try_module_get(THIS_MODULE);
+ return 0;
+}
+
+static int sensor_release(struct inode *inode, struct file *filp)
+{
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l)
+{
+ printk("sensor: read is not implemented\n");
+ return -1;
+}
+
+static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l)
+{
+ printk("sensor: write is not implemented\n");
+ return -1;
+}
+
+static int sensor_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case IOCTL_SET_ADDR:
+ if (copy_from_user(&i2c_addr, (void *)arg, 4))
+ return -EFAULT;
+ break;
+ case IOCTL_SET_CLK:
+ if (copy_from_user(&i2c_clk, (void *)arg, 4))
+ return -EFAULT;
+ break;
+ case IOCTL_WRITE_REG:
+ {
+ u8 regval[2];
+
+ if (copy_from_user(regval, (void *)arg, 2))
+ return -EFAULT;
+
+ write_reg(regval[0], regval[1]);
+ break;
+ }
+ case IOCTL_READ_REG:
+ {
+ u8 reg, val;
+
+ if (copy_from_user(&reg, (void *)arg, 1))
+ return -EFAULT;
+
+ val = read_reg(reg);
+
+ if (copy_to_user((void *)(arg + 1), &val, 1))
+ return -EFAULT;
+ break;
+ }
+ default:
+ printk("Not supported command: 0x%x\n", cmd);
+ return -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static struct video_device jz_v4l_device = {
+ .name = "jz sensor",
+ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE |
+ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY
+ .fops = &sensor_fops,
+ .minor = -1,
+};
+
+/*
+ * Module init and exit
+ */
+
+static int __init jz_sensor_init(void)
+{
+ int ret;
+// cim_dev = kzalloc(sizeof(struct cim_device), GFP_KERNEL);
+ jz_sensor = video_device_alloc();
+ memcpy(jz_sensor, &jz_v4l_device, sizeof(struct video_device));
+ jz_sensor->release = video_device_release;
+// ret = jz_register_chrdev(SENSOR_MINOR, "sensor", &sensor_fops, NULL);
+ ret = video_register_device(jz_sensor, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ return ret;
+ }
+
+ printk("Ingenic CMOS camera sensor driver registered\n");
+
+ return 0;
+}
+
+static void __exit jz_sensor_exit(void)
+{
+// jz_unregister_chrdev(SENSOR_MINOR, "sensor");
+ video_unregister_device(jz_sensor);
+}
+
+module_init(jz_sensor_init);
+module_exit(jz_sensor_exit);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index adc205c49fb..15f1c1feccb 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -251,7 +251,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.mrq.cmd = &brq.cmd;
brq.mrq.data = &brq.data;
+#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0
+ brq.cmd.arg = blk_rq_pos(req) + 16384;
+#else
brq.cmd.arg = blk_rq_pos(req);
+#endif
if (!mmc_card_blockaddr(card))
brq.cmd.arg <<= 9;
brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 72f2df19326..35199e4fd8d 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -140,7 +140,13 @@ static int mmc_decode_csd(struct mmc_card *card)
e = UNSTUFF_BITS(resp, 47, 3);
m = UNSTUFF_BITS(resp, 62, 12);
+
+#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0
+ csd->capacity = (1 + m) << (e + 2);
+ csd->capacity -= 16384;
+#else
csd->capacity = (1 + m) << (e + 2);
+#endif
csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 65c32bf98ff..69f3e710e08 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -109,7 +109,13 @@ static int mmc_decode_csd(struct mmc_card *card)
e = UNSTUFF_BITS(resp, 47, 3);
m = UNSTUFF_BITS(resp, 62, 12);
+
+#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0
+ csd->capacity = (1 + m) << (e + 2);
+ csd->capacity -= 16384;
+#else
csd->capacity = (1 + m) << (e + 2);
+#endif
csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
@@ -137,7 +143,13 @@ static int mmc_decode_csd(struct mmc_card *card)
csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
m = UNSTUFF_BITS(resp, 48, 22);
+
+#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0
csd->capacity = (1 + m) << 10;
+ csd->capacity -= 16384;
+#else
+ csd->capacity = (1 + m) << 10;
+#endif
csd->read_blkbits = 9;
csd->read_partial = 0;
@@ -268,9 +280,11 @@ static int mmc_switch_hs(struct mmc_card *card)
goto out;
if ((status[16] & 0xF) != 1) {
+#if 0
printk(KERN_WARNING "%s: Problem switching card "
"into high-speed mode!\n",
mmc_hostname(card->host));
+#endif
} else {
mmc_card_set_highspeed(card);
mmc_set_timing(card->host, MMC_TIMING_SD_HS);
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 891ef18bd77..c774b9a9b3e 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -4,6 +4,104 @@
comment "MMC/SD/SDIO Host Controller Drivers"
+config MMC_JZ
+ tristate "JZ SD/Multimedia Card Interface support"
+ depends on SOC_JZ4730 || SOC_JZ4740
+ help
+ This selects the Ingenic JZ4730/JZ4740 SD/Multimedia card Interface.
+ If you have abIngenic platform with a Multimedia Card slot,
+ say Y or M here.
+
+ If unsure, say N.
+choice
+ depends on MMC_JZ
+ prompt "MMC BUS Width"
+ default JZ_MMC_BUS_4
+ help
+ This defines the BUS Width of the Ingenic JZ4730/JZ4740 SD/Multimedia card Interface.
+
+config JZ_MMC_BUS_1
+ bool "1 Bit Bus"
+ help
+ 1 Bit SD/Multimedia Card Bus
+
+config JZ_MMC_BUS_4
+ bool "4 Bit Bus"
+ help
+ 4 Bit SD/Multimedia Card Bus
+
+endchoice
+
+config MSC0_JZ4750
+ tristate "JZ4750 SD/Multimedia Card 0 Interface support"
+ depends on SOC_JZ4750 || SOC_JZ4750D
+ help
+ This selects the Ingenic JZ4750 SD/Multimedia card 0 Interface.
+ If you have a Ingenic platform with a Multimedia Card slot,
+ say Y or M here.
+
+ If unsure, say N.
+
+choice
+ depends on MSC0_JZ4750
+ prompt "MSC0 BUS Width"
+ default JZ4750_MSC0_BUS_4
+ help
+ This defines the BUS Width of the Ingenic JZ4750 SD/Multimedia card Interface.
+
+config JZ4750_MSC0_BUS_1
+ bool "1 Bit Bus"
+ help
+ 1 Bit SD/Multimedia Card Bus
+
+config JZ4750_MSC0_BUS_4
+ bool "4 Bit Bus"
+ help
+ 4 Bit SD/Multimedia Card Bus
+
+config JZ4750_MSC0_BUS_8
+ bool "8 Bit Bus"
+ help
+ 8 Bit Multimedia Card Bus
+
+endchoice
+
+config MSC1_JZ4750
+ tristate "JZ4750 SD/Multimedia Card 1 Interface support"
+ depends on SOC_JZ4750 || SOC_JZ4750D
+ help
+ This selects the Ingenic JZ4750 SD/Multimedia card 1 Interface.
+ If you have a Ingenic platform with a Multimedia Card slot,
+ say Y or M here.
+
+ If unsure, say N.
+
+choice
+ depends on MSC1_JZ4750
+ prompt "MSC1 BUS Width"
+ default JZ4750_MSC1_BUS_4
+ help
+ This defines the BUS Width of the Ingenic JZ4750 SD/Multimedia card Interface.
+
+config JZ4750_MSC1_BUS_1
+ bool "1 Bit Bus"
+ help
+ 1 Bit SD/Multimedia Card Bus
+
+config JZ4750_MSC1_BUS_4
+ bool "4 Bit Bus"
+ help
+ 4 Bit SD/Multimedia Card Bus
+endchoice
+
+config JZ4750_BOOT_FROM_MSC0
+ tristate "JZ4750 Boot from SD/Multimedia Card Interface support"
+ depends on SOC_JZ4750 || SOC_JZ4750D
+ help
+ This selects boot from the Sd/Multimedia Card.
+
+ If unsure,say N.
+
config MMC_ARMMMCI
tristate "ARM AMBA Multimedia Card Interface support"
depends on ARM_AMBA
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index cf153f62845..bbeefce06fa 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -6,6 +6,10 @@ ifeq ($(CONFIG_MMC_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
+obj-$(CONFIG_MMC_JZ) += jz_mmc.o
+obj-$(CONFIG_MSC0_JZ4750) += jz4750_mmc.o
+obj-$(CONFIG_MSC1_JZ4750) += jz4750_mmc.o
+
obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_IMX) += imxmmc.o
diff --git a/drivers/mmc/host/jz4750_mmc.c b/drivers/mmc/host/jz4750_mmc.c
new file mode 100644
index 00000000000..2cfe4228116
--- /dev/null
+++ b/drivers/mmc/host/jz4750_mmc.c
@@ -0,0 +1,1037 @@
+/*
+ * linux/drivers/mmc/jz_mmc.c - JZ SD/MMC driver
+ *
+ * Copyright (C) 2005 - 2008 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/pm.h>
+#include <linux/scatterlist.h>
+
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <asm/jzsoc.h>
+
+#include "jz4750_mmc.h"
+
+#define DRIVER_NAME "jz-mmc"
+
+#define USE_DMA
+
+static int r_type = 0;
+static int rxdmachan = 0;
+static int txdmachan = 0;
+static int mmc_slot_enable = 0;
+static int auto_select_bus = MSC_4BIT_BUS; /* default 4 bit bus*/
+
+/* Start the MMC clock and operation */
+static inline int jz_mmc_start_op(void)
+{
+ REG_MSC_STRPCL(MSC_ID) = MSC_STRPCL_START_OP;
+
+ return MMC_NO_ERROR;
+}
+
+static inline u32 jz_mmc_calc_clkrt(int is_low, u32 rate)
+{
+ u32 clkrt;
+ u32 clk_src = is_low ? 24000000 : 48000000;
+
+ clkrt = 0;
+ while (rate < clk_src) {
+ clkrt++;
+ clk_src >>= 1;
+ }
+ return clkrt;
+}
+
+/* Select the MMC clock frequency */
+static int jz_mmc_set_clock(u32 rate)
+{
+ int clkrt;
+
+ /* __cpm_select_msc_clk_high will select 48M clock for MMC/SD card
+ * perhaps this will made some card with bad quality init fail,or
+ * bad stabilization.
+ */
+ if (rate > SD_CLOCK_FAST) {
+ __cpm_select_msc_clk_high(MSC_ID,1); /* select clock source from CPM */
+ clkrt = jz_mmc_calc_clkrt(0, rate);
+ } else {
+ __cpm_select_msc_clk(MSC_ID,1); /* select clock source from CPM */
+ clkrt = jz_mmc_calc_clkrt(1, rate);
+ }
+
+#ifndef CONFIG_FPGA
+ REG_MSC_CLKRT(MSC_ID) = clkrt;
+#else
+ REG_MSC_CLKRT(MSC_ID) = 7;
+#endif
+ return MMC_NO_ERROR;
+}
+
+static void jz_mmc_enable_irq(struct jz_mmc_host *host, unsigned int mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->imask &= ~mask;
+ REG_MSC_IMASK(MSC_ID) = host->imask;
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void jz_mmc_disable_irq(struct jz_mmc_host *host, unsigned int mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->imask |= mask;
+ REG_MSC_IMASK(MSC_ID) = host->imask;
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+void jz_set_dma_block_size(int dmanr, int nbyte);
+
+#ifdef USE_DMA
+static inline void
+jz_mmc_start_dma(int chan, unsigned long phyaddr, int count, int mode)
+{
+ unsigned long flags;
+
+ flags = claim_dma_lock();
+ disable_dma(chan);
+ clear_dma_ff(chan);
+ jz_set_dma_block_size(chan, 32);
+ set_dma_mode(chan, mode);
+ set_dma_addr(chan, phyaddr);
+ set_dma_count(chan, count + 31);
+ enable_dma(chan);
+ release_dma_lock(flags);
+}
+
+static irqreturn_t jz_mmc_dma_rx_callback(int irq, void *devid)
+{
+ int chan = rxdmachan;
+
+ disable_dma(chan);
+ if (__dmac_channel_address_error_detected(chan)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n",
+ __FUNCTION__);
+ __dmac_channel_clear_address_error(chan);
+ }
+ if (__dmac_channel_transmit_end_detected(chan)) {
+ __dmac_channel_clear_transmit_end(chan);
+ }
+ return IRQ_HANDLED;
+}
+static irqreturn_t jz_mmc_dma_tx_callback(int irq, void *devid)
+{
+ int chan = txdmachan;
+
+ disable_dma(chan);
+ if (__dmac_channel_address_error_detected(chan)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n",
+ __FUNCTION__);
+ __dmac_channel_clear_address_error(chan);
+ }
+ if (__dmac_channel_transmit_end_detected(chan)) {
+ __dmac_channel_clear_transmit_end(chan);
+ }
+ return IRQ_HANDLED;
+}
+
+/* Prepare DMA to start data transfer from the MMC card */
+static void jz_mmc_rx_setup_data(struct jz_mmc_host *host,
+ struct mmc_data *data)
+{
+ unsigned int nob = data->blocks;
+ int channelrx = rxdmachan;
+ int i;
+ u32 size;
+
+ if (data->flags & MMC_DATA_STREAM)
+ nob = 0xffff;
+
+ REG_MSC_NOB(MSC_ID) = nob;
+ REG_MSC_BLKLEN(MSC_ID) = data->blksz;
+ size = nob * data->blksz;
+
+ if (data->flags & MMC_DATA_READ) {
+ host->dma.dir = DMA_FROM_DEVICE;
+ } else {
+ host->dma.dir = DMA_TO_DEVICE;
+ }
+
+ host->dma.len =
+ dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ host->dma.dir);
+
+ for (i = 0; i < host->dma.len; i++) {
+ host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
+ host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]);
+ dma_cache_wback_inv((unsigned long)
+ CKSEG0ADDR(sg_dma_address(data->sg)) +
+ data->sg->offset,
+ host->sg_cpu[i].dcmd);
+ jz_mmc_start_dma(channelrx, host->sg_cpu[i].dtadr,
+ host->sg_cpu[i].dcmd, DMA_MODE_READ);
+ }
+}
+
+/* Prepare DMA to start data transfer from the MMC card */
+static void jz_mmc_tx_setup_data(struct jz_mmc_host *host,
+ struct mmc_data *data)
+{
+ unsigned int nob = data->blocks;
+ int channeltx = txdmachan;
+ int i;
+ u32 size;
+
+ if (data->flags & MMC_DATA_STREAM)
+ nob = 0xffff;
+
+ REG_MSC_NOB(MSC_ID) = nob;
+ REG_MSC_BLKLEN(MSC_ID) = data->blksz;
+ size = nob * data->blksz;
+
+ if (data->flags & MMC_DATA_READ) {
+ host->dma.dir = DMA_FROM_DEVICE;
+ } else {
+ host->dma.dir = DMA_TO_DEVICE;
+ }
+
+ host->dma.len =
+ dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ host->dma.dir);
+
+ for (i = 0; i < host->dma.len; i++) {
+ host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
+ host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]);
+ dma_cache_wback_inv((unsigned long)
+ CKSEG0ADDR(sg_dma_address(data->sg)) +
+ data->sg->offset,
+ host->sg_cpu[i].dcmd);
+ jz_mmc_start_dma(channeltx, host->sg_cpu[i].dtadr,
+ host->sg_cpu[i].dcmd, DMA_MODE_WRITE);
+ }
+}
+#else
+static void jz_mmc_receive_pio(struct jz_mmc_host *host)
+{
+
+ struct mmc_data *data = 0;
+ int sg_len = 0, max = 0, count = 0;
+ u32 *buf = 0;
+ struct scatterlist *sg;
+ unsigned int nob;
+
+ data = host->mrq->data;
+ nob = data->blocks;
+ REG_MSC_NOB(MSC_ID) = nob;
+ REG_MSC_BLKLEN(MSC_ID) = data->blksz;
+
+ max = host->pio.len;
+ if (host->pio.index < host->dma.len) {
+ sg = &data->sg[host->pio.index];
+ buf = sg_virt(sg) + host->pio.offset;
+
+ /* This is the space left inside the buffer */
+ sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
+ /* Check to if we need less then the size of the sg_buffer */
+ if (sg_len < max) max = sg_len;
+ }
+ max = max / 4;
+ for(count = 0; count < max; count++) {
+ while (REG_MSC_STAT(MSC_ID) & MSC_STAT_DATA_FIFO_EMPTY)
+ ;
+ *buf++ = REG_MSC_RXFIFO(MSC_ID);
+ }
+ host->pio.len -= count;
+ host->pio.offset += count;
+
+ if (sg_len && count == sg_len) {
+ host->pio.index++;
+ host->pio.offset = 0;
+ }
+}
+
+static void jz_mmc_send_pio(struct jz_mmc_host *host)
+{
+
+ struct mmc_data *data = 0;
+ int sg_len, max, count = 0;
+ u32 *wbuf = 0;
+ struct scatterlist *sg;
+ unsigned int nob;
+
+ data = host->mrq->data;
+ nob = data->blocks;
+
+ REG_MSC_NOB(MSC_ID) = nob;
+ REG_MSC_BLKLEN(MSC_ID) = data->blksz;
+
+ /* This is the pointer to the data buffer */
+ sg = &data->sg[host->pio.index];
+ wbuf = sg_virt(sg) + host->pio.offset;
+
+ /* This is the space left inside the buffer */
+ sg_len = data->sg[host->pio.index].length - host->pio.offset;
+
+ /* Check to if we need less then the size of the sg_buffer */
+ max = (sg_len > host->pio.len) ? host->pio.len : sg_len;
+ max = max / 4;
+ for(count = 0; count < max; count++ ) {
+ while (REG_MSC_STAT(MSC_ID) & MSC_STAT_DATA_FIFO_FULL)
+ ;
+ REG_MSC_TXFIFO(MSC_ID) = *wbuf++;
+ }
+
+ host->pio.len -= count;
+ host->pio.offset += count;
+
+ if (count == sg_len) {
+ host->pio.index++;
+ host->pio.offset = 0;
+ }
+}
+
+static int
+jz_mmc_prepare_data(struct jz_mmc_host *host, struct mmc_data *data)
+{
+ int datalen = data->blocks * data->blksz;
+
+ host->dma.dir = DMA_BIDIRECTIONAL;
+ host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len, host->dma.dir);
+ if (host->dma.len == 0)
+ return -ETIMEDOUT;
+
+ host->pio.index = 0;
+ host->pio.offset = 0;
+ host->pio.len = datalen;
+ return 0;
+}
+#endif
+
+static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat);
+
+static void jz_mmc_finish_request(struct jz_mmc_host *host, struct mmc_request *mrq)
+{
+ host->mrq = NULL;
+ host->cmd = NULL;
+ host->data = NULL;
+ mmc_request_done(host->mmc, mrq);
+}
+
+static void jz_mmc_start_cmd(struct jz_mmc_host *host,
+ struct mmc_command *cmd, unsigned int cmdat)
+{
+ u32 timeout = 0x3fffff;
+ unsigned int stat;
+ struct jz_mmc_host *hst = host;
+ WARN_ON(host->cmd != NULL);
+ host->cmd = cmd;
+
+ /* mask interrupts */
+ REG_MSC_IMASK(MSC_ID) = 0xffff;
+
+ /* clear status */
+ REG_MSC_IREG(MSC_ID) = 0xffff;
+
+ if (cmd->flags & MMC_RSP_BUSY)
+ cmdat |= MSC_CMDAT_BUSY;
+
+#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
+ switch (RSP_TYPE(mmc_resp_type(cmd))) {
+ case RSP_TYPE(MMC_RSP_R1): /* r1,r1b, r6, r7 */
+ cmdat |= MSC_CMDAT_RESPONSE_R1;
+ r_type = 1;
+ break;
+ case RSP_TYPE(MMC_RSP_R3):
+ cmdat |= MSC_CMDAT_RESPONSE_R3;
+ r_type = 1;
+ break;
+ case RSP_TYPE(MMC_RSP_R2):
+ cmdat |= MSC_CMDAT_RESPONSE_R2;
+ r_type = 2;
+ break;
+ default:
+ break;
+ }
+
+ REG_MSC_CMD(MSC_ID) = cmd->opcode;
+
+ /* Set argument */
+#ifdef CONFIG_MSC0_JZ4750
+#ifdef CONFIG_JZ4750_MSC0_BUS_1
+ if (cmd->opcode == 6) {
+ /* set 1 bit sd card bus*/
+ if (cmd->arg ==2)
+ REG_MSC_ARG(MSC_ID) = 0;
+
+ /* set 1 bit mmc card bus*/
+ if (cmd->arg == 0x3b70101) {
+ REG_MSC_ARG(MSC_ID) = 0x3b70001;
+ }
+ } else
+ REG_MSC_ARG(MSC_ID) = cmd->arg;
+
+#elif defined CONFIG_JZ4750_MSC0_BUS_8
+ if (cmd->opcode == 6) {
+ /* set 8 bit mmc card bus*/
+ if (cmd->arg == 0x3b70101)
+ REG_MSC_ARG(MSC_ID) = 0x3b70201;
+ else
+ REG_MSC_ARG(MSC_ID) = cmd->arg;
+
+ } else
+ REG_MSC_ARG(MSC_ID) = cmd->arg;
+#else
+ REG_MSC_ARG(MSC_ID) = cmd->arg;
+#endif /* CONFIG_JZ4750_MSC0_BUS_1 */
+#else
+#ifdef CONFIG_JZ4750_MSC1_BUS_1
+ if (cmd->opcode == 6) {
+ /* set 1 bit sd card bus*/
+ if (cmd->arg ==2)
+ REG_MSC_ARG(MSC_ID) = 0;
+
+ /* set 1 bit mmc card bus*/
+ if (cmd->arg == 0x3b70101) {
+ REG_MSC_ARG(MSC_ID) = 0x3b70001;
+ }
+ } else
+ REG_MSC_ARG(MSC_ID) = cmd->arg;
+
+#else
+ REG_MSC_ARG(MSC_ID) = cmd->arg;
+#endif /* CONFIG_JZ4750_MSC1_BUS_1 */
+#endif /* CONFIG_MSC0_JZ4750*/
+
+ /* Set command */
+ REG_MSC_CMDAT(MSC_ID) = cmdat;
+
+ /* Send command */
+ jz_mmc_start_op();
+
+ while (timeout-- && !(REG_MSC_STAT(MSC_ID) & MSC_STAT_END_CMD_RES))
+ ;
+
+ REG_MSC_IREG(MSC_ID) = MSC_IREG_END_CMD_RES; /* clear irq flag */
+ if (cmd->opcode == 12) {
+ while (timeout-- && !(REG_MSC_IREG(MSC_ID) & MSC_IREG_PRG_DONE))
+ ;
+ REG_MSC_IREG(MSC_ID) = MSC_IREG_PRG_DONE; /* clear status */
+ }
+ if (!mmc_slot_enable) {
+ /* It seems that MSC can't report the MSC_STAT_TIME_OUT_RES when
+ * card was removed. We force to return here.
+ */
+ cmd->error = -ETIMEDOUT;
+ jz_mmc_finish_request(hst, hst->mrq);
+ return;
+ }
+
+ if (SD_IO_SEND_OP_COND == cmd->opcode) {
+ /*
+ * Don't support SDIO card currently.
+ */
+ cmd->error = -ETIMEDOUT;
+ jz_mmc_finish_request(hst, hst->mrq);
+ return;
+ }
+
+ /* Check for status */
+ stat = REG_MSC_STAT(MSC_ID);
+ jz_mmc_cmd_done(hst, stat);
+ if (host->data) {
+ if (cmd->opcode == MMC_WRITE_BLOCK || cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
+#ifdef USE_DMA
+ jz_mmc_tx_setup_data(host, host->data);
+#else
+ jz_mmc_send_pio(host);
+ else
+ jz_mmc_receive_pio(host);
+#endif
+ }
+}
+
+static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat)
+{
+ struct mmc_command *cmd = host->cmd;
+ int i, temp[16];
+ u8 *buf;
+ u32 data, v, w1, w2;
+
+ if (!cmd)
+ return 0;
+
+ host->cmd = NULL;
+ buf = (u8 *) temp;
+ switch (r_type) {
+ case 1:
+ {
+ data = REG_MSC_RES(MSC_ID);
+ buf[0] = (data >> 8) & 0xff;
+ buf[1] = data & 0xff;
+ data = REG_MSC_RES(MSC_ID);
+ buf[2] = (data >> 8) & 0xff;
+ buf[3] = data & 0xff;
+ data = REG_MSC_RES(MSC_ID);
+ buf[4] = data & 0xff;
+ cmd->resp[0] =
+ buf[1] << 24 | buf[2] << 16 | buf[3] << 8 |
+ buf[4];
+ break;
+ }
+ case 2:
+ {
+ data = REG_MSC_RES(MSC_ID);
+ v = data & 0xffff;
+ for (i = 0; i < 4; i++) {
+ data = REG_MSC_RES(MSC_ID);
+ w1 = data & 0xffff;
+ data = REG_MSC_RES(MSC_ID);
+ w2 = data & 0xffff;
+ cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
+ v = w2;
+ }
+ break;
+ }
+ case 0:
+ break;
+ }
+ if (stat & MSC_STAT_TIME_OUT_RES) {
+ printk("MSC_STAT_TIME_OUT_RES\n");
+ cmd->error = -ETIMEDOUT;
+ } else if (stat & MSC_STAT_CRC_RES_ERR && cmd->flags & MMC_RSP_CRC) {
+ printk("MSC_STAT_CRC\n");
+ if (cmd->opcode == MMC_ALL_SEND_CID ||
+ cmd->opcode == MMC_SEND_CSD ||
+ cmd->opcode == MMC_SEND_CID) {
+ /* a bogus CRC error can appear if the msb of
+ the 15 byte response is a one */
+ if ((cmd->resp[0] & 0x80000000) == 0)
+ cmd->error = -EILSEQ;
+ }
+ }
+ /*
+ * Did I mention this is Sick. We always need to
+ * discard the upper 8 bits of the first 16-bit word.
+ */
+ if (host->data && cmd->error == 0)
+ jz_mmc_enable_irq(host, MSC_IMASK_DATA_TRAN_DONE);
+ else
+ jz_mmc_finish_request(host, host->mrq);
+
+ return 1;
+}
+
+static int jz_mmc_data_done(struct jz_mmc_host *host, unsigned int stat)
+{
+ struct mmc_data *data = host->data;
+
+ if (!data)
+ return 0;
+ REG_MSC_IREG(MSC_ID) = MSC_IREG_DATA_TRAN_DONE; /* clear status */
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
+ host->dma_dir);
+ if (stat & MSC_STAT_TIME_OUT_READ) {
+ printk("MMC/SD timeout, MMC_STAT 0x%x\n", stat);
+ data->error = -ETIMEDOUT;
+ } else if (REG_MSC_STAT(MSC_ID) &
+ (MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR)) {
+ printk("MMC/SD CRC error, MMC_STAT 0x%x\n", stat);
+ data->error = -EILSEQ;
+ }
+ /*
+ * There appears to be a hardware design bug here. There seems to
+ * be no way to find out how much data was transferred to the card.
+ * This means that if there was an error on any block, we mark all
+ * data blocks as being in error.
+ */
+ if (data->error == 0)
+ data->bytes_xfered = data->blocks * data->blksz;
+ else
+ data->bytes_xfered = 0;
+
+ jz_mmc_disable_irq(host, MSC_IMASK_DATA_TRAN_DONE);
+ host->data = NULL;
+ if (host->mrq->stop) {
+ jz_mmc_start_cmd(host, host->mrq->stop, 0);
+ } else {
+ jz_mmc_finish_request(host, host->mrq);
+ }
+ return 1;
+}
+
+static void jz_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct jz_mmc_host *host = mmc_priv(mmc);
+ unsigned int cmdat;
+
+ /* Save current request for the future processing */
+ host->mrq = mrq;
+ host->data = mrq->data;
+ cmdat = host->cmdat;
+ host->cmdat &= ~MSC_CMDAT_INIT;
+
+ if (mrq->data) {
+ cmdat &= ~MSC_CMDAT_BUSY;
+#ifdef USE_DMA
+ if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6))
+
+ cmdat |=
+ MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN |
+ MSC_CMDAT_DMA_EN;
+ else {
+#ifdef CONFIG_MSC0_JZ4750
+#ifdef CONFIG_JZ4750_MSC0_BUS_1
+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK;
+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN |
+ MSC_CMDAT_DMA_EN;
+#elif defined CONFIG_JZ4750_MSC0_BUS_4
+ if(auto_select_bus == MSC_1BIT_BUS) {
+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK;
+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN |
+ MSC_CMDAT_DMA_EN;
+ } else {
+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK;
+ cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT | MSC_CMDAT_DATA_EN |
+ MSC_CMDAT_DMA_EN;
+ }
+#else
+ cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_DMA_EN;
+#endif /* CONFIG_JZ4750_MSC0_BUS_1 */
+#else
+#ifdef CONFIG_JZ4750_MSC1_BUS_1
+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK;
+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN |
+ MSC_CMDAT_DMA_EN;
+#else
+ cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_DMA_EN;
+#endif /* CONFIG_JZ4750_MSC1_BUS_1 */
+#endif /* CONFIG_MSC0_JZ4750 */
+ }
+ if (mrq->data->flags & MMC_DATA_WRITE)
+ cmdat |= MSC_CMDAT_WRITE;
+
+ if (mrq->data->flags & MMC_DATA_STREAM)
+ cmdat |= MSC_CMDAT_STREAM_BLOCK;
+ if (mrq->cmd->opcode != MMC_WRITE_BLOCK
+ && mrq->cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)
+ jz_mmc_rx_setup_data(host, mrq->data);
+#else /*USE_DMA*/
+
+ if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6))
+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN;
+ else {
+#ifdef CONFIG_MSC0_JZ4750
+#ifdef CONFIG_JZ4750_MSC0_BUS_1
+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK;
+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN;
+#elif defined CONFIG_JZ4750_MSC0_BUS_4
+ if(auto_select_bus == MSC_1BIT_BUS) {
+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK;
+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN;
+ } else {
+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK;
+ cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT | MSC_CMDAT_DATA_EN;
+ }
+#else
+ cmdat |= MSC_CMDAT_DATA_EN;
+#endif
+#else
+#ifdef CONFIG_JZ4750_MSC1_BUS_1
+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK;
+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN;
+#else
+ cmdat |= MSC_CMDAT_DATA_EN;
+#endif /* CONFIG_JZ4750_MSC1_BUS_1 */
+#endif /* CONFIG_MSC0_JZ4750 */
+ }
+ if (mrq->data->flags & MMC_DATA_WRITE)
+ cmdat |= MSC_CMDAT_WRITE;
+
+ if (mrq->data->flags & MMC_DATA_STREAM)
+ cmdat |= MSC_CMDAT_STREAM_BLOCK;
+ jz_mmc_prepare_data(host, host->data);
+#endif /*USE_DMA*/
+ }
+ jz_mmc_start_cmd(host, mrq->cmd, cmdat);
+}
+
+static irqreturn_t jz_mmc_irq(int irq, void *devid)
+{
+ struct jz_mmc_host *host = devid;
+ unsigned int ireg;
+ int handled = 0;
+
+ ireg = REG_MSC_IREG(MSC_ID);
+
+ if (ireg) {
+ unsigned stat = REG_MSC_STAT(MSC_ID);
+ if (ireg & MSC_IREG_DATA_TRAN_DONE)
+ handled |= jz_mmc_data_done(host, stat);
+ }
+ return IRQ_RETVAL(handled);
+}
+
+/* Returns true if MMC slot is empty */
+static int jz_mmc_slot_is_empty(int slot)
+{
+ int empty;
+
+#ifdef CONFIG_FPGA
+ return 0;
+#endif
+
+#ifdef CONFIG_MSC1_JZ4750
+ empty = (__msc1_card_detected(slot) == 0) ? 1 : 0;
+#else
+ empty = (__msc0_card_detected(slot) == 0) ? 1 : 0;
+#endif
+
+ if (empty) {
+
+ /* wait for card insertion */
+#ifdef CONFIG_SOC_JZ4750
+#ifdef CONFIG_MSC1_JZ4750
+ __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN);
+#else
+ __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN);
+#endif
+#else
+ __gpio_as_irq_fall_edge(MSC1_HOTPLUG_PIN);
+#endif
+
+ } else {
+ /* wait for card removal */
+#ifdef CONFIG_SOC_JZ4750
+#ifdef CONFIG_MSC1_JZ4750
+ __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN);
+#else
+ __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN);
+#endif
+#else
+ __gpio_as_irq_rise_edge(MSC1_HOTPLUG_PIN);
+#endif
+ }
+
+ return empty;
+}
+
+static irqreturn_t jz_mmc_detect_irq(int irq, void *devid)
+{
+ struct jz_mmc_host *host = (struct jz_mmc_host *) devid;
+
+ auto_select_bus = MSC_4BIT_BUS;
+ if (jz_mmc_slot_is_empty(0)) {
+ mmc_slot_enable = 0;
+ mmc_detect_change(host->mmc, 50);
+ } else {
+ mmc_slot_enable = 1;
+ mmc_detect_change(host->mmc, 50);
+ }
+ return IRQ_HANDLED;
+}
+
+static int jz_mmc_get_ro(struct mmc_host *mmc)
+{
+ struct jz_mmc_host *host = mmc_priv(mmc);
+
+ if (host->pdata && host->pdata->get_ro)
+ return host->pdata->get_ro(mmc_dev(mmc));
+ /* Host doesn't support read only detection so assume writeable */
+ return 0;
+}
+
+/* set clock and power */
+static void jz_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct jz_mmc_host *host = mmc_priv(mmc);
+
+ if (ios->clock)
+ jz_mmc_set_clock(ios->clock);
+
+ if (host->power_mode != ios->power_mode) {
+ host->power_mode = ios->power_mode;
+
+ if (ios->power_mode == MMC_POWER_ON)
+ host->cmdat |= CMDAT_INIT;
+ }
+
+ if (ios->bus_width == MMC_BUS_WIDTH_4) {
+ auto_select_bus = MSC_4BIT_BUS;
+ host->cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT;
+ }
+ else if (ios->bus_width == MMC_BUS_WIDTH_8) {
+ host->cmdat |= MSC_CMDAT_BUS_WIDTH_8BIT;
+ auto_select_bus = MSC_8BIT_BUS;
+ } else {
+ /* 1 bit bus*/
+ host->cmdat &= ~MSC_CMDAT_BUS_WIDTH_8BIT;
+ auto_select_bus = MSC_1BIT_BUS;
+ }
+}
+
+static const struct mmc_host_ops jz_mmc_ops = {
+ .request = jz_mmc_request,
+ .get_ro = jz_mmc_get_ro,
+ .set_ios = jz_mmc_set_ios,
+};
+
+static int jz_mmc_probe(struct platform_device *pdev)
+{
+ int retval;
+ struct mmc_host *mmc;
+ struct jz_mmc_host *host = NULL;
+ int irq;
+ struct resource *r;
+
+#ifdef CONFIG_MSC0_JZ4750
+#ifdef CONFIG_SOC_JZ4750
+ __gpio_as_msc0_8bit(); // for jz4750
+#else
+ __gpio_as_msc0_4bit(); // for jz4750d
+#endif
+ __msc0_init_io();
+ __msc0_enable_power();
+#else
+ __gpio_as_msc1_4bit();
+ __msc1_init_io();
+ __msc1_enable_power();
+#endif
+ __msc_reset(MSC_ID);
+ REG_MSC_LPM(MSC_ID) = 0x1;
+
+ MMC_IRQ_MASK();
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!r || irq < 0)
+ return -ENXIO;
+
+ r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
+ if (!r)
+ return -EBUSY;
+
+ mmc = mmc_alloc_host(sizeof(struct jz_mmc_host), &pdev->dev);
+ if (!mmc) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ mmc->ops = &jz_mmc_ops;
+ mmc->f_min = MMC_CLOCK_SLOW;
+ mmc->f_max = SD_CLOCK_HIGH;
+ /*
+ * We can do SG-DMA, but we don't because we never know how much
+ * data we successfully wrote to the card.
+ */
+ mmc->max_phys_segs = NR_SG;
+
+ mmc->max_seg_size = PAGE_SIZE * 16;
+ mmc->max_req_size = mmc->max_seg_size;
+ mmc->max_blk_size = 4095;
+ /*
+ * Block count register is 16 bits.
+ */
+ mmc->max_blk_count = 65535;
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->pdata = pdev->dev.platform_data;
+ mmc->ocr_avail = host->pdata ?
+ host->pdata->ocr_mask : MMC_VDD_32_33 | MMC_VDD_33_34;
+ host->mmc->caps =
+ MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
+ /*
+ *MMC_CAP_4_BIT_DATA (1 << 0) The host can do 4 bit transfers
+ *
+ */
+ host->sg_cpu =
+ dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma,
+ GFP_KERNEL);
+ if (!host->sg_cpu) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ spin_lock_init(&host->lock);
+ host->irq = IRQ_MSC; /* is it useful ?*/
+ host->imask = 0xffff;
+ /*
+ * Ensure that the host controller is shut down, and setup
+ * with our defaults.
+ */
+ retval = request_irq(IRQ_MSC, jz_mmc_irq, 0, "MMC/SD", host);
+ if (retval) {
+ printk(KERN_ERR "MMC/SD: can't request MMC/SD IRQ\n");
+ return retval;
+ }
+
+ jz_mmc_slot_is_empty(0);
+ /* Request card detect interrupt */
+
+ retval = request_irq(MSC_HOTPLUG_IRQ, jz_mmc_detect_irq, 0, //SA_INTERRUPT,
+ "MMC card detect", host);
+ if (retval) {
+ printk(KERN_ERR "MMC/SD: can't request card detect IRQ\n");
+ goto err1;
+ }
+#ifdef USE_DMA
+ /* Request MMC Rx DMA channel */
+ rxdmachan =
+ jz_request_dma(DMA_ID_MSC_RX, "MMC Rx", jz_mmc_dma_rx_callback,
+ 0, host);
+ if (rxdmachan < 0) {
+ printk(KERN_ERR "jz_request_dma failed for MMC Rx\n");
+ goto err2;
+ }
+
+ if (rxdmachan < HALF_DMA_NUM)
+ REG_DMAC_DMACR(0) |= DMAC_DMACR_FMSC;
+ else
+ REG_DMAC_DMACR(1) |= DMAC_DMACR_FMSC;
+
+ /* Request MMC Tx DMA channel */
+ txdmachan =
+ jz_request_dma(DMA_ID_MSC_TX, "MMC Tx", jz_mmc_dma_tx_callback,
+ 0, host);
+ if (txdmachan < 0) {
+ printk(KERN_ERR "jz_request_dma failed for MMC Tx\n");
+ goto err3;
+ }
+
+ if (txdmachan < HALF_DMA_NUM)
+ REG_DMAC_DMACR(0) |= DMAC_DMACR_FMSC;
+ else
+ REG_DMAC_DMACR(1) |= DMAC_DMACR_FMSC;
+
+#endif
+ platform_set_drvdata(pdev, mmc);
+ mmc_add_host(mmc);
+
+ printk(JZ_SOC_NAME ": SD/MMC card driver registered.\n");
+
+ /* Detect card during initialization */
+#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D)
+ if (!jz_mmc_slot_is_empty(0)) {
+ mmc_slot_enable = 1;
+ mmc_detect_change(host->mmc, 0);
+ }
+#endif
+ return 0;
+
+err1:free_irq(IRQ_MSC, &host);
+#ifdef USE_DMA
+ err2:jz_free_dma(rxdmachan);
+ err3:jz_free_dma(txdmachan);
+#endif
+out:
+ if (host) {
+ if (host->sg_cpu)
+ dma_free_coherent(&pdev->dev, PAGE_SIZE,
+ host->sg_cpu, host->sg_dma);
+ }
+ if (mmc)
+ mmc_free_host(mmc);
+ return -1;
+}
+
+static int jz_mmc_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ unsigned long flags;
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (mmc) {
+ struct jz_mmc_host *host = mmc_priv(mmc);
+
+ if (host->pdata && host->pdata->exit)
+ host->pdata->exit(&pdev->dev, mmc);
+
+ mmc_remove_host(mmc);
+
+ local_irq_save(flags);
+ __msc0_disable_power();
+ jz_free_dma(rxdmachan);
+ jz_free_dma(txdmachan);
+ free_irq(IRQ_MSC, host);
+ local_irq_restore(flags);
+ mmc_free_host(mmc);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int jz_mmc_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct mmc_host *mmc = platform_get_drvdata(dev);
+ int ret = 0;
+
+ printk("%s(): called.\n", __func__);
+
+ if (mmc)
+ ret = mmc_suspend_host(mmc, state);
+
+ return ret;
+}
+
+static int jz_mmc_resume(struct platform_device *dev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(dev);
+ int ret = 0;
+
+ printk("%s(): called.\n", __func__);
+
+ if (mmc)
+ ret = mmc_resume_host(mmc);
+
+ return ret;
+}
+#else
+#define jz_mmc_suspend NULL
+#define jz_mmc_resume NULL
+#endif
+
+static struct platform_driver jz_mmc_driver = {
+ .probe = jz_mmc_probe,
+ .remove = jz_mmc_remove,
+ .suspend = jz_mmc_suspend,
+ .resume = jz_mmc_resume,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init jz_mmc_init(void)
+{
+ return platform_driver_register(&jz_mmc_driver);
+}
+
+static void __exit jz_mmc_exit(void)
+{
+ platform_driver_unregister(&jz_mmc_driver);
+}
+
+module_init(jz_mmc_init);
+module_exit(jz_mmc_exit);
+
+MODULE_DESCRIPTION("JZ47XX SD/Multimedia Card Interface Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/jz4750_mmc.h b/drivers/mmc/host/jz4750_mmc.h
new file mode 100644
index 00000000000..8577db68220
--- /dev/null
+++ b/drivers/mmc/host/jz4750_mmc.h
@@ -0,0 +1,88 @@
+#ifndef __JZ4750_MMC_H__
+#define __JZ4750_MMC_H__
+
+#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */
+#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */
+#define SD_CLOCK_FAST 24000000 /* 24 MHz for SD Cards */
+#define SD_CLOCK_HIGH 24000000 /* 24 MHz for SD Cards */
+#define MMC_NO_ERROR 0
+
+#define NR_SG 1
+
+#ifdef CONFIG_MSC0_JZ4750
+#define MSC_ID 0
+#define MSC_HOTPLUG_IRQ MSC0_HOTPLUG_IRQ
+#define IRQ_MSC IRQ_MSC0
+#define DMA_ID_MSC_RX DMA_ID_MSC0_RX
+#define DMA_ID_MSC_TX DMA_ID_MSC0_TX
+#define MSC_HOTPLUG_PIN MSC0_HOTPLUG_PIN
+#else
+#define MSC_ID 1
+#define MSC_HOTPLUG_IRQ MSC1_HOTPLUG_IRQ
+#define IRQ_MSC IRQ_MSC1
+#define DMA_ID_MSC_RX DMA_ID_MSC1_RX
+#define DMA_ID_MSC_TX DMA_ID_MSC1_TX
+#define MSC_HOTPLUG_PIN MSC1_HOTPLUG_PIN
+#endif
+
+#define MSC_1BIT_BUS 0
+#define MSC_4BIT_BUS 1
+#define MSC_8BIT_BUS 2
+
+#define SZ_4K 0x00001000
+
+struct jz_mmc_host {
+ struct mmc_host *mmc;
+ spinlock_t lock;
+ struct {
+ int len;
+ int dir;
+ } dma;
+ struct {
+ int index;
+ int offset;
+ int len;
+ } pio;
+ int irq;
+ unsigned int clkrt;
+ unsigned int cmdat;
+ unsigned int imask;
+ unsigned int power_mode;
+ struct jz_mmc_platform_data *pdata;
+ struct mmc_request *mrq;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ dma_addr_t sg_dma;
+ struct jzsoc_dma_desc *sg_cpu;
+ unsigned int dma_len;
+ unsigned int dma_dir;
+};
+
+#define MMC_IRQ_MASK() \
+do { \
+ REG_MSC_IMASK(MSC_ID) = 0xffff; \
+ REG_MSC_IREG(MSC_ID) = 0xffff; \
+} while (0)
+
+typedef struct jzsoc_dma_desc {
+ volatile u32 ddadr; /* Points to the next descriptor + flags */
+ volatile u32 dsadr; /* DSADR value for the current transfer */
+ volatile u32 dtadr; /* DTADR value for the current transfer */
+ volatile u32 dcmd; /* DCMD value for the current transfer */
+} jzsoc_dma_desc;
+
+#include <linux/interrupt.h>
+
+struct device;
+struct mmc_host;
+
+struct jz_mmc_platform_data {
+ unsigned int ocr_mask; /* available voltages */
+ unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */
+ int (*init)(struct device *, irq_handler_t , void *);
+ int (*get_ro)(struct device *);
+ void (*setpower)(struct device *, unsigned int);
+ void (*exit)(struct device *, void *);
+};
+
+#endif /* __JZ4750_MMC_H__ */
diff --git a/drivers/mmc/host/jz_mmc.c b/drivers/mmc/host/jz_mmc.c
new file mode 100644
index 00000000000..fa9dd8c9069
--- /dev/null
+++ b/drivers/mmc/host/jz_mmc.c
@@ -0,0 +1,998 @@
+/*
+ * linux/drivers/mmc/jz_mmc.c - JZ SD/MMC driver
+ *
+ * Copyright (C) 2005 - 2008 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/pm.h>
+#include <linux/scatterlist.h>
+
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <asm/jzsoc.h>
+
+#include "jz_mmc.h"
+
+#define DRIVER_NAME "jz-mmc"
+
+#define NR_SG 1
+
+#if defined(CONFIG_SOC_JZ4725) || defined(CONFIG_SOC_JZ4720)
+#undef USE_DMA
+#else
+#define USE_DMA
+#endif
+
+struct jz_mmc_host {
+ struct mmc_host *mmc;
+ spinlock_t lock;
+ struct {
+ int len;
+ int dir;
+ } dma;
+ struct {
+ int index;
+ int offset;
+ int len;
+ } pio;
+ int irq;
+ unsigned int clkrt;
+ unsigned int cmdat;
+ unsigned int imask;
+ unsigned int power_mode;
+ struct jz_mmc_platform_data *pdata;
+ struct mmc_request *mrq;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ dma_addr_t sg_dma;
+ struct jzsoc_dma_desc *sg_cpu;
+ unsigned int dma_len;
+ unsigned int dma_dir;
+ struct pm_dev *pmdev;
+};
+
+static int r_type = 0;
+
+#define MMC_IRQ_MASK() \
+do { \
+ REG_MSC_IMASK = 0xff; \
+ REG_MSC_IREG = 0xff; \
+} while (0)
+
+static int rxdmachan = 0;
+static int txdmachan = 0;
+static int mmc_slot_enable = 0;
+
+/* Stop the MMC clock and wait while it happens */
+static inline int jz_mmc_stop_clock(void)
+{
+ int timeout = 1000;
+
+ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP;
+ while (timeout && (REG_MSC_STAT & MSC_STAT_CLK_EN)) {
+ timeout--;
+ if (timeout == 0)
+ return 0;
+ udelay(1);
+ }
+ return MMC_NO_ERROR;
+}
+
+/* Start the MMC clock and operation */
+static inline int jz_mmc_start_clock(void)
+{
+ REG_MSC_STRPCL =
+ MSC_STRPCL_CLOCK_CONTROL_START | MSC_STRPCL_START_OP;
+ return MMC_NO_ERROR;
+}
+
+static inline u32 jz_mmc_calc_clkrt(int is_sd, u32 rate)
+{
+ u32 clkrt;
+ u32 clk_src = is_sd ? 24000000 : 20000000;
+
+ clkrt = 0;
+ while (rate < clk_src) {
+ clkrt++;
+ clk_src >>= 1;
+ }
+ return clkrt;
+}
+
+/* Select the MMC clock frequency */
+static int jz_mmc_set_clock(u32 rate)
+{
+ int clkrt;
+
+ jz_mmc_stop_clock();
+ __cpm_select_msc_clk(1); /* select clock source from CPM */
+ clkrt = jz_mmc_calc_clkrt(1, rate);
+ REG_MSC_CLKRT = clkrt;
+ return MMC_NO_ERROR;
+}
+
+static void jz_mmc_enable_irq(struct jz_mmc_host *host, unsigned int mask)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&host->lock, flags);
+ host->imask &= ~mask;
+ REG_MSC_IMASK = host->imask;
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void jz_mmc_disable_irq(struct jz_mmc_host *host, unsigned int mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->imask |= mask;
+ REG_MSC_IMASK = host->imask;
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+void jz_set_dma_block_size(int dmanr, int nbyte);
+
+#ifdef USE_DMA
+static inline void
+jz_mmc_start_dma(int chan, unsigned long phyaddr, int count, int mode)
+{
+ unsigned long flags;
+
+ flags = claim_dma_lock();
+ disable_dma(chan);
+ clear_dma_ff(chan);
+ jz_set_dma_block_size(chan, 32);
+ set_dma_mode(chan, mode);
+ set_dma_addr(chan, phyaddr);
+ set_dma_count(chan, count + 31);
+ enable_dma(chan);
+ release_dma_lock(flags);
+}
+
+static irqreturn_t jz_mmc_dma_rx_callback(int irq, void *devid)
+{
+ int chan = rxdmachan;
+
+ disable_dma(chan);
+ if (__dmac_channel_address_error_detected(chan)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n",
+ __FUNCTION__);
+ __dmac_channel_clear_address_error(chan);
+ }
+ if (__dmac_channel_transmit_end_detected(chan)) {
+ __dmac_channel_clear_transmit_end(chan);
+ }
+ return IRQ_HANDLED;
+}
+static irqreturn_t jz_mmc_dma_tx_callback(int irq, void *devid)
+{
+ int chan = txdmachan;
+
+ disable_dma(chan);
+ if (__dmac_channel_address_error_detected(chan)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n",
+ __FUNCTION__);
+ __dmac_channel_clear_address_error(chan);
+ }
+ if (__dmac_channel_transmit_end_detected(chan)) {
+ __dmac_channel_clear_transmit_end(chan);
+ }
+ return IRQ_HANDLED;
+}
+
+/* Prepare DMA to start data transfer from the MMC card */
+static void jz_mmc_rx_setup_data(struct jz_mmc_host *host,
+ struct mmc_data *data)
+{
+ unsigned int nob = data->blocks;
+ int channelrx = rxdmachan;
+ int i;
+ u32 size;
+
+ if (data->flags & MMC_DATA_STREAM)
+ nob = 0xffff;
+
+ REG_MSC_NOB = nob;
+ REG_MSC_BLKLEN = data->blksz;
+ size = nob * data->blksz;
+
+ if (data->flags & MMC_DATA_READ) {
+ host->dma.dir = DMA_FROM_DEVICE;
+ } else {
+ host->dma.dir = DMA_TO_DEVICE;
+ }
+
+ host->dma.len =
+ dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ host->dma.dir);
+
+ for (i = 0; i < host->dma.len; i++) {
+ host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
+ host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]);
+ dma_cache_wback_inv((unsigned long)
+ CKSEG0ADDR(sg_dma_address(data->sg)) +
+ data->sg->offset,
+ host->sg_cpu[i].dcmd);
+ jz_mmc_start_dma(channelrx, host->sg_cpu[i].dtadr,
+ host->sg_cpu[i].dcmd, DMA_MODE_READ);
+ }
+}
+
+/* Prepare DMA to start data transfer from the MMC card */
+static void jz_mmc_tx_setup_data(struct jz_mmc_host *host,
+ struct mmc_data *data)
+{
+ unsigned int nob = data->blocks;
+ int channeltx = txdmachan;
+ int i;
+ u32 size;
+
+ if (data->flags & MMC_DATA_STREAM)
+ nob = 0xffff;
+
+ REG_MSC_NOB = nob;
+ REG_MSC_BLKLEN = data->blksz;
+ size = nob * data->blksz;
+
+ if (data->flags & MMC_DATA_READ) {
+ host->dma.dir = DMA_FROM_DEVICE;
+ } else {
+ host->dma.dir = DMA_TO_DEVICE;
+ }
+
+ host->dma.len =
+ dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ host->dma.dir);
+
+ for (i = 0; i < host->dma.len; i++) {
+ host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
+ host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]);
+ dma_cache_wback_inv((unsigned long)
+ CKSEG0ADDR(sg_dma_address(data->sg)) +
+ data->sg->offset,
+ host->sg_cpu[i].dcmd);
+ jz_mmc_start_dma(channeltx, host->sg_cpu[i].dtadr,
+ host->sg_cpu[i].dcmd, DMA_MODE_WRITE);
+ }
+}
+#else
+static void jz_mmc_receive_pio(struct jz_mmc_host *host)
+{
+
+ struct mmc_data *data = 0;
+ int sg_len = 0, max = 0, count = 0;
+ u32 *buf = 0;
+ struct scatterlist *sg;
+ unsigned int nob;
+
+ data = host->mrq->data;
+ nob = data->blocks;
+ REG_MSC_NOB = nob;
+ REG_MSC_BLKLEN = data->blksz;
+
+ max = host->pio.len;
+ if (host->pio.index < host->dma.len) {
+ sg = &data->sg[host->pio.index];
+ buf = sg_virt(sg) + host->pio.offset;
+
+ /* This is the space left inside the buffer */
+ sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
+ /* Check to if we need less then the size of the sg_buffer */
+ if (sg_len < max) max = sg_len;
+ }
+ max = max / 4;
+ for(count = 0; count < max; count++) {
+ while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY)
+ ;
+ *buf++ = REG_MSC_RXFIFO;
+ }
+ host->pio.len -= count;
+ host->pio.offset += count;
+
+ if (sg_len && count == sg_len) {
+ host->pio.index++;
+ host->pio.offset = 0;
+ }
+}
+
+static void jz_mmc_send_pio(struct jz_mmc_host *host)
+{
+
+ struct mmc_data *data = 0;
+ int sg_len, max, count = 0;
+ u32 *wbuf = 0;
+ struct scatterlist *sg;
+ unsigned int nob;
+
+ data = host->mrq->data;
+ nob = data->blocks;
+
+ REG_MSC_NOB = nob;
+ REG_MSC_BLKLEN = data->blksz;
+
+ /* This is the pointer to the data buffer */
+ sg = &data->sg[host->pio.index];
+ wbuf = sg_virt(sg) + host->pio.offset;
+
+ /* This is the space left inside the buffer */
+ sg_len = data->sg[host->pio.index].length - host->pio.offset;
+
+ /* Check to if we need less then the size of the sg_buffer */
+ max = (sg_len > host->pio.len) ? host->pio.len : sg_len;
+ max = max / 4;
+ for(count = 0; count < max; count++ ) {
+ while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_FULL)
+ ;
+ REG_MSC_TXFIFO = *wbuf++;
+ }
+
+ host->pio.len -= count;
+ host->pio.offset += count;
+
+ if (count == sg_len) {
+ host->pio.index++;
+ host->pio.offset = 0;
+ }
+}
+
+static int
+jz_mmc_prepare_data(struct jz_mmc_host *host, struct mmc_data *data)
+{
+ int datalen = data->blocks * data->blksz;
+
+ host->dma.dir = DMA_BIDIRECTIONAL;
+ host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len, host->dma.dir);
+ if (host->dma.len == 0)
+ return -ETIMEDOUT;
+
+ host->pio.index = 0;
+ host->pio.offset = 0;
+ host->pio.len = datalen;
+ return 0;
+}
+#endif
+
+static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat);
+
+static void jz_mmc_finish_request(struct jz_mmc_host *host, struct mmc_request *mrq)
+{
+ jz_mmc_stop_clock();
+ host->mrq = NULL;
+ host->cmd = NULL;
+ host->data = NULL;
+ mmc_request_done(host->mmc, mrq);
+}
+
+static void jz_mmc_start_cmd(struct jz_mmc_host *host,
+ struct mmc_command *cmd, unsigned int cmdat)
+{
+ u32 timeout = 0x3fffff;
+ unsigned int stat;
+ struct jz_mmc_host *hst = host;
+ WARN_ON(host->cmd != NULL);
+ host->cmd = cmd;
+
+ /* stop MMC clock */
+ jz_mmc_stop_clock();
+
+ /* mask interrupts */
+ REG_MSC_IMASK = 0xff;
+
+ /* clear status */
+ REG_MSC_IREG = 0xff;
+
+ if (cmd->flags & MMC_RSP_BUSY)
+ cmdat |= MSC_CMDAT_BUSY;
+
+#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
+ switch (RSP_TYPE(mmc_resp_type(cmd))) {
+ case RSP_TYPE(MMC_RSP_R1): /* r1,r1b, r6, r7 */
+ cmdat |= MSC_CMDAT_RESPONSE_R1;
+ r_type = 1;
+ break;
+ case RSP_TYPE(MMC_RSP_R3):
+ cmdat |= MSC_CMDAT_RESPONSE_R3;
+ r_type = 1;
+ break;
+ case RSP_TYPE(MMC_RSP_R2):
+ cmdat |= MSC_CMDAT_RESPONSE_R2;
+ r_type = 2;
+ break;
+ default:
+ break;
+ }
+ REG_MSC_CMD = cmd->opcode;
+
+ /* Set argument */
+#ifdef CONFIG_JZ_MMC_BUS_1
+ if (cmd->opcode == 6) {
+ /* set 1 bit sd card bus*/
+ if (cmd->arg ==2)
+ REG_MSC_ARG = 0;
+
+ /* set 1 bit mmc card bus*/
+ if (cmd->arg == 0x3b70101)
+ REG_MSC_ARG = 0x3b70001;
+ } else
+ REG_MSC_ARG = cmd->arg;
+#else
+ REG_MSC_ARG = cmd->arg;
+#endif
+
+ /* Set command */
+ REG_MSC_CMDAT = cmdat;
+
+ /* Send command */
+ jz_mmc_start_clock();
+
+ while (timeout-- && !(REG_MSC_STAT & MSC_STAT_END_CMD_RES))
+ ;
+
+ REG_MSC_IREG = MSC_IREG_END_CMD_RES; /* clear irq flag */
+ if (cmd->opcode == 12) {
+ while (timeout-- && !(REG_MSC_IREG & MSC_IREG_PRG_DONE))
+ ;
+ REG_MSC_IREG = MSC_IREG_PRG_DONE; /* clear status */
+ }
+ if (!mmc_slot_enable) {
+ /* It seems that MSC can't report the MSC_STAT_TIME_OUT_RES when
+ * card was removed. We force to return here.
+ */
+ cmd->error = -ETIMEDOUT;
+ jz_mmc_finish_request(hst, hst->mrq);
+ return;
+ }
+
+ if (SD_IO_SEND_OP_COND == cmd->opcode) {
+ /*
+ * Don't support SDIO card currently.
+ */
+ cmd->error = -ETIMEDOUT;
+ jz_mmc_finish_request(hst, hst->mrq);
+ return;
+ }
+
+ /* Check for status */
+ stat = REG_MSC_STAT;
+ jz_mmc_cmd_done(hst, stat);
+ if (host->data) {
+ if (cmd->opcode == MMC_WRITE_BLOCK || cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
+#ifdef USE_DMA
+ jz_mmc_tx_setup_data(host, host->data);
+#else
+ jz_mmc_send_pio(host);
+ else
+ jz_mmc_receive_pio(host);
+#endif
+ }
+}
+
+static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat)
+{
+ struct mmc_command *cmd = host->cmd;
+ int i, temp[16];
+ u8 *buf;
+ u32 data, v, w1, w2;
+
+ if (!cmd)
+ return 0;
+
+ host->cmd = NULL;
+ buf = (u8 *) temp;
+ switch (r_type) {
+ case 1:
+ {
+ data = REG_MSC_RES;
+ buf[0] = (data >> 8) & 0xff;
+ buf[1] = data & 0xff;
+ data = REG_MSC_RES;
+ buf[2] = (data >> 8) & 0xff;
+ buf[3] = data & 0xff;
+ data = REG_MSC_RES;
+ buf[4] = data & 0xff;
+ cmd->resp[0] =
+ buf[1] << 24 | buf[2] << 16 | buf[3] << 8 |
+ buf[4];
+ break;
+ }
+ case 2:
+ {
+ data = REG_MSC_RES;
+ v = data & 0xffff;
+ for (i = 0; i < 4; i++) {
+ data = REG_MSC_RES;
+ w1 = data & 0xffff;
+ data = REG_MSC_RES;
+ w2 = data & 0xffff;
+ cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
+ v = w2;
+ }
+ break;
+ }
+ case 0:
+ break;
+ }
+ if (stat & MSC_STAT_TIME_OUT_RES) {
+ printk("MSC_STAT_TIME_OUT_RES\n");
+ cmd->error = -ETIMEDOUT;
+ } else if (stat & MSC_STAT_CRC_RES_ERR && cmd->flags & MMC_RSP_CRC) {
+ printk("MSC_STAT_CRC\n");
+ if (cmd->opcode == MMC_ALL_SEND_CID ||
+ cmd->opcode == MMC_SEND_CSD ||
+ cmd->opcode == MMC_SEND_CID) {
+ /* a bogus CRC error can appear if the msb of
+ the 15 byte response is a one */
+ if ((cmd->resp[0] & 0x80000000) == 0)
+ cmd->error = -EILSEQ;
+ }
+ }
+ /*
+ * Did I mention this is Sick. We always need to
+ * discard the upper 8 bits of the first 16-bit word.
+ */
+ if (host->data && cmd->error == 0)
+ jz_mmc_enable_irq(host, MSC_IMASK_DATA_TRAN_DONE);
+ else
+ jz_mmc_finish_request(host, host->mrq);
+
+ return 1;
+}
+
+static int jz_mmc_data_done(struct jz_mmc_host *host, unsigned int stat)
+{
+ struct mmc_data *data = host->data;
+
+ if (!data)
+ return 0;
+ REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE; /* clear status */
+ jz_mmc_stop_clock();
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
+ host->dma_dir);
+ if (stat & MSC_STAT_TIME_OUT_READ) {
+ printk("MMC/SD timeout, MMC_STAT 0x%x\n", stat);
+ data->error = -ETIMEDOUT;
+ } else if (REG_MSC_STAT &
+ (MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR)) {
+ printk("MMC/SD CRC error, MMC_STAT 0x%x\n", stat);
+ data->error = -EILSEQ;
+ }
+ /*
+ * There appears to be a hardware design bug here. There seems to
+ * be no way to find out how much data was transferred to the card.
+ * This means that if there was an error on any block, we mark all
+ * data blocks as being in error.
+ */
+ if (data->error == 0)
+ data->bytes_xfered = data->blocks * data->blksz;
+ else
+ data->bytes_xfered = 0;
+
+ jz_mmc_disable_irq(host, MSC_IMASK_DATA_TRAN_DONE);
+ host->data = NULL;
+ if (host->mrq->stop) {
+ jz_mmc_stop_clock();
+ jz_mmc_start_cmd(host, host->mrq->stop, 0);
+ } else {
+ jz_mmc_finish_request(host, host->mrq);
+ }
+ return 1;
+}
+
+static void jz_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct jz_mmc_host *host = mmc_priv(mmc);
+ unsigned int cmdat;
+
+ /* stop MMC clock */
+ jz_mmc_stop_clock();
+
+ /* Save current request for the future processing */
+ host->mrq = mrq;
+ host->data = mrq->data;
+ cmdat = host->cmdat;
+ host->cmdat &= ~MSC_CMDAT_INIT;
+
+ if (mrq->data) {
+ cmdat &= ~MSC_CMDAT_BUSY;
+#ifdef USE_DMA
+ if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6))
+
+ cmdat |=
+ MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN |
+ MSC_CMDAT_DMA_EN;
+ else {
+#ifdef CONFIG_JZ_MMC_BUS_1
+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT;
+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN |
+ MSC_CMDAT_DMA_EN;
+#else
+ cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_DMA_EN;
+#endif
+ }
+ if (mrq->data->flags & MMC_DATA_WRITE)
+ cmdat |= MSC_CMDAT_WRITE;
+
+ if (mrq->data->flags & MMC_DATA_STREAM)
+ cmdat |= MSC_CMDAT_STREAM_BLOCK;
+ if (mrq->cmd->opcode != MMC_WRITE_BLOCK
+ && mrq->cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)
+ jz_mmc_rx_setup_data(host, mrq->data);
+#else /*USE_DMA*/
+
+ if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6))
+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN;
+ else {
+#ifdef CONFIG_JZ_MMC_BUS_1
+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT;
+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN;
+#else
+ cmdat |= MSC_CMDAT_DATA_EN;
+#endif
+ }
+ if (mrq->data->flags & MMC_DATA_WRITE)
+ cmdat |= MSC_CMDAT_WRITE;
+
+ if (mrq->data->flags & MMC_DATA_STREAM)
+ cmdat |= MSC_CMDAT_STREAM_BLOCK;
+ jz_mmc_prepare_data(host, host->data);
+#endif /*USE_DMA*/
+ }
+ jz_mmc_start_cmd(host, mrq->cmd, cmdat);
+}
+
+static irqreturn_t jz_mmc_irq(int irq, void *devid)
+{
+ struct jz_mmc_host *host = devid;
+ unsigned int ireg;
+ int handled = 0;
+
+ ireg = REG_MSC_IREG;
+
+ if (ireg) {
+ unsigned stat = REG_MSC_STAT;
+ if (ireg & MSC_IREG_DATA_TRAN_DONE)
+ handled |= jz_mmc_data_done(host, stat);
+ }
+ return IRQ_RETVAL(handled);
+}
+
+/* Returns true if MMC slot is empty */
+static int jz_mmc_slot_is_empty(int slot)
+{
+ int empty;
+
+ empty = (__msc_card_detected(slot) == 0) ? 1 : 0;
+
+ if (empty) {
+ /* wait for card insertion */
+#ifdef CONFIG_MIPS_JZ4740_LYRA
+ __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN);
+#else
+ __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN);
+#endif
+ } else {
+ /* wait for card removal */
+#ifdef CONFIG_MIPS_JZ4740_LYRA
+ __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN);
+#else
+ __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN);
+#endif
+ }
+
+ return empty;
+}
+
+static irqreturn_t jz_mmc_detect_irq(int irq, void *devid)
+{
+ struct jz_mmc_host *host = (struct jz_mmc_host *) devid;
+
+ if (jz_mmc_slot_is_empty(0)) {
+ mmc_slot_enable = 0;
+ mmc_detect_change(host->mmc, 50);
+ } else {
+ mmc_slot_enable = 1;
+ mmc_detect_change(host->mmc, 50);
+ }
+ return IRQ_HANDLED;
+}
+
+static int jz_mmc_get_ro(struct mmc_host *mmc)
+{
+ struct jz_mmc_host *host = mmc_priv(mmc);
+
+ if (host->pdata && host->pdata->get_ro)
+ return host->pdata->get_ro(mmc_dev(mmc));
+ /* Host doesn't support read only detection so assume writeable */
+ return 0;
+}
+
+/* set clock and power */
+static void jz_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct jz_mmc_host *host = mmc_priv(mmc);
+
+ if (ios->clock)
+ jz_mmc_set_clock(ios->clock);
+ else
+ jz_mmc_stop_clock();
+
+ if (host->power_mode != ios->power_mode) {
+ host->power_mode = ios->power_mode;
+
+ if (ios->power_mode == MMC_POWER_ON)
+ host->cmdat |= CMDAT_INIT;
+ }
+
+ if ((ios->bus_width == MMC_BUS_WIDTH_4) || (ios->bus_width == MMC_BUS_WIDTH_8))
+ host->cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT;
+ else
+ host->cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT;
+}
+
+static const struct mmc_host_ops jz_mmc_ops = {
+ .request = jz_mmc_request,
+ .get_ro = jz_mmc_get_ro,
+ .set_ios = jz_mmc_set_ios,
+};
+
+static int jz_mmc_probe(struct platform_device *pdev)
+{
+ int retval;
+ struct mmc_host *mmc;
+ struct jz_mmc_host *host = NULL;
+ int irq;
+ struct resource *r;
+
+ __gpio_as_msc();
+ __msc_init_io();
+ __msc_enable_power();
+
+ __msc_reset();
+
+ /* On reset, stop MMC clock */
+ jz_mmc_stop_clock();
+
+ MMC_IRQ_MASK();
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!r || irq < 0)
+ return -ENXIO;
+
+ r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
+ if (!r)
+ return -EBUSY;
+
+ mmc = mmc_alloc_host(sizeof(struct jz_mmc_host), &pdev->dev);
+ if (!mmc) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ mmc->ops = &jz_mmc_ops;
+ mmc->f_min = MMC_CLOCK_SLOW;
+ mmc->f_max = SD_CLOCK_FAST;
+ /*
+ * We can do SG-DMA, but we don't because we never know how much
+ * data we successfully wrote to the card.
+ */
+ mmc->max_phys_segs = NR_SG;
+ /*
+ * Our hardware DMA can handle a maximum of one page per SG entry.
+ */
+ mmc->max_seg_size = PAGE_SIZE;
+ /*
+ * Block length register is 10 bits.
+ */
+ mmc->max_blk_size = 1023;
+ /*
+ * Block count register is 16 bits.
+ */
+ mmc->max_blk_count = 65535;
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->pdata = pdev->dev.platform_data;
+ mmc->ocr_avail = host->pdata ?
+ host->pdata->ocr_mask : MMC_VDD_32_33 | MMC_VDD_33_34;
+ host->mmc->caps =
+ MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED
+ | MMC_CAP_MMC_HIGHSPEED;
+ /*
+ *MMC_CAP_4_BIT_DATA (1 << 0) The host can do 4 bit transfers
+ *
+ */
+ host->sg_cpu =
+ dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma,
+ GFP_KERNEL);
+ if (!host->sg_cpu) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ spin_lock_init(&host->lock);
+ host->irq = IRQ_MSC;
+ host->imask = 0xff;
+ /*
+ * Ensure that the host controller is shut down, and setup
+ * with our defaults.
+ */
+ retval = request_irq(IRQ_MSC, jz_mmc_irq, 0, "MMC/SD", host);
+ if (retval) {
+ printk(KERN_ERR "MMC/SD: can't request MMC/SD IRQ\n");
+ return retval;
+ }
+ jz_mmc_slot_is_empty(0);
+ /* Request card detect interrupt */
+
+ retval = request_irq(MSC_HOTPLUG_IRQ, jz_mmc_detect_irq, 0, //SA_INTERRUPT,
+ "MMC card detect", host);
+ if (retval) {
+ printk(KERN_ERR "MMC/SD: can't request card detect IRQ\n");
+ goto err1;
+ }
+#ifdef USE_DMA
+ /* Request MMC Rx DMA channel */
+ rxdmachan =
+ jz_request_dma(DMA_ID_MSC_RX, "MMC Rx", jz_mmc_dma_rx_callback,
+ 0, host);
+ if (rxdmachan < 0) {
+ printk(KERN_ERR "jz_request_dma failed for MMC Rx\n");
+ goto err2;
+ }
+
+ /* Request MMC Tx DMA channel */
+ txdmachan =
+ jz_request_dma(DMA_ID_MSC_TX, "MMC Tx", jz_mmc_dma_tx_callback,
+ 0, host);
+ if (txdmachan < 0) {
+ printk(KERN_ERR "jz_request_dma failed for MMC Tx\n");
+ goto err3;
+ }
+#endif
+ platform_set_drvdata(pdev, mmc);
+ mmc_add_host(mmc);
+
+ printk(JZ_SOC_NAME ": SD/MMC card driver registered.\n");
+
+ /* Detect card during initialization */
+#ifdef CONFIG_SOC_JZ4740
+ if (!jz_mmc_slot_is_empty(0)) {
+ mmc_slot_enable = 1;
+ mmc_detect_change(host->mmc, 0);
+ }
+#endif
+ return 0;
+
+err1:free_irq(IRQ_MSC, &host);
+#ifdef USE_DMA
+ err2:jz_free_dma(rxdmachan);
+ err3:jz_free_dma(txdmachan);
+#endif
+out:
+ if (host) {
+ if (host->sg_cpu)
+ dma_free_coherent(&pdev->dev, PAGE_SIZE,
+ host->sg_cpu, host->sg_dma);
+ }
+ if (mmc)
+ mmc_free_host(mmc);
+ return -1;
+}
+
+static int jz_mmc_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ unsigned long flags;
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (mmc) {
+ struct jz_mmc_host *host = mmc_priv(mmc);
+
+ if (host->pdata && host->pdata->exit)
+ host->pdata->exit(&pdev->dev, mmc);
+
+ mmc_remove_host(mmc);
+
+ local_irq_save(flags);
+ jz_mmc_stop_clock();
+ __msc_disable_power();
+ jz_free_dma(rxdmachan);
+ jz_free_dma(txdmachan);
+ free_irq(IRQ_MSC, host);
+ local_irq_restore(flags);
+ mmc_free_host(mmc);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+pm_message_t state;
+static int jz_mmc_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct mmc_host *mmc = platform_get_drvdata(dev);
+ int ret = 0;
+
+ __msc_disable_power();
+ if (mmc)
+ ret = mmc_suspend_host(mmc, state);
+
+ return ret;
+}
+
+static int jz_mmc_resume(struct platform_device *dev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(dev);
+ int ret = 0;
+#if 0
+ /*for sandisk BB0807011816D and other strange cards*/
+ int i;
+
+ for(i = 104; i < 110; i++)
+ __gpio_as_input(i);
+
+ /* perhaps you should mdelay more */
+ mdelay(1000);
+ __gpio_as_msc();
+#endif
+ __msc_init_io();
+ __msc_enable_power();
+ __msc_reset();
+
+ if (!jz_mmc_slot_is_empty(0)) {
+ mmc_slot_enable = 1;
+ mmc_detect_change(mmc, 10);
+ }
+
+ if (mmc)
+ ret = mmc_resume_host(mmc);
+
+ return ret;
+}
+#else
+#define jz_mmc_suspend NULL
+#define jz_mmc_resume NULL
+#endif
+
+static struct platform_driver jz_mmc_driver = {
+ .probe = jz_mmc_probe,
+ .remove = jz_mmc_remove,
+ .suspend = jz_mmc_suspend,
+ .resume = jz_mmc_resume,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init jz_mmc_init(void)
+{
+ return platform_driver_register(&jz_mmc_driver);
+}
+
+static void __exit jz_mmc_exit(void)
+{
+ platform_driver_unregister(&jz_mmc_driver);
+}
+
+module_init(jz_mmc_init);
+module_exit(jz_mmc_exit);
+
+MODULE_DESCRIPTION("JZ47XX SD/Multimedia Card Interface Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/jz_mmc.h b/drivers/mmc/host/jz_mmc.h
new file mode 100644
index 00000000000..c733529b7fb
--- /dev/null
+++ b/drivers/mmc/host/jz_mmc.h
@@ -0,0 +1,65 @@
+#ifndef __JZ_MMC_H__
+#define __JZ_MMC_H__
+
+#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */
+#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */
+#define SD_CLOCK_FAST 24000000 /* 24 MHz for SD Cards */
+#define MMC_NO_ERROR 0
+/* Extra MMC commands for state control */
+/* Use negative numbers to disambiguate */
+#define MMC_CIM_RESET -1
+#define MMC_SET_CLOCK 100
+
+typedef struct jzsoc_dma_desc {
+ volatile u32 ddadr; /* Points to the next descriptor + flags */
+ volatile u32 dsadr; /* DSADR value for the current transfer */
+ volatile u32 dtadr; /* DTADR value for the current transfer */
+ volatile u32 dcmd; /* DCMD value for the current transfer */
+} jzsoc_dma_desc;
+
+
+
+
+#include <linux/interrupt.h>
+
+struct device;
+struct mmc_host;
+
+struct jz_mmc_platform_data {
+ unsigned int ocr_mask; /* available voltages */
+ unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */
+ int (*init)(struct device *, irq_handler_t , void *);
+ int (*get_ro)(struct device *);
+ void (*setpower)(struct device *, unsigned int);
+ void (*exit)(struct device *, void *);
+};
+
+//extern void pxa_set_mci_info(struct pxamci_platform_data *info);
+
+
+
+#define SZ_1K 0x00000400
+#define SZ_4K 0x00001000
+#define SZ_8K 0x00002000
+#define SZ_16K 0x00004000
+#define SZ_64K 0x00010000
+#define SZ_128K 0x00020000
+#define SZ_256K 0x00040000
+#define SZ_512K 0x00080000
+
+#define SZ_1M 0x00100000
+#define SZ_2M 0x00200000
+#define SZ_4M 0x00400000
+#define SZ_8M 0x00800000
+#define SZ_16M 0x01000000
+#define SZ_32M 0x02000000
+#define SZ_64M 0x04000000
+#define SZ_128M 0x08000000
+#define SZ_256M 0x10000000
+#define SZ_512M 0x20000000
+
+#define SZ_1G 0x40000000
+#define SZ_2G 0x80000000
+
+
+#endif /* __JZ_MMC_H__ */
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 82d1e4de475..4920e63c097 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -17,7 +17,13 @@ obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_CHAR) += mtdchar.o
obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
+
+ifeq ($(CONFIG_JZSOC), y)
+obj-$(CONFIG_MTD_BLOCK) += mtdblock-jz.o
+else
obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
+endif
+
obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o
obj-$(CONFIG_FTL) += ftl.o
obj-$(CONFIG_NFTL) += nftl.o
@@ -26,6 +32,8 @@ obj-$(CONFIG_RFD_FTL) += rfd_ftl.o
obj-$(CONFIG_SSFDC) += ssfdc.o
obj-$(CONFIG_MTD_OOPS) += mtdoops.o
+obj-$(CONFIG_UDC_USE_LB_CACHE) += udc_cache.o
+
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o
diff --git a/drivers/mtd/mtd-utils/COPYING b/drivers/mtd/mtd-utils/COPYING
new file mode 100644
index 00000000000..60549be514a
--- /dev/null
+++ b/drivers/mtd/mtd-utils/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/drivers/mtd/mtd-utils/MAKEDEV b/drivers/mtd/mtd-utils/MAKEDEV
new file mode 100644
index 00000000000..b31e61fd61b
--- /dev/null
+++ b/drivers/mtd/mtd-utils/MAKEDEV
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+function mkftl () {
+ mknod /dev/ftl$1 b 44 $2
+ for a in `seq 1 15`; do
+ mknod /dev/ftl$1$a b 44 `expr $2 + $a`
+ done
+}
+function mknftl () {
+ mknod /dev/nftl$1 b 93 $2
+ for a in `seq 1 15`; do
+ mknod /dev/nftl$1$a b 93 `expr $2 + $a`
+ done
+}
+function mkrfd () {
+ mknod /dev/rfd$1 b 256 $2
+ for a in `seq 1 15`; do
+ mknod /dev/rfd$1$a b 256 `expr $2 + $a`
+ done
+}
+function mkinftl () {
+ mknod /dev/inftl$1 b 96 $2
+ for a in `seq 1 15`; do
+ mknod /dev/inftl$1$a b 96 `expr $2 + $a`
+ done
+}
+
+M=0
+for C in a b c d e f g h i j k l m n o p; do
+ mkftl $C $M
+ mknftl $C $M
+ mkrfd $C $M
+ mkinftl $C $M
+ let M=M+16
+done
+
+for a in `seq 0 16` ; do
+ mknod /dev/mtd$a c 90 `expr $a + $a`
+ mknod /dev/mtdr$a c 90 `expr $a + $a + 1`
+ mknod /dev/mtdblock$a b 31 $a
+done
+
diff --git a/drivers/mtd/mtd-utils/Makefile b/drivers/mtd/mtd-utils/Makefile
new file mode 100644
index 00000000000..6895fdd1d12
--- /dev/null
+++ b/drivers/mtd/mtd-utils/Makefile
@@ -0,0 +1,105 @@
+
+# -*- sh -*-
+
+OPTFLAGS := -O2 -Wall
+SBINDIR=/usr/sbin
+MANDIR=/usr/share/man
+INCLUDEDIR=/usr/include
+CROSS=mipsel-linux-
+CC := $(CROSS)gcc
+CFLAGS := -I./include $(OPTFLAGS)
+
+ifeq ($(origin CROSS),undefined)
+ BUILDDIR := .
+else
+# Remove the trailing slash to make the directory name
+ BUILDDIR := .#$(CROSS:-=)
+endif
+
+ifeq ($(WITHOUT_XATTR), 1)
+ CFLAGS += -DWITHOUT_XATTR
+endif
+
+#RAWTARGETS = ftl_format flash_erase flash_eraseall nanddump doc_loadbios \
+# ftl_check mkfs.jffs2 flash_lock flash_unlock flash_info \
+# flash_otp_info flash_otp_dump mtd_debug flashcp nandwrite nandtest \
+# jffs2dump \
+# nftldump nftl_format docfdisk \
+# rfddump rfdformat \
+# serve_image recv_image \
+# sumtool #jffs2reader
+
+RAWTARGETS = flash_erase flash_eraseall nanddump nanddump_vfat \
+ flash_info \
+ flash_otp_info flash_otp_dump nandwrite nandwrite_mlc \
+ nandtest \
+ sumtool #jffs2reader
+
+TARGETS = $(foreach target,$(RAWTARGETS),$(BUILDDIR)/$(target))
+
+SYMLINKS =
+
+%: %.o
+ $(CC) $(CFLAGS) $(LDFLAGS) -g -o $@ $^
+
+$(BUILDDIR)/%.o: %.c
+ mkdir -p $(BUILDDIR)
+ $(CC) $(CFLAGS) -g -c -o $@ $< -g -Wp,-MD,$(BUILDDIR)/.$(<F).dep
+
+.SUFFIXES:
+
+all: $(TARGETS)
+ mkdir -p $(BUILDDIR)/mtd-utils-dir
+ cp $(TARGETS) $(BUILDDIR)/mtd-utils-dir
+ make -C $(BUILDDIR)/ubi-utils
+
+IGNORE=${wildcard $(BUILDDIR)/.*.c.dep}
+-include ${IGNORE}
+
+clean:
+ rm -f $(BUILDDIR)/*.o $(TARGETS) $(BUILDDIR)/.*.c.dep $(SYMLINKS)
+ rm -fr $(BUILDDIR)/target-bins-dir
+ if [ "$(BUILDDIR)x" != ".x" ]; then rm -rf $(BUILDDIR); fi
+ make -C $(BUILDDIR)/ubi-utils clean
+
+$(SYMLINKS):
+ ln -sf ../fs/jffs2/$@ $@
+
+$(BUILDDIR)/mkfs.jffs2: $(BUILDDIR)/crc32.o \
+ $(BUILDDIR)/compr_rtime.o \
+ $(BUILDDIR)/mkfs.jffs2.o \
+ $(BUILDDIR)/compr_zlib.o \
+ $(BUILDDIR)/compr_lzo.o \
+ $(BUILDDIR)/compr.o \
+ $(BUILDDIR)/rbtree.o
+ $(CC) $(LDFLAGS) -o $@ $^ -lz -llzo2
+
+$(BUILDDIR)/flash_eraseall: $(BUILDDIR)/crc32.o $(BUILDDIR)/flash_eraseall.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+$(BUILDDIR)/jffs2reader: $(BUILDDIR)/jffs2reader.o
+ $(CC) $(LDFLAGS) -o $@ $^ -lz
+
+$(BUILDDIR)/jffs2dump: $(BUILDDIR)/jffs2dump.o $(BUILDDIR)/crc32.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+$(BUILDDIR)/sumtool: $(BUILDDIR)/sumtool.o $(BUILDDIR)/crc32.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+$(BUILDDIR)/serve_image: $(BUILDDIR)/serve_image.o $(BUILDDIR)/crc32.o $(BUILDDIR)/fec.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+$(BUILDDIR)/recv_image: $(BUILDDIR)/recv_image.o $(BUILDDIR)/crc32.o $(BUILDDIR)/fec.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+$(BUILDDIR)/fectest: $(BUILDDIR)/fectest.o $(BUILDDIR)/crc32.o $(BUILDDIR)/fec.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+
+
+install: ${TARGETS}
+ mkdir -p ${DESTDIR}/${SBINDIR}
+ install -m0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/
+ mkdir -p ${DESTDIR}/${MANDIR}/man1
+ gzip -9c mkfs.jffs2.1 > ${DESTDIR}/${MANDIR}/man1/mkfs.jffs2.1.gz
+ make -C $(BUILDDIR)/ubi-utils install
diff --git a/drivers/mtd/mtd-utils/compr.c b/drivers/mtd/mtd-utils/compr.c
new file mode 100644
index 00000000000..7028c936a08
--- /dev/null
+++ b/drivers/mtd/mtd-utils/compr.c
@@ -0,0 +1,538 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ * University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory
+ * in the jffs2 directory.
+ */
+
+#include "compr.h"
+#include <string.h>
+#include <stdlib.h>
+#include <linux/jffs2.h>
+
+#define FAVOUR_LZO_PERCENT 80
+
+extern int page_size;
+
+/* LIST IMPLEMENTATION (from linux/list.h) */
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = (void *) 0;
+ entry->prev = (void *) 0;
+}
+
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+
+/* Available compressors are on this list */
+static LIST_HEAD(jffs2_compressor_list);
+
+/* Actual compression mode */
+static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
+
+void jffs2_set_compression_mode(int mode)
+{
+ jffs2_compression_mode = mode;
+}
+
+int jffs2_get_compression_mode(void)
+{
+ return jffs2_compression_mode;
+}
+
+/* Statistics for blocks stored without compression */
+static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
+
+/* Compression test stuffs */
+
+static int jffs2_compression_check = 0;
+
+static unsigned char *jffs2_compression_check_buf = NULL;
+
+void jffs2_compression_check_set(int yesno)
+{
+ jffs2_compression_check = yesno;
+}
+
+int jffs2_compression_check_get(void)
+{
+ return jffs2_compression_check;
+}
+
+static int jffs2_error_cnt = 0;
+
+int jffs2_compression_check_errorcnt_get(void)
+{
+ return jffs2_error_cnt;
+}
+
+#define JFFS2_BUFFER_FILL 0x55
+
+/* Called before compression (if compression_check is setted) to prepare
+ the buffer for buffer overflow test */
+static void jffs2_decompression_test_prepare(unsigned char *buf, int size)
+{
+ memset(buf,JFFS2_BUFFER_FILL,size+1);
+}
+
+/* Called after compression (if compression_check is setted) to test the result */
+static void jffs2_decompression_test(struct jffs2_compressor *compr,
+ unsigned char *data_in, unsigned char *output_buf,
+ uint32_t cdatalen, uint32_t datalen, uint32_t buf_size)
+{
+ uint32_t i;
+
+ /* buffer overflow test */
+ for (i=buf_size;i>cdatalen;i--) {
+ if (output_buf[i]!=JFFS2_BUFFER_FILL) {
+ fprintf(stderr,"COMPR_ERROR: buffer overflow at %s. "
+ "(bs=%d csize=%d b[%d]=%d)\n", compr->name,
+ buf_size, cdatalen, i, (int)(output_buf[i]));
+ jffs2_error_cnt++;
+ return;
+ }
+ }
+ /* allocing temporary buffer for decompression */
+ if (!jffs2_compression_check_buf) {
+ jffs2_compression_check_buf = malloc(page_size);
+ if (!jffs2_compression_check_buf) {
+ fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n");
+ jffs2_compression_check = 0;
+ return;
+ }
+ }
+ /* decompressing */
+ if (!compr->decompress) {
+ fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name);
+ jffs2_error_cnt++;
+ return;
+ }
+ if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen,NULL)) {
+ fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name);
+ jffs2_error_cnt++;
+ }
+ /* validate decompression */
+ else {
+ for (i=0;i<datalen;i++) {
+ if (data_in[i]!=jffs2_compression_check_buf[i]) {
+ fprintf(stderr,"JFFS2 compression check: data mismatch at %s (pos %d).\n", compr->name, i);
+ jffs2_error_cnt++;
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Return 1 to use this compression
+ */
+static int jffs2_is_best_compression(struct jffs2_compressor *this,
+ struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
+{
+ switch (jffs2_compression_mode) {
+ case JFFS2_COMPR_MODE_SIZE:
+ if (bestsize > size)
+ return 1;
+ return 0;
+ case JFFS2_COMPR_MODE_FAVOURLZO:
+ if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size))
+ return 1;
+ if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
+ return 1;
+ if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
+ return 1;
+ if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size)
+ return 1;
+
+ return 0;
+ }
+ /* Shouldn't happen */
+ return 0;
+}
+
+/* jffs2_compress:
+ * @data: Pointer to uncompressed data
+ * @cdata: Pointer to returned pointer to buffer for compressed data
+ * @datalen: On entry, holds the amount of data available for compression.
+ * On exit, expected to hold the amount of data actually compressed.
+ * @cdatalen: On entry, holds the amount of space available for compressed
+ * data. On exit, expected to hold the actual size of the compressed
+ * data.
+ *
+ * Returns: Lower byte to be stored with data indicating compression type used.
+ * Zero is used to show that the data could not be compressed - the
+ * compressed version was actually larger than the original.
+ * Upper byte will be used later. (soon)
+ *
+ * If the cdata buffer isn't large enough to hold all the uncompressed data,
+ * jffs2_compress should compress as much as will fit, and should set
+ * *datalen accordingly to show the amount of data which were compressed.
+ */
+uint16_t jffs2_compress( unsigned char *data_in, unsigned char **cpage_out,
+ uint32_t *datalen, uint32_t *cdatalen)
+{
+ int ret = JFFS2_COMPR_NONE;
+ int compr_ret;
+ struct jffs2_compressor *this, *best=NULL;
+ unsigned char *output_buf = NULL, *tmp_buf;
+ uint32_t orig_slen, orig_dlen;
+ uint32_t best_slen=0, best_dlen=0;
+
+ switch (jffs2_compression_mode) {
+ case JFFS2_COMPR_MODE_NONE:
+ break;
+ case JFFS2_COMPR_MODE_PRIORITY:
+ orig_slen = *datalen;
+ orig_dlen = *cdatalen;
+ output_buf = malloc(orig_dlen+jffs2_compression_check);
+ if (!output_buf) {
+ fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. Compression failed.\n");
+ goto out;
+ }
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ /* Skip decompress-only backwards-compatibility and disabled modules */
+ if ((!this->compress)||(this->disabled))
+ continue;
+
+ this->usecount++;
+
+ if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
+ jffs2_decompression_test_prepare(output_buf, orig_dlen);
+
+ *datalen = orig_slen;
+ *cdatalen = orig_dlen;
+ compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
+ this->usecount--;
+ if (!compr_ret) {
+ ret = this->compr;
+ this->stat_compr_blocks++;
+ this->stat_compr_orig_size += *datalen;
+ this->stat_compr_new_size += *cdatalen;
+ if (jffs2_compression_check)
+ jffs2_decompression_test(this, data_in, output_buf, *cdatalen, *datalen, orig_dlen);
+ break;
+ }
+ }
+ if (ret == JFFS2_COMPR_NONE) free(output_buf);
+ break;
+ case JFFS2_COMPR_MODE_FAVOURLZO:
+ case JFFS2_COMPR_MODE_SIZE:
+ orig_slen = *datalen;
+ orig_dlen = *cdatalen;
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ uint32_t needed_buf_size;
+
+ if (jffs2_compression_mode == JFFS2_COMPR_MODE_FAVOURLZO)
+ needed_buf_size = orig_slen + jffs2_compression_check;
+ else
+ needed_buf_size = orig_dlen + jffs2_compression_check;
+
+ /* Skip decompress-only backwards-compatibility and disabled modules */
+ if ((!this->compress)||(this->disabled))
+ continue;
+ /* Allocating memory for output buffer if necessary */
+ if ((this->compr_buf_size < needed_buf_size) && (this->compr_buf)) {
+ free(this->compr_buf);
+ this->compr_buf_size=0;
+ this->compr_buf=NULL;
+ }
+ if (!this->compr_buf) {
+ tmp_buf = malloc(needed_buf_size);
+ if (!tmp_buf) {
+ fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
+ continue;
+ }
+ else {
+ this->compr_buf = tmp_buf;
+ this->compr_buf_size = orig_dlen;
+ }
+ }
+ this->usecount++;
+ if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
+ jffs2_decompression_test_prepare(this->compr_buf,this->compr_buf_size);
+ *datalen = orig_slen;
+ *cdatalen = orig_dlen;
+ compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
+ this->usecount--;
+ if (!compr_ret) {
+ if (jffs2_compression_check)
+ jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen, this->compr_buf_size);
+ if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
+ && (*cdatalen < *datalen)) {
+ best_dlen = *cdatalen;
+ best_slen = *datalen;
+ best = this;
+ }
+ }
+ }
+ if (best_dlen) {
+ *cdatalen = best_dlen;
+ *datalen = best_slen;
+ output_buf = best->compr_buf;
+ best->compr_buf = NULL;
+ best->compr_buf_size = 0;
+ best->stat_compr_blocks++;
+ best->stat_compr_orig_size += best_slen;
+ best->stat_compr_new_size += best_dlen;
+ ret = best->compr;
+ }
+ break;
+ default:
+ fprintf(stderr,"mkfs.jffs2: unknow compression mode.\n");
+ }
+out:
+ if (ret == JFFS2_COMPR_NONE) {
+ *cpage_out = data_in;
+ *datalen = *cdatalen;
+ none_stat_compr_blocks++;
+ none_stat_compr_size += *datalen;
+ }
+ else {
+ *cpage_out = output_buf;
+ }
+ return ret;
+}
+
+
+int jffs2_register_compressor(struct jffs2_compressor *comp)
+{
+ struct jffs2_compressor *this;
+
+ if (!comp->name) {
+ fprintf(stderr,"NULL compressor name at registering JFFS2 compressor. Failed.\n");
+ return -1;
+ }
+ comp->compr_buf_size=0;
+ comp->compr_buf=NULL;
+ comp->usecount=0;
+ comp->stat_compr_orig_size=0;
+ comp->stat_compr_new_size=0;
+ comp->stat_compr_blocks=0;
+ comp->stat_decompr_blocks=0;
+
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ if (this->priority < comp->priority) {
+ list_add(&comp->list, this->list.prev);
+ goto out;
+ }
+ }
+ list_add_tail(&comp->list, &jffs2_compressor_list);
+out:
+ return 0;
+}
+
+int jffs2_unregister_compressor(struct jffs2_compressor *comp)
+{
+
+ if (comp->usecount) {
+ fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n");
+ return -1;
+ }
+ list_del(&comp->list);
+
+ return 0;
+}
+
+#define JFFS2_STAT_BUF_SIZE 16000
+
+char *jffs2_list_compressors(void)
+{
+ struct jffs2_compressor *this;
+ char *buf, *act_buf;
+
+ act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
+ if ((this->disabled)||(!this->compress))
+ act_buf += sprintf(act_buf,"disabled");
+ else
+ act_buf += sprintf(act_buf,"enabled");
+ act_buf += sprintf(act_buf,"\n");
+ }
+ return buf;
+}
+
+char *jffs2_stats(void)
+{
+ struct jffs2_compressor *this;
+ char *buf, *act_buf;
+
+ act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE);
+
+ act_buf += sprintf(act_buf,"Compression mode: ");
+ switch (jffs2_compression_mode) {
+ case JFFS2_COMPR_MODE_NONE:
+ act_buf += sprintf(act_buf,"none");
+ break;
+ case JFFS2_COMPR_MODE_PRIORITY:
+ act_buf += sprintf(act_buf,"priority");
+ break;
+ case JFFS2_COMPR_MODE_SIZE:
+ act_buf += sprintf(act_buf,"size");
+ break;
+ case JFFS2_COMPR_MODE_FAVOURLZO:
+ act_buf += sprintf(act_buf, "favourlzo");
+ break;
+ default:
+ act_buf += sprintf(act_buf,"unkown");
+ break;
+ }
+ act_buf += sprintf(act_buf,"\nCompressors:\n");
+ act_buf += sprintf(act_buf,"%10s ","none");
+ act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks,
+ none_stat_compr_size, none_stat_decompr_blocks);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ act_buf += sprintf(act_buf,"%10s (prio:%d) ",this->name,this->priority);
+ if ((this->disabled)||(!this->compress))
+ act_buf += sprintf(act_buf,"- ");
+ else
+ act_buf += sprintf(act_buf,"+ ");
+ act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this->stat_compr_blocks,
+ this->stat_compr_new_size, this->stat_compr_orig_size,
+ this->stat_decompr_blocks);
+ act_buf += sprintf(act_buf,"\n");
+ }
+ return buf;
+}
+
+int jffs2_set_compression_mode_name(const char *name)
+{
+ if (!strcmp("none",name)) {
+ jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+ return 0;
+ }
+ if (!strcmp("priority",name)) {
+ jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
+ return 0;
+ }
+ if (!strcmp("size",name)) {
+ jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
+ return 0;
+ }
+ if (!strcmp("favourlzo", name)) {
+ jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int jffs2_compressor_Xable(const char *name, int disabled)
+{
+ struct jffs2_compressor *this;
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ if (!strcmp(this->name, name)) {
+ this->disabled = disabled;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int jffs2_enable_compressor_name(const char *name)
+{
+ return jffs2_compressor_Xable(name, 0);
+}
+
+int jffs2_disable_compressor_name(const char *name)
+{
+ return jffs2_compressor_Xable(name, 1);
+}
+
+int jffs2_set_compressor_priority(const char *name, int priority)
+{
+ struct jffs2_compressor *this,*comp;
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ if (!strcmp(this->name, name)) {
+ this->priority = priority;
+ comp = this;
+ goto reinsert;
+ }
+ }
+ fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name);
+ return 1;
+reinsert:
+ /* list is sorted in the order of priority, so if
+ we change it we have to reinsert it into the
+ good place */
+ list_del(&comp->list);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ if (this->priority < comp->priority) {
+ list_add(&comp->list, this->list.prev);
+ return 0;
+ }
+ }
+ list_add_tail(&comp->list, &jffs2_compressor_list);
+ return 0;
+}
+
+
+int jffs2_compressors_init(void)
+{
+#ifdef CONFIG_JFFS2_ZLIB
+ jffs2_zlib_init();
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+ jffs2_rtime_init();
+#endif
+#ifdef CONFIG_JFFS2_LZO
+ jffs2_lzo_init();
+#endif
+ return 0;
+}
+
+int jffs2_compressors_exit(void)
+{
+#ifdef CONFIG_JFFS2_RTIME
+ jffs2_rtime_exit();
+#endif
+#ifdef CONFIG_JFFS2_ZLIB
+ jffs2_zlib_exit();
+#endif
+#ifdef CONFIG_JFFS2_LZO
+ jffs2_lzo_exit();
+#endif
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/compr.h b/drivers/mtd/mtd-utils/compr.h
new file mode 100644
index 00000000000..51bf0dd6350
--- /dev/null
+++ b/drivers/mtd/mtd-utils/compr.h
@@ -0,0 +1,119 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ * University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in the
+ * jffs2 directory.
+ */
+
+#ifndef __JFFS2_COMPR_H__
+#define __JFFS2_COMPR_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "linux/jffs2.h"
+
+#define CONFIG_JFFS2_ZLIB
+#define CONFIG_JFFS2_RTIME
+#define CONFIG_JFFS2_LZO
+
+#define JFFS2_RUBINMIPS_PRIORITY 10
+#define JFFS2_DYNRUBIN_PRIORITY 20
+#define JFFS2_RTIME_PRIORITY 50
+#define JFFS2_ZLIB_PRIORITY 60
+#define JFFS2_LZO_PRIORITY 80
+
+#define JFFS2_COMPR_MODE_NONE 0
+#define JFFS2_COMPR_MODE_PRIORITY 1
+#define JFFS2_COMPR_MODE_SIZE 2
+#define JFFS2_COMPR_MODE_FAVOURLZO 3
+
+#define kmalloc(a,b) malloc(a)
+#define kfree(a) free(a)
+#ifndef GFP_KERNEL
+#define GFP_KERNEL 0
+#endif
+
+#define vmalloc(a) malloc(a)
+#define vfree(a) free(a)
+
+#define printk(...) fprintf(stderr,__VA_ARGS__)
+
+#define KERN_EMERG
+#define KERN_ALERT
+#define KERN_CRIT
+#define KERN_ERR
+#define KERN_WARNING
+#define KERN_NOTICE
+#define KERN_INFO
+#define KERN_DEBUG
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+void jffs2_set_compression_mode(int mode);
+int jffs2_get_compression_mode(void);
+int jffs2_set_compression_mode_name(const char *mode_name);
+
+int jffs2_enable_compressor_name(const char *name);
+int jffs2_disable_compressor_name(const char *name);
+
+int jffs2_set_compressor_priority(const char *name, int priority);
+
+struct jffs2_compressor {
+ struct list_head list;
+ int priority; /* used by prirority comr. mode */
+ char *name;
+ char compr; /* JFFS2_COMPR_XXX */
+ int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t *srclen, uint32_t *destlen, void *model);
+ int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
+ uint32_t cdatalen, uint32_t datalen, void *model);
+ int usecount;
+ int disabled; /* if seted the compressor won't compress */
+ unsigned char *compr_buf; /* used by size compr. mode */
+ uint32_t compr_buf_size; /* used by size compr. mode */
+ uint32_t stat_compr_orig_size;
+ uint32_t stat_compr_new_size;
+ uint32_t stat_compr_blocks;
+ uint32_t stat_decompr_blocks;
+};
+
+int jffs2_register_compressor(struct jffs2_compressor *comp);
+int jffs2_unregister_compressor(struct jffs2_compressor *comp);
+
+int jffs2_compressors_init(void);
+int jffs2_compressors_exit(void);
+
+uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out,
+ uint32_t *datalen, uint32_t *cdatalen);
+
+/* If it is setted, a decompress will be called after every compress */
+void jffs2_compression_check_set(int yesno);
+int jffs2_compression_check_get(void);
+int jffs2_compression_check_errorcnt_get(void);
+
+char *jffs2_list_compressors(void);
+char *jffs2_stats(void);
+
+/* Compressor modules */
+
+/* These functions will be called by jffs2_compressors_init/exit */
+#ifdef CONFIG_JFFS2_ZLIB
+int jffs2_zlib_init(void);
+void jffs2_zlib_exit(void);
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+int jffs2_rtime_init(void);
+void jffs2_rtime_exit(void);
+#endif
+#ifdef CONFIG_JFFS2_LZO
+int jffs2_lzo_init(void);
+void jffs2_lzo_exit(void);
+#endif
+
+#endif /* __JFFS2_COMPR_H__ */
diff --git a/drivers/mtd/mtd-utils/compr_lzo.c b/drivers/mtd/mtd-utils/compr_lzo.c
new file mode 100644
index 00000000000..a0bb3621d32
--- /dev/null
+++ b/drivers/mtd/mtd-utils/compr_lzo.c
@@ -0,0 +1,120 @@
+/*
+ * JFFS2 LZO Compression Interface.
+ *
+ * Copyright (C) 2007 Nokia Corporation. All rights reserved.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <asm/types.h>
+#include <linux/jffs2.h>
+#include <lzo/lzo1x.h>
+#include "compr.h"
+
+extern int page_size;
+
+static void *lzo_mem;
+static void *lzo_compress_buf;
+
+/*
+ * Note about LZO compression.
+ *
+ * We want to use the _999_ compression routine which gives better compression
+ * rates at the expense of time. Decompression time is unaffected. We might as
+ * well use the standard lzo library routines for this but they will overflow
+ * the destination buffer since they don't check the destination size.
+ *
+ * We therefore compress to a temporary buffer and copy if it will fit.
+ *
+ */
+static int jffs2_lzo_cmpr(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
+{
+ uint32_t compress_size;
+ int ret;
+
+ ret = lzo1x_999_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem);
+
+ if (ret != LZO_E_OK)
+ return -1;
+
+ if (compress_size > *dstlen)
+ return -1;
+
+ memcpy(cpage_out, lzo_compress_buf, compress_size);
+ *dstlen = compress_size;
+
+ return 0;
+}
+
+static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t srclen, uint32_t destlen, void *model)
+{
+ int ret;
+ uint32_t dl;
+
+ ret = lzo1x_decompress_safe(data_in,srclen,cpage_out,&dl,NULL);
+
+ if (ret != LZO_E_OK || dl != destlen)
+ return -1;
+
+ return 0;
+}
+
+static struct jffs2_compressor jffs2_lzo_comp = {
+ .priority = JFFS2_LZO_PRIORITY,
+ .name = "lzo",
+ .compr = JFFS2_COMPR_LZO,
+ .compress = &jffs2_lzo_cmpr,
+ .decompress = &jffs2_lzo_decompress,
+ .disabled = 1,
+};
+
+int jffs2_lzo_init(void)
+{
+ int ret;
+
+ lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
+ if (!lzo_mem)
+ return -1;
+
+ /* Worse case LZO compression size from their FAQ */
+ lzo_compress_buf = malloc(page_size + (page_size / 16) + 64 + 3);
+ if (!lzo_compress_buf) {
+ free(lzo_mem);
+ return -1;
+ }
+
+ ret = jffs2_register_compressor(&jffs2_lzo_comp);
+ if (ret < 0) {
+ free(lzo_compress_buf);
+ free(lzo_mem);
+ }
+
+ return ret;
+}
+
+void jffs2_lzo_exit(void)
+{
+ jffs2_unregister_compressor(&jffs2_lzo_comp);
+ free(lzo_compress_buf);
+ free(lzo_mem);
+}
diff --git a/drivers/mtd/mtd-utils/compr_rtime.c b/drivers/mtd/mtd-utils/compr_rtime.c
new file mode 100644
index 00000000000..131536cf693
--- /dev/null
+++ b/drivers/mtd/mtd-utils/compr_rtime.c
@@ -0,0 +1,119 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by Arjan van de Ven <arjanv@redhat.com>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * Very simple lz77-ish encoder.
+ *
+ * Theory of operation: Both encoder and decoder have a list of "last
+ * occurrences" for every possible source-value; after sending the
+ * first source-byte, the second byte indicated the "run" length of
+ * matches
+ *
+ * The algorithm is intended to only send "whole bytes", no bit-messing.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "compr.h"
+
+/* _compress returns the compressed size, -1 if bigger */
+static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
+{
+ short positions[256];
+ int outpos = 0;
+ int pos=0;
+
+ memset(positions,0,sizeof(positions));
+
+ while (pos < (*sourcelen) && outpos <= (*dstlen)-2) {
+ int backpos, runlen=0;
+ unsigned char value;
+
+ value = data_in[pos];
+
+ cpage_out[outpos++] = data_in[pos++];
+
+ backpos = positions[value];
+ positions[value]=pos;
+
+ while ((backpos < pos) && (pos < (*sourcelen)) &&
+ (data_in[pos]==data_in[backpos++]) && (runlen<255)) {
+ pos++;
+ runlen++;
+ }
+ cpage_out[outpos++] = runlen;
+ }
+
+ if (outpos >= pos) {
+ /* We failed */
+ return -1;
+ }
+
+ /* Tell the caller how much we managed to compress, and how much space it took */
+ *sourcelen = pos;
+ *dstlen = outpos;
+ return 0;
+}
+
+
+static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t srclen, uint32_t destlen, void *model)
+{
+ short positions[256];
+ int outpos = 0;
+ int pos=0;
+
+ memset(positions,0,sizeof(positions));
+
+ while (outpos<destlen) {
+ unsigned char value;
+ int backoffs;
+ int repeat;
+
+ value = data_in[pos++];
+ cpage_out[outpos++] = value; /* first the verbatim copied byte */
+ repeat = data_in[pos++];
+ backoffs = positions[value];
+
+ positions[value]=outpos;
+ if (repeat) {
+ if (backoffs + repeat >= outpos) {
+ while(repeat) {
+ cpage_out[outpos++] = cpage_out[backoffs++];
+ repeat--;
+ }
+ } else {
+ memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat);
+ outpos+=repeat;
+ }
+ }
+ }
+ return 0;
+}
+
+
+static struct jffs2_compressor jffs2_rtime_comp = {
+ .priority = JFFS2_RTIME_PRIORITY,
+ .name = "rtime",
+ .disabled = 0,
+ .compr = JFFS2_COMPR_RTIME,
+ .compress = &jffs2_rtime_compress,
+ .decompress = &jffs2_rtime_decompress,
+};
+
+int jffs2_rtime_init(void)
+{
+ return jffs2_register_compressor(&jffs2_rtime_comp);
+}
+
+void jffs2_rtime_exit(void)
+{
+ jffs2_unregister_compressor(&jffs2_rtime_comp);
+}
diff --git a/drivers/mtd/mtd-utils/compr_zlib.c b/drivers/mtd/mtd-utils/compr_zlib.c
new file mode 100644
index 00000000000..400b18a15a7
--- /dev/null
+++ b/drivers/mtd/mtd-utils/compr_zlib.c
@@ -0,0 +1,145 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ *
+ * The original JFFS, from which the design for JFFS2 was derived,
+ * was designed and implemented by Axis Communications AB.
+ *
+ * The contents of this file are subject to the Red Hat eCos Public
+ * License Version 1.1 (the "Licence"); you may not use this file
+ * except in compliance with the Licence. You may obtain a copy of
+ * the Licence at http://www.redhat.com/
+ *
+ * Software distributed under the Licence is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing rights and
+ * limitations under the Licence.
+ *
+ * The Original Code is JFFS2 - Journalling Flash File System, version 2
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the RHEPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the RHEPL or the GPL.
+ */
+
+#include <stdint.h>
+#include <zlib.h>
+#include <stdio.h>
+#include <asm/types.h>
+#include <linux/jffs2.h>
+#include "compr.h"
+
+#define min(x,y) ((x)<(y)?(x):(y))
+
+/* Plan: call deflate() with avail_in == *sourcelen,
+ avail_out = *dstlen - 12 and flush == Z_FINISH.
+ If it doesn't manage to finish, call it again with
+ avail_in == 0 and avail_out set to the remaining 12
+ bytes for it to clean up.
+Q: Is 12 bytes sufficient?
+ */
+#define STREAM_END_SPACE 12
+
+int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
+{
+ z_stream strm;
+ int ret;
+
+ if (*dstlen <= STREAM_END_SPACE)
+ return -1;
+
+ strm.zalloc = (void *)0;
+ strm.zfree = (void *)0;
+
+ if (Z_OK != deflateInit(&strm, 3)) {
+ return -1;
+ }
+ strm.next_in = data_in;
+ strm.total_in = 0;
+
+ strm.next_out = cpage_out;
+ strm.total_out = 0;
+
+ while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) {
+ strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE);
+ strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
+ ret = deflate(&strm, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK) {
+ deflateEnd(&strm);
+ return -1;
+ }
+ }
+ strm.avail_out += STREAM_END_SPACE;
+ strm.avail_in = 0;
+ ret = deflate(&strm, Z_FINISH);
+ if (ret != Z_STREAM_END) {
+ deflateEnd(&strm);
+ return -1;
+ }
+ deflateEnd(&strm);
+
+ if (strm.total_out >= strm.total_in)
+ return -1;
+
+
+ *dstlen = strm.total_out;
+ *sourcelen = strm.total_in;
+ return 0;
+}
+
+int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t srclen, uint32_t destlen, void *model)
+{
+ z_stream strm;
+ int ret;
+
+ strm.zalloc = (void *)0;
+ strm.zfree = (void *)0;
+
+ if (Z_OK != inflateInit(&strm)) {
+ return 1;
+ }
+ strm.next_in = data_in;
+ strm.avail_in = srclen;
+ strm.total_in = 0;
+
+ strm.next_out = cpage_out;
+ strm.avail_out = destlen;
+ strm.total_out = 0;
+
+ while((ret = inflate(&strm, Z_FINISH)) == Z_OK)
+ ;
+
+ inflateEnd(&strm);
+ return 0;
+}
+
+static struct jffs2_compressor jffs2_zlib_comp = {
+ .priority = JFFS2_ZLIB_PRIORITY,
+ .name = "zlib",
+ .disabled = 0,
+ .compr = JFFS2_COMPR_ZLIB,
+ .compress = &jffs2_zlib_compress,
+ .decompress = &jffs2_zlib_decompress,
+};
+
+int jffs2_zlib_init(void)
+{
+ return jffs2_register_compressor(&jffs2_zlib_comp);
+}
+
+void jffs2_zlib_exit(void)
+{
+ jffs2_unregister_compressor(&jffs2_zlib_comp);
+}
diff --git a/drivers/mtd/mtd-utils/crc32.c b/drivers/mtd/mtd-utils/crc32.c
new file mode 100644
index 00000000000..6b1e50c42d9
--- /dev/null
+++ b/drivers/mtd/mtd-utils/crc32.c
@@ -0,0 +1,95 @@
+/*
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ *
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to hight-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
+ *
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
+ */
+
+#include <stdint.h>
+
+const uint32_t crc32_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
diff --git a/drivers/mtd/mtd-utils/crc32.h b/drivers/mtd/mtd-utils/crc32.h
new file mode 100644
index 00000000000..ee3145bc159
--- /dev/null
+++ b/drivers/mtd/mtd-utils/crc32.h
@@ -0,0 +1,19 @@
+#ifndef CRC32_H
+#define CRC32_H
+
+#include <stdint.h>
+
+extern const uint32_t crc32_table[256];
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+ static inline uint32_t
+crc32(uint32_t val, const void *ss, int len)
+{
+ const unsigned char *s = ss;
+ while (--len >= 0)
+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
+ return val;
+}
+
+#endif
diff --git a/drivers/mtd/mtd-utils/device_table.txt b/drivers/mtd/mtd-utils/device_table.txt
new file mode 100644
index 00000000000..74fdc560533
--- /dev/null
+++ b/drivers/mtd/mtd-utils/device_table.txt
@@ -0,0 +1,129 @@
+# This is a sample device table file for use with mkfs.jffs2. You can
+# do all sorts of interesting things with a device table file. For
+# example, if you want to adjust the permissions on a particular file
+# you can just add an entry like:
+# /sbin/foobar f 2755 0 0 - - - - -
+# and (assuming the file /sbin/foobar exists) it will be made setuid
+# root (regardless of what its permissions are on the host filesystem.
+#
+# Device table entries take the form of:
+# <name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
+# where name is the file name, type can be one of:
+# f A regular file
+# d Directory
+# c Character special device file
+# b Block special device file
+# p Fifo (named pipe)
+# uid is the user id for the target file, gid is the group id for the
+# target file. The rest of the entried apply only to device special
+# file.
+
+# When building a target filesystem, it is desirable to not have to
+# become root and then run 'mknod' a thousand times. Using a device
+# table you can create device nodes and directories "on the fly".
+# Furthermore, you can use a single table entry to create a many device
+# minors. For example, if I wanted to create /dev/hda and /dev/hda[0-15]
+# I could just use the following two table entries:
+# /dev/hda b 640 0 0 3 0 0 0 -
+# /dev/hda b 640 0 0 3 1 1 1 15
+#
+# Have fun
+# -Erik Andersen <andersen@codepoet.org>
+#
+
+#<name> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
+/dev d 755 0 0 - - - - -
+/dev/mem c 640 0 0 1 1 0 0 -
+/dev/kmem c 640 0 0 1 2 0 0 -
+/dev/null c 640 0 0 1 3 0 0 -
+/dev/zero c 640 0 0 1 5 0 0 -
+/dev/random c 640 0 0 1 8 0 0 -
+/dev/urandom c 640 0 0 1 9 0 0 -
+/dev/tty c 666 0 0 5 0 0 0 -
+/dev/tty c 666 0 0 4 0 0 1 6
+/dev/console c 640 0 0 5 1 0 0 -
+/dev/ram b 640 0 0 1 1 0 0 -
+/dev/ram b 640 0 0 1 0 0 1 4
+/dev/loop b 640 0 0 7 0 0 1 2
+/dev/ptmx c 666 0 0 5 2 0 0 -
+#/dev/ttyS c 640 0 0 4 64 0 1 4
+#/dev/psaux c 640 0 0 10 1 0 0 -
+#/dev/rtc c 640 0 0 10 135 0 0 -
+
+# Adjust permissions on some normal files
+#/etc/shadow f 600 0 0 - - - - -
+#/bin/tinylogin f 4755 0 0 - - - - -
+
+# User-mode Linux stuff
+/dev/ubda b 640 0 0 98 0 0 0 -
+/dev/ubda b 640 0 0 98 1 1 1 15
+
+# IDE Devices
+/dev/hda b 640 0 0 3 0 0 0 -
+/dev/hda b 640 0 0 3 1 1 1 15
+/dev/hdb b 640 0 0 3 64 0 0 -
+/dev/hdb b 640 0 0 3 65 1 1 15
+#/dev/hdc b 640 0 0 22 0 0 0 -
+#/dev/hdc b 640 0 0 22 1 1 1 15
+#/dev/hdd b 640 0 0 22 64 0 0 -
+#/dev/hdd b 640 0 0 22 65 1 1 15
+#/dev/hde b 640 0 0 33 0 0 0 -
+#/dev/hde b 640 0 0 33 1 1 1 15
+#/dev/hdf b 640 0 0 33 64 0 0 -
+#/dev/hdf b 640 0 0 33 65 1 1 15
+#/dev/hdg b 640 0 0 34 0 0 0 -
+#/dev/hdg b 640 0 0 34 1 1 1 15
+#/dev/hdh b 640 0 0 34 64 0 0 -
+#/dev/hdh b 640 0 0 34 65 1 1 15
+
+# SCSI Devices
+#/dev/sda b 640 0 0 8 0 0 0 -
+#/dev/sda b 640 0 0 8 1 1 1 15
+#/dev/sdb b 640 0 0 8 16 0 0 -
+#/dev/sdb b 640 0 0 8 17 1 1 15
+#/dev/sdc b 640 0 0 8 32 0 0 -
+#/dev/sdc b 640 0 0 8 33 1 1 15
+#/dev/sdd b 640 0 0 8 48 0 0 -
+#/dev/sdd b 640 0 0 8 49 1 1 15
+#/dev/sde b 640 0 0 8 64 0 0 -
+#/dev/sde b 640 0 0 8 65 1 1 15
+#/dev/sdf b 640 0 0 8 80 0 0 -
+#/dev/sdf b 640 0 0 8 81 1 1 15
+#/dev/sdg b 640 0 0 8 96 0 0 -
+#/dev/sdg b 640 0 0 8 97 1 1 15
+#/dev/sdh b 640 0 0 8 112 0 0 -
+#/dev/sdh b 640 0 0 8 113 1 1 15
+#/dev/sg c 640 0 0 21 0 0 1 15
+#/dev/scd b 640 0 0 11 0 0 1 15
+#/dev/st c 640 0 0 9 0 0 1 8
+#/dev/nst c 640 0 0 9 128 0 1 8
+#/dev/st c 640 0 0 9 32 1 1 4
+#/dev/st c 640 0 0 9 64 1 1 4
+#/dev/st c 640 0 0 9 96 1 1 4
+
+# Floppy disk devices
+#/dev/fd b 640 0 0 2 0 0 1 2
+#/dev/fd0d360 b 640 0 0 2 4 0 0 -
+#/dev/fd1d360 b 640 0 0 2 5 0 0 -
+#/dev/fd0h1200 b 640 0 0 2 8 0 0 -
+#/dev/fd1h1200 b 640 0 0 2 9 0 0 -
+#/dev/fd0u1440 b 640 0 0 2 28 0 0 -
+#/dev/fd1u1440 b 640 0 0 2 29 0 0 -
+#/dev/fd0u2880 b 640 0 0 2 32 0 0 -
+#/dev/fd1u2880 b 640 0 0 2 33 0 0 -
+
+# All the proprietary cdrom devices in the world
+#/dev/aztcd b 640 0 0 29 0 0 0 -
+#/dev/bpcd b 640 0 0 41 0 0 0 -
+#/dev/capi20 c 640 0 0 68 0 0 1 2
+#/dev/cdu31a b 640 0 0 15 0 0 0 -
+#/dev/cdu535 b 640 0 0 24 0 0 0 -
+#/dev/cm206cd b 640 0 0 32 0 0 0 -
+#/dev/sjcd b 640 0 0 18 0 0 0 -
+#/dev/sonycd b 640 0 0 15 0 0 0 -
+#/dev/gscd b 640 0 0 16 0 0 0 -
+#/dev/sbpcd b 640 0 0 25 0 0 0 -
+#/dev/sbpcd b 640 0 0 25 0 0 1 4
+#/dev/mcd b 640 0 0 23 0 0 0 -
+#/dev/optcd b 640 0 0 17 0 0 0 -
+
diff --git a/drivers/mtd/mtd-utils/doc_loadbios.c b/drivers/mtd/mtd-utils/doc_loadbios.c
new file mode 100644
index 00000000000..0a11fd203f6
--- /dev/null
+++ b/drivers/mtd/mtd-utils/doc_loadbios.c
@@ -0,0 +1,148 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+
+#include <mtd/mtd-user.h>
+
+unsigned char databuf[512];
+
+int main(int argc,char **argv)
+{
+ mtd_info_t meminfo;
+ int ifd,ofd;
+ struct stat statbuf;
+ erase_info_t erase;
+ unsigned long retlen, ofs, iplsize, ipltailsize;
+ unsigned char *iplbuf;
+ iplbuf = NULL;
+
+ if (argc < 3) {
+ fprintf(stderr,"You must specify a device,"
+ " the source firmware file and the offset\n");
+ return 1;
+ }
+
+ // Open and size the device
+ if ((ofd = open(argv[1],O_RDWR)) < 0) {
+ perror("Open flash device");
+ return 1;
+ }
+
+ if ((ifd = open(argv[2], O_RDONLY)) < 0) {
+ perror("Open firmware file\n");
+ close(ofd);
+ return 1;
+ }
+
+ if (fstat(ifd, &statbuf) != 0) {
+ perror("Stat firmware file");
+ goto error;
+ }
+
+#if 0
+ if (statbuf.st_size > 65536) {
+ printf("Firmware too large (%ld bytes)\n",statbuf.st_size);
+ goto error;
+ }
+#endif
+
+ if (ioctl(ofd,MEMGETINFO,&meminfo) != 0) {
+ perror("ioctl(MEMGETINFO)");
+ goto error;
+ }
+
+ iplsize = (ipltailsize = 0);
+ if (argc >= 4) {
+ /* DoC Millennium has IPL in the first 1K of flash memory */
+ /* You may want to specify the offset 1024 to store
+ the firmware next to IPL. */
+ iplsize = strtoul(argv[3], NULL, 0);
+ ipltailsize = iplsize % meminfo.erasesize;
+ }
+
+ if (lseek(ofd, iplsize - ipltailsize, SEEK_SET) < 0) {
+ perror("lseek");
+ goto error;
+ }
+
+ if (ipltailsize) {
+ iplbuf = malloc(ipltailsize);
+ if (iplbuf == NULL) {
+ fprintf(stderr, "Not enough memory for IPL tail buffer of"
+ " %lu bytes\n", (unsigned long) ipltailsize);
+ goto error;
+ }
+ printf("Reading IPL%s area of length %lu at offset %lu\n",
+ (iplsize - ipltailsize) ? " tail" : "",
+ (long unsigned) ipltailsize,
+ (long unsigned) (iplsize - ipltailsize));
+ if (read(ofd, iplbuf, ipltailsize) != ipltailsize) {
+ perror("read");
+ goto error;
+ }
+ }
+
+ erase.length = meminfo.erasesize;
+
+ for (ofs = iplsize - ipltailsize ;
+ ofs < iplsize + statbuf.st_size ;
+ ofs += meminfo.erasesize) {
+ erase.start = ofs;
+ printf("Performing Flash Erase of length %lu at offset %lu\n",
+ (long unsigned) erase.length, (long unsigned) erase.start);
+
+ if (ioctl(ofd,MEMERASE,&erase) != 0) {
+ perror("ioctl(MEMERASE)");
+ goto error;
+ }
+ }
+
+ if (lseek(ofd, iplsize - ipltailsize, SEEK_SET) < 0) {
+ perror("lseek");
+ goto error;
+ }
+
+ if (ipltailsize) {
+ printf("Writing IPL%s area of length %lu at offset %lu\n",
+ (iplsize - ipltailsize) ? " tail" : "",
+ (long unsigned) ipltailsize,
+ (long unsigned) (iplsize - ipltailsize));
+ if (write(ofd, iplbuf, ipltailsize) != ipltailsize) {
+ perror("write");
+ goto error;
+ }
+ }
+
+ printf("Writing the firmware of length %lu at %lu... ",
+ (unsigned long) statbuf.st_size,
+ (unsigned long) iplsize);
+ do {
+ retlen = read(ifd, databuf, 512);
+ if (retlen < 512)
+ memset(databuf+retlen, 0xff, 512-retlen);
+ if (write(ofd, databuf, 512) != 512) {
+ perror("write");
+ goto error;
+ }
+ } while (retlen == 512);
+ printf("Done.\n");
+
+ if (iplbuf != NULL)
+ free(iplbuf);
+ close(ifd);
+ close(ofd);
+ return 0;
+
+error:
+ if (iplbuf != NULL)
+ free(iplbuf);
+ close(ifd);
+ close(ofd);
+ return 1;
+}
diff --git a/drivers/mtd/mtd-utils/docfdisk.c b/drivers/mtd/mtd-utils/docfdisk.c
new file mode 100644
index 00000000000..56fffc4d6e4
--- /dev/null
+++ b/drivers/mtd/mtd-utils/docfdisk.c
@@ -0,0 +1,317 @@
+/*
+ * docfdisk.c: Modify INFTL partition tables
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define _XOPEN_SOURCE 500 /* for pread/pwrite */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <string.h>
+
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+#include <mtd/inftl-user.h>
+#include <mtd_swab.h>
+
+unsigned char *buf;
+
+mtd_info_t meminfo;
+erase_info_t erase;
+int fd;
+struct INFTLMediaHeader *mh;
+
+#define MAXSCAN 10
+
+void show_header(int mhoffs) {
+ int i, unitsize, numunits, bmbits, numpart;
+ int start, end, num, nextunit;
+ unsigned int flags;
+ struct INFTLPartition *ip;
+
+ bmbits = le32_to_cpu(mh->BlockMultiplierBits);
+ printf(" bootRecordID = %s\n"
+ " NoOfBootImageBlocks = %d\n"
+ " NoOfBinaryPartitions = %d\n"
+ " NoOfBDTLPartitions = %d\n"
+ " BlockMultiplierBits = %d\n"
+ " FormatFlags = %d\n"
+ " OsakVersion = %d.%d.%d.%d\n"
+ " PercentUsed = %d\n",
+ mh->bootRecordID, le32_to_cpu(mh->NoOfBootImageBlocks),
+ le32_to_cpu(mh->NoOfBinaryPartitions),
+ le32_to_cpu(mh->NoOfBDTLPartitions),
+ bmbits,
+ le32_to_cpu(mh->FormatFlags),
+ ((unsigned char *) &mh->OsakVersion)[0] & 0xf,
+ ((unsigned char *) &mh->OsakVersion)[1] & 0xf,
+ ((unsigned char *) &mh->OsakVersion)[2] & 0xf,
+ ((unsigned char *) &mh->OsakVersion)[3] & 0xf,
+ le32_to_cpu(mh->PercentUsed));
+
+ numpart = le32_to_cpu(mh->NoOfBinaryPartitions) +
+ le32_to_cpu(mh->NoOfBDTLPartitions);
+ unitsize = meminfo.erasesize >> bmbits;
+ numunits = meminfo.size / unitsize;
+ nextunit = mhoffs / unitsize;
+ nextunit++;
+ printf("Unitsize is %d bytes. Device has %d units.\n",
+ unitsize, numunits);
+ if (numunits > 32768) {
+ printf("WARNING: More than 32768 units! Unexpectedly small BlockMultiplierBits.\n");
+ }
+ if (bmbits && (numunits <= 16384)) {
+ printf("NOTICE: Unexpectedly large BlockMultiplierBits.\n");
+ }
+ for (i = 0; i < 4; i++) {
+ ip = &(mh->Partitions[i]);
+ flags = le32_to_cpu(ip->flags);
+ start = le32_to_cpu(ip->firstUnit);
+ end = le32_to_cpu(ip->lastUnit);
+ num = le32_to_cpu(ip->virtualUnits);
+ if (start < nextunit) {
+ printf("ERROR: Overlapping or misordered partitions!\n");
+ }
+ if (start > nextunit) {
+ printf(" Unpartitioned space: %d bytes\n"
+ " virtualUnits = %d\n"
+ " firstUnit = %d\n"
+ " lastUnit = %d\n",
+ (start - nextunit) * unitsize, start - nextunit,
+ nextunit, start - 1);
+ }
+ if (flags & INFTL_BINARY)
+ printf(" Partition %d (BDK):", i+1);
+ else
+ printf(" Partition %d (BDTL):", i+1);
+ printf(" %d bytes\n"
+ " virtualUnits = %d\n"
+ " firstUnit = %d\n"
+ " lastUnit = %d\n"
+ " flags = 0x%x\n"
+ " spareUnits = %d\n",
+ num * unitsize, num, start, end,
+ le32_to_cpu(ip->flags), le32_to_cpu(ip->spareUnits));
+ if (num > (1 + end - start)) {
+ printf("ERROR: virtualUnits not consistent with first/lastUnit!\n");
+ }
+ end++;
+ if (end > nextunit)
+ nextunit = end;
+ if (flags & INFTL_LAST)
+ break;
+ }
+ if (i >= 4) {
+ printf("Odd. Last partition was not marked with INFTL_LAST.\n");
+ i--;
+ }
+ if ((i+1) != numpart) {
+ printf("ERROR: Number of partitions != (NoOfBinaryPartitions + NoOfBDTLPartitions)\n");
+ }
+ if (nextunit > numunits) {
+ printf("ERROR: Partitions appear to extend beyond end of device!\n");
+ }
+ if (nextunit < numunits) {
+ printf(" Unpartitioned space: %d bytes\n"
+ " virtualUnits = %d\n"
+ " firstUnit = %d\n"
+ " lastUnit = %d\n",
+ (numunits - nextunit) * unitsize, numunits - nextunit,
+ nextunit, numunits - 1);
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ int ret, i, mhblock, unitsize, block;
+ unsigned int nblocks[4], npart;
+ unsigned int totblocks;
+ struct INFTLPartition *ip;
+ unsigned char *oobbuf;
+ struct mtd_oob_buf oob;
+ char line[20];
+ int mhoffs;
+ struct INFTLMediaHeader *mh2;
+
+ if (argc < 2) {
+ printf(
+ "Usage: %s <mtddevice> [<size1> [<size2> [<size3> [<size4]]]]\n"
+ " Sizes are in device units (run with no sizes to show unitsize and current\n"
+ " partitions). Last size = 0 means go to end of device.\n",
+ argv[0]);
+ return 1;
+ }
+
+ npart = argc - 2;
+ if (npart > 4) {
+ printf("Max 4 partitions allowed.\n");
+ return 1;
+ }
+
+ for (i = 0; i < npart; i++) {
+ nblocks[i] = strtoul(argv[2+i], NULL, 0);
+ if (i && !nblocks[i-1]) {
+ printf("No sizes allowed after 0\n");
+ return 1;
+ }
+ }
+
+ // Open and size the device
+ if ((fd = open(argv[1], O_RDWR)) < 0) {
+ perror("Open flash device");
+ return 1;
+ }
+
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ perror("ioctl(MEMGETINFO)");
+ return 1;
+ }
+
+ printf("Device size is %d bytes. Erasesize is %d bytes.\n",
+ meminfo.size, meminfo.erasesize);
+
+ buf = malloc(meminfo.erasesize);
+ oobbuf = malloc((meminfo.erasesize / meminfo.writesize) * meminfo.oobsize);
+ if (!buf || !oobbuf) {
+ printf("Can't malloc block buffer\n");
+ return 1;
+ }
+ oob.length = meminfo.oobsize;
+
+ mh = (struct INFTLMediaHeader *) buf;
+
+ for (mhblock = 0; mhblock < MAXSCAN; mhblock++) {
+ if ((ret = pread(fd, buf, meminfo.erasesize, mhblock * meminfo.erasesize)) < 0) {
+ if (errno == EBADMSG) {
+ printf("ECC error at eraseblock %d\n", mhblock);
+ continue;
+ }
+ perror("Read eraseblock");
+ return 1;
+ }
+ if (ret != meminfo.erasesize) {
+ printf("Short read!\n");
+ return 1;
+ }
+ if (!strcmp("BNAND", mh->bootRecordID)) break;
+ }
+ if (mhblock >= MAXSCAN) {
+ printf("Unable to find INFTL Media Header\n");
+ return 1;
+ }
+ printf("Found INFTL Media Header at block %d:\n", mhblock);
+ mhoffs = mhblock * meminfo.erasesize;
+
+ oob.ptr = oobbuf;
+ oob.start = mhoffs;
+ for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
+ if (ioctl(fd, MEMREADOOB, &oob)) {
+ perror("ioctl(MEMREADOOB)");
+ return 1;
+ }
+ oob.start += meminfo.writesize;
+ oob.ptr += meminfo.oobsize;
+ }
+
+ show_header(mhoffs);
+
+ if (!npart)
+ return 0;
+
+ printf("\n"
+ "-------------------------------------------------------------------------\n");
+
+ unitsize = meminfo.erasesize >> le32_to_cpu(mh->BlockMultiplierBits);
+ totblocks = meminfo.size / unitsize;
+ block = mhoffs / unitsize;
+ block++;
+
+ mh->NoOfBDTLPartitions = 0;
+ mh->NoOfBinaryPartitions = npart;
+
+ for (i = 0; i < npart; i++) {
+ ip = &(mh->Partitions[i]);
+ ip->firstUnit = cpu_to_le32(block);
+ if (!nblocks[i])
+ nblocks[i] = totblocks - block;
+ ip->virtualUnits = cpu_to_le32(nblocks[i]);
+ block += nblocks[i];
+ ip->lastUnit = cpu_to_le32(block-1);
+ ip->spareUnits = 0;
+ ip->flags = cpu_to_le32(INFTL_BINARY);
+ }
+ if (block > totblocks) {
+ printf("Requested partitions extend beyond end of device.\n");
+ return 1;
+ }
+ ip->flags = cpu_to_le32(INFTL_BINARY | INFTL_LAST);
+
+ /* update the spare as well */
+ mh2 = (struct INFTLMediaHeader *) (buf + 4096);
+ memcpy((void *) mh2, (void *) mh, sizeof(struct INFTLMediaHeader));
+
+ printf("\nProposed new Media Header:\n");
+ show_header(mhoffs);
+
+ printf("\nReady to update device. Type 'yes' to proceed, anything else to abort: ");
+ fgets(line, sizeof(line), stdin);
+ if (strcmp("yes\n", line))
+ return 0;
+ printf("Updating MediaHeader...\n");
+
+ erase.start = mhoffs;
+ erase.length = meminfo.erasesize;
+ if (ioctl(fd, MEMERASE, &erase)) {
+ perror("ioctl(MEMERASE)");
+ printf("Your MediaHeader may be hosed. UHOH!\n");
+ return 1;
+ }
+
+ oob.ptr = oobbuf;
+ oob.start = mhoffs;
+ for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
+ memset(oob.ptr, 0xff, 6); // clear ECC.
+ if (ioctl(fd, MEMWRITEOOB, &oob)) {
+ perror("ioctl(MEMWRITEOOB)");
+ printf("Your MediaHeader may be hosed. UHOH!\n");
+ return 1;
+ }
+ if ((ret = pwrite(fd, buf, meminfo.writesize, oob.start)) < 0) {
+ perror("Write page");
+ printf("Your MediaHeader may be hosed. UHOH!\n");
+ return 1;
+ }
+ if (ret != meminfo.writesize) {
+ printf("Short write!\n");
+ printf("Your MediaHeader may be hosed. UHOH!\n");
+ return 1;
+ }
+
+ oob.start += meminfo.writesize;
+ oob.ptr += meminfo.oobsize;
+ buf += meminfo.writesize;
+ }
+
+ printf("Success. REBOOT or unload the diskonchip module to update partitions!\n");
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/feature-removal-schedule.txt b/drivers/mtd/mtd-utils/feature-removal-schedule.txt
new file mode 100644
index 00000000000..d0116f887b7
--- /dev/null
+++ b/drivers/mtd/mtd-utils/feature-removal-schedule.txt
@@ -0,0 +1,9 @@
+The following is a list of files and features that are going to be
+removed in the mtd-utils source tree. Every entry should contain what
+exactly is going away, why it is happening, and who is going to be doing
+the work. When the feature is removed from the utils, it should also
+be removed from this file.
+
+---------------------------
+
+---------------------------
diff --git a/drivers/mtd/mtd-utils/fec.c b/drivers/mtd/mtd-utils/fec.c
new file mode 100644
index 00000000000..09e8453f05d
--- /dev/null
+++ b/drivers/mtd/mtd-utils/fec.c
@@ -0,0 +1,917 @@
+/*
+ * fec.c -- forward error correction based on Vandermonde matrices
+ * 980624
+ * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
+ *
+ * Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
+ * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
+ * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+/*
+ * The following parameter defines how many bits are used for
+ * field elements. The code supports any value from 2 to 16
+ * but fastest operation is achieved with 8 bit elements
+ * This is the only parameter you may want to change.
+ */
+#ifndef GF_BITS
+#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * compatibility stuff
+ */
+#ifdef MSDOS /* but also for others, e.g. sun... */
+#define NEED_BCOPY
+#define bcmp(a,b,n) memcmp(a,b,n)
+#endif
+
+#ifdef NEED_BCOPY
+#define bcopy(s, d, siz) memcpy((d), (s), (siz))
+#define bzero(d, siz) memset((d), '\0', (siz))
+#endif
+
+/*
+ * stuff used for testing purposes only
+ */
+
+#ifdef TEST
+#define DEB(x)
+#define DDB(x) x
+#define DEBUG 0 /* minimal debugging */
+#ifdef MSDOS
+#include <time.h>
+struct timeval {
+ unsigned long ticks;
+};
+#define gettimeofday(x, dummy) { (x)->ticks = clock() ; }
+#define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC )
+typedef unsigned long u_long ;
+typedef unsigned short u_short ;
+#else /* typically, unix systems */
+#include <sys/time.h>
+#define DIFF_T(a,b) \
+ (1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) )
+#endif
+
+#define TICK(t) \
+ {struct timeval x ; \
+ gettimeofday(&x, NULL) ; \
+ t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \
+ }
+#define TOCK(t) \
+ { u_long t1 ; TICK(t1) ; \
+ if (t1 < t) t = 256000000 + t1 - t ; \
+ else t = t1 - t ; \
+ if (t == 0) t = 1 ;}
+
+u_long ticks[10]; /* vars for timekeeping */
+#else
+#define DEB(x)
+#define DDB(x)
+#define TICK(x)
+#define TOCK(x)
+#endif /* TEST */
+
+/*
+ * You should not need to change anything beyond this point.
+ * The first part of the file implements linear algebra in GF.
+ *
+ * gf is the type used to store an element of the Galois Field.
+ * Must constain at least GF_BITS bits.
+ *
+ * Note: unsigned char will work up to GF(256) but int seems to run
+ * faster on the Pentium. We use int whenever have to deal with an
+ * index, since they are generally faster.
+ */
+#if (GF_BITS < 2 && GF_BITS >16)
+#error "GF_BITS must be 2 .. 16"
+#endif
+#if (GF_BITS <= 8)
+typedef unsigned char gf;
+#else
+typedef unsigned short gf;
+#endif
+
+#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */
+
+/*
+ * Primitive polynomials - see Lin & Costello, Appendix A,
+ * and Lee & Messerschmitt, p. 453.
+ */
+static char *allPp[] = { /* GF_BITS polynomial */
+ NULL, /* 0 no code */
+ NULL, /* 1 no code */
+ "111", /* 2 1+x+x^2 */
+ "1101", /* 3 1+x+x^3 */
+ "11001", /* 4 1+x+x^4 */
+ "101001", /* 5 1+x^2+x^5 */
+ "1100001", /* 6 1+x+x^6 */
+ "10010001", /* 7 1 + x^3 + x^7 */
+ "101110001", /* 8 1+x^2+x^3+x^4+x^8 */
+ "1000100001", /* 9 1+x^4+x^9 */
+ "10010000001", /* 10 1+x^3+x^10 */
+ "101000000001", /* 11 1+x^2+x^11 */
+ "1100101000001", /* 12 1+x+x^4+x^6+x^12 */
+ "11011000000001", /* 13 1+x+x^3+x^4+x^13 */
+ "110000100010001", /* 14 1+x+x^6+x^10+x^14 */
+ "1100000000000001", /* 15 1+x+x^15 */
+ "11010000000010001" /* 16 1+x+x^3+x^12+x^16 */
+};
+
+
+/*
+ * To speed up computations, we have tables for logarithm, exponent
+ * and inverse of a number. If GF_BITS <= 8, we use a table for
+ * multiplication as well (it takes 64K, no big deal even on a PDA,
+ * especially because it can be pre-initialized an put into a ROM!),
+ * otherwhise we use a table of logarithms.
+ * In any case the macro gf_mul(x,y) takes care of multiplications.
+ */
+
+static gf gf_exp[2*GF_SIZE]; /* index->poly form conversion table */
+static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */
+static gf inverse[GF_SIZE+1]; /* inverse of field elem. */
+ /* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */
+
+/*
+ * modnn(x) computes x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1,
+ * without a slow divide.
+ */
+static inline gf
+modnn(int x)
+{
+ while (x >= GF_SIZE) {
+ x -= GF_SIZE;
+ x = (x >> GF_BITS) + (x & GF_SIZE);
+ }
+ return x;
+}
+
+#define SWAP(a,b,t) {t tmp; tmp=a; a=b; b=tmp;}
+
+/*
+ * gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much
+ * faster to use a multiplication table.
+ *
+ * USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying
+ * many numbers by the same constant. In this case the first
+ * call sets the constant, and others perform the multiplications.
+ * A value related to the multiplication is held in a local variable
+ * declared with USE_GF_MULC . See usage in addmul1().
+ */
+#if (GF_BITS <= 8)
+static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];
+
+#define gf_mul(x,y) gf_mul_table[x][y]
+
+#define USE_GF_MULC register gf * __gf_mulc_
+#define GF_MULC0(c) __gf_mulc_ = gf_mul_table[c]
+#define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x]
+
+static void
+init_mul_table()
+{
+ int i, j;
+ for (i=0; i< GF_SIZE+1; i++)
+ for (j=0; j< GF_SIZE+1; j++)
+ gf_mul_table[i][j] = gf_exp[modnn(gf_log[i] + gf_log[j]) ] ;
+
+ for (j=0; j< GF_SIZE+1; j++)
+ gf_mul_table[0][j] = gf_mul_table[j][0] = 0;
+}
+#else /* GF_BITS > 8 */
+static inline gf
+gf_mul(x,y)
+{
+ if ( (x) == 0 || (y)==0 ) return 0;
+
+ return gf_exp[gf_log[x] + gf_log[y] ] ;
+}
+#define init_mul_table()
+
+#define USE_GF_MULC register gf * __gf_mulc_
+#define GF_MULC0(c) __gf_mulc_ = &gf_exp[ gf_log[c] ]
+#define GF_ADDMULC(dst, x) { if (x) dst ^= __gf_mulc_[ gf_log[x] ] ; }
+#endif
+
+/*
+ * Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m]
+ * Lookup tables:
+ * index->polynomial form gf_exp[] contains j= \alpha^i;
+ * polynomial form -> index form gf_log[ j = \alpha^i ] = i
+ * \alpha=x is the primitive element of GF(2^m)
+ *
+ * For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple
+ * multiplication of two numbers can be resolved without calling modnn
+ */
+
+/*
+ * i use malloc so many times, it is easier to put checks all in
+ * one place.
+ */
+static void *
+my_malloc(int sz, char *err_string)
+{
+ void *p = malloc( sz );
+ if (p == NULL) {
+ fprintf(stderr, "-- malloc failure allocating %s\n", err_string);
+ exit(1) ;
+ }
+ return p ;
+}
+
+#define NEW_GF_MATRIX(rows, cols) \
+ (gf *)my_malloc(rows * cols * sizeof(gf), " ## __LINE__ ## " )
+
+/*
+ * initialize the data structures used for computations in GF.
+ */
+static void
+generate_gf(void)
+{
+ int i;
+ gf mask;
+ char *Pp = allPp[GF_BITS] ;
+
+ mask = 1; /* x ** 0 = 1 */
+ gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */
+ /*
+ * first, generate the (polynomial representation of) powers of \alpha,
+ * which are stored in gf_exp[i] = \alpha ** i .
+ * At the same time build gf_log[gf_exp[i]] = i .
+ * The first GF_BITS powers are simply bits shifted to the left.
+ */
+ for (i = 0; i < GF_BITS; i++, mask <<= 1 ) {
+ gf_exp[i] = mask;
+ gf_log[gf_exp[i]] = i;
+ /*
+ * If Pp[i] == 1 then \alpha ** i occurs in poly-repr
+ * gf_exp[GF_BITS] = \alpha ** GF_BITS
+ */
+ if ( Pp[i] == '1' )
+ gf_exp[GF_BITS] ^= mask;
+ }
+ /*
+ * now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can als
+ * compute its inverse.
+ */
+ gf_log[gf_exp[GF_BITS]] = GF_BITS;
+ /*
+ * Poly-repr of \alpha ** (i+1) is given by poly-repr of
+ * \alpha ** i shifted left one-bit and accounting for any
+ * \alpha ** GF_BITS term that may occur when poly-repr of
+ * \alpha ** i is shifted.
+ */
+ mask = 1 << (GF_BITS - 1 ) ;
+ for (i = GF_BITS + 1; i < GF_SIZE; i++) {
+ if (gf_exp[i - 1] >= mask)
+ gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1);
+ else
+ gf_exp[i] = gf_exp[i - 1] << 1;
+ gf_log[gf_exp[i]] = i;
+ }
+ /*
+ * log(0) is not defined, so use a special value
+ */
+ gf_log[0] = GF_SIZE ;
+ /* set the extended gf_exp values for fast multiply */
+ for (i = 0 ; i < GF_SIZE ; i++)
+ gf_exp[i + GF_SIZE] = gf_exp[i] ;
+
+ /*
+ * again special cases. 0 has no inverse. This used to
+ * be initialized to GF_SIZE, but it should make no difference
+ * since noone is supposed to read from here.
+ */
+ inverse[0] = 0 ;
+ inverse[1] = 1;
+ for (i=2; i<=GF_SIZE; i++)
+ inverse[i] = gf_exp[GF_SIZE-gf_log[i]];
+}
+
+/*
+ * Various linear algebra operations that i use often.
+ */
+
+/*
+ * addmul() computes dst[] = dst[] + c * src[]
+ * This is used often, so better optimize it! Currently the loop is
+ * unrolled 16 times, a good value for 486 and pentium-class machines.
+ * The case c=0 is also optimized, whereas c=1 is not. These
+ * calls are unfrequent in my typical apps so I did not bother.
+ *
+ * Note that gcc on
+ */
+#define addmul(dst, src, c, sz) \
+ if (c != 0) addmul1(dst, src, c, sz)
+
+#define UNROLL 16 /* 1, 4, 8, 16 */
+static void
+addmul1(gf *dst1, gf *src1, gf c, int sz)
+{
+ USE_GF_MULC ;
+ register gf *dst = dst1, *src = src1 ;
+ gf *lim = &dst[sz - UNROLL + 1] ;
+
+ GF_MULC0(c) ;
+
+#if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */
+ for (; dst < lim ; dst += UNROLL, src += UNROLL ) {
+ GF_ADDMULC( dst[0] , src[0] );
+ GF_ADDMULC( dst[1] , src[1] );
+ GF_ADDMULC( dst[2] , src[2] );
+ GF_ADDMULC( dst[3] , src[3] );
+#if (UNROLL > 4)
+ GF_ADDMULC( dst[4] , src[4] );
+ GF_ADDMULC( dst[5] , src[5] );
+ GF_ADDMULC( dst[6] , src[6] );
+ GF_ADDMULC( dst[7] , src[7] );
+#endif
+#if (UNROLL > 8)
+ GF_ADDMULC( dst[8] , src[8] );
+ GF_ADDMULC( dst[9] , src[9] );
+ GF_ADDMULC( dst[10] , src[10] );
+ GF_ADDMULC( dst[11] , src[11] );
+ GF_ADDMULC( dst[12] , src[12] );
+ GF_ADDMULC( dst[13] , src[13] );
+ GF_ADDMULC( dst[14] , src[14] );
+ GF_ADDMULC( dst[15] , src[15] );
+#endif
+ }
+#endif
+ lim += UNROLL - 1 ;
+ for (; dst < lim; dst++, src++ ) /* final components */
+ GF_ADDMULC( *dst , *src );
+}
+
+/*
+ * computes C = AB where A is n*k, B is k*m, C is n*m
+ */
+static void
+matmul(gf *a, gf *b, gf *c, int n, int k, int m)
+{
+ int row, col, i ;
+
+ for (row = 0; row < n ; row++) {
+ for (col = 0; col < m ; col++) {
+ gf *pa = &a[ row * k ];
+ gf *pb = &b[ col ];
+ gf acc = 0 ;
+ for (i = 0; i < k ; i++, pa++, pb += m )
+ acc ^= gf_mul( *pa, *pb ) ;
+ c[ row * m + col ] = acc ;
+ }
+ }
+}
+
+#ifdef DEBUG
+/*
+ * returns 1 if the square matrix is identiy
+ * (only for test)
+ */
+static int
+is_identity(gf *m, int k)
+{
+ int row, col ;
+ for (row=0; row<k; row++)
+ for (col=0; col<k; col++)
+ if ( (row==col && *m != 1) ||
+ (row!=col && *m != 0) )
+ return 0 ;
+ else
+ m++ ;
+ return 1 ;
+}
+#endif /* debug */
+
+/*
+ * invert_mat() takes a matrix and produces its inverse
+ * k is the size of the matrix.
+ * (Gauss-Jordan, adapted from Numerical Recipes in C)
+ * Return non-zero if singular.
+ */
+DEB( int pivloops=0; int pivswaps=0 ; /* diagnostic */)
+static int
+invert_mat(gf *src, int k)
+{
+ gf c, *p ;
+ int irow, icol, row, col, i, ix ;
+
+ int error = 1 ;
+ int *indxc = my_malloc(k*sizeof(int), "indxc");
+ int *indxr = my_malloc(k*sizeof(int), "indxr");
+ int *ipiv = my_malloc(k*sizeof(int), "ipiv");
+ gf *id_row = NEW_GF_MATRIX(1, k);
+ gf *temp_row = NEW_GF_MATRIX(1, k);
+
+ bzero(id_row, k*sizeof(gf));
+ DEB( pivloops=0; pivswaps=0 ; /* diagnostic */ )
+ /*
+ * ipiv marks elements already used as pivots.
+ */
+ for (i = 0; i < k ; i++)
+ ipiv[i] = 0 ;
+
+ for (col = 0; col < k ; col++) {
+ gf *pivot_row ;
+ /*
+ * Zeroing column 'col', look for a non-zero element.
+ * First try on the diagonal, if it fails, look elsewhere.
+ */
+ irow = icol = -1 ;
+ if (ipiv[col] != 1 && src[col*k + col] != 0) {
+ irow = col ;
+ icol = col ;
+ goto found_piv ;
+ }
+ for (row = 0 ; row < k ; row++) {
+ if (ipiv[row] != 1) {
+ for (ix = 0 ; ix < k ; ix++) {
+ DEB( pivloops++ ; )
+ if (ipiv[ix] == 0) {
+ if (src[row*k + ix] != 0) {
+ irow = row ;
+ icol = ix ;
+ goto found_piv ;
+ }
+ } else if (ipiv[ix] > 1) {
+ fprintf(stderr, "singular matrix\n");
+ goto fail ;
+ }
+ }
+ }
+ }
+ if (icol == -1) {
+ fprintf(stderr, "XXX pivot not found!\n");
+ goto fail ;
+ }
+found_piv:
+ ++(ipiv[icol]) ;
+ /*
+ * swap rows irow and icol, so afterwards the diagonal
+ * element will be correct. Rarely done, not worth
+ * optimizing.
+ */
+ if (irow != icol) {
+ for (ix = 0 ; ix < k ; ix++ ) {
+ SWAP( src[irow*k + ix], src[icol*k + ix], gf) ;
+ }
+ }
+ indxr[col] = irow ;
+ indxc[col] = icol ;
+ pivot_row = &src[icol*k] ;
+ c = pivot_row[icol] ;
+ if (c == 0) {
+ fprintf(stderr, "singular matrix 2\n");
+ goto fail ;
+ }
+ if (c != 1 ) { /* otherwhise this is a NOP */
+ /*
+ * this is done often , but optimizing is not so
+ * fruitful, at least in the obvious ways (unrolling)
+ */
+ DEB( pivswaps++ ; )
+ c = inverse[ c ] ;
+ pivot_row[icol] = 1 ;
+ for (ix = 0 ; ix < k ; ix++ )
+ pivot_row[ix] = gf_mul(c, pivot_row[ix] );
+ }
+ /*
+ * from all rows, remove multiples of the selected row
+ * to zero the relevant entry (in fact, the entry is not zero
+ * because we know it must be zero).
+ * (Here, if we know that the pivot_row is the identity,
+ * we can optimize the addmul).
+ */
+ id_row[icol] = 1;
+ if (bcmp(pivot_row, id_row, k*sizeof(gf)) != 0) {
+ for (p = src, ix = 0 ; ix < k ; ix++, p += k ) {
+ if (ix != icol) {
+ c = p[icol] ;
+ p[icol] = 0 ;
+ addmul(p, pivot_row, c, k );
+ }
+ }
+ }
+ id_row[icol] = 0;
+ } /* done all columns */
+ for (col = k-1 ; col >= 0 ; col-- ) {
+ if (indxr[col] <0 || indxr[col] >= k)
+ fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]);
+ else if (indxc[col] <0 || indxc[col] >= k)
+ fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]);
+ else
+ if (indxr[col] != indxc[col] ) {
+ for (row = 0 ; row < k ; row++ ) {
+ SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf) ;
+ }
+ }
+ }
+ error = 0 ;
+fail:
+ free(indxc);
+ free(indxr);
+ free(ipiv);
+ free(id_row);
+ free(temp_row);
+ return error ;
+}
+
+/*
+ * fast code for inverting a vandermonde matrix.
+ * XXX NOTE: It assumes that the matrix
+ * is not singular and _IS_ a vandermonde matrix. Only uses
+ * the second column of the matrix, containing the p_i's.
+ *
+ * Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but
+ * largely revised for my purposes.
+ * p = coefficients of the matrix (p_i)
+ * q = values of the polynomial (known)
+ */
+
+int
+invert_vdm(gf *src, int k)
+{
+ int i, j, row, col ;
+ gf *b, *c, *p;
+ gf t, xx ;
+
+ if (k == 1) /* degenerate case, matrix must be p^0 = 1 */
+ return 0 ;
+ /*
+ * c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1
+ * b holds the coefficient for the matrix inversion
+ */
+ c = NEW_GF_MATRIX(1, k);
+ b = NEW_GF_MATRIX(1, k);
+
+ p = NEW_GF_MATRIX(1, k);
+
+ for ( j=1, i = 0 ; i < k ; i++, j+=k ) {
+ c[i] = 0 ;
+ p[i] = src[j] ; /* p[i] */
+ }
+ /*
+ * construct coeffs. recursively. We know c[k] = 1 (implicit)
+ * and start P_0 = x - p_0, then at each stage multiply by
+ * x - p_i generating P_i = x P_{i-1} - p_i P_{i-1}
+ * After k steps we are done.
+ */
+ c[k-1] = p[0] ; /* really -p(0), but x = -x in GF(2^m) */
+ for (i = 1 ; i < k ; i++ ) {
+ gf p_i = p[i] ; /* see above comment */
+ for (j = k-1 - ( i - 1 ) ; j < k-1 ; j++ )
+ c[j] ^= gf_mul( p_i, c[j+1] ) ;
+ c[k-1] ^= p_i ;
+ }
+
+ for (row = 0 ; row < k ; row++ ) {
+ /*
+ * synthetic division etc.
+ */
+ xx = p[row] ;
+ t = 1 ;
+ b[k-1] = 1 ; /* this is in fact c[k] */
+ for (i = k-2 ; i >= 0 ; i-- ) {
+ b[i] = c[i+1] ^ gf_mul(xx, b[i+1]) ;
+ t = gf_mul(xx, t) ^ b[i] ;
+ }
+ for (col = 0 ; col < k ; col++ )
+ src[col*k + row] = gf_mul(inverse[t], b[col] );
+ }
+ free(c) ;
+ free(b) ;
+ free(p) ;
+ return 0 ;
+}
+
+static int fec_initialized = 0 ;
+static void
+init_fec()
+{
+ TICK(ticks[0]);
+ generate_gf();
+ TOCK(ticks[0]);
+ DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);)
+ TICK(ticks[0]);
+ init_mul_table();
+ TOCK(ticks[0]);
+ DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);)
+ fec_initialized = 1 ;
+}
+
+/*
+ * This section contains the proper FEC encoding/decoding routines.
+ * The encoding matrix is computed starting with a Vandermonde matrix,
+ * and then transforming it into a systematic matrix.
+ */
+
+#define FEC_MAGIC 0xFECC0DEC
+
+struct fec_parms {
+ u_long magic ;
+ int k, n ; /* parameters of the code */
+ gf *enc_matrix ;
+} ;
+
+void
+fec_free(struct fec_parms *p)
+{
+ if (p==NULL ||
+ p->magic != ( ( (FEC_MAGIC ^ p->k) ^ p->n) ^ (int)(p->enc_matrix)) ) {
+ fprintf(stderr, "bad parameters to fec_free\n");
+ return ;
+ }
+ free(p->enc_matrix);
+ free(p);
+}
+
+/*
+ * create a new encoder, returning a descriptor. This contains k,n and
+ * the encoding matrix.
+ */
+struct fec_parms *
+fec_new(int k, int n)
+{
+ int row, col ;
+ gf *p, *tmp_m ;
+
+ struct fec_parms *retval ;
+
+ if (fec_initialized == 0)
+ init_fec();
+
+ if (k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n ) {
+ fprintf(stderr, "Invalid parameters k %d n %d GF_SIZE %d\n",
+ k, n, GF_SIZE );
+ return NULL ;
+ }
+ retval = my_malloc(sizeof(struct fec_parms), "new_code");
+ retval->k = k ;
+ retval->n = n ;
+ retval->enc_matrix = NEW_GF_MATRIX(n, k);
+ retval->magic = ( ( FEC_MAGIC ^ k) ^ n) ^ (int)(retval->enc_matrix) ;
+ tmp_m = NEW_GF_MATRIX(n, k);
+ /*
+ * fill the matrix with powers of field elements, starting from 0.
+ * The first row is special, cannot be computed with exp. table.
+ */
+ tmp_m[0] = 1 ;
+ for (col = 1; col < k ; col++)
+ tmp_m[col] = 0 ;
+ for (p = tmp_m + k, row = 0; row < n-1 ; row++, p += k) {
+ for ( col = 0 ; col < k ; col ++ )
+ p[col] = gf_exp[modnn(row*col)];
+ }
+
+ /*
+ * quick code to build systematic matrix: invert the top
+ * k*k vandermonde matrix, multiply right the bottom n-k rows
+ * by the inverse, and construct the identity matrix at the top.
+ */
+ TICK(ticks[3]);
+ invert_vdm(tmp_m, k); /* much faster than invert_mat */
+ matmul(tmp_m + k*k, tmp_m, retval->enc_matrix + k*k, n - k, k, k);
+ /*
+ * the upper matrix is I so do not bother with a slow multiply
+ */
+ bzero(retval->enc_matrix, k*k*sizeof(gf) );
+ for (p = retval->enc_matrix, col = 0 ; col < k ; col++, p += k+1 )
+ *p = 1 ;
+ free(tmp_m);
+ TOCK(ticks[3]);
+
+ DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n",
+ ticks[3]);)
+ DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");)
+ return retval ;
+}
+
+/*
+ * fec_encode accepts as input pointers to n data packets of size sz,
+ * and produces as output a packet pointed to by fec, computed
+ * with index "index".
+ */
+void
+fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz)
+{
+ int i, k = code->k ;
+ gf *p ;
+
+ if (GF_BITS > 8)
+ sz /= 2 ;
+
+ if (index < k)
+ bcopy(src[index], fec, sz*sizeof(gf) ) ;
+ else if (index < code->n) {
+ p = &(code->enc_matrix[index*k] );
+ bzero(fec, sz*sizeof(gf));
+ for (i = 0; i < k ; i++)
+ addmul(fec, src[i], p[i], sz ) ;
+ } else
+ fprintf(stderr, "Invalid index %d (max %d)\n",
+ index, code->n - 1 );
+}
+
+void fec_encode_linear(struct fec_parms *code, gf *src, gf *fec, int index, int sz)
+{
+ int i, k = code->k ;
+ gf *p ;
+
+ if (GF_BITS > 8)
+ sz /= 2 ;
+
+ if (index < k)
+ bcopy(src + (index * sz), fec, sz*sizeof(gf) ) ;
+ else if (index < code->n) {
+ p = &(code->enc_matrix[index*k] );
+ bzero(fec, sz*sizeof(gf));
+ for (i = 0; i < k ; i++)
+ addmul(fec, src + (i * sz), p[i], sz ) ;
+ } else
+ fprintf(stderr, "Invalid index %d (max %d)\n",
+ index, code->n - 1 );
+}
+/*
+ * shuffle move src packets in their position
+ */
+static int
+shuffle(gf *pkt[], int index[], int k)
+{
+ int i;
+
+ for ( i = 0 ; i < k ; ) {
+ if (index[i] >= k || index[i] == i)
+ i++ ;
+ else {
+ /*
+ * put pkt in the right position (first check for conflicts).
+ */
+ int c = index[i] ;
+
+ if (index[c] == c) {
+ DEB(fprintf(stderr, "\nshuffle, error at %d\n", i);)
+ return 1 ;
+ }
+ SWAP(index[i], index[c], int) ;
+ SWAP(pkt[i], pkt[c], gf *) ;
+ }
+ }
+ DEB( /* just test that it works... */
+ for ( i = 0 ; i < k ; i++ ) {
+ if (index[i] < k && index[i] != i) {
+ fprintf(stderr, "shuffle: after\n");
+ for (i=0; i<k ; i++) fprintf(stderr, "%3d ", index[i]);
+ fprintf(stderr, "\n");
+ return 1 ;
+ }
+ }
+ )
+ return 0 ;
+}
+
+/*
+ * build_decode_matrix constructs the encoding matrix given the
+ * indexes. The matrix must be already allocated as
+ * a vector of k*k elements, in row-major order
+ */
+static gf *
+build_decode_matrix(struct fec_parms *code, gf *pkt[], int index[])
+{
+ int i , k = code->k ;
+ gf *p, *matrix = NEW_GF_MATRIX(k, k);
+
+ TICK(ticks[9]);
+ for (i = 0, p = matrix ; i < k ; i++, p += k ) {
+#if 1 /* this is simply an optimization, not very useful indeed */
+ if (index[i] < k) {
+ bzero(p, k*sizeof(gf) );
+ p[i] = 1 ;
+ } else
+#endif
+ if (index[i] < code->n )
+ bcopy( &(code->enc_matrix[index[i]*k]), p, k*sizeof(gf) );
+ else {
+ fprintf(stderr, "decode: invalid index %d (max %d)\n",
+ index[i], code->n - 1 );
+ free(matrix) ;
+ return NULL ;
+ }
+ }
+ TICK(ticks[9]);
+ if (invert_mat(matrix, k)) {
+ free(matrix);
+ matrix = NULL ;
+ }
+ TOCK(ticks[9]);
+ return matrix ;
+}
+
+/*
+ * fec_decode receives as input a vector of packets, the indexes of
+ * packets, and produces the correct vector as output.
+ *
+ * Input:
+ * code: pointer to code descriptor
+ * pkt: pointers to received packets. They are modified
+ * to store the output packets (in place)
+ * index: pointer to packet indexes (modified)
+ * sz: size of each packet
+ */
+int
+fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz)
+{
+ gf *m_dec ;
+ gf **new_pkt ;
+ int row, col , k = code->k ;
+
+ if (GF_BITS > 8)
+ sz /= 2 ;
+
+ if (shuffle(pkt, index, k)) /* error if true */
+ return 1 ;
+ m_dec = build_decode_matrix(code, pkt, index);
+
+ if (m_dec == NULL)
+ return 1 ; /* error */
+ /*
+ * do the actual decoding
+ */
+ new_pkt = my_malloc (k * sizeof (gf * ), "new pkt pointers" );
+ for (row = 0 ; row < k ; row++ ) {
+ if (index[row] >= k) {
+ new_pkt[row] = my_malloc (sz * sizeof (gf), "new pkt buffer" );
+ bzero(new_pkt[row], sz * sizeof(gf) ) ;
+ for (col = 0 ; col < k ; col++ )
+ addmul(new_pkt[row], pkt[col], m_dec[row*k + col], sz) ;
+ }
+ }
+ /*
+ * move pkts to their final destination
+ */
+ for (row = 0 ; row < k ; row++ ) {
+ if (index[row] >= k) {
+ bcopy(new_pkt[row], pkt[row], sz*sizeof(gf));
+ free(new_pkt[row]);
+ }
+ }
+ free(new_pkt);
+ free(m_dec);
+
+ return 0;
+}
+
+/*********** end of FEC code -- beginning of test code ************/
+
+#if (TEST || DEBUG)
+void
+test_gf()
+{
+ int i ;
+ /*
+ * test gf tables. Sufficiently tested...
+ */
+ for (i=0; i<= GF_SIZE; i++) {
+ if (gf_exp[gf_log[i]] != i)
+ fprintf(stderr, "bad exp/log i %d log %d exp(log) %d\n",
+ i, gf_log[i], gf_exp[gf_log[i]]);
+
+ if (i != 0 && gf_mul(i, inverse[i]) != 1)
+ fprintf(stderr, "bad mul/inv i %d inv %d i*inv(i) %d\n",
+ i, inverse[i], gf_mul(i, inverse[i]) );
+ if (gf_mul(0,i) != 0)
+ fprintf(stderr, "bad mul table 0,%d\n",i);
+ if (gf_mul(i,0) != 0)
+ fprintf(stderr, "bad mul table %d,0\n",i);
+ }
+}
+#endif /* TEST */
diff --git a/drivers/mtd/mtd-utils/fectest.c b/drivers/mtd/mtd-utils/fectest.c
new file mode 100644
index 00000000000..d5893b91a5b
--- /dev/null
+++ b/drivers/mtd/mtd-utils/fectest.c
@@ -0,0 +1,92 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "mcast_image.h"
+#include "crc32.h"
+
+#define ERASE_SIZE 131072
+//#define PKT_SIZE 1400
+#define NR_PKTS ((ERASE_SIZE + PKT_SIZE - 1) / PKT_SIZE)
+#define DROPS 8
+
+int main(void)
+{
+ int i, j;
+ unsigned char buf[NR_PKTS * PKT_SIZE];
+ unsigned char pktbuf[(NR_PKTS + DROPS) * PKT_SIZE];
+ struct fec_parms *fec;
+ unsigned char *srcs[NR_PKTS];
+ unsigned char *pkt[NR_PKTS + DROPS];
+ int pktnr[NR_PKTS + DROPS];
+ struct timeval then, now;
+
+ srand(3453);
+ for (i=0; i < sizeof(buf); i++)
+ if (i < ERASE_SIZE)
+ buf[i] = rand();
+ else
+ buf[i] = 0;
+
+ for (i=0; i < NR_PKTS + DROPS; i++)
+ srcs[i] = buf + (i * PKT_SIZE);
+
+ for (i=0; i < NR_PKTS + DROPS; i++) {
+ pkt[i] = malloc(PKT_SIZE);
+ pktnr[i] = -1;
+ }
+ fec = fec_new(NR_PKTS, NR_PKTS + DROPS);
+ if (!fec) {
+ printf("fec_init() failed\n");
+ exit(1);
+ }
+ j = 0;
+ for (i=0; i < NR_PKTS + DROPS; i++) {
+#if 1
+ if (i == 27 || i == 40 || i == 44 || i == 45 || i == 56 )
+ continue;
+#endif
+ if (i == 69 || i == 93 || i == 103)
+ continue;
+ fec_encode(fec, srcs, pkt[j], i, PKT_SIZE);
+ pktnr[j] = i;
+ j++;
+ }
+ gettimeofday(&then, NULL);
+ if (fec_decode(fec, pkt, pktnr, PKT_SIZE)) {
+ printf("Decode failed\n");
+ exit(1);
+ }
+
+ for (i=0; i < NR_PKTS; i++)
+ memcpy(pktbuf + (i*PKT_SIZE), pkt[i], PKT_SIZE);
+ gettimeofday(&now, NULL);
+ now.tv_sec -= then.tv_sec;
+ now.tv_usec -= then.tv_usec;
+ if (now.tv_usec < 0) {
+ now.tv_usec += 1000000;
+ now.tv_sec--;
+ }
+
+ if (memcmp(pktbuf, buf, ERASE_SIZE)) {
+ int fd;
+ printf("Compare failed\n");
+ fd = open("before", O_WRONLY|O_TRUNC|O_CREAT, 0644);
+ if (fd >= 0)
+ write(fd, buf, ERASE_SIZE);
+ close(fd);
+ fd = open("after", O_WRONLY|O_TRUNC|O_CREAT, 0644);
+ if (fd >= 0)
+ write(fd, pktbuf, ERASE_SIZE);
+
+ exit(1);
+ }
+
+ printf("Decoded in %ld.%06lds\n", now.tv_sec, now.tv_usec);
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/flash_erase.c b/drivers/mtd/mtd-utils/flash_erase.c
new file mode 100644
index 00000000000..87316176081
--- /dev/null
+++ b/drivers/mtd/mtd-utils/flash_erase.c
@@ -0,0 +1,189 @@
+/*
+ * flash_erase.c -- erase parts of a MTD device
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <mtd/mtd-user.h>
+
+int region_erase(int Fd, int start, int count, int unlock, int regcount)
+{
+ int i, j;
+ region_info_t * reginfo;
+
+ reginfo = calloc(regcount, sizeof(region_info_t));
+
+ for(i = 0; i < regcount; i++)
+ {
+ reginfo[i].regionindex = i;
+ if(ioctl(Fd,MEMGETREGIONINFO,&(reginfo[i])) != 0)
+ return 8;
+ else
+ printf("Region %d is at %d of %d sector and with sector "
+ "size %x\n", i, reginfo[i].offset, reginfo[i].numblocks,
+ reginfo[i].erasesize);
+ }
+
+ // We have all the information about the chip we need.
+
+ for(i = 0; i < regcount; i++)
+ { //Loop through the regions
+ region_info_t * r = &(reginfo[i]);
+
+ if((start >= reginfo[i].offset) &&
+ (start < (r->offset + r->numblocks*r->erasesize)))
+ break;
+ }
+
+ if(i >= regcount)
+ {
+ printf("Starting offset %x not within chip.\n", start);
+ return 8;
+ }
+
+ //We are now positioned within region i of the chip, so start erasing
+ //count sectors from there.
+
+ for(j = 0; (j < count)&&(i < regcount); j++)
+ {
+ erase_info_t erase;
+ region_info_t * r = &(reginfo[i]);
+
+ erase.start = start;
+ erase.length = r->erasesize;
+
+ if(unlock != 0)
+ { //Unlock the sector first.
+ if(ioctl(Fd, MEMUNLOCK, &erase) != 0)
+ {
+ perror("\nMTD Unlock failure");
+ close(Fd);
+ return 8;
+ }
+ }
+ printf("\rPerforming Flash Erase of length 0x%llx at offset 0x%llx",
+ erase.length, erase.start);
+ fflush(stdout);
+ if(ioctl(Fd, MEMERASE, &erase) != 0)
+ {
+ perror("\nMTD Erase failure");
+ close(Fd);
+ return 8;
+ }
+
+
+ start += erase.length;
+ if(start >= (r->offset + r->numblocks*r->erasesize))
+ { //We finished region i so move to region i+1
+ printf("\nMoving to region %d\n", i+1);
+ i++;
+ }
+ }
+
+ printf(" done\n");
+
+ return 0;
+}
+
+int non_region_erase(int Fd, int start, int count, int unlock)
+{
+ mtd_info_t meminfo;
+
+ if (ioctl(Fd,MEMGETINFO,&meminfo) == 0)
+ {
+ erase_info_t erase;
+
+ erase.start = start;
+
+ erase.length = meminfo.erasesize;
+
+ for (; count > 0; count--) {
+ printf("\rPerforming Flash Erase of length 0x%llx at offset 0x%llx",
+ erase.length, erase.start);
+ fflush(stdout);
+
+ if(unlock != 0)
+ {
+ //Unlock the sector first.
+ printf("\rPerforming Flash unlock at offset 0x%llx",erase.start);
+ if(ioctl(Fd, MEMUNLOCK, &erase) != 0)
+ {
+ perror("\nMTD Unlock failure");
+ close(Fd);
+ return 8;
+ }
+ }
+
+ if (ioctl(Fd,MEMERASE,&erase) != 0)
+ {
+ perror("\nMTD Erase failure");
+ close(Fd);
+ return 8;
+ }
+ erase.start += meminfo.erasesize;
+ }
+ printf(" done\n");
+ }
+ return 0;
+}
+
+int main(int argc,char *argv[])
+{
+ int regcount;
+ int Fd;
+ int start;
+ int count;
+ int unlock;
+ int res = 0;
+
+ if (1 >= argc || !strcmp(argv[1], "-h") || !strcmp (argv[1], "--help") ) {
+ printf("Usage: flash_erase MTD-device [start] [cnt (# erase blocks)] [lock]\n"
+ " flash_erase -h | --help\n") ;
+ return 16 ;
+ }
+
+ if (argc > 2)
+ start = strtol(argv[2], NULL, 0);
+ else
+ start = 0;
+
+ if (argc > 3)
+ count = strtol(argv[3], NULL, 0);
+ else
+ count = 1;
+
+ if(argc > 4)
+ unlock = strtol(argv[4], NULL, 0);
+ else
+ unlock = 0;
+
+
+ // Open and size the device
+ if ((Fd = open(argv[1],O_RDWR)) < 0)
+ {
+ fprintf(stderr,"File open error\n");
+ return 8;
+ }
+
+ printf("Erase Total %d Units\n", count);
+
+ if (ioctl(Fd,MEMGETREGIONCOUNT,&regcount) == 0)
+ {
+ if(regcount == 0)
+ {
+ res = non_region_erase(Fd, start, count, unlock);
+ }
+ else
+ {
+ res = region_erase(Fd, start, count, unlock, regcount);
+ }
+ }
+
+ return res;
+}
diff --git a/drivers/mtd/mtd-utils/flash_eraseall.c b/drivers/mtd/mtd-utils/flash_eraseall.c
new file mode 100644
index 00000000000..6541329e9a5
--- /dev/null
+++ b/drivers/mtd/mtd-utils/flash_eraseall.c
@@ -0,0 +1,286 @@
+/* eraseall.c -- erase the whole of a MTD device
+
+ Copyright (C) 2000 Arcom Control System Ltd
+
+ Renamed to flash_eraseall.c
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <libgen.h>
+#include <ctype.h>
+#include <time.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include "crc32.h"
+
+#include <mtd/mtd-user.h>
+#include <mtd/jffs2-user.h>
+
+#define PROGRAM "flash_eraseall"
+#define VERSION "$Revision: 1.1.1.1 $"
+
+static const char *exe_name;
+static const char *mtd_device;
+static int quiet; /* true -- don't output progress */
+static int jffs2; // format for jffs2 usage
+
+static void process_options (int argc, char *argv[]);
+static void display_help (void);
+static void display_version (void);
+static struct jffs2_unknown_node cleanmarker;
+int target_endian = __BYTE_ORDER;
+
+int main (int argc, char *argv[])
+{
+ mtd_info_t meminfo;
+ int fd, clmpos = 0, clmlen = 8;
+ erase_info_t erase;
+ int isNAND, bbtest = 1;
+
+ process_options(argc, argv);
+
+
+ if ((fd = open(mtd_device, O_RDWR)) < 0) {
+ fprintf(stderr, "%s: %s: %s\n", exe_name, mtd_device, strerror(errno));
+ exit(1);
+ }
+
+
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ fprintf(stderr, "%s: %s: unable to get MTD device info\n", exe_name, mtd_device);
+ exit(1);
+ }
+
+ erase.length = meminfo.erasesize;
+ isNAND = meminfo.type == MTD_NANDFLASH ? 1 : 0;
+
+ if (jffs2) {
+ cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
+ cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
+ if (!isNAND)
+ cleanmarker.totlen = cpu_to_je32 (sizeof (struct jffs2_unknown_node));
+ else {
+ struct nand_oobinfo oobinfo;
+
+ if (ioctl(fd, MEMGETOOBSEL, &oobinfo) != 0) {
+ fprintf(stderr, "%s: %s: unable to get NAND oobinfo\n", exe_name, mtd_device);
+ exit(1);
+ }
+
+ /* Check for autoplacement */
+ if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
+ /* Get the position of the free bytes */
+ if (!oobinfo.oobfree[0][1]) {
+ fprintf (stderr, " Eeep. Autoplacement selected and no empty space in oob\n");
+ exit(1);
+ }
+ clmpos = oobinfo.oobfree[0][0];
+ clmlen = oobinfo.oobfree[0][1];
+ if (clmlen > 8)
+ clmlen = 8;
+ } else {
+ /* Legacy mode */
+ switch (meminfo.oobsize) {
+ case 8:
+ clmpos = 6;
+ clmlen = 2;
+ break;
+ case 16:
+ clmpos = 8;
+ clmlen = 8;
+ break;
+ case 64:
+ clmpos = 16;
+ clmlen = 8;
+ break;
+ }
+ }
+ cleanmarker.totlen = cpu_to_je32(8);
+ }
+ cleanmarker.hdr_crc = cpu_to_je32 (crc32 (0, &cleanmarker, sizeof (struct jffs2_unknown_node) - 4));
+ }
+
+ for (erase.start = 0; erase.start < meminfo.size; erase.start += meminfo.erasesize) {
+ if (bbtest) {
+ unsigned long long offset = erase.start;
+ int ret = ioctl(fd, MEMGETBADBLOCK, &offset);
+ if (ret > 0) {
+ if (!quiet)
+ printf ("\nSkipping bad block at 0x%09llx\n", erase.start);
+ continue;
+ } else if (ret < 0) {
+ if (errno == EOPNOTSUPP) {
+ bbtest = 0;
+ if (isNAND) {
+ fprintf(stderr, "%s: %s: Bad block check not available\n", exe_name, mtd_device);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "\n%s: %s: MTD get bad block failed: %s\n", exe_name, mtd_device, strerror(errno));
+ exit(1);
+ }
+ }
+ }
+
+ if (!quiet) {
+ printf
+ ("\rErasing %d Kibyte @ %llx -- %2u %% complete.",
+ meminfo.erasesize / 1024, erase.start,
+ (unsigned long long)
+ (erase.start + meminfo.erasesize) * 100 / meminfo.size);
+ }
+ fflush(stdout);
+
+ if (ioctl(fd, MEMERASE, &erase) != 0) {
+ fprintf(stderr, "\n%s: %s: MTD Erase failure: %s\n", exe_name, mtd_device, strerror(errno));
+ continue;
+ }
+
+ /* format for JFFS2 ? */
+ if (!jffs2)
+ continue;
+
+ /* write cleanmarker */
+ if (isNAND) {
+ struct mtd_oob_buf oob;
+ oob.ptr = (unsigned char *) &cleanmarker;
+ oob.start = erase.start + clmpos;
+ oob.length = clmlen;
+ if (ioctl (fd, MEMWRITEOOB, &oob) != 0) {
+ fprintf(stderr, "\n%s: %s: MTD writeoob failure: %s\n", exe_name, mtd_device, strerror(errno));
+ continue;
+ }
+ } else {
+ if (lseek (fd, erase.start, SEEK_SET) < 0) {
+ fprintf(stderr, "\n%s: %s: MTD lseek failure: %s\n", exe_name, mtd_device, strerror(errno));
+ continue;
+ }
+ if (write (fd , &cleanmarker, sizeof (cleanmarker)) != sizeof (cleanmarker)) {
+ fprintf(stderr, "\n%s: %s: MTD write failure: %s\n", exe_name, mtd_device, strerror(errno));
+ continue;
+ }
+ }
+ if (!quiet)
+ printf (" Cleanmarker written at %x.", erase.start);
+ }
+ if (!quiet)
+ printf("\n");
+
+ return 0;
+}
+
+
+void process_options (int argc, char *argv[])
+{
+ int error = 0;
+
+ exe_name = argv[0];
+
+ for (;;) {
+ int option_index = 0;
+ static const char *short_options = "jq";
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 0},
+ {"version", no_argument, 0, 0},
+ {"jffs2", no_argument, 0, 'j'},
+ {"quiet", no_argument, 0, 'q'},
+ {"silent", no_argument, 0, 'q'},
+
+ {0, 0, 0, 0},
+ };
+
+ int c = getopt_long(argc, argv, short_options,
+ long_options, &option_index);
+ if (c == EOF) {
+ break;
+ }
+
+ switch (c) {
+ case 0:
+ switch (option_index) {
+ case 0:
+ display_help();
+ break;
+ case 1:
+ display_version();
+ break;
+ }
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'j':
+ jffs2 = 1;
+ break;
+ case '?':
+ error = 1;
+ break;
+ }
+ }
+ if (optind == argc) {
+ fprintf(stderr, "%s: no MTD device specified\n", exe_name);
+ error = 1;
+ }
+ if (error) {
+ fprintf(stderr, "Try `%s --help' for more information.\n",
+ exe_name);
+ exit(1);
+ }
+
+ mtd_device = argv[optind];
+}
+
+
+void display_help (void)
+{
+ printf("Usage: %s [OPTION] MTD_DEVICE\n"
+ "Erases all of the specified MTD device.\n"
+ "\n"
+ " -j, --jffs2 format the device for jffs2\n"
+ " -q, --quiet don't display progress messages\n"
+ " --silent same as --quiet\n"
+ " --help display this help and exit\n"
+ " --version output version information and exit\n",
+ exe_name);
+ exit(0);
+}
+
+
+void display_version (void)
+{
+ printf(PROGRAM " " VERSION "\n"
+ "\n"
+ "Copyright (C) 2000 Arcom Control Systems Ltd\n"
+ "\n"
+ PROGRAM " comes with NO WARRANTY\n"
+ "to the extent permitted by law.\n"
+ "\n"
+ "You may redistribute copies of " PROGRAM "\n"
+ "under the terms of the GNU General Public Licence.\n"
+ "See the file `COPYING' for more information.\n");
+ exit(0);
+}
diff --git a/drivers/mtd/mtd-utils/flash_info.c b/drivers/mtd/mtd-utils/flash_info.c
new file mode 100644
index 00000000000..f5ed1c6ff78
--- /dev/null
+++ b/drivers/mtd/mtd-utils/flash_info.c
@@ -0,0 +1,55 @@
+/*
+ * flash_info.c -- print info about a MTD device
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+
+#include <mtd/mtd-user.h>
+
+int main(int argc,char *argv[])
+{
+ int regcount;
+ int Fd;
+
+ if (1 >= argc)
+ {
+ fprintf(stderr,"Usage: flash_info device\n");
+ return 16;
+ }
+
+ // Open and size the device
+ if ((Fd = open(argv[1],O_RDONLY)) < 0)
+ {
+ fprintf(stderr,"File open error\n");
+ return 8;
+ }
+
+ if (ioctl(Fd,MEMGETREGIONCOUNT,&regcount) == 0)
+ {
+ int i;
+ region_info_t reginfo;
+ printf("Device %s has %d erase regions\n", argv[1], regcount);
+ for (i = 0; i < regcount; i++)
+ {
+ reginfo.regionindex = i;
+ if(ioctl(Fd, MEMGETREGIONINFO, &reginfo) == 0)
+ {
+ printf("Region %d is at 0x%x with size 0x%x and "
+ "has 0x%x blocks\n", i, reginfo.offset,
+ reginfo.erasesize, reginfo.numblocks);
+ }
+ else
+ {
+ printf("Strange can not read region %d from a %d region device\n",
+ i, regcount);
+ }
+ }
+ }
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/flash_lock.c b/drivers/mtd/mtd-utils/flash_lock.c
new file mode 100644
index 00000000000..dca679456ef
--- /dev/null
+++ b/drivers/mtd/mtd-utils/flash_lock.c
@@ -0,0 +1,84 @@
+/*
+ * FILE flash_lock.c
+ *
+ * This utility locks one or more sectors of flash device.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <string.h>
+
+#include <mtd/mtd-user.h>
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ struct mtd_info_user mtdInfo;
+ struct erase_info_user mtdLockInfo;
+ int num_sectors;
+ int ofs;
+
+ /*
+ * Parse command line options
+ */
+ if(argc != 4)
+ {
+ fprintf(stderr, "USAGE: %s <mtd device> <ofs in hex> <num of sectors in decimal or -1 for all sectors>\n", argv[0]);
+ exit(1);
+ }
+ else if(strncmp(argv[1], "/dev/mtd", 8) != 0)
+ {
+ fprintf(stderr, "'%s' is not a MTD device. Must specify mtd device: /dev/mtd?\n", argv[1]);
+ exit(1);
+ }
+
+ fd = open(argv[1], O_RDWR);
+ if(fd < 0)
+ {
+ fprintf(stderr, "Could not open mtd device: %s\n", argv[1]);
+ exit(1);
+ }
+
+ if(ioctl(fd, MEMGETINFO, &mtdInfo))
+ {
+ fprintf(stderr, "Could not get MTD device info from %s\n", argv[1]);
+ close(fd);
+ exit(1);
+ }
+ sscanf(argv[2], "%x",&ofs);
+ sscanf(argv[3], "%d",&num_sectors);
+ if(ofs > mtdInfo.size - mtdInfo.erasesize)
+ {
+ fprintf(stderr, "%x is beyond device size %x\n",ofs,(unsigned int)(mtdInfo.size - mtdInfo.erasesize));
+ exit(1);
+ }
+
+ if (num_sectors == -1) {
+ num_sectors = mtdInfo.size/mtdInfo.erasesize;
+ }
+ else {
+ if(num_sectors > mtdInfo.size/mtdInfo.erasesize)
+ {
+ fprintf(stderr, "%d are too many sectors, device only has %d\n",num_sectors,(int)(mtdInfo.size/mtdInfo.erasesize));
+ exit(1);
+ }
+ }
+
+ mtdLockInfo.start = ofs;
+ mtdLockInfo.length = num_sectors * mtdInfo.erasesize;
+ if(ioctl(fd, MEMLOCK, &mtdLockInfo))
+ {
+ fprintf(stderr, "Could not lock MTD device: %s\n", argv[1]);
+ close(fd);
+ exit(1);
+ }
+
+ return 0;
+}
+
diff --git a/drivers/mtd/mtd-utils/flash_otp_dump.c b/drivers/mtd/mtd-utils/flash_otp_dump.c
new file mode 100644
index 00000000000..a18130d24e6
--- /dev/null
+++ b/drivers/mtd/mtd-utils/flash_otp_dump.c
@@ -0,0 +1,54 @@
+/*
+ * flash_otp_dump.c -- display One-Time-Programm data
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <mtd/mtd-user.h>
+
+int main(int argc,char *argv[])
+{
+ int fd, val, i, offset, ret;
+ unsigned char buf[16];
+
+ if (argc != 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) {
+ fprintf(stderr,"Usage: %s [ -f | -u ] <device>\n", argv[0]);
+ return EINVAL;
+ }
+
+ fd = open(argv[2], O_RDONLY);
+ if (fd < 0) {
+ perror(argv[2]);
+ return errno;
+ }
+
+ val = argv[1][1] == 'f' ? MTD_OTP_FACTORY : MTD_OTP_USER;
+ ret = ioctl(fd, OTPSELECT, &val);
+ if (ret < 0) {
+ perror("OTPSELECT");
+ return errno;
+ }
+
+ printf("OTP %s data for %s\n",
+ argv[1][1] == 'f' ? "factory" : "user", argv[2]);
+ offset = 0;
+ while ((ret = read(fd, buf, sizeof(buf)))) {
+ if (ret < 0) {
+ perror("read()");
+ return errno;
+ }
+ printf("0x%04x:", offset);
+ for (i = 0; i < ret; i++)
+ printf(" %02x", buf[i]);
+ printf("\n");
+ offset += ret;
+ }
+
+ close(fd);
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/flash_otp_info.c b/drivers/mtd/mtd-utils/flash_otp_info.c
new file mode 100644
index 00000000000..c9486ee5407
--- /dev/null
+++ b/drivers/mtd/mtd-utils/flash_otp_info.c
@@ -0,0 +1,63 @@
+/*
+ * flash_otp_info.c -- print info about One-Time-Programm data
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <mtd/mtd-user.h>
+
+int main(int argc,char *argv[])
+{
+ int fd, val, i, ret;
+
+ if (argc != 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) {
+ fprintf(stderr,"Usage: %s [ -f | -u ] <device>\n", argv[0]);
+ return EINVAL;
+ }
+
+ fd = open(argv[2], O_RDONLY);
+ if (fd < 0) {
+ perror(argv[2]);
+ return errno;
+ }
+
+ val = argv[1][1] == 'f' ? MTD_OTP_FACTORY : MTD_OTP_USER;
+ ret = ioctl(fd, OTPSELECT, &val);
+ if (ret < 0) {
+ perror("OTPSELECT");
+ return errno;
+ }
+
+ ret = ioctl(fd, OTPGETREGIONCOUNT, &val);
+ if (ret < 0) {
+ perror("OTPGETREGIONCOUNT");
+ return errno;
+ }
+
+ printf("Number of OTP %s blocks on %s: %d\n",
+ argv[1][1] == 'f' ? "factory" : "user", argv[2], val);
+
+ if (val > 0) {
+ struct otp_info info[val];
+
+ ret = ioctl(fd, OTPGETREGIONINFO, &info);
+ if (ret < 0) {
+ perror("OTPGETREGIONCOUNT");
+ return errno;
+ }
+
+ for (i = 0; i < val; i++)
+ printf("block %2d: offset = 0x%04x "
+ "size = %2d bytes %s\n",
+ i, info[i].start, info[i].length,
+ info[i].locked ? "[locked]" : "[unlocked]");
+ }
+
+ close(fd);
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/flash_otp_lock.c b/drivers/mtd/mtd-utils/flash_otp_lock.c
new file mode 100644
index 00000000000..d0e06cdb781
--- /dev/null
+++ b/drivers/mtd/mtd-utils/flash_otp_lock.c
@@ -0,0 +1,70 @@
+/*
+ * flash_otp_lock.c -- lock area of One-Time-Program data
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <mtd/mtd-user.h>
+
+int main(int argc,char *argv[])
+{
+ int fd, val, ret, offset, size;
+ char *p, buf[8];
+
+ if (argc != 5 || strcmp(argv[1], "-u")) {
+ fprintf(stderr, "Usage: %s -u <device> <offset> <size>\n", argv[0]);
+ fprintf(stderr, "offset and size must match on OTP region boundaries\n");
+ fprintf(stderr, "CAUTION! ONCE LOCKED, OTP REGIONS CAN'T BE UNLOCKED!\n");
+ return EINVAL;
+ }
+
+ fd = open(argv[2], O_WRONLY);
+ if (fd < 0) {
+ perror(argv[2]);
+ return errno;
+ }
+
+ val = MTD_OTP_USER;
+ ret = ioctl(fd, OTPSELECT, &val);
+ if (ret < 0) {
+ perror("OTPSELECT");
+ return errno;
+ }
+
+ offset = strtoul(argv[3], &p, 0);
+ if (argv[3][0] == 0 || *p != 0) {
+ fprintf(stderr, "%s: bad offset value\n", argv[0]);
+ return ERANGE;
+ }
+
+ size = strtoul(argv[4], &p, 0);
+ if (argv[4][0] == 0 || *p != 0) {
+ fprintf(stderr, "%s: bad size value\n", argv[0]);
+ return ERANGE;
+ }
+
+ printf("About to lock OTP user data on %s from 0x%x to 0x%x\n",
+ argv[2], offset, offset + size);
+ printf("Are you sure (yes|no)? ");
+ if (fgets(buf, sizeof(buf), stdin) && strcmp(buf, "yes\n") == 0) {
+ struct otp_info info;
+ info.start = offset;
+ info.length = size;
+ ret = ioctl(fd, OTPLOCK, &info);
+ if (ret < 0) {
+ perror("OTPLOCK");
+ return errno;
+ }
+ printf("Done.\n");
+ } else {
+ printf("Aborted\n");
+ }
+
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/flash_otp_write.c b/drivers/mtd/mtd-utils/flash_otp_write.c
new file mode 100644
index 00000000000..f01df514393
--- /dev/null
+++ b/drivers/mtd/mtd-utils/flash_otp_write.c
@@ -0,0 +1,96 @@
+/*
+ * flash_otp_write.c -- write One-Time-Program data
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <mtd/mtd-user.h>
+
+int main(int argc,char *argv[])
+{
+ int fd, val, ret, size, wrote, len;
+ mtd_info_t mtdInfo;
+ off_t offset;
+ char *p, buf[2048];
+
+ if (argc != 4 || strcmp(argv[1], "-u")) {
+ fprintf(stderr, "Usage: %s -u <device> <offset>\n", argv[0]);
+ fprintf(stderr, "the raw data to write should be provided on stdin\n");
+ fprintf(stderr, "CAUTION! ONCE SET TO 0, OTP DATA BITS CAN'T BE ERASED!\n");
+ return EINVAL;
+ }
+
+ fd = open(argv[2], O_WRONLY);
+ if (fd < 0) {
+ perror(argv[2]);
+ return errno;
+ }
+
+ val = MTD_OTP_USER;
+ ret = ioctl(fd, OTPSELECT, &val);
+ if (ret < 0) {
+ perror("OTPSELECT");
+ return errno;
+ }
+
+ if (ioctl(fd, MEMGETINFO, &mtdInfo)) {
+ perror("MEMGETINFO");
+ return errno;
+ }
+
+ offset = strtoul(argv[3], &p, 0);
+ if (argv[3][0] == 0 || *p != 0) {
+ fprintf(stderr, "%s: bad offset value\n", argv[0]);
+ return ERANGE;
+ }
+
+ if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+ perror("lseek()");
+ return errno;
+ }
+
+ printf("Writing OTP user data on %s at offset 0x%lx\n", argv[2], offset);
+
+ if (mtdInfo.type == MTD_NANDFLASH)
+ len = mtdInfo.writesize;
+ else
+ len = 256;
+
+ wrote = 0;
+ while ((size = read(0, buf, len))) {
+ if (size < 0) {
+ perror("read()");
+ return errno;
+ }
+ p = buf;
+ while (size > 0) {
+ if (mtdInfo.type == MTD_NANDFLASH) {
+ /* Fill remain buffers with 0xff */
+ memset(buf + size, 0xff, mtdInfo.writesize - size);
+ size = mtdInfo.writesize;
+ }
+ ret = write(fd, p, size);
+ if (ret < 0) {
+ perror("write()");
+ return errno;
+ }
+ if (ret == 0) {
+ printf("write() returned 0 after writing %d bytes\n", wrote);
+ return 0;
+ }
+ p += ret;
+ wrote += ret;
+ size -= ret;
+ }
+ }
+
+ printf("Wrote %d bytes of OTP user data\n", wrote);
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/flash_unlock.c b/drivers/mtd/mtd-utils/flash_unlock.c
new file mode 100644
index 00000000000..648dc4f42d9
--- /dev/null
+++ b/drivers/mtd/mtd-utils/flash_unlock.c
@@ -0,0 +1,64 @@
+/*
+ * FILE flash_unlock.c
+ *
+ * This utility unlock all sectors of flash device.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <string.h>
+
+#include <mtd/mtd-user.h>
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ struct mtd_info_user mtdInfo;
+ struct erase_info_user mtdLockInfo;
+
+ /*
+ * Parse command line options
+ */
+ if(argc != 2)
+ {
+ fprintf(stderr, "USAGE: %s <mtd device>\n", argv[0]);
+ exit(1);
+ }
+ else if(strncmp(argv[1], "/dev/mtd", 8) != 0)
+ {
+ fprintf(stderr, "'%s' is not a MTD device. Must specify mtd device: /dev/mtd?\n", argv[1]);
+ exit(1);
+ }
+
+ fd = open(argv[1], O_RDWR);
+ if(fd < 0)
+ {
+ fprintf(stderr, "Could not open mtd device: %s\n", argv[1]);
+ exit(1);
+ }
+
+ if(ioctl(fd, MEMGETINFO, &mtdInfo))
+ {
+ fprintf(stderr, "Could not get MTD device info from %s\n", argv[1]);
+ close(fd);
+ exit(1);
+ }
+
+ mtdLockInfo.start = 0;
+ mtdLockInfo.length = mtdInfo.size;
+ if(ioctl(fd, MEMUNLOCK, &mtdLockInfo))
+ {
+ fprintf(stderr, "Could not unlock MTD device: %s\n", argv[1]);
+ close(fd);
+ exit(1);
+ }
+
+ return 0;
+}
+
diff --git a/drivers/mtd/mtd-utils/flashcp.c b/drivers/mtd/mtd-utils/flashcp.c
new file mode 100644
index 00000000000..7f7764a6d9f
--- /dev/null
+++ b/drivers/mtd/mtd-utils/flashcp.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2d3D, Inc.
+ * Written by Abraham vd Merwe <abraham@2d3d.co.za>
+ * All rights reserved.
+ *
+ * Renamed to flashcp.c to avoid conflicts with fcp from fsh package
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <mtd/mtd-user.h>
+#include <getopt.h>
+
+typedef int bool;
+#define true 1
+#define false 0
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+/* for debugging purposes only */
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG(fmt,args...) { log_printf (LOG_ERROR,"%d: ",__LINE__); log_printf (LOG_ERROR,fmt,## args); }
+#else
+#undef DEBUG
+#define DEBUG(fmt,args...)
+#endif
+
+#define KB(x) ((x) / 1024)
+#define PERCENTAGE(x,total) (((x) * 100) / (total))
+
+/* size of read/write buffer */
+#define BUFSIZE (10 * 1024)
+
+/* cmd-line flags */
+#define FLAG_NONE 0x00
+#define FLAG_VERBOSE 0x01
+#define FLAG_HELP 0x02
+#define FLAG_FILENAME 0x04
+#define FLAG_DEVICE 0x08
+
+/* error levels */
+#define LOG_NORMAL 1
+#define LOG_ERROR 2
+
+static void log_printf (int level,const char *fmt, ...)
+{
+ FILE *fp = level == LOG_NORMAL ? stdout : stderr;
+ va_list ap;
+ va_start (ap,fmt);
+ vfprintf (fp,fmt,ap);
+ va_end (ap);
+ fflush (fp);
+}
+
+static void showusage (const char *progname,bool error)
+{
+ int level = error ? LOG_ERROR : LOG_NORMAL;
+
+ log_printf (level,
+ "\n"
+ "Flash Copy - Written by Abraham van der Merwe <abraham@2d3d.co.za>\n"
+ "\n"
+ "usage: %s [ -v | --verbose ] <filename> <device>\n"
+ " %s -h | --help\n"
+ "\n"
+ " -h | --help Show this help message\n"
+ " -v | --verbose Show progress reports\n"
+ " <filename> File which you want to copy to flash\n"
+ " <device> Flash device to write to (e.g. /dev/mtd0, /dev/mtd1, etc.)\n"
+ "\n",
+ progname,progname);
+
+ exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+static int safe_open (const char *pathname,int flags)
+{
+ int fd;
+
+ fd = open (pathname,flags);
+ if (fd < 0)
+ {
+ log_printf (LOG_ERROR,"While trying to open %s",pathname);
+ if (flags & O_RDWR)
+ log_printf (LOG_ERROR," for read/write access");
+ else if (flags & O_RDONLY)
+ log_printf (LOG_ERROR," for read access");
+ else if (flags & O_WRONLY)
+ log_printf (LOG_ERROR," for write access");
+ log_printf (LOG_ERROR,": %m\n");
+ exit (EXIT_FAILURE);
+ }
+
+ return (fd);
+}
+
+static void safe_read (int fd,const char *filename,void *buf,size_t count,bool verbose)
+{
+ ssize_t result;
+
+ result = read (fd,buf,count);
+ if (count != result)
+ {
+ if (verbose) log_printf (LOG_NORMAL,"\n");
+ if (result < 0)
+ {
+ log_printf (LOG_ERROR,"While reading data from %s: %m\n",filename);
+ exit (EXIT_FAILURE);
+ }
+ log_printf (LOG_ERROR,"Short read count returned while reading from %s\n",filename);
+ exit (EXIT_FAILURE);
+ }
+}
+
+static void safe_rewind (int fd,const char *filename)
+{
+ if (lseek (fd,0L,SEEK_SET) < 0)
+ {
+ log_printf (LOG_ERROR,"While seeking to start of %s: %m\n",filename);
+ exit (EXIT_FAILURE);
+ }
+}
+
+/******************************************************************************/
+
+static int dev_fd = -1,fil_fd = -1;
+
+static void cleanup (void)
+{
+ if (dev_fd > 0) close (dev_fd);
+ if (fil_fd > 0) close (fil_fd);
+}
+
+int main (int argc,char *argv[])
+{
+ const char *progname,*filename = NULL,*device = NULL;
+ int i,flags = FLAG_NONE;
+ ssize_t result;
+ size_t size,written;
+ struct mtd_info_user mtd;
+ struct erase_info_user erase;
+ struct stat filestat;
+ unsigned char src[BUFSIZE],dest[BUFSIZE];
+
+ (progname = strrchr (argv[0],'/')) ? progname++ : (progname = argv[0]);
+
+ /*********************
+ * parse cmd-line
+ *****************/
+
+ for (;;) {
+ int option_index = 0;
+ static const char *short_options = "hv";
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"verbose", no_argument, 0, 'v'},
+ {0, 0, 0, 0},
+ };
+
+ int c = getopt_long(argc, argv, short_options,
+ long_options, &option_index);
+ if (c == EOF) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ flags |= FLAG_HELP;
+ DEBUG("Got FLAG_HELP\n");
+ break;
+ case 'v':
+ flags |= FLAG_VERBOSE;
+ DEBUG("Got FLAG_VERBOSE\n");
+ break;
+ default:
+ DEBUG("Unknown parameter: %s\n",argv[option_index]);
+ showusage (progname,true);
+ }
+ }
+ if (optind+2 == argc) {
+ flags |= FLAG_FILENAME;
+ filename = argv[optind];
+ DEBUG("Got filename: %s\n",filename);
+
+ flags |= FLAG_DEVICE;
+ device = argv[optind+1];
+ DEBUG("Got device: %s\n",device);
+ }
+
+ if (flags & FLAG_HELP || progname == NULL || device == NULL)
+ showusage (progname,flags != FLAG_HELP);
+
+ atexit (cleanup);
+
+ /* get some info about the flash device */
+ dev_fd = safe_open (device,O_SYNC | O_RDWR);
+ if (ioctl (dev_fd,MEMGETINFO,&mtd) < 0)
+ {
+ DEBUG("ioctl(): %m\n");
+ log_printf (LOG_ERROR,"This doesn't seem to be a valid MTD flash device!\n");
+ exit (EXIT_FAILURE);
+ }
+
+ /* get some info about the file we want to copy */
+ fil_fd = safe_open (filename,O_RDONLY);
+ if (fstat (fil_fd,&filestat) < 0)
+ {
+ log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename);
+ exit (EXIT_FAILURE);
+ }
+
+ /* does it fit into the device/partition? */
+ if (filestat.st_size > mtd.size)
+ {
+ log_printf (LOG_ERROR,"%s won't fit into %s!\n",filename,device);
+ exit (EXIT_FAILURE);
+ }
+
+ /*****************************************************
+ * erase enough blocks so that we can write the file *
+ *****************************************************/
+
+#warning "Check for smaller erase regions"
+
+ erase.start = 0;
+ erase.length = filestat.st_size & ~(mtd.erasesize - 1);
+ if (filestat.st_size % mtd.erasesize) erase.length += mtd.erasesize;
+ if (flags & FLAG_VERBOSE)
+ {
+ /* if the user wants verbose output, erase 1 block at a time and show him/her what's going on */
+ int blocks = erase.length / mtd.erasesize;
+ erase.length = mtd.erasesize;
+ log_printf (LOG_NORMAL,"Erasing blocks: 0/%d (0%%)",blocks);
+ for (i = 1; i <= blocks; i++)
+ {
+ log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (%d%%)",i,blocks,PERCENTAGE (i,blocks));
+ if (ioctl (dev_fd,MEMERASE,&erase) < 0)
+ {
+ log_printf (LOG_NORMAL,"\n");
+ log_printf (LOG_ERROR,
+ "While erasing blocks 0x%.8x-0x%.8x on %s: %m\n",
+ (unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
+ exit (EXIT_FAILURE);
+ }
+ erase.start += mtd.erasesize;
+ }
+ log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (100%%)\n",blocks,blocks);
+ }
+ else
+ {
+ /* if not, erase the whole chunk in one shot */
+ if (ioctl (dev_fd,MEMERASE,&erase) < 0)
+ {
+ log_printf (LOG_ERROR,
+ "While erasing blocks from 0x%.8x-0x%.8x on %s: %m\n",
+ (unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
+ exit (EXIT_FAILURE);
+ }
+ }
+ DEBUG("Erased %u / %luk bytes\n",erase.length,filestat.st_size);
+
+ /**********************************
+ * write the entire file to flash *
+ **********************************/
+
+ if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%luk (0%%)",KB (filestat.st_size));
+ size = filestat.st_size;
+ i = BUFSIZE;
+ written = 0;
+ while (size)
+ {
+ if (size < BUFSIZE) i = size;
+ if (flags & FLAG_VERBOSE)
+ log_printf (LOG_NORMAL,"\rWriting data: %dk/%luk (%lu%%)",
+ KB (written + i),
+ KB (filestat.st_size),
+ PERCENTAGE (written + i,filestat.st_size));
+
+ /* read from filename */
+ safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
+
+ /* write to device */
+ result = write (dev_fd,src,i);
+ if (i != result)
+ {
+ if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"\n");
+ if (result < 0)
+ {
+ log_printf (LOG_ERROR,
+ "While writing data to 0x%.8x-0x%.8x on %s: %m\n",
+ written,written + i,device);
+ exit (EXIT_FAILURE);
+ }
+ log_printf (LOG_ERROR,
+ "Short write count returned while writing to x%.8x-0x%.8x on %s: %d/%lu bytes written to flash\n",
+ written,written + i,device,written + result,filestat.st_size);
+ exit (EXIT_FAILURE);
+ }
+
+ written += i;
+ size -= i;
+ }
+ if (flags & FLAG_VERBOSE)
+ log_printf (LOG_NORMAL,
+ "\rWriting data: %luk/%luk (100%%)\n",
+ KB (filestat.st_size),
+ KB (filestat.st_size));
+ DEBUG("Wrote %d / %luk bytes\n",written,filestat.st_size);
+
+ /**********************************
+ * verify that flash == file data *
+ **********************************/
+
+ safe_rewind (fil_fd,filename);
+ safe_rewind (dev_fd,device);
+ size = filestat.st_size;
+ i = BUFSIZE;
+ written = 0;
+ if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%luk (0%%)",KB (filestat.st_size));
+ while (size)
+ {
+ if (size < BUFSIZE) i = size;
+ if (flags & FLAG_VERBOSE)
+ log_printf (LOG_NORMAL,
+ "\rVerifying data: %dk/%luk (%lu%%)",
+ KB (written + i),
+ KB (filestat.st_size),
+ PERCENTAGE (written + i,filestat.st_size));
+
+ /* read from filename */
+ safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
+
+ /* read from device */
+ safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE);
+
+ /* compare buffers */
+ if (memcmp (src,dest,i))
+ {
+ log_printf (LOG_ERROR,
+ "File does not seem to match flash data. First mismatch at 0x%.8x-0x%.8x\n",
+ written,written + i);
+ exit (EXIT_FAILURE);
+ }
+
+ written += i;
+ size -= i;
+ }
+ if (flags & FLAG_VERBOSE)
+ log_printf (LOG_NORMAL,
+ "\rVerifying data: %luk/%luk (100%%)\n",
+ KB (filestat.st_size),
+ KB (filestat.st_size));
+ DEBUG("Verified %d / %luk bytes\n",written,filestat.st_size);
+
+ exit (EXIT_SUCCESS);
+}
+
diff --git a/drivers/mtd/mtd-utils/ftl_check.c b/drivers/mtd/mtd-utils/ftl_check.c
new file mode 100644
index 00000000000..f41e79a34ec
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ftl_check.c
@@ -0,0 +1,232 @@
+/* Ported to MTD system.
+ * Based on:
+ */
+/*======================================================================
+
+ Utility to create an FTL partition in a memory region
+
+ ftl_check.c 1.10 1999/10/25 20:01:35
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+ ======================================================================*/
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <mtd/mtd-user.h>
+#include <mtd/ftl-user.h>
+
+#include <byteswap.h>
+#include <endian.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define TO_LE32(x) (x)
+# define TO_LE16(x) (x)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+# define TO_LE32(x) (bswap_32(x))
+# define TO_LE16(x) (bswap_16(x))
+#else
+# error cannot detect endianess
+#endif
+
+#define FROM_LE32(x) TO_LE32(x)
+#define FROM_LE16(x) TO_LE16(x)
+
+/*====================================================================*/
+
+static void print_size(u_int s)
+{
+ if ((s > 0x100000) && ((s % 0x100000) == 0))
+ printf("%d mb", s / 0x100000);
+ else if ((s > 0x400) && ((s % 0x400) == 0))
+ printf("%d kb", s / 0x400);
+ else
+ printf("%d bytes", s);
+}
+
+/*====================================================================*/
+
+static void check_partition(int fd, int verbose)
+{
+ mtd_info_t mtd;
+ erase_unit_header_t hdr, hdr2;
+ u_int i, j, nbam, *bam;
+ int control, data, free, deleted;
+
+ /* Get partition size, block size */
+ if (ioctl(fd, MEMGETINFO, &mtd) != 0) {
+ perror("get info failed");
+ return;
+ }
+
+ printf("Memory region info:\n");
+ printf(" Region size = ");
+ print_size(mtd.size);
+ printf(" Erase block size = ");
+ print_size(mtd.erasesize);
+ printf("\n\n");
+
+ for (i = 0; i < mtd.size/mtd.erasesize; i++) {
+ if (lseek(fd, (i * mtd.erasesize), SEEK_SET) == -1) {
+ perror("seek failed");
+ break;
+ }
+ read(fd, &hdr, sizeof(hdr));
+ if ((FROM_LE32(hdr.FormattedSize) > 0) &&
+ (FROM_LE32(hdr.FormattedSize) <= mtd.size) &&
+ (FROM_LE16(hdr.NumEraseUnits) > 0) &&
+ (FROM_LE16(hdr.NumEraseUnits) <= mtd.size/mtd.erasesize))
+ break;
+ }
+ if (i == mtd.size/mtd.erasesize) {
+ fprintf(stderr, "No valid erase unit headers!\n");
+ return;
+ }
+
+ printf("Partition header:\n");
+ printf(" Formatted size = ");
+ print_size(FROM_LE32(hdr.FormattedSize));
+ printf(", erase units = %d, transfer units = %d\n",
+ FROM_LE16(hdr.NumEraseUnits), hdr.NumTransferUnits);
+ printf(" Erase unit size = ");
+ print_size(1 << hdr.EraseUnitSize);
+ printf(", virtual block size = ");
+ print_size(1 << hdr.BlockSize);
+ printf("\n");
+
+ /* Create basic block allocation table for control blocks */
+ nbam = (mtd.erasesize >> hdr.BlockSize);
+ bam = malloc(nbam * sizeof(u_int));
+
+ for (i = 0; i < FROM_LE16(hdr.NumEraseUnits); i++) {
+ if (lseek(fd, (i << hdr.EraseUnitSize), SEEK_SET) == -1) {
+ perror("seek failed");
+ break;
+ }
+ if (read(fd, &hdr2, sizeof(hdr2)) == -1) {
+ perror("read failed");
+ break;
+ }
+ printf("\nErase unit %d:\n", i);
+ if ((hdr2.FormattedSize != hdr.FormattedSize) ||
+ (hdr2.NumEraseUnits != hdr.NumEraseUnits) ||
+ (hdr2.SerialNumber != hdr.SerialNumber))
+ printf(" Erase unit header is corrupt.\n");
+ else if (FROM_LE16(hdr2.LogicalEUN) == 0xffff)
+ printf(" Transfer unit, erase count = %d\n", FROM_LE32(hdr2.EraseCount));
+ else {
+ printf(" Logical unit %d, erase count = %d\n",
+ FROM_LE16(hdr2.LogicalEUN), FROM_LE32(hdr2.EraseCount));
+ if (lseek(fd, (i << hdr.EraseUnitSize)+FROM_LE32(hdr.BAMOffset),
+ SEEK_SET) == -1) {
+ perror("seek failed");
+ break;
+ }
+ if (read(fd, bam, nbam * sizeof(u_int)) == -1) {
+ perror("read failed");
+ break;
+ }
+ free = deleted = control = data = 0;
+ for (j = 0; j < nbam; j++) {
+ if (BLOCK_FREE(FROM_LE32(bam[j])))
+ free++;
+ else if (BLOCK_DELETED(FROM_LE32(bam[j])))
+ deleted++;
+ else switch (BLOCK_TYPE(FROM_LE32(bam[j]))) {
+ case BLOCK_CONTROL: control++; break;
+ case BLOCK_DATA: data++; break;
+ default: break;
+ }
+ }
+ printf(" Block allocation: %d control, %d data, %d free,"
+ " %d deleted\n", control, data, free, deleted);
+ }
+ }
+} /* format_partition */
+
+/* Show usage information */
+void showusage(char *pname)
+{
+ fprintf(stderr, "usage: %s [-v] device\n", pname);
+ fprintf(stderr, "-v verbose messages\n");
+}
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+ int verbose;
+ int optch, errflg, fd;
+ struct stat buf;
+
+ errflg = 0;
+ verbose = 0;
+ while ((optch = getopt(argc, argv, "vh")) != -1) {
+ switch (optch) {
+ case 'h':
+ errflg = 1; break;
+ case 'v':
+ verbose = 1; break;
+ default:
+ errflg = -1; break;
+ }
+ }
+ if (errflg || (optind != argc-1)) {
+ showusage(argv[0]);
+ exit(errflg > 0 ? 0 : EXIT_FAILURE);
+ }
+
+ if (stat(argv[optind], &buf) != 0) {
+ perror("status check failed");
+ exit(EXIT_FAILURE);
+ }
+ if (!(buf.st_mode & S_IFCHR)) {
+ fprintf(stderr, "%s is not a character special device\n",
+ argv[optind]);
+ exit(EXIT_FAILURE);
+ }
+ fd = open(argv[optind], O_RDONLY);
+ if (fd == -1) {
+ perror("open failed");
+ exit(EXIT_FAILURE);
+ }
+
+ check_partition(fd, verbose);
+ close(fd);
+
+ exit(EXIT_SUCCESS);
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/ftl_format.c b/drivers/mtd/mtd-utils/ftl_format.c
new file mode 100644
index 00000000000..ae00c994141
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ftl_format.c
@@ -0,0 +1,342 @@
+/* Ported to MTD system.
+ * Based on:
+ */
+/*======================================================================
+
+ Utility to create an FTL partition in a memory region
+
+ ftl_format.c 1.13 1999/10/25 20:01:35
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+ ======================================================================*/
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <mtd/mtd-user.h>
+#include <mtd/ftl-user.h>
+
+#include <byteswap.h>
+#include <endian.h>
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define TO_LE32(x) (x)
+# define TO_LE16(x) (x)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+# define TO_LE32(x) (bswap_32(x))
+# define TO_LE16(x) (bswap_16(x))
+#else
+# error cannot detect endianess
+#endif
+
+#define FROM_LE32(x) TO_LE32(x)
+#define FROM_LE16(x) TO_LE16(x)
+
+/*====================================================================*/
+
+static void print_size(u_int s)
+{
+ if ((s > 0x100000) && ((s % 0x100000) == 0))
+ printf("%d mb", s / 0x100000);
+ else if ((s > 0x400) && ((s % 0x400) == 0))
+ printf("%d kb", s / 0x400);
+ else
+ printf("%d bytes", s);
+}
+
+/*====================================================================*/
+
+static const char LinkTarget[] = {
+ 0x13, 0x03, 'C', 'I', 'S'
+};
+static const char DataOrg[] = {
+ 0x46, 0x39, 0x00, 'F', 'T', 'L', '1', '0', '0', 0x00
+};
+
+static void build_header(erase_unit_header_t *hdr, u_int RegionSize,
+ u_int BlockSize, u_int Spare, int Reserve,
+ u_int BootSize)
+{
+ u_int i, BootUnits, nbam, __FormattedSize;
+
+ /* Default everything to the erased state */
+ memset(hdr, 0xff, sizeof(*hdr));
+ memcpy(hdr->LinkTargetTuple, LinkTarget, 5);
+ memcpy(hdr->DataOrgTuple, DataOrg, 10);
+ hdr->EndTuple[0] = hdr->EndTuple[1] = 0xff;
+ BootSize = (BootSize + (BlockSize-1)) & ~(BlockSize-1);
+ BootUnits = BootSize / BlockSize;
+
+ /* We only support 512-byte blocks */
+ hdr->BlockSize = 9;
+ hdr->EraseUnitSize = 0;
+ for (i = BlockSize; i > 1; i >>= 1)
+ hdr->EraseUnitSize++;
+ hdr->EraseCount = TO_LE32(0);
+ hdr->FirstPhysicalEUN = TO_LE16(BootUnits);
+ hdr->NumEraseUnits = TO_LE16((RegionSize - BootSize) >> hdr->EraseUnitSize);
+ hdr->NumTransferUnits = Spare;
+ __FormattedSize = RegionSize - ((Spare + BootUnits) << hdr->EraseUnitSize);
+ /* Leave a little bit of space between the CIS and BAM */
+ hdr->BAMOffset = TO_LE32(0x80);
+ /* Adjust size to account for BAM space */
+ nbam = ((1 << (hdr->EraseUnitSize - hdr->BlockSize)) * sizeof(u_int)
+ + FROM_LE32(hdr->BAMOffset) + (1 << hdr->BlockSize) - 1) >> hdr->BlockSize;
+
+ __FormattedSize -=
+ (FROM_LE16(hdr->NumEraseUnits) - Spare) * (nbam << hdr->BlockSize);
+ __FormattedSize -= ((__FormattedSize * Reserve / 100) & ~0xfff);
+
+ hdr->FormattedSize = TO_LE32(__FormattedSize);
+
+ /* hdr->FirstVMAddress defaults to erased state */
+ hdr->NumVMPages = TO_LE16(0);
+ hdr->Flags = 0;
+ /* hdr->Code defaults to erased state */
+ hdr->SerialNumber = TO_LE32(time(NULL));
+ /* hdr->AltEUHOffset defaults to erased state */
+
+} /* build_header */
+
+/*====================================================================*/
+
+static int format_partition(int fd, int quiet, int interrogate,
+ u_int spare, int reserve, u_int bootsize)
+{
+ mtd_info_t mtd;
+ erase_info_t erase;
+ erase_unit_header_t hdr;
+ u_int step, lun, i, nbam, *bam;
+
+ /* Get partition size, block size */
+ if (ioctl(fd, MEMGETINFO, &mtd) != 0) {
+ perror("get info failed");
+ return -1;
+ }
+
+#if 0
+ /* Intel Series 100 Flash: skip first block */
+ if ((region.JedecMfr == 0x89) && (region.JedecInfo == 0xaa) &&
+ (bootsize == 0)) {
+ if (!quiet)
+ printf("Skipping first block to protect CIS info...\n");
+ bootsize = 1;
+ }
+#endif
+
+ /* Create header */
+ build_header(&hdr, mtd.size, mtd.erasesize,
+ spare, reserve, bootsize);
+
+ if (!quiet) {
+ printf("Partition size = ");
+ print_size(mtd.size);
+ printf(", erase unit size = ");
+ print_size(mtd.erasesize);
+ printf(", %d transfer units\n", spare);
+ if (bootsize != 0) {
+ print_size(FROM_LE16(hdr.FirstPhysicalEUN) << hdr.EraseUnitSize);
+ printf(" allocated for boot image\n");
+ }
+ printf("Reserved %d%%, formatted size = ", reserve);
+ print_size(FROM_LE32(hdr.FormattedSize));
+ printf("\n");
+ fflush(stdout);
+ }
+
+ if (interrogate) {
+ char str[3];
+ printf("This will destroy all data on the target device. "
+ "Confirm (y/n): ");
+ if (fgets(str, 3, stdin) == NULL)
+ return -1;
+ if ((strcmp(str, "y\n") != 0) && (strcmp(str, "Y\n") != 0))
+ return -1;
+ }
+
+ /* Create basic block allocation table for control blocks */
+ nbam = ((mtd.erasesize >> hdr.BlockSize) * sizeof(u_int)
+ + FROM_LE32(hdr.BAMOffset) + (1 << hdr.BlockSize) - 1) >> hdr.BlockSize;
+ bam = malloc(nbam * sizeof(u_int));
+ for (i = 0; i < nbam; i++)
+ bam[i] = TO_LE32(BLOCK_CONTROL);
+
+ /* Erase partition */
+ if (!quiet) {
+ printf("Erasing all blocks...\n");
+ fflush(stdout);
+ }
+ erase.length = mtd.erasesize;
+ erase.start = mtd.erasesize * FROM_LE16(hdr.FirstPhysicalEUN);
+ for (i = 0; i < FROM_LE16(hdr.NumEraseUnits); i++) {
+ if (ioctl(fd, MEMERASE, &erase) < 0) {
+ if (!quiet) {
+ putchar('\n');
+ fflush(stdout);
+ }
+ perror("block erase failed");
+ return -1;
+ }
+ erase.start += erase.length;
+ if (!quiet) {
+ if (mtd.size <= 0x800000) {
+ if (erase.start % 0x100000) {
+ if (!(erase.start % 0x20000)) putchar('-');
+ }
+ else putchar('+');
+ }
+ else {
+ if (erase.start % 0x800000) {
+ if (!(erase.start % 0x100000)) putchar('+');
+ }
+ else putchar('*');
+ }
+ fflush(stdout);
+ }
+ }
+ if (!quiet) putchar('\n');
+
+ /* Prepare erase units */
+ if (!quiet) {
+ printf("Writing erase unit headers...\n");
+ fflush(stdout);
+ }
+ lun = 0;
+ /* Distribute transfer units over the entire region */
+ step = (spare) ? (FROM_LE16(hdr.NumEraseUnits)/spare) : (FROM_LE16(hdr.NumEraseUnits)+1);
+ for (i = 0; i < FROM_LE16(hdr.NumEraseUnits); i++) {
+ u_int ofs = (i + FROM_LE16(hdr.FirstPhysicalEUN)) << hdr.EraseUnitSize;
+ if (lseek(fd, ofs, SEEK_SET) == -1) {
+ perror("seek failed");
+ break;
+ }
+ /* Is this a transfer unit? */
+ if (((i+1) % step) == 0)
+ hdr.LogicalEUN = TO_LE16(0xffff);
+ else {
+ hdr.LogicalEUN = TO_LE16(lun);
+ lun++;
+ }
+ if (write(fd, &hdr, sizeof(hdr)) == -1) {
+ perror("write failed");
+ break;
+ }
+ if (lseek(fd, ofs + FROM_LE32(hdr.BAMOffset), SEEK_SET) == -1) {
+ perror("seek failed");
+ break;
+ }
+ if (write(fd, bam, nbam * sizeof(u_int)) == -1) {
+ perror("write failed");
+ break;
+ }
+ }
+ if (i < FROM_LE16(hdr.NumEraseUnits))
+ return -1;
+ else
+ return 0;
+} /* format_partition */
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+ int quiet, interrogate, reserve;
+ int optch, errflg, fd, ret;
+ u_int spare, bootsize;
+ char *s;
+ extern char *optarg;
+ struct stat buf;
+
+ quiet = 0;
+ interrogate = 0;
+ spare = 1;
+ reserve = 5;
+ errflg = 0;
+ bootsize = 0;
+
+ while ((optch = getopt(argc, argv, "qir:s:b:")) != -1) {
+ switch (optch) {
+ case 'q':
+ quiet = 1; break;
+ case 'i':
+ interrogate = 1; break;
+ case 's':
+ spare = strtoul(optarg, NULL, 0); break;
+ case 'r':
+ reserve = strtoul(optarg, NULL, 0); break;
+ case 'b':
+ bootsize = strtoul(optarg, &s, 0);
+ if ((*s == 'k') || (*s == 'K'))
+ bootsize *= 1024;
+ break;
+ default:
+ errflg = 1; break;
+ }
+ }
+ if (errflg || (optind != argc-1)) {
+ fprintf(stderr, "usage: %s [-q] [-i] [-s spare-blocks]"
+ " [-r reserve-percent] [-b bootsize] device\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (stat(argv[optind], &buf) != 0) {
+ perror("status check failed");
+ exit(EXIT_FAILURE);
+ }
+ if (!(buf.st_mode & S_IFCHR)) {
+ fprintf(stderr, "%s is not a character special device\n",
+ argv[optind]);
+ exit(EXIT_FAILURE);
+ }
+ fd = open(argv[optind], O_RDWR);
+ if (fd == -1) {
+ perror("open failed");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = format_partition(fd, quiet, interrogate, spare, reserve,
+ bootsize);
+ if (!quiet) {
+ if (ret)
+ printf("format failed.\n");
+ else
+ printf("format successful.\n");
+ }
+ close(fd);
+
+ exit((ret) ? EXIT_FAILURE : EXIT_SUCCESS);
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/include/linux/jffs2.h b/drivers/mtd/mtd-utils/include/linux/jffs2.h
new file mode 100644
index 00000000000..61847ebcf7b
--- /dev/null
+++ b/drivers/mtd/mtd-utils/include/linux/jffs2.h
@@ -0,0 +1,218 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@infradead.org>
+ *
+ * For licensing information, see the file 'LICENCE' in the
+ * jffs2 directory.
+ *
+ * $Id: jffs2.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ *
+ */
+
+#ifndef __LINUX_JFFS2_H__
+#define __LINUX_JFFS2_H__
+
+/* You must include something which defines the C99 uintXX_t types.
+ We don't do it from here because this file is used in too many
+ different environments. */
+
+#define JFFS2_SUPER_MAGIC 0x72b6
+
+/* Values we may expect to find in the 'magic' field */
+#define JFFS2_OLD_MAGIC_BITMASK 0x1984
+#define JFFS2_MAGIC_BITMASK 0x1985
+#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */
+#define JFFS2_EMPTY_BITMASK 0xffff
+#define JFFS2_DIRTY_BITMASK 0x0000
+
+/* Summary node MAGIC marker */
+#define JFFS2_SUM_MAGIC 0x02851885
+
+/* We only allow a single char for length, and 0xFF is empty flash so
+ we don't want it confused with a real length. Hence max 254.
+*/
+#define JFFS2_MAX_NAME_LEN 254
+
+/* How small can we sensibly write nodes? */
+#define JFFS2_MIN_DATA_LEN 128
+
+#define JFFS2_COMPR_NONE 0x00
+#define JFFS2_COMPR_ZERO 0x01
+#define JFFS2_COMPR_RTIME 0x02
+#define JFFS2_COMPR_RUBINMIPS 0x03
+#define JFFS2_COMPR_COPY 0x04
+#define JFFS2_COMPR_DYNRUBIN 0x05
+#define JFFS2_COMPR_ZLIB 0x06
+#define JFFS2_COMPR_LZO 0x07
+/* Compatibility flags. */
+#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
+#define JFFS2_NODE_ACCURATE 0x2000
+/* INCOMPAT: Fail to mount the filesystem */
+#define JFFS2_FEATURE_INCOMPAT 0xc000
+/* ROCOMPAT: Mount read-only */
+#define JFFS2_FEATURE_ROCOMPAT 0x8000
+/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
+#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
+/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
+#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
+
+#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
+#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
+#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
+#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
+
+#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
+
+#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
+#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
+
+/* XATTR Related */
+#define JFFS2_XPREFIX_USER 1 /* for "user." */
+#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */
+#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */
+#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */
+#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */
+
+#define JFFS2_ACL_VERSION 0x0001
+
+// Maybe later...
+//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
+//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
+
+
+#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at
+ mount time, don't wait for it to
+ happen later */
+#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific
+ compression type */
+
+
+/* These can go once we've made sure we've caught all uses without
+ byteswapping */
+
+typedef struct {
+ uint32_t v32;
+} __attribute__((packed)) jint32_t;
+
+typedef struct {
+ uint32_t m;
+} __attribute__((packed)) jmode_t;
+
+typedef struct {
+ uint16_t v16;
+} __attribute__((packed)) jint16_t;
+
+struct jffs2_unknown_node
+{
+ /* All start like this */
+ jint16_t magic;
+ jint16_t nodetype;
+ jint32_t totlen; /* So we can skip over nodes we don't grok */
+ jint32_t hdr_crc;
+} __attribute__((packed));
+
+struct jffs2_raw_dirent
+{
+ jint16_t magic;
+ jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */
+ jint32_t totlen;
+ jint32_t hdr_crc;
+ jint32_t pino;
+ jint32_t version;
+ jint32_t ino; /* == zero for unlink */
+ jint32_t mctime;
+ uint8_t nsize;
+ uint8_t type;
+ uint8_t unused[2];
+ jint32_t node_crc;
+ jint32_t name_crc;
+ uint8_t name[0];
+} __attribute__((packed));
+
+/* The JFFS2 raw inode structure: Used for storage on physical media. */
+/* The uid, gid, atime, mtime and ctime members could be longer, but
+ are left like this for space efficiency. If and when people decide
+ they really need them extended, it's simple enough to add support for
+ a new type of raw node.
+*/
+struct jffs2_raw_inode
+{
+ jint16_t magic; /* A constant magic number. */
+ jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */
+ jint32_t totlen; /* Total length of this node (inc data, etc.) */
+ jint32_t hdr_crc;
+ jint32_t ino; /* Inode number. */
+ jint32_t version; /* Version number. */
+ jmode_t mode; /* The file's type or mode. */
+ jint16_t uid; /* The file's owner. */
+ jint16_t gid; /* The file's group. */
+ jint32_t isize; /* Total resultant size of this inode (used for truncations) */
+ jint32_t atime; /* Last access time. */
+ jint32_t mtime; /* Last modification time. */
+ jint32_t ctime; /* Change time. */
+ jint32_t offset; /* Where to begin to write. */
+ jint32_t csize; /* (Compressed) data size */
+ jint32_t dsize; /* Size of the node's data. (after decompression) */
+ uint8_t compr; /* Compression algorithm used */
+ uint8_t usercompr; /* Compression algorithm requested by the user */
+ jint16_t flags; /* See JFFS2_INO_FLAG_* */
+ jint32_t data_crc; /* CRC for the (compressed) data. */
+ jint32_t node_crc; /* CRC for the raw inode (excluding data) */
+ uint8_t data[0];
+} __attribute__((packed));
+
+struct jffs2_raw_xattr {
+ jint16_t magic;
+ jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */
+ jint32_t totlen;
+ jint32_t hdr_crc;
+ jint32_t xid; /* XATTR identifier number */
+ jint32_t version;
+ uint8_t xprefix;
+ uint8_t name_len;
+ jint16_t value_len;
+ jint32_t data_crc;
+ jint32_t node_crc;
+ uint8_t data[0];
+} __attribute__((packed));
+
+struct jffs2_raw_xref
+{
+ jint16_t magic;
+ jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */
+ jint32_t totlen;
+ jint32_t hdr_crc;
+ jint32_t ino; /* inode number */
+ jint32_t xid; /* XATTR identifier number */
+ jint32_t xseqno; /* xref sequencial number */
+ jint32_t node_crc;
+} __attribute__((packed));
+
+struct jffs2_raw_summary
+{
+ jint16_t magic;
+ jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */
+ jint32_t totlen;
+ jint32_t hdr_crc;
+ jint32_t sum_num; /* number of sum entries*/
+ jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */
+ jint32_t padded; /* sum of the size of padding nodes */
+ jint32_t sum_crc; /* summary information crc */
+ jint32_t node_crc; /* node crc */
+ jint32_t sum[0]; /* inode summary info */
+} __attribute__((packed));
+
+union jffs2_node_union
+{
+ struct jffs2_raw_inode i;
+ struct jffs2_raw_dirent d;
+ struct jffs2_raw_xattr x;
+ struct jffs2_raw_xref r;
+ struct jffs2_raw_summary s;
+ struct jffs2_unknown_node u;
+};
+
+#endif /* __LINUX_JFFS2_H__ */
diff --git a/drivers/mtd/mtd-utils/include/mtd/ftl-user.h b/drivers/mtd/mtd-utils/include/mtd/ftl-user.h
new file mode 100644
index 00000000000..42edc8cb297
--- /dev/null
+++ b/drivers/mtd/mtd-utils/include/mtd/ftl-user.h
@@ -0,0 +1,76 @@
+/*
+ * $Id: ftl-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ *
+ * Derived from (and probably identical to):
+ * ftl.h 1.7 1999/10/25 20:23:17
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above. If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef __MTD_FTL_USER_H__
+#define __MTD_FTL_USER_H__
+
+typedef struct erase_unit_header_t {
+ u_int8_t LinkTargetTuple[5];
+ u_int8_t DataOrgTuple[10];
+ u_int8_t NumTransferUnits;
+ u_int32_t EraseCount;
+ u_int16_t LogicalEUN;
+ u_int8_t BlockSize;
+ u_int8_t EraseUnitSize;
+ u_int16_t FirstPhysicalEUN;
+ u_int16_t NumEraseUnits;
+ u_int32_t FormattedSize;
+ u_int32_t FirstVMAddress;
+ u_int16_t NumVMPages;
+ u_int8_t Flags;
+ u_int8_t Code;
+ u_int32_t SerialNumber;
+ u_int32_t AltEUHOffset;
+ u_int32_t BAMOffset;
+ u_int8_t Reserved[12];
+ u_int8_t EndTuple[2];
+} erase_unit_header_t;
+
+/* Flags in erase_unit_header_t */
+#define HIDDEN_AREA 0x01
+#define REVERSE_POLARITY 0x02
+#define DOUBLE_BAI 0x04
+
+/* Definitions for block allocation information */
+
+#define BLOCK_FREE(b) ((b) == 0xffffffff)
+#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe))
+
+#define BLOCK_TYPE(b) ((b) & 0x7f)
+#define BLOCK_ADDRESS(b) ((b) & ~0x7f)
+#define BLOCK_NUMBER(b) ((b) >> 9)
+#define BLOCK_CONTROL 0x30
+#define BLOCK_DATA 0x40
+#define BLOCK_REPLACEMENT 0x60
+#define BLOCK_BAD 0x70
+
+#endif /* __MTD_FTL_USER_H__ */
diff --git a/drivers/mtd/mtd-utils/include/mtd/inftl-user.h b/drivers/mtd/mtd-utils/include/mtd/inftl-user.h
new file mode 100644
index 00000000000..a137de134e1
--- /dev/null
+++ b/drivers/mtd/mtd-utils/include/mtd/inftl-user.h
@@ -0,0 +1,91 @@
+/*
+ * $Id: inftl-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ *
+ * Parts of INFTL headers shared with userspace
+ *
+ */
+
+#ifndef __MTD_INFTL_USER_H__
+#define __MTD_INFTL_USER_H__
+
+#define OSAK_VERSION 0x5120
+#define PERCENTUSED 98
+
+#define SECTORSIZE 512
+
+/* Block Control Information */
+
+struct inftl_bci {
+ uint8_t ECCsig[6];
+ uint8_t Status;
+ uint8_t Status1;
+} __attribute__((packed));
+
+struct inftl_unithead1 {
+ uint16_t virtualUnitNo;
+ uint16_t prevUnitNo;
+ uint8_t ANAC;
+ uint8_t NACs;
+ uint8_t parityPerField;
+ uint8_t discarded;
+} __attribute__((packed));
+
+struct inftl_unithead2 {
+ uint8_t parityPerField;
+ uint8_t ANAC;
+ uint16_t prevUnitNo;
+ uint16_t virtualUnitNo;
+ uint8_t NACs;
+ uint8_t discarded;
+} __attribute__((packed));
+
+struct inftl_unittail {
+ uint8_t Reserved[4];
+ uint16_t EraseMark;
+ uint16_t EraseMark1;
+} __attribute__((packed));
+
+union inftl_uci {
+ struct inftl_unithead1 a;
+ struct inftl_unithead2 b;
+ struct inftl_unittail c;
+};
+
+struct inftl_oob {
+ struct inftl_bci b;
+ union inftl_uci u;
+};
+
+
+/* INFTL Media Header */
+
+struct INFTLPartition {
+ __u32 virtualUnits;
+ __u32 firstUnit;
+ __u32 lastUnit;
+ __u32 flags;
+ __u32 spareUnits;
+ __u32 Reserved0;
+ __u32 Reserved1;
+} __attribute__((packed));
+
+struct INFTLMediaHeader {
+ char bootRecordID[8];
+ __u32 NoOfBootImageBlocks;
+ __u32 NoOfBinaryPartitions;
+ __u32 NoOfBDTLPartitions;
+ __u32 BlockMultiplierBits;
+ __u32 FormatFlags;
+ __u32 OsakVersion;
+ __u32 PercentUsed;
+ struct INFTLPartition Partitions[4];
+} __attribute__((packed));
+
+/* Partition flag types */
+#define INFTL_BINARY 0x20000000
+#define INFTL_BDTL 0x40000000
+#define INFTL_LAST 0x80000000
+
+#endif /* __MTD_INFTL_USER_H__ */
+
+
diff --git a/drivers/mtd/mtd-utils/include/mtd/jffs2-user.h b/drivers/mtd/mtd-utils/include/mtd/jffs2-user.h
new file mode 100644
index 00000000000..2ebfb4419c5
--- /dev/null
+++ b/drivers/mtd/mtd-utils/include/mtd/jffs2-user.h
@@ -0,0 +1,82 @@
+/*
+ * $Id: jffs2-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ *
+ * JFFS2 definitions for use in user space only
+ */
+
+#ifndef __JFFS2_USER_H__
+#define __JFFS2_USER_H__
+
+/* This file is blessed for inclusion by userspace */
+#include <linux/jffs2.h>
+#include <endian.h>
+#include <byteswap.h>
+
+#undef cpu_to_je16
+#undef cpu_to_je32
+#undef cpu_to_jemode
+#undef je16_to_cpu
+#undef je32_to_cpu
+#undef jemode_to_cpu
+
+extern int target_endian;
+
+#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
+#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
+
+#define cpu_to_je16(x) ((jint16_t){t16(x)})
+#define cpu_to_je32(x) ((jint32_t){t32(x)})
+#define cpu_to_jemode(x) ((jmode_t){t32(x)})
+
+#define je16_to_cpu(x) (t16((x).v16))
+#define je32_to_cpu(x) (t32((x).v32))
+#define jemode_to_cpu(x) (t32((x).m))
+
+#define le16_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
+#define le32_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
+#define cpu_to_le16(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
+#define cpu_to_le32(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
+
+/* XATTR/POSIX-ACL related definition */
+/* Namespaces copied from xattr.h and posix_acl_xattr.h */
+#define XATTR_USER_PREFIX "user."
+#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
+#define XATTR_SECURITY_PREFIX "security."
+#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1)
+#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access"
+#define POSIX_ACL_XATTR_ACCESS_LEN (sizeof (POSIX_ACL_XATTR_ACCESS) - 1)
+#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default"
+#define POSIX_ACL_XATTR_DEFAULT_LEN (sizeof (POSIX_ACL_XATTR_DEFAULT) - 1)
+#define XATTR_TRUSTED_PREFIX "trusted."
+#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1)
+
+struct jffs2_acl_entry {
+ jint16_t e_tag;
+ jint16_t e_perm;
+ jint32_t e_id;
+};
+
+struct jffs2_acl_entry_short {
+ jint16_t e_tag;
+ jint16_t e_perm;
+};
+
+struct jffs2_acl_header {
+ jint32_t a_version;
+};
+
+/* copied from include/linux/posix_acl_xattr.h */
+#define POSIX_ACL_XATTR_VERSION 0x0002
+
+struct posix_acl_xattr_entry {
+ uint16_t e_tag;
+ uint16_t e_perm;
+ uint32_t e_id;
+};
+
+struct posix_acl_xattr_header {
+ uint32_t a_version;
+ struct posix_acl_xattr_entry a_entries[0];
+};
+
+#endif /* __JFFS2_USER_H__ */
diff --git a/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h b/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h
new file mode 100644
index 00000000000..1eac18bfffe
--- /dev/null
+++ b/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h
@@ -0,0 +1,186 @@
+/*
+ * Portions of MTD ABI definition which are shared by kernel and user space
+ */
+
+#ifndef __MTD_ABI_H__
+#define __MTD_ABI_H__
+
+#include <linux/types.h>
+
+#ifndef __KERNEL__
+#define __user
+#endif
+
+typedef uint64_t size_mtd_t;
+typedef uint64_t loff_mtd_t;
+
+struct erase_info_user {
+ __u64 start;
+ __u64 length;
+};
+
+struct erase_info_user64 {
+ __u64 start;
+ __u64 length;
+};
+
+struct mtd_oob_buf {
+ __u32 start;
+ __u32 length;
+ unsigned char __user *ptr;
+};
+
+struct mtd_oob_buf64 {
+ __u64 start;
+ __u32 pad;
+ __u32 length;
+ __u64 usr_ptr;
+};
+
+struct mtd_page_buf {
+ uint32_t start; //page start address
+ uint32_t ooblength;
+ uint32_t datlength;
+ unsigned char __user *oobptr;
+ unsigned char __user *datptr;
+};
+
+#define MTD_ABSENT 0
+#define MTD_RAM 1
+#define MTD_ROM 2
+#define MTD_NORFLASH 3
+#define MTD_NANDFLASH 4
+#define MTD_DATAFLASH 6
+#define MTD_UBIVOLUME 7
+
+#define MTD_WRITEABLE 0x400 /* Device is writeable */
+#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
+#define MTD_NO_ERASE 0x1000 /* No erase necessary */
+#define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */
+
+#define MTD_MTDBLOCK_JZ_INVALID 0x4000 /* Device doesn't works over mtdblock-jz */
+#define MTD_NAND_CPU_MODE 0x8000 /* Using cpu mode for NAND */
+
+// Some common devices / combinations of capabilities
+#define MTD_CAP_ROM 0
+#define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
+#define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE)
+#define MTD_CAP_NANDFLASH (MTD_WRITEABLE)
+
+/* ECC byte placement */
+#define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended)
+#define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode)
+#define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme
+#define MTD_NANDECC_PLACEONLY 3 // Use the given placement in the structure (Do not store ecc result on read)
+#define MTD_NANDECC_AUTOPL_USR 4 // Use the given autoplacement scheme rather than using the default
+
+/* OTP mode selection */
+#define MTD_OTP_OFF 0
+#define MTD_OTP_FACTORY 1
+#define MTD_OTP_USER 2
+
+struct mtd_info_user {
+ __u8 type;
+ __u32 flags;
+ __u64 size; // Total size of the MTD
+ __u32 erasesize;
+ __u32 writesize;
+ __u32 oobsize; // Amount of OOB data per block (e.g. 16)
+ /* The below two fields are obsolete and broken, do not use them
+ * (TODO: remove at some point) */
+ __u32 ecctype;
+ __u32 eccsize;
+};
+
+struct region_info_user {
+ __u64 offset; /* At which this region starts,
+ * from the beginning of the MTD */
+ __u32 erasesize; /* For this region */
+ __u32 numblocks; /* Number of blocks in this region */
+ __u32 regionindex;
+};
+
+struct otp_info {
+ __u32 start;
+ __u32 length;
+ __u32 locked;
+};
+
+#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
+#define MEMERASE _IOW('M', 2, struct erase_info_user)
+#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
+#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf)
+#define MEMLOCK _IOW('M', 5, struct erase_info_user)
+#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
+#define MEMGETREGIONCOUNT _IOR('M', 7, int)
+#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
+#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
+#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
+#define MEMGETBADBLOCK _IOW('M', 11, loff_mtd_t)
+#define MEMSETBADBLOCK _IOW('M', 12, loff_mtd_t)
+#define OTPSELECT _IOR('M', 13, int)
+#define OTPGETREGIONCOUNT _IOW('M', 14, int)
+#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
+#define OTPLOCK _IOR('M', 16, struct otp_info)
+#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
+#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
+#define MTDFILEMODE _IO('M', 19)
+#define MEMERASE64 _IOW('M', 20, struct erase_info_user64)
+#define MEMWRITEOOB64 _IOWR('M', 21, struct mtd_oob_buf64)
+#define MEMREADOOB64 _IOWR('M', 22, struct mtd_oob_buf64)
+#define MEMWRITEPAGE _IOWR('M', 23, struct mtd_page_buf)
+
+/*
+ * Obsolete legacy interface. Keep it in order not to break userspace
+ * interfaces
+ */
+struct nand_oobinfo {
+ __u32 useecc;
+ __u32 eccbytes;
+ __u32 oobfree[8][2];
+ __u32 eccpos[104];
+};
+
+struct nand_oobfree {
+ __u32 offset;
+ __u32 length;
+};
+
+#define MTD_MAX_OOBFREE_ENTRIES 8
+/*
+ * ECC layout control structure. Exported to userspace for
+ * diagnosis and to allow creation of raw images
+ */
+struct nand_ecclayout {
+ __u32 eccbytes;
+ __u32 eccpos[128];
+ __u32 oobavail;
+ struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
+};
+
+/**
+ * struct mtd_ecc_stats - error correction stats
+ *
+ * @corrected: number of corrected bits
+ * @failed: number of uncorrectable errors
+ * @badblocks: number of bad blocks in this partition
+ * @bbtblocks: number of blocks reserved for bad block tables
+ */
+struct mtd_ecc_stats {
+ __u32 corrected;
+ __u32 failed;
+ __u32 badblocks;
+ __u32 bbtblocks;
+};
+
+/*
+ * Read/write file modes for access to MTD
+ */
+enum mtd_file_modes {
+ MTD_MODE_NORMAL = MTD_OTP_OFF,
+ MTD_MODE_OTP_FACTORY = MTD_OTP_FACTORY,
+ MTD_MODE_OTP_USER = MTD_OTP_USER,
+ MTD_MODE_RAW,
+};
+
+#endif /* __MTD_ABI_H__ */
diff --git a/drivers/mtd/mtd-utils/include/mtd/mtd-user.h b/drivers/mtd/mtd-utils/include/mtd/mtd-user.h
new file mode 100644
index 00000000000..170ceca3b2d
--- /dev/null
+++ b/drivers/mtd/mtd-utils/include/mtd/mtd-user.h
@@ -0,0 +1,19 @@
+/*
+ * MTD ABI header for use by user space only.
+ */
+
+#ifndef __MTD_USER_H__
+#define __MTD_USER_H__
+
+#include <stdint.h>
+
+/* This file is blessed for inclusion by userspace */
+#include <mtd/mtd-abi.h>
+
+typedef struct mtd_info_user mtd_info_t;
+typedef struct erase_info_user erase_info_t;
+typedef struct region_info_user region_info_t;
+typedef struct nand_oobinfo nand_oobinfo_t;
+typedef struct nand_ecclayout nand_ecclayout_t;
+
+#endif /* __MTD_USER_H__ */
diff --git a/drivers/mtd/mtd-utils/include/mtd/nftl-user.h b/drivers/mtd/mtd-utils/include/mtd/nftl-user.h
new file mode 100644
index 00000000000..b53a930aee2
--- /dev/null
+++ b/drivers/mtd/mtd-utils/include/mtd/nftl-user.h
@@ -0,0 +1,76 @@
+/*
+ * $Id: nftl-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ *
+ * Parts of NFTL headers shared with userspace
+ *
+ */
+
+#ifndef __MTD_NFTL_USER_H__
+#define __MTD_NFTL_USER_H__
+
+/* Block Control Information */
+
+struct nftl_bci {
+ unsigned char ECCSig[6];
+ uint8_t Status;
+ uint8_t Status1;
+}__attribute__((packed));
+
+/* Unit Control Information */
+
+struct nftl_uci0 {
+ uint16_t VirtUnitNum;
+ uint16_t ReplUnitNum;
+ uint16_t SpareVirtUnitNum;
+ uint16_t SpareReplUnitNum;
+} __attribute__((packed));
+
+struct nftl_uci1 {
+ uint32_t WearInfo;
+ uint16_t EraseMark;
+ uint16_t EraseMark1;
+} __attribute__((packed));
+
+struct nftl_uci2 {
+ uint16_t FoldMark;
+ uint16_t FoldMark1;
+ uint32_t unused;
+} __attribute__((packed));
+
+union nftl_uci {
+ struct nftl_uci0 a;
+ struct nftl_uci1 b;
+ struct nftl_uci2 c;
+};
+
+struct nftl_oob {
+ struct nftl_bci b;
+ union nftl_uci u;
+};
+
+/* NFTL Media Header */
+
+struct NFTLMediaHeader {
+ char DataOrgID[6];
+ uint16_t NumEraseUnits;
+ uint16_t FirstPhysicalEUN;
+ uint32_t FormattedSize;
+ unsigned char UnitSizeFactor;
+} __attribute__((packed));
+
+#define MAX_ERASE_ZONES (8192 - 512)
+
+#define ERASE_MARK 0x3c69
+#define SECTOR_FREE 0xff
+#define SECTOR_USED 0x55
+#define SECTOR_IGNORE 0x11
+#define SECTOR_DELETED 0x00
+
+#define FOLD_MARK_IN_PROGRESS 0x5555
+
+#define ZONE_GOOD 0xff
+#define ZONE_BAD_ORIGINAL 0
+#define ZONE_BAD_MARKED 7
+
+
+#endif /* __MTD_NFTL_USER_H__ */
diff --git a/drivers/mtd/mtd-utils/include/mtd/ubi-header.h b/drivers/mtd/mtd-utils/include/mtd/ubi-header.h
new file mode 100644
index 00000000000..386fa3c6171
--- /dev/null
+++ b/drivers/mtd/mtd-utils/include/mtd/ubi-header.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Ðртём)
+ * Thomas Gleixner
+ * Frank Haverkamp
+ * Oliver Lohmann
+ * Andreas Arnez
+ */
+
+/*
+ * This file defines the layout of UBI headers and all the other UBI on-flash
+ * data structures. May be included by user-space.
+ */
+
+#ifndef __UBI_HEADER_H__
+#define __UBI_HEADER_H__
+
+#include <stdint.h>
+
+/* The version of UBI images supported by this implementation */
+#define UBI_VERSION 1
+
+/* The highest erase counter value supported by this implementation */
+#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF
+
+/* The initial CRC32 value used when calculating CRC checksums */
+#define UBI_CRC32_INIT 0xFFFFFFFFU
+
+/* Erase counter header magic number (ASCII "UBI#") */
+#define UBI_EC_HDR_MAGIC 0x55424923
+/* Volume identifier header magic number (ASCII "UBI!") */
+#define UBI_VID_HDR_MAGIC 0x55424921
+
+/*
+ * Volume type constants used in the volume identifier header.
+ *
+ * @UBI_VID_DYNAMIC: dynamic volume
+ * @UBI_VID_STATIC: static volume
+ */
+enum {
+ UBI_VID_DYNAMIC = 1,
+ UBI_VID_STATIC = 2
+};
+
+/*
+ * Volume flags used in the volume table record.
+ *
+ * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume
+ *
+ * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume
+ * table. UBI automatically re-sizes the volume which has this flag and makes
+ * the volume to be of largest possible size. This means that if after the
+ * initialization UBI finds out that there are available physical eraseblocks
+ * present on the device, it automatically appends all of them to the volume
+ * (the physical eraseblocks reserved for bad eraseblocks handling and other
+ * reserved physical eraseblocks are not taken). So, if there is a volume with
+ * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical
+ * eraseblocks will be zero after UBI is loaded, because all of them will be
+ * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared
+ * after the volume had been initialized.
+ *
+ * The auto-resize feature is useful for device production purposes. For
+ * example, different NAND flash chips may have different amount of initial bad
+ * eraseblocks, depending of particular chip instance. Manufacturers of NAND
+ * chips usually guarantee that the amount of initial bad eraseblocks does not
+ * exceed certain percent, e.g. 2%. When one creates an UBI image which will be
+ * flashed to the end devices in production, he does not know the exact amount
+ * of good physical eraseblocks the NAND chip on the device will have, but this
+ * number is required to calculate the volume sized and put them to the volume
+ * table of the UBI image. In this case, one of the volumes (e.g., the one
+ * which will store the root file system) is marked as "auto-resizable", and
+ * UBI will adjust its size on the first boot if needed.
+ *
+ * Note, first UBI reserves some amount of physical eraseblocks for bad
+ * eraseblock handling, and then re-sizes the volume, not vice-versa. This
+ * means that the pool of reserved physical eraseblocks will always be present.
+ */
+enum {
+ UBI_VTBL_AUTORESIZE_FLG = 0x01,
+};
+
+/*
+ * Compatibility constants used by internal volumes.
+ *
+ * @UBI_COMPAT_DELETE: delete this internal volume before anything is written
+ * to the flash
+ * @UBI_COMPAT_RO: attach this device in read-only mode
+ * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its
+ * physical eraseblocks, don't allow the wear-leveling unit to move them
+ * @UBI_COMPAT_REJECT: reject this UBI image
+ */
+enum {
+ UBI_COMPAT_DELETE = 1,
+ UBI_COMPAT_RO = 2,
+ UBI_COMPAT_PRESERVE = 4,
+ UBI_COMPAT_REJECT = 5
+};
+
+/* Sizes of UBI headers */
+#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr)
+#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
+
+/* Sizes of UBI headers without the ending CRC */
+#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(uint32_t))
+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(uint32_t))
+
+/**
+ * struct ubi_ec_hdr - UBI erase counter header.
+ * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
+ * @version: version of UBI implementation which is supposed to accept this
+ * UBI image
+ * @padding1: reserved for future, zeroes
+ * @ec: the erase counter
+ * @vid_hdr_offset: where the VID header starts
+ * @data_offset: where the user data start
+ * @padding2: reserved for future, zeroes
+ * @hdr_crc: erase counter header CRC checksum
+ *
+ * The erase counter header takes 64 bytes and has a plenty of unused space for
+ * future usage. The unused fields are zeroed. The @version field is used to
+ * indicate the version of UBI implementation which is supposed to be able to
+ * work with this UBI image. If @version is greater then the current UBI
+ * version, the image is rejected. This may be useful in future if something
+ * is changed radically. This field is duplicated in the volume identifier
+ * header.
+ *
+ * The @vid_hdr_offset and @data_offset fields contain the offset of the the
+ * volume identifier header and user data, relative to the beginning of the
+ * physical eraseblock. These values have to be the same for all physical
+ * eraseblocks.
+ */
+struct ubi_ec_hdr {
+ uint32_t magic;
+ uint8_t version;
+ uint8_t padding1[3];
+ uint64_t ec; /* Warning: the current limit is 31-bit anyway! */
+ uint32_t vid_hdr_offset;
+ uint32_t data_offset;
+ uint8_t padding2[36];
+ uint32_t hdr_crc;
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_vid_hdr - on-flash UBI volume identifier header.
+ * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC)
+ * @version: UBI implementation version which is supposed to accept this UBI
+ * image (%UBI_VERSION)
+ * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
+ * @copy_flag: if this logical eraseblock was copied from another physical
+ * eraseblock (for wear-leveling reasons)
+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
+ * @vol_id: ID of this volume
+ * @lnum: logical eraseblock number
+ * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be
+ * removed, kept only for not breaking older UBI users)
+ * @data_size: how many bytes of data this logical eraseblock contains
+ * @used_ebs: total number of used logical eraseblocks in this volume
+ * @data_pad: how many bytes at the end of this physical eraseblock are not
+ * used
+ * @data_crc: CRC checksum of the data stored in this logical eraseblock
+ * @padding1: reserved for future, zeroes
+ * @sqnum: sequence number
+ * @padding2: reserved for future, zeroes
+ * @hdr_crc: volume identifier header CRC checksum
+ *
+ * The @sqnum is the value of the global sequence counter at the time when this
+ * VID header was created. The global sequence counter is incremented each time
+ * UBI writes a new VID header to the flash, i.e. when it maps a logical
+ * eraseblock to a new physical eraseblock. The global sequence counter is an
+ * unsigned 64-bit integer and we assume it never overflows. The @sqnum
+ * (sequence number) is used to distinguish between older and newer versions of
+ * logical eraseblocks.
+ *
+ * There are 2 situations when there may be more then one physical eraseblock
+ * corresponding to the same logical eraseblock, i.e., having the same @vol_id
+ * and @lnum values in the volume identifier header. Suppose we have a logical
+ * eraseblock L and it is mapped to the physical eraseblock P.
+ *
+ * 1. Because UBI may erase physical eraseblocks asynchronously, the following
+ * situation is possible: L is asynchronously erased, so P is scheduled for
+ * erasure, then L is written to,i.e. mapped to another physical eraseblock P1,
+ * so P1 is written to, then an unclean reboot happens. Result - there are 2
+ * physical eraseblocks P and P1 corresponding to the same logical eraseblock
+ * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the
+ * flash.
+ *
+ * 2. From time to time UBI moves logical eraseblocks to other physical
+ * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P
+ * to P1, and an unclean reboot happens before P is physically erased, there
+ * are two physical eraseblocks P and P1 corresponding to L and UBI has to
+ * select one of them when the flash is attached. The @sqnum field says which
+ * PEB is the original (obviously P will have lower @sqnum) and the copy. But
+ * it is not enough to select the physical eraseblock with the higher sequence
+ * number, because the unclean reboot could have happen in the middle of the
+ * copying process, so the data in P is corrupted. It is also not enough to
+ * just select the physical eraseblock with lower sequence number, because the
+ * data there may be old (consider a case if more data was added to P1 after
+ * the copying). Moreover, the unclean reboot may happen when the erasure of P
+ * was just started, so it result in unstable P, which is "mostly" OK, but
+ * still has unstable bits.
+ *
+ * UBI uses the @copy_flag field to indicate that this logical eraseblock is a
+ * copy. UBI also calculates data CRC when the data is moved and stores it at
+ * the @data_crc field of the copy (P1). So when UBI needs to pick one physical
+ * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is
+ * examined. If it is cleared, the situation* is simple and the newer one is
+ * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC
+ * checksum is correct, this physical eraseblock is selected (P1). Otherwise
+ * the older one (P) is selected.
+ *
+ * Note, there is an obsolete @leb_ver field which was used instead of @sqnum
+ * in the past. But it is not used anymore and we keep it in order to be able
+ * to deal with old UBI images. It will be removed at some point.
+ *
+ * There are 2 sorts of volumes in UBI: user volumes and internal volumes.
+ * Internal volumes are not seen from outside and are used for various internal
+ * UBI purposes. In this implementation there is only one internal volume - the
+ * layout volume. Internal volumes are the main mechanism of UBI extensions.
+ * For example, in future one may introduce a journal internal volume. Internal
+ * volumes have their own reserved range of IDs.
+ *
+ * The @compat field is only used for internal volumes and contains the "degree
+ * of their compatibility". It is always zero for user volumes. This field
+ * provides a mechanism to introduce UBI extensions and to be still compatible
+ * with older UBI binaries. For example, if someone introduced a journal in
+ * future, he would probably use %UBI_COMPAT_DELETE compatibility for the
+ * journal volume. And in this case, older UBI binaries, which know nothing
+ * about the journal volume, would just delete this volume and work perfectly
+ * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image
+ * - it just ignores the Ext3fs journal.
+ *
+ * The @data_crc field contains the CRC checksum of the contents of the logical
+ * eraseblock if this is a static volume. In case of dynamic volumes, it does
+ * not contain the CRC checksum as a rule. The only exception is when the
+ * data of the physical eraseblock was moved by the wear-leveling unit, then
+ * the wear-leveling unit calculates the data CRC and stores it in the
+ * @data_crc field. And of course, the @copy_flag is %in this case.
+ *
+ * The @data_size field is used only for static volumes because UBI has to know
+ * how many bytes of data are stored in this eraseblock. For dynamic volumes,
+ * this field usually contains zero. The only exception is when the data of the
+ * physical eraseblock was moved to another physical eraseblock for
+ * wear-leveling reasons. In this case, UBI calculates CRC checksum of the
+ * contents and uses both @data_crc and @data_size fields. In this case, the
+ * @data_size field contains data size.
+ *
+ * The @used_ebs field is used only for static volumes and indicates how many
+ * eraseblocks the data of the volume takes. For dynamic volumes this field is
+ * not used and always contains zero.
+ *
+ * The @data_pad is calculated when volumes are created using the alignment
+ * parameter. So, effectively, the @data_pad field reduces the size of logical
+ * eraseblocks of this volume. This is very handy when one uses block-oriented
+ * software (say, cramfs) on top of the UBI volume.
+ */
+struct ubi_vid_hdr {
+ uint32_t magic;
+ uint8_t version;
+ uint8_t vol_type;
+ uint8_t copy_flag;
+ uint8_t compat;
+ uint32_t vol_id;
+ uint32_t lnum;
+ uint32_t leb_ver; /* obsolete, to be removed, don't use */
+ uint32_t data_size;
+ uint32_t used_ebs;
+ uint32_t data_pad;
+ uint32_t data_crc;
+ uint8_t padding1[4];
+ uint64_t sqnum;
+ uint8_t padding2[12];
+ uint32_t hdr_crc;
+} __attribute__ ((packed));
+
+/* Internal UBI volumes count */
+#define UBI_INT_VOL_COUNT 1
+
+/*
+ * Starting ID of internal volumes. There is reserved room for 4096 internal
+ * volumes.
+ */
+#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
+
+/* The layout volume contains the volume table */
+
+#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START
+#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC
+#define UBI_LAYOUT_VOLUME_ALIGN 1
+#define UBI_LAYOUT_VOLUME_EBS 2
+#define UBI_LAYOUT_VOLUME_NAME "layout volume"
+#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
+
+/* The maximum number of volumes per one UBI device */
+#define UBI_MAX_VOLUMES 128
+
+/* The maximum volume name length */
+#define UBI_VOL_NAME_MAX 127
+
+/* Size of the volume table record */
+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
+
+/* Size of the volume table record without the ending CRC */
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(uint32_t))
+
+/**
+ * struct ubi_vtbl_record - a record in the volume table.
+ * @reserved_pebs: how many physical eraseblocks are reserved for this volume
+ * @alignment: volume alignment
+ * @data_pad: how many bytes are unused at the end of the each physical
+ * eraseblock to satisfy the requested alignment
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @upd_marker: if volume update was started but not finished
+ * @name_len: volume name length
+ * @name: the volume name
+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
+ * @padding: reserved, zeroes
+ * @crc: a CRC32 checksum of the record
+ *
+ * The volume table records are stored in the volume table, which is stored in
+ * the layout volume. The layout volume consists of 2 logical eraseblock, each
+ * of which contains a copy of the volume table (i.e., the volume table is
+ * duplicated). The volume table is an array of &struct ubi_vtbl_record
+ * objects indexed by the volume ID.
+ *
+ * If the size of the logical eraseblock is large enough to fit
+ * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES
+ * records. Otherwise, it contains as many records as it can fit (i.e., size of
+ * logical eraseblock divided by sizeof(struct ubi_vtbl_record)).
+ *
+ * The @upd_marker flag is used to implement volume update. It is set to %1
+ * before update and set to %0 after the update. So if the update operation was
+ * interrupted, UBI knows that the volume is corrupted.
+ *
+ * The @alignment field is specified when the volume is created and cannot be
+ * later changed. It may be useful, for example, when a block-oriented file
+ * system works on top of UBI. The @data_pad field is calculated using the
+ * logical eraseblock size and @alignment. The alignment must be multiple to the
+ * minimal flash I/O unit. If @alignment is 1, all the available space of
+ * the physical eraseblocks is used.
+ *
+ * Empty records contain all zeroes and the CRC checksum of those zeroes.
+ */
+struct ubi_vtbl_record {
+ uint32_t reserved_pebs;
+ uint32_t alignment;
+ uint32_t data_pad;
+ uint8_t vol_type;
+ uint8_t upd_marker;
+ uint16_t name_len;
+ uint8_t name[UBI_VOL_NAME_MAX+1];
+ uint8_t flags;
+ uint8_t padding[23];
+ uint32_t crc;
+} __attribute__ ((packed));
+
+#endif /* !__UBI_HEADER_H__ */
diff --git a/drivers/mtd/mtd-utils/include/mtd/ubi-user.h b/drivers/mtd/mtd-utils/include/mtd/ubi-user.h
new file mode 100644
index 00000000000..cb0536d2d47
--- /dev/null
+++ b/drivers/mtd/mtd-utils/include/mtd/ubi-user.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Artem Bityutskiy (Битюцкий Ðртём)
+ */
+
+#ifndef __UBI_USER_H__
+#define __UBI_USER_H__
+
+#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into
+ separate files was to avoid #ifdef __KERNEL__ */
+#define __user
+#endif
+/*
+ * UBI device creation (the same as MTD device attachment)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI
+ * control device. The caller has to properly fill and pass
+ * &struct ubi_attach_req object - UBI will attach the MTD device specified in
+ * the request and return the newly created UBI device number as the ioctl
+ * return value.
+ *
+ * UBI device deletion (the same as MTD device detachment)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI
+ * control device.
+ *
+ * UBI volume creation
+ * ~~~~~~~~~~~~~~~~~~~
+ *
+ * UBI volumes are created via the %UBI_IOCMKVOL IOCTL command of UBI character
+ * device. A &struct ubi_mkvol_req object has to be properly filled and a
+ * pointer to it has to be passed to the IOCTL.
+ *
+ * UBI volume deletion
+ * ~~~~~~~~~~~~~~~~~~~
+ *
+ * To delete a volume, the %UBI_IOCRMVOL IOCTL command of the UBI character
+ * device should be used. A pointer to the 32-bit volume ID hast to be passed
+ * to the IOCTL.
+ *
+ * UBI volume re-size
+ * ~~~~~~~~~~~~~~~~~~
+ *
+ * To re-size a volume, the %UBI_IOCRSVOL IOCTL command of the UBI character
+ * device should be used. A &struct ubi_rsvol_req object has to be properly
+ * filled and a pointer to it has to be passed to the IOCTL.
+ *
+ * UBI volume update
+ * ~~~~~~~~~~~~~~~~~
+ *
+ * Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the
+ * corresponding UBI volume character device. A pointer to a 64-bit update
+ * size should be passed to the IOCTL. After this, UBI expects user to write
+ * this number of bytes to the volume character device. The update is finished
+ * when the claimed number of bytes is passed. So, the volume update sequence
+ * is something like:
+ *
+ * fd = open("/dev/my_volume");
+ * ioctl(fd, UBI_IOCVOLUP, &image_size);
+ * write(fd, buf, image_size);
+ * close(fd);
+ *
+ * Atomic eraseblock change
+ * ~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Atomic eraseblock change operation is done via the %UBI_IOCEBCH IOCTL
+ * command of the corresponding UBI volume character device. A pointer to
+ * &struct ubi_leb_change_req has to be passed to the IOCTL. Then the user is
+ * expected to write the requested amount of bytes. This is similar to the
+ * "volume update" IOCTL.
+ */
+
+/*
+ * When a new UBI volume or UBI device is created, users may either specify the
+ * volume/device number they want to create or to let UBI automatically assign
+ * the number using these constants.
+ */
+#define UBI_VOL_NUM_AUTO (-1)
+#define UBI_DEV_NUM_AUTO (-1)
+
+/* Maximum volume name length */
+#define UBI_MAX_VOLUME_NAME 127
+
+/* IOCTL commands of UBI character devices */
+
+#define UBI_IOC_MAGIC 'o'
+
+/* Create an UBI volume */
+#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req)
+/* Remove an UBI volume */
+#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t)
+/* Re-size an UBI volume */
+#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req)
+
+/* IOCTL commands of the UBI control character device */
+
+#define UBI_CTRL_IOC_MAGIC 'o'
+
+/* Attach an MTD device */
+#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req)
+/* Detach an MTD device */
+#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t)
+
+/* IOCTL commands of UBI volume character devices */
+
+#define UBI_VOL_IOC_MAGIC 'O'
+
+/* Start UBI volume update */
+#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t)
+/* An eraseblock erasure command, used for debugging, disabled by default */
+#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
+/* An atomic eraseblock change command */
+#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t)
+/* Start UBI leb read */
+#define UBI_IOCLEBREAD _IOWR(UBI_VOL_IOC_MAGIC, 3, struct ubi_leb)
+
+/* Maximum MTD device name length supported by UBI */
+#define MAX_UBI_MTD_NAME_LEN 127
+
+/*
+ * UBI data type hint constants.
+ *
+ * UBI_LONGTERM: long-term data
+ * UBI_SHORTTERM: short-term data
+ * UBI_UNKNOWN: data persistence is unknown
+ *
+ * These constants are used when data is written to UBI volumes in order to
+ * help the UBI wear-leveling unit to find more appropriate physical
+ * eraseblocks.
+ */
+enum {
+ UBI_LONGTERM = 1,
+ UBI_SHORTTERM = 2,
+ UBI_UNKNOWN = 3,
+};
+
+/*
+ * UBI volume type constants.
+ *
+ * @UBI_DYNAMIC_VOLUME: dynamic volume
+ * @UBI_STATIC_VOLUME: static volume
+ */
+enum {
+ UBI_DYNAMIC_VOLUME = 3,
+ UBI_STATIC_VOLUME = 4,
+};
+
+/**
+ * struct ubi_attach_req - attach MTD device request.
+ * @ubi_num: UBI device number to create
+ * @mtd_num: MTD device number to attach
+ * @vid_hdr_offset: VID header offset (use defaults if %0)
+ * @padding: reserved for future, not used, has to be zeroed
+ *
+ * This data structure is used to specify MTD device UBI has to attach and the
+ * parameters it has to use. The number which should be assigned to the new UBI
+ * device is passed in @ubi_num. UBI may automatically assign the number if
+ * @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in
+ * @ubi_num.
+ *
+ * Most applications should pass %0 in @vid_hdr_offset to make UBI use default
+ * offset of the VID header within physical eraseblocks. The default offset is
+ * the next min. I/O unit after the EC header. For example, it will be offset
+ * 512 in case of a 512 bytes page NAND flash with no sub-page support. Or
+ * it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages.
+ *
+ * But in rare cases, if this optimizes things, the VID header may be placed to
+ * a different offset. For example, the boot-loader might do things faster if the
+ * VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. As
+ * the boot-loader would not normally need to read EC headers (unless it needs
+ * UBI in RW mode), it might be faster to calculate ECC. This is weird example,
+ * but it real-life example. So, in this example, @vid_hdr_offer would be
+ * 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes
+ * aligned, which is OK, as UBI is clever enough to realize this is 4th sub-page
+ * of the first page and add needed padding.
+ */
+struct ubi_attach_req {
+ int32_t ubi_num;
+ int32_t mtd_num;
+ int32_t vid_hdr_offset;
+ uint8_t padding[12];
+};
+
+/**
+ * struct ubi_mkvol_req - volume description data structure used in
+ * volume creation requests.
+ * @vol_id: volume number
+ * @alignment: volume alignment
+ * @bytes: volume size in bytes
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @padding1: reserved for future, not used, has to be zeroed
+ * @name_len: volume name length
+ * @padding2: reserved for future, not used, has to be zeroed
+ * @name: volume name
+ *
+ * This structure is used by user-space programs when creating new volumes. The
+ * @used_bytes field is only necessary when creating static volumes.
+ *
+ * The @alignment field specifies the required alignment of the volume logical
+ * eraseblock. This means, that the size of logical eraseblocks will be aligned
+ * to this number, i.e.,
+ * (UBI device logical eraseblock size) mod (@alignment) = 0.
+ *
+ * To put it differently, the logical eraseblock of this volume may be slightly
+ * shortened in order to make it properly aligned. The alignment has to be
+ * multiple of the flash minimal input/output unit, or %1 to utilize the entire
+ * available space of logical eraseblocks.
+ *
+ * The @alignment field may be useful, for example, when one wants to maintain
+ * a block device on top of an UBI volume. In this case, it is desirable to fit
+ * an integer number of blocks in logical eraseblocks of this UBI volume. With
+ * alignment it is possible to update this volume using plane UBI volume image
+ * BLOBs, without caring about how to properly align them.
+ */
+struct ubi_mkvol_req {
+ int32_t vol_id;
+ int32_t alignment;
+ int64_t bytes;
+ int8_t vol_type;
+ int8_t padding1;
+ int16_t name_len;
+ int8_t padding2[4];
+ char name[UBI_MAX_VOLUME_NAME + 1];
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_rsvol_req - a data structure used in volume re-size requests.
+ * @vol_id: ID of the volume to re-size
+ * @bytes: new size of the volume in bytes
+ *
+ * Re-sizing is possible for both dynamic and static volumes. But while dynamic
+ * volumes may be re-sized arbitrarily, static volumes cannot be made to be
+ * smaller then the number of bytes they bear. To arbitrarily shrink a static
+ * volume, it must be wiped out first (by means of volume update operation with
+ * zero number of bytes).
+ */
+struct ubi_rsvol_req {
+ int64_t bytes;
+ int32_t vol_id;
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_leb_change_req - a data structure used in atomic logical
+ * eraseblock change requests.
+ * @lnum: logical eraseblock number to change
+ * @bytes: how many bytes will be written to the logical eraseblock
+ * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
+ * @padding: reserved for future, not used, has to be zeroed
+ */
+struct ubi_leb_change_req {
+ int32_t lnum;
+ int32_t bytes;
+ uint8_t dtype;
+ uint8_t padding[7];
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_leb - a data structure describe LEB.
+ * @lnum: logical eraseblock number to dump
+ * @lebbuf: LEB data buffer
+ */
+struct ubi_leb{
+ unsigned int lnum;
+ char __user *buf;
+};
+
+#endif /* __UBI_USER_H__ */
diff --git a/drivers/mtd/mtd-utils/include/mtd_swab.h b/drivers/mtd/mtd-utils/include/mtd_swab.h
new file mode 100644
index 00000000000..c3340a6438f
--- /dev/null
+++ b/drivers/mtd/mtd-utils/include/mtd_swab.h
@@ -0,0 +1,51 @@
+#ifndef MTD_SWAB_H
+#define MTD_SWAB_H
+
+#include <endian.h>
+
+#define swab16(x) \
+ ((uint16_t)( \
+ (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
+ (((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
+#define swab32(x) \
+ ((uint32_t)( \
+ (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
+ (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
+ (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
+ (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
+
+#define swab64(x) \
+ ((uint64_t)( \
+ (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \
+ (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
+ (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
+ (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
+ (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
+ (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
+ (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
+ (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) ))
+
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le16(x) ({ uint16_t _x = x; swab16(_x); })
+#define cpu_to_le32(x) ({ uint32_t _x = x; swab32(_x); })
+#define cpu_to_le64(x) ({ uint64_t _x = x; swab64(_x); })
+#define cpu_to_be16(x) (x)
+#define cpu_to_be32(x) (x)
+#define cpu_to_be64(x) (x)
+#else
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_le64(x) (x)
+#define cpu_to_be16(x) ({ uint16_t _x = x; swab16(_x); })
+#define cpu_to_be32(x) ({ uint32_t _x = x; swab32(_x); })
+#define cpu_to_be64(x) ({ uint64_t _x = x; swab64(_x); })
+#endif
+#define le16_to_cpu(x) cpu_to_le16(x)
+#define be16_to_cpu(x) cpu_to_be16(x)
+#define le32_to_cpu(x) cpu_to_le32(x)
+#define be32_to_cpu(x) cpu_to_be32(x)
+#define le64_to_cpu(x) cpu_to_le64(x)
+#define be64_to_cpu(x) cpu_to_be64(x)
+
+#endif
diff --git a/drivers/mtd/mtd-utils/jffs-dump.c b/drivers/mtd/mtd-utils/jffs-dump.c
new file mode 100644
index 00000000000..31cdad21f91
--- /dev/null
+++ b/drivers/mtd/mtd-utils/jffs-dump.c
@@ -0,0 +1,359 @@
+/*
+ * Dump JFFS filesystem.
+ * Useful when it buggers up.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define BLOCK_SIZE 1024
+#define JFFS_MAGIC 0x34383931 /* "1984" */
+#define JFFS_MAX_NAME_LEN 256
+#define JFFS_MIN_INO 1
+#define JFFS_TRACE_INDENT 4
+#define JFFS_ALIGN_SIZE 4
+#define MAX_CHUNK_SIZE 32768
+
+/* How many padding bytes should be inserted between two chunks of data
+ on the flash? */
+#define JFFS_GET_PAD_BYTES(size) ((JFFS_ALIGN_SIZE \
+ - ((uint32_t)(size) % JFFS_ALIGN_SIZE)) \
+ % JFFS_ALIGN_SIZE)
+
+#define JFFS_EMPTY_BITMASK 0xffffffff
+#define JFFS_MAGIC_BITMASK 0x34383931
+#define JFFS_DIRTY_BITMASK 0x00000000
+
+#define min(x,y) (x) > (y) ? (y) : (x)
+
+struct jffs_raw_inode
+{
+ uint32_t magic; /* A constant magic number. */
+ uint32_t ino; /* Inode number. */
+ uint32_t pino; /* Parent's inode number. */
+ uint32_t version; /* Version number. */
+ uint32_t mode; /* file_type, mode */
+ uint16_t uid;
+ uint16_t gid;
+ uint32_t atime;
+ uint32_t mtime;
+ uint32_t ctime;
+ uint32_t offset; /* Where to begin to write. */
+ uint32_t dsize; /* Size of the file data. */
+ uint32_t rsize; /* How much are going to be replaced? */
+ uint8_t nsize; /* Name length. */
+ uint8_t nlink; /* Number of links. */
+ uint8_t spare : 6; /* For future use. */
+ uint8_t rename : 1; /* Is this a special rename? */
+ uint8_t deleted : 1; /* Has this file been deleted? */
+ uint8_t accurate; /* The inode is obsolete if accurate == 0. */
+ uint32_t dchksum; /* Checksum for the data. */
+ uint16_t nchksum; /* Checksum for the name. */
+ uint16_t chksum; /* Checksum for the raw_inode. */
+};
+
+
+struct jffs_file
+{
+ struct jffs_raw_inode inode;
+ char *name;
+ unsigned char *data;
+};
+
+
+char *root_directory_name = NULL;
+int fs_pos = 0;
+int verbose = 0;
+
+#define ENDIAN_HOST 0
+#define ENDIAN_BIG 1
+#define ENDIAN_LITTLE 2
+int endian = ENDIAN_HOST;
+
+static uint32_t jffs_checksum(void *data, int size);
+void jffs_print_trace(const char *path, int depth);
+int make_root_dir(FILE *fs, int first_ino, const char *root_dir_path,
+ int depth);
+void write_file(struct jffs_file *f, FILE *fs, struct stat st);
+void read_data(struct jffs_file *f, const char *path, int offset);
+int mkfs(FILE *fs, const char *path, int ino, int parent, int depth);
+
+
+ static uint32_t
+jffs_checksum(void *data, int size)
+{
+ uint32_t sum = 0;
+ uint8_t *ptr = (uint8_t *)data;
+
+ while (size-- > 0)
+ {
+ sum += *ptr++;
+ }
+
+ return sum;
+}
+
+
+ void
+jffs_print_trace(const char *path, int depth)
+{
+ int path_len = strlen(path);
+ int out_pos = depth * JFFS_TRACE_INDENT;
+ int pos = path_len - 1;
+ char *out = (char *)alloca(depth * JFFS_TRACE_INDENT + path_len + 1);
+
+ if (verbose >= 2)
+ {
+ fprintf(stderr, "jffs_print_trace(): path: \"%s\"\n", path);
+ }
+
+ if (!out) {
+ fprintf(stderr, "jffs_print_trace(): Allocation failed.\n");
+ fprintf(stderr, " path: \"%s\"\n", path);
+ fprintf(stderr, "depth: %d\n", depth);
+ exit(1);
+ }
+
+ memset(out, ' ', depth * JFFS_TRACE_INDENT);
+
+ if (path[pos] == '/')
+ {
+ pos--;
+ }
+ while (path[pos] && (path[pos] != '/'))
+ {
+ pos--;
+ }
+ for (pos++; path[pos] && (path[pos] != '/'); pos++)
+ {
+ out[out_pos++] = path[pos];
+ }
+ out[out_pos] = '\0';
+ fprintf(stderr, "%s\n", out);
+}
+
+
+/* Print the contents of a raw inode. */
+ void
+jffs_print_raw_inode(struct jffs_raw_inode *raw_inode)
+{
+ fprintf(stdout, "jffs_raw_inode: inode number: %u, version %u\n", raw_inode->ino, raw_inode->version);
+ fprintf(stdout, "{\n");
+ fprintf(stdout, " 0x%08x, /* magic */\n", raw_inode->magic);
+ fprintf(stdout, " 0x%08x, /* ino */\n", raw_inode->ino);
+ fprintf(stdout, " 0x%08x, /* pino */\n", raw_inode->pino);
+ fprintf(stdout, " 0x%08x, /* version */\n", raw_inode->version);
+ fprintf(stdout, " 0x%08x, /* mode */\n", raw_inode->mode);
+ fprintf(stdout, " 0x%04x, /* uid */\n", raw_inode->uid);
+ fprintf(stdout, " 0x%04x, /* gid */\n", raw_inode->gid);
+ fprintf(stdout, " 0x%08x, /* atime */\n", raw_inode->atime);
+ fprintf(stdout, " 0x%08x, /* mtime */\n", raw_inode->mtime);
+ fprintf(stdout, " 0x%08x, /* ctime */\n", raw_inode->ctime);
+ fprintf(stdout, " 0x%08x, /* offset */\n", raw_inode->offset);
+ fprintf(stdout, " 0x%08x, /* dsize */\n", raw_inode->dsize);
+ fprintf(stdout, " 0x%08x, /* rsize */\n", raw_inode->rsize);
+ fprintf(stdout, " 0x%02x, /* nsize */\n", raw_inode->nsize);
+ fprintf(stdout, " 0x%02x, /* nlink */\n", raw_inode->nlink);
+ fprintf(stdout, " 0x%02x, /* spare */\n",
+ raw_inode->spare);
+ fprintf(stdout, " %u, /* rename */\n",
+ raw_inode->rename);
+ fprintf(stdout, " %u, /* deleted */\n",
+ raw_inode->deleted);
+ fprintf(stdout, " 0x%02x, /* accurate */\n",
+ raw_inode->accurate);
+ fprintf(stdout, " 0x%08x, /* dchksum */\n", raw_inode->dchksum);
+ fprintf(stdout, " 0x%04x, /* nchksum */\n", raw_inode->nchksum);
+ fprintf(stdout, " 0x%04x, /* chksum */\n", raw_inode->chksum);
+ fprintf(stdout, "}\n");
+}
+
+static void write_val32(uint32_t *adr, uint32_t val)
+{
+ switch(endian) {
+ case ENDIAN_HOST:
+ *adr = val;
+ break;
+ case ENDIAN_LITTLE:
+ *adr = __cpu_to_le32(val);
+ break;
+ case ENDIAN_BIG:
+ *adr = __cpu_to_be32(val);
+ break;
+ }
+}
+
+static void write_val16(uint16_t *adr, uint16_t val)
+{
+ switch(endian) {
+ case ENDIAN_HOST:
+ *adr = val;
+ break;
+ case ENDIAN_LITTLE:
+ *adr = __cpu_to_le16(val);
+ break;
+ case ENDIAN_BIG:
+ *adr = __cpu_to_be16(val);
+ break;
+ }
+}
+
+static uint32_t read_val32(uint32_t *adr)
+{
+ uint32_t val;
+
+ switch(endian) {
+ case ENDIAN_HOST:
+ val = *adr;
+ break;
+ case ENDIAN_LITTLE:
+ val = __le32_to_cpu(*adr);
+ break;
+ case ENDIAN_BIG:
+ val = __be32_to_cpu(*adr);
+ break;
+ }
+ return val;
+}
+
+static uint16_t read_val16(uint16_t *adr)
+{
+ uint16_t val;
+
+ switch(endian) {
+ case ENDIAN_HOST:
+ val = *adr;
+ break;
+ case ENDIAN_LITTLE:
+ val = __le16_to_cpu(*adr);
+ break;
+ case ENDIAN_BIG:
+ val = __be16_to_cpu(*adr);
+ break;
+ }
+ return val;
+}
+
+ int
+main(int argc, char **argv)
+{
+ int fs;
+ struct stat sb;
+ uint32_t wordbuf;
+ off_t pos = 0;
+ off_t end;
+ struct jffs_raw_inode ino;
+ unsigned char namebuf[4096];
+ int myino = -1;
+
+ if (argc < 2) {
+ printf("no filesystem given\n");
+ exit(1);
+ }
+
+ fs = open(argv[1], O_RDONLY);
+ if (fs < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ if (argc > 2) {
+ myino = atol(argv[2]);
+ printf("Printing ino #%d\n" , myino);
+ }
+
+ if (fstat(fs, &sb) < 0) {
+ perror("stat");
+ close(fs);
+ exit(1);
+ }
+ end = sb.st_size;
+
+ while (pos < end) {
+ if (pread(fs, &wordbuf, 4, pos) < 0) {
+ perror("pread");
+ exit(1);
+ }
+
+ switch(wordbuf) {
+ case JFFS_EMPTY_BITMASK:
+ // printf("0xff started at 0x%lx\n", pos);
+ for (; pos < end && wordbuf == JFFS_EMPTY_BITMASK; pos += 4) {
+ if (pread(fs, &wordbuf, 4, pos) < 0) {
+ perror("pread");
+ exit(1);
+ }
+ }
+ if (pos < end)
+ pos -= 4;
+ // printf("0xff ended at 0x%lx\n", pos);
+ continue;
+
+ case JFFS_DIRTY_BITMASK:
+ // printf("0x00 started at 0x%lx\n", pos);
+ for (; pos < end && wordbuf == JFFS_DIRTY_BITMASK; pos += 4) {
+ if (pread(fs, &wordbuf, 4, pos) < 0) {
+ perror("pread");
+ exit(1);
+ }
+ }
+ if (pos < end)
+ pos -=4;
+ // printf("0x00 ended at 0x%lx\n", pos);
+ continue;
+
+ default:
+ printf("Argh. Dirty memory at 0x%lx\n", pos);
+ // file_hexdump(fs, pos, 128);
+ for (pos += 4; pos < end; pos += 4) {
+ if (pread(fs, &wordbuf, 4, pos) < 0) {
+ perror("pread");
+ exit(1);
+ }
+ if (wordbuf == JFFS_MAGIC_BITMASK)
+ break;
+ }
+
+ case JFFS_MAGIC_BITMASK:
+ if (pread(fs, &ino, sizeof(ino), pos) < 0) {
+ perror("pread");
+ exit(1);
+ }
+ if (myino == -1 || ino.ino == myino) {
+ printf("Magic found at 0x%lx\n", pos);
+ jffs_print_raw_inode(&ino);
+ }
+ pos += sizeof(ino);
+
+ if (myino == -1 || ino.ino == myino) {
+ if (ino.nsize) {
+ if (pread(fs, namebuf, min(ino.nsize, 4095), pos) < 0) {
+ perror("pread");
+ exit(1);
+ }
+ if (ino.nsize < 4095)
+ namebuf[ino.nsize] = 0;
+ else
+ namebuf[4095] = 0;
+ printf("Name: \"%s\"\n", namebuf);
+ } else {
+ printf("No Name\n");
+ }
+ }
+ pos += (ino.nsize + 3) & ~3;
+
+ pos += (ino.dsize + 3) & ~3;
+ }
+
+
+
+ }
+}
diff --git a/drivers/mtd/mtd-utils/jffs2dump.c b/drivers/mtd/mtd-utils/jffs2dump.c
new file mode 100644
index 00000000000..65034deded5
--- /dev/null
+++ b/drivers/mtd/mtd-utils/jffs2dump.c
@@ -0,0 +1,690 @@
+/*
+ * dumpjffs2.c
+ *
+ * Copyright (C) 2003 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Overview:
+ * This utility dumps the contents of a binary JFFS2 image
+ *
+ *
+ * Bug/ToDo:
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <asm/types.h>
+#include <dirent.h>
+#include <mtd/jffs2-user.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <getopt.h>
+#include "crc32.h"
+#include "summary.h"
+
+#define PROGRAM "jffs2dump"
+#define VERSION "$Revision: 1.1.1.1 $"
+
+#define PAD(x) (((x)+3)&~3)
+
+/* For outputting a byte-swapped version of the input image. */
+#define cnv_e32(x) ((jint32_t){bswap_32(x.v32)})
+#define cnv_e16(x) ((jint16_t){bswap_16(x.v16)})
+
+#define t32_backwards(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?bswap_32(__b):__b; })
+#define cpu_to_e32(x) ((jint32_t){t32_backwards(x)})
+
+// Global variables
+long imglen; // length of image
+char *data; // image data
+
+void display_help (void)
+{
+ printf("Usage: dumpjffs2 [OPTION] INPUTFILE\n"
+ "Dumps the contents of a binary JFFS2 image.\n"
+ "\n"
+ " --help display this help and exit\n"
+ " --version output version information and exit\n"
+ "-b --bigendian image is big endian\n"
+ "-l --littleendian image is little endian\n"
+ "-c --content dump image contents\n"
+ "-e fname --endianconvert=fname convert image endianness, output to file fname\n"
+ "-r --recalccrc recalc name and data crc on endian conversion\n"
+ "-d len --datsize=len size of data chunks, when oob data in binary image (NAND only)\n"
+ "-o len --oobsize=len size of oob data chunk in binary image (NAND only)\n"
+ "-v --verbose verbose output\n");
+ exit(0);
+}
+
+void display_version (void)
+{
+ printf(PROGRAM " " VERSION "\n"
+ "\n"
+ "Copyright (C) 2003 Thomas Gleixner \n"
+ "\n"
+ PROGRAM " comes with NO WARRANTY\n"
+ "to the extent permitted by law.\n"
+ "\n"
+ "You may redistribute copies of " PROGRAM "\n"
+ "under the terms of the GNU General Public Licence.\n"
+ "See the file `COPYING' for more information.\n");
+ exit(0);
+}
+
+// Option variables
+
+int verbose; // verbose output
+char *img; // filename of image
+int dumpcontent; // dump image content
+int target_endian = __BYTE_ORDER; // image endianess
+int convertendian; // convert endianness
+int recalccrc; // recalc name and data crc's on endian conversion
+char cnvfile[256]; // filename for conversion output
+int datsize; // Size of data chunks, when oob data is inside the binary image
+int oobsize; // Size of oob chunks, when oob data is inside the binary image
+
+void process_options (int argc, char *argv[])
+{
+ int error = 0;
+
+ for (;;) {
+ int option_index = 0;
+ static const char *short_options = "blce:rd:o:v";
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 0},
+ {"version", no_argument, 0, 0},
+ {"bigendian", no_argument, 0, 'b'},
+ {"littleendian", no_argument, 0, 'l'},
+ {"content", no_argument, 0, 'c'},
+ {"endianconvert", required_argument, 0, 'e'},
+ {"datsize", required_argument, 0, 'd'},
+ {"oobsize", required_argument, 0, 'o'},
+ {"recalccrc", required_argument, 0, 'r'},
+ {"verbose", no_argument, 0, 'v'},
+ {0, 0, 0, 0},
+ };
+
+ int c = getopt_long(argc, argv, short_options,
+ long_options, &option_index);
+ if (c == EOF) {
+ break;
+ }
+
+ switch (c) {
+ case 0:
+ switch (option_index) {
+ case 0:
+ display_help();
+ break;
+ case 1:
+ display_version();
+ break;
+ }
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'b':
+ target_endian = __BIG_ENDIAN;
+ break;
+ case 'l':
+ target_endian = __LITTLE_ENDIAN;
+ break;
+ case 'c':
+ dumpcontent = 1;
+ break;
+ case 'd':
+ datsize = atoi(optarg);
+ break;
+ case 'o':
+ oobsize = atoi(optarg);
+ break;
+ case 'e':
+ convertendian = 1;
+ strcpy (cnvfile, optarg);
+ break;
+ case 'r':
+ recalccrc = 1;
+ break;
+ case '?':
+ error = 1;
+ break;
+ }
+ }
+
+ if ((argc - optind) != 1 || error)
+ display_help ();
+
+ img = argv[optind];
+}
+
+
+/*
+ * Dump image contents
+ */
+void do_dumpcontent (void)
+{
+ char *p = data, *p_free_begin;
+ union jffs2_node_union *node;
+ int empty = 0, dirty = 0;
+ char name[256];
+ uint32_t crc;
+ uint16_t type;
+ int bitchbitmask = 0;
+ int obsolete;
+
+ p_free_begin = NULL;
+ while ( p < (data + imglen)) {
+ node = (union jffs2_node_union*) p;
+
+ /* Skip empty space */
+ if (!p_free_begin)
+ p_free_begin = p;
+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+ p += 4;
+ empty += 4;
+ continue;
+ }
+
+ if (p != p_free_begin)
+ printf("Empty space found from 0x%08x to 0x%08x\n", p_free_begin-data, p-data);
+ p_free_begin = NULL;
+
+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
+ if (!bitchbitmask++)
+ printf ("Wrong bitmask at 0x%08x, 0x%04x\n", p - data, je16_to_cpu (node->u.magic));
+ p += 4;
+ dirty += 4;
+ continue;
+ }
+ bitchbitmask = 0;
+
+ type = je16_to_cpu(node->u.nodetype);
+ if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+ obsolete = 1;
+ type |= JFFS2_NODE_ACCURATE;
+ } else
+ obsolete = 0;
+ /* Set accurate for CRC check */
+ node->u.nodetype = cpu_to_je16(type);
+
+ crc = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+ if (crc != je32_to_cpu (node->u.hdr_crc)) {
+ printf ("Wrong hdr_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc);
+ p += 4;
+ dirty += 4;
+ continue;
+ }
+
+ switch(je16_to_cpu(node->u.nodetype)) {
+
+ case JFFS2_NODETYPE_INODE:
+ printf ("%8s Inode node at 0x%08x, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+ obsolete ? "Obsolete" : "",
+ p - data, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+ je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize),
+ je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+ crc = crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
+ if (crc != je32_to_cpu (node->i.node_crc)) {
+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.node_crc), crc);
+ p += PAD(je32_to_cpu (node->i.totlen));
+ dirty += PAD(je32_to_cpu (node->i.totlen));;
+ continue;
+ }
+
+ crc = crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
+ if (crc != je32_to_cpu(node->i.data_crc)) {
+ printf ("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.data_crc), crc);
+ p += PAD(je32_to_cpu (node->i.totlen));
+ dirty += PAD(je32_to_cpu (node->i.totlen));;
+ continue;
+ }
+
+ p += PAD(je32_to_cpu (node->i.totlen));
+ break;
+
+ case JFFS2_NODETYPE_DIRENT:
+ memcpy (name, node->d.name, node->d.nsize);
+ name [node->d.nsize] = 0x0;
+ printf ("%8s Dirent node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n",
+ obsolete ? "Obsolete" : "",
+ p - data, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+ je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
+ node->d.nsize, name);
+
+ crc = crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
+ if (crc != je32_to_cpu (node->d.node_crc)) {
+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.node_crc), crc);
+ p += PAD(je32_to_cpu (node->d.totlen));
+ dirty += PAD(je32_to_cpu (node->d.totlen));;
+ continue;
+ }
+
+ crc = crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
+ if (crc != je32_to_cpu(node->d.name_crc)) {
+ printf ("Wrong name_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.name_crc), crc);
+ p += PAD(je32_to_cpu (node->d.totlen));
+ dirty += PAD(je32_to_cpu (node->d.totlen));;
+ continue;
+ }
+
+ p += PAD(je32_to_cpu (node->d.totlen));
+ break;
+
+ case JFFS2_NODETYPE_SUMMARY: {
+
+ int i;
+ struct jffs2_sum_marker * sm;
+
+ printf("%8s Inode Sum node at 0x%08x, totlen 0x%08x, sum_num %5d, cleanmarker size %5d\n",
+ obsolete ? "Obsolete" : "",
+ p - data,
+ je32_to_cpu (node->s.totlen),
+ je32_to_cpu (node->s.sum_num),
+ je32_to_cpu (node->s.cln_mkr));
+
+ crc = crc32 (0, node, sizeof (struct jffs2_raw_summary) - 8);
+ if (crc != je32_to_cpu (node->s.node_crc)) {
+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.node_crc), crc);
+ p += PAD(je32_to_cpu (node->s.totlen));
+ dirty += PAD(je32_to_cpu (node->s.totlen));;
+ continue;
+ }
+
+ crc = crc32(0, p + sizeof (struct jffs2_raw_summary), je32_to_cpu (node->s.totlen) - sizeof(struct jffs2_raw_summary));
+ if (crc != je32_to_cpu(node->s.sum_crc)) {
+ printf ("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.sum_crc), crc);
+ p += PAD(je32_to_cpu (node->s.totlen));
+ dirty += PAD(je32_to_cpu (node->s.totlen));;
+ continue;
+ }
+
+ if (verbose) {
+ void *sp;
+ sp = (p + sizeof(struct jffs2_raw_summary));
+
+ for(i=0; i<je32_to_cpu(node->s.sum_num); i++) {
+
+ switch(je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
+ case JFFS2_NODETYPE_INODE : {
+
+ struct jffs2_sum_inode_flash *spi;
+ spi = sp;
+
+ printf ("%14s #ino %5d, version %5d, offset 0x%08x, totlen 0x%08x\n",
+ "",
+ je32_to_cpu (spi->inode),
+ je32_to_cpu (spi->version),
+ je32_to_cpu (spi->offset),
+ je32_to_cpu (spi->totlen));
+
+ sp += JFFS2_SUMMARY_INODE_SIZE;
+ break;
+ }
+
+ case JFFS2_NODETYPE_DIRENT : {
+
+ char name[255];
+ struct jffs2_sum_dirent_flash *spd;
+ spd = sp;
+
+ memcpy(name,spd->name,spd->nsize);
+ name [spd->nsize] = 0x0;
+
+ printf ("%14s dirent offset 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s \n",
+ "",
+ je32_to_cpu (spd->offset),
+ je32_to_cpu (spd->totlen),
+ je32_to_cpu (spd->pino),
+ je32_to_cpu (spd->version),
+ je32_to_cpu (spd->ino),
+ spd->nsize,
+ name);
+
+ sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
+ break;
+ }
+
+ default :
+ printf("Unknown summary node!\n");
+ break;
+ }
+ }
+
+ sm = (struct jffs2_sum_marker *) ((char *)p + je32_to_cpu(node->s.totlen) - sizeof(struct jffs2_sum_marker));
+
+ printf("%14s Sum Node Offset 0x%08x, Magic 0x%08x, Padded size 0x%08x\n",
+ "",
+ je32_to_cpu(sm->offset),
+ je32_to_cpu(sm->magic),
+ je32_to_cpu(node->s.padded));
+ }
+
+ p += PAD(je32_to_cpu (node->s.totlen));
+ break;
+ }
+
+ case JFFS2_NODETYPE_CLEANMARKER:
+ if (verbose) {
+ printf ("%8s Cleanmarker at 0x%08x, totlen 0x%08x\n",
+ obsolete ? "Obsolete" : "",
+ p - data, je32_to_cpu (node->u.totlen));
+ }
+ p += PAD(je32_to_cpu (node->u.totlen));
+ break;
+
+ case JFFS2_NODETYPE_PADDING:
+ if (verbose) {
+ printf ("%8s Padding node at 0x%08x, totlen 0x%08x\n",
+ obsolete ? "Obsolete" : "",
+ p - data, je32_to_cpu (node->u.totlen));
+ }
+ p += PAD(je32_to_cpu (node->u.totlen));
+ break;
+
+ case 0xffff:
+ p += 4;
+ empty += 4;
+ break;
+
+ default:
+ if (verbose) {
+ printf ("%8s Unknown node at 0x%08x, totlen 0x%08x\n",
+ obsolete ? "Obsolete" : "",
+ p - data, je32_to_cpu (node->u.totlen));
+ }
+ p += PAD(je32_to_cpu (node->u.totlen));
+ dirty += PAD(je32_to_cpu (node->u.totlen));
+
+ }
+ }
+
+ if (verbose)
+ printf ("Empty space: %d, dirty space: %d\n", empty, dirty);
+}
+
+/*
+ * Convert endianess
+ */
+void do_endianconvert (void)
+{
+ char *p = data;
+ union jffs2_node_union *node, newnode;
+ int fd, len;
+ jint32_t mode;
+ uint32_t crc;
+
+ fd = open (cnvfile, O_WRONLY | O_CREAT, 0644);
+ if (fd < 0) {
+ fprintf (stderr, "Cannot open / create file: %s\n", cnvfile);
+ return;
+ }
+
+ while ( p < (data + imglen)) {
+ node = (union jffs2_node_union*) p;
+
+ /* Skip empty space */
+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+ write (fd, p, 4);
+ p += 4;
+ continue;
+ }
+
+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
+ printf ("Wrong bitmask at 0x%08x, 0x%04x\n", p - data, je16_to_cpu (node->u.magic));
+ newnode.u.magic = cnv_e16 (node->u.magic);
+ newnode.u.nodetype = cnv_e16 (node->u.nodetype);
+ write (fd, &newnode, 4);
+ p += 4;
+ continue;
+ }
+
+ crc = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+ if (crc != je32_to_cpu (node->u.hdr_crc)) {
+ printf ("Wrong hdr_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc);
+ }
+
+ switch(je16_to_cpu(node->u.nodetype)) {
+
+ case JFFS2_NODETYPE_INODE:
+
+ newnode.i.magic = cnv_e16 (node->i.magic);
+ newnode.i.nodetype = cnv_e16 (node->i.nodetype);
+ newnode.i.totlen = cnv_e32 (node->i.totlen);
+ newnode.i.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+ newnode.i.ino = cnv_e32 (node->i.ino);
+ newnode.i.version = cnv_e32 (node->i.version);
+ mode.v32 = node->i.mode.m;
+ mode = cnv_e32 (mode);
+ newnode.i.mode.m = mode.v32;
+ newnode.i.uid = cnv_e16 (node->i.uid);
+ newnode.i.gid = cnv_e16 (node->i.gid);
+ newnode.i.isize = cnv_e32 (node->i.isize);
+ newnode.i.atime = cnv_e32 (node->i.atime);
+ newnode.i.mtime = cnv_e32 (node->i.mtime);
+ newnode.i.ctime = cnv_e32 (node->i.ctime);
+ newnode.i.offset = cnv_e32 (node->i.offset);
+ newnode.i.csize = cnv_e32 (node->i.csize);
+ newnode.i.dsize = cnv_e32 (node->i.dsize);
+ newnode.i.compr = node->i.compr;
+ newnode.i.usercompr = node->i.usercompr;
+ newnode.i.flags = cnv_e16 (node->i.flags);
+ if (recalccrc) {
+ len = je32_to_cpu(node->i.csize);
+ newnode.i.data_crc = cpu_to_e32 ( crc32(0, p + sizeof (struct jffs2_raw_inode), len));
+ } else
+ newnode.i.data_crc = cnv_e32 (node->i.data_crc);
+
+ newnode.i.node_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_raw_inode) - 8));
+
+ write (fd, &newnode, sizeof (struct jffs2_raw_inode));
+ write (fd, p + sizeof (struct jffs2_raw_inode), PAD (je32_to_cpu (node->i.totlen) - sizeof (struct jffs2_raw_inode)));
+
+ p += PAD(je32_to_cpu (node->i.totlen));
+ break;
+
+ case JFFS2_NODETYPE_DIRENT:
+ newnode.d.magic = cnv_e16 (node->d.magic);
+ newnode.d.nodetype = cnv_e16 (node->d.nodetype);
+ newnode.d.totlen = cnv_e32 (node->d.totlen);
+ newnode.d.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+ newnode.d.pino = cnv_e32 (node->d.pino);
+ newnode.d.version = cnv_e32 (node->d.version);
+ newnode.d.ino = cnv_e32 (node->d.ino);
+ newnode.d.mctime = cnv_e32 (node->d.mctime);
+ newnode.d.nsize = node->d.nsize;
+ newnode.d.type = node->d.type;
+ newnode.d.unused[0] = node->d.unused[0];
+ newnode.d.unused[1] = node->d.unused[1];
+ newnode.d.node_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_raw_dirent) - 8));
+ if (recalccrc)
+ newnode.d.name_crc = cpu_to_e32 ( crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize));
+ else
+ newnode.d.name_crc = cnv_e32 (node->d.name_crc);
+
+ write (fd, &newnode, sizeof (struct jffs2_raw_dirent));
+ write (fd, p + sizeof (struct jffs2_raw_dirent), PAD (je32_to_cpu (node->d.totlen) - sizeof (struct jffs2_raw_dirent)));
+ p += PAD(je32_to_cpu (node->d.totlen));
+ break;
+
+ case JFFS2_NODETYPE_CLEANMARKER:
+ case JFFS2_NODETYPE_PADDING:
+ newnode.u.magic = cnv_e16 (node->u.magic);
+ newnode.u.nodetype = cnv_e16 (node->u.nodetype);
+ newnode.u.totlen = cnv_e32 (node->u.totlen);
+ newnode.u.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+
+ write (fd, &newnode, sizeof (struct jffs2_unknown_node));
+ len = PAD(je32_to_cpu (node->u.totlen) - sizeof (struct jffs2_unknown_node));
+ if (len > 0)
+ write (fd, p + sizeof (struct jffs2_unknown_node), len);
+
+ p += PAD(je32_to_cpu (node->u.totlen));
+ break;
+
+ case JFFS2_NODETYPE_SUMMARY : {
+ struct jffs2_sum_marker *sm_ptr;
+ int i,sum_len;
+ int counter = 0;
+
+ newnode.s.magic = cnv_e16 (node->s.magic);
+ newnode.s.nodetype = cnv_e16 (node->s.nodetype);
+ newnode.s.totlen = cnv_e32 (node->s.totlen);
+ newnode.s.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+ newnode.s.sum_num = cnv_e32 (node->s.sum_num);
+ newnode.s.cln_mkr = cnv_e32 (node->s.cln_mkr);
+ newnode.s.padded = cnv_e32 (node->s.padded);
+
+ newnode.s.node_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_raw_summary) - 8));
+
+ // summary header
+ p += sizeof (struct jffs2_raw_summary);
+
+ // summary data
+ sum_len = je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary) - sizeof (struct jffs2_sum_marker);
+
+ for (i=0; i<je32_to_cpu (node->s.sum_num); i++) {
+ union jffs2_sum_flash *fl_ptr;
+
+ fl_ptr = (union jffs2_sum_flash *) p;
+
+ switch (je16_to_cpu (fl_ptr->u.nodetype)) {
+ case JFFS2_NODETYPE_INODE:
+
+ fl_ptr->i.nodetype = cnv_e16 (fl_ptr->i.nodetype);
+ fl_ptr->i.inode = cnv_e32 (fl_ptr->i.inode);
+ fl_ptr->i.version = cnv_e32 (fl_ptr->i.version);
+ fl_ptr->i.offset = cnv_e32 (fl_ptr->i.offset);
+ fl_ptr->i.totlen = cnv_e32 (fl_ptr->i.totlen);
+ p += sizeof (struct jffs2_sum_inode_flash);
+ counter += sizeof (struct jffs2_sum_inode_flash);
+ break;
+
+ case JFFS2_NODETYPE_DIRENT:
+ fl_ptr->d.nodetype = cnv_e16 (fl_ptr->d.nodetype);
+ fl_ptr->d.totlen = cnv_e32 (fl_ptr->d.totlen);
+ fl_ptr->d.offset = cnv_e32 (fl_ptr->d.offset);
+ fl_ptr->d.pino = cnv_e32 (fl_ptr->d.pino);
+ fl_ptr->d.version = cnv_e32 (fl_ptr->d.version);
+ fl_ptr->d.ino = cnv_e32 (fl_ptr->d.ino);
+ p += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
+ counter += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
+ break;
+
+ default :
+ printf("Unknown node in summary information!!! nodetype(%x)\n", je16_to_cpu (fl_ptr->u.nodetype));
+ exit(EXIT_FAILURE);
+ break;
+ }
+
+ }
+
+ //pad
+ p += sum_len - counter;
+
+ // summary marker
+ sm_ptr = (struct jffs2_sum_marker *) p;
+ sm_ptr->offset = cnv_e32 (sm_ptr->offset);
+ sm_ptr->magic = cnv_e32 (sm_ptr->magic);
+ p += sizeof (struct jffs2_sum_marker);
+
+ // generate new crc on sum data
+ newnode.s.sum_crc = cpu_to_e32 ( crc32(0, ((char *) node) + sizeof (struct jffs2_raw_summary),
+ je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary)));
+
+ // write out new node header
+ write(fd, &newnode, sizeof (struct jffs2_raw_summary));
+ // write out new summary data
+ write(fd, &node->s.sum, sum_len + sizeof (struct jffs2_sum_marker));
+
+ break;
+ }
+
+ case 0xffff:
+ write (fd, p, 4);
+ p += 4;
+ break;
+
+ default:
+ printf ("Unknown node type: 0x%04x at 0x%08x, totlen 0x%08x\n", je16_to_cpu (node->u.nodetype), p - data, je32_to_cpu (node->u.totlen));
+ p += PAD(je32_to_cpu (node->u.totlen));
+
+ }
+ }
+
+ close (fd);
+
+}
+
+/*
+ * Main program
+ */
+int main(int argc, char **argv)
+{
+ int fd;
+
+ process_options(argc, argv);
+
+ /* Open the input file */
+ if ((fd = open(img, O_RDONLY)) == -1) {
+ perror("open input file");
+ exit(1);
+ }
+
+ // get image length
+ imglen = lseek(fd, 0, SEEK_END);
+ lseek (fd, 0, SEEK_SET);
+
+ data = malloc (imglen);
+ if (!data) {
+ perror("out of memory");
+ close (fd);
+ exit(1);
+ }
+
+ if (datsize && oobsize) {
+ int idx = 0;
+ long len = imglen;
+ uint8_t oob[oobsize];
+ printf ("Peeling data out of combined data/oob image\n");
+ while (len) {
+ // read image data
+ read (fd, &data[idx], datsize);
+ read (fd, oob, oobsize);
+ idx += datsize;
+ imglen -= oobsize;
+ len -= datsize + oobsize;
+ }
+
+ } else {
+ // read image data
+ read (fd, data, imglen);
+ }
+ // Close the input file
+ close(fd);
+
+ if (dumpcontent)
+ do_dumpcontent ();
+
+ if (convertendian)
+ do_endianconvert ();
+
+ // free memory
+ free (data);
+
+ // Return happy
+ exit (0);
+}
diff --git a/drivers/mtd/mtd-utils/jffs2reader.c b/drivers/mtd/mtd-utils/jffs2reader.c
new file mode 100644
index 00000000000..cde1d06ca6e
--- /dev/null
+++ b/drivers/mtd/mtd-utils/jffs2reader.c
@@ -0,0 +1,939 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * jffs2reader v0.0.18 A jffs2 image reader
+ *
+ * Copyright (c) 2001 Jari Kirma <Jari.Kirma@hut.fi>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose, including commercial applications, and to alter it and
+ * redistribute it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ * not claim that you wrote the original software. If you use this
+ * software in a product, an acknowledgment in the product
+ * documentation would be appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must
+ * not be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ *
+ *
+ *********
+ * This code was altered September 2001
+ * Changes are Copyright (c) Erik Andersen <andersen@codepoet.org>
+ *
+ * In compliance with (2) above, this is hereby marked as an altered
+ * version of this software. It has been altered as follows:
+ * *) Listing a directory now mimics the behavior of 'ls -l'
+ * *) Support for recursive listing has been added
+ * *) Without options, does a recursive 'ls' on the whole filesystem
+ * *) option parsing now uses getopt()
+ * *) Now uses printf, and error messages go to stderr.
+ * *) The copyright notice has been cleaned up and reformatted
+ * *) The code has been reformatted
+ * *) Several twisty code paths have been fixed so I can understand them.
+ * -Erik, 1 September 2001
+ *
+ * *) Made it show major/minor numbers for device nodes
+ * *) Made it show symlink targets
+ * -Erik, 13 September 2001
+ */
+
+
+/*
+TODO:
+
+- Add CRC checking code to places marked with XXX.
+- Add support for other node compression types.
+
+- Test with real life images.
+- Maybe port into bootloader.
+ */
+
+/*
+BUGS:
+
+- Doesn't check CRC checksums.
+ */
+
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <dirent.h>
+#include <zlib.h>
+#include <linux/jffs2.h>
+
+#define SCRATCH_SIZE (5*1024*1024)
+
+#ifndef MAJOR
+/* FIXME: I am using illicit insider knowledge of
+ * kernel major/minor representation... */
+#define MAJOR(dev) (((dev)>>8)&0xff)
+#define MINOR(dev) ((dev)&0xff)
+#endif
+
+
+#define DIRENT_INO(dirent) ((dirent)!=NULL?(dirent)->ino:0)
+#define DIRENT_PINO(dirent) ((dirent)!=NULL?(dirent)->pino:0)
+
+struct dir {
+ struct dir *next;
+ uint8_t type;
+ uint8_t nsize;
+ uint32_t ino;
+ char name[256];
+};
+
+void putblock(char *, size_t, size_t *, struct jffs2_raw_inode *);
+struct dir *putdir(struct dir *, struct jffs2_raw_dirent *);
+void printdir(char *o, size_t size, struct dir *d, char *path,
+ int recurse);
+void freedir(struct dir *);
+
+struct jffs2_raw_inode *find_raw_inode(char *o, size_t size, uint32_t ino);
+struct jffs2_raw_dirent *resolvedirent(char *, size_t, uint32_t, uint32_t,
+ char *, uint8_t);
+struct jffs2_raw_dirent *resolvename(char *, size_t, uint32_t, char *, uint8_t);
+struct jffs2_raw_dirent *resolveinode(char *, size_t, uint32_t);
+
+struct jffs2_raw_dirent *resolvepath0(char *, size_t, uint32_t, char *,
+ uint32_t *, int);
+struct jffs2_raw_dirent *resolvepath(char *, size_t, uint32_t, char *,
+ uint32_t *);
+
+void lsdir(char *, size_t, char *, int);
+void catfile(char *, size_t, char *, char *, size_t, size_t *);
+
+int main(int, char **);
+
+/* writes file node into buffer, to the proper position. */
+/* reading all valid nodes in version order reconstructs the file. */
+
+/*
+ b - buffer
+ bsize - buffer size
+ rsize - result size
+ n - node
+ */
+
+void putblock(char *b, size_t bsize, size_t * rsize,
+ struct jffs2_raw_inode *n)
+{
+ uLongf dlen = n->dsize;
+
+ if (n->isize > bsize || (n->offset + dlen) > bsize) {
+ fprintf(stderr, "File does not fit into buffer!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (*rsize < n->isize)
+ bzero(b + *rsize, n->isize - *rsize);
+
+ switch (n->compr) {
+ case JFFS2_COMPR_ZLIB:
+ uncompress((Bytef *) b + n->offset, &dlen,
+ (Bytef *) ((char *) n) + sizeof(struct jffs2_raw_inode),
+ (uLongf) n->csize);
+ break;
+
+ case JFFS2_COMPR_NONE:
+ memcpy(b + n->offset,
+ ((char *) n) + sizeof(struct jffs2_raw_inode), dlen);
+ break;
+
+ case JFFS2_COMPR_ZERO:
+ bzero(b + n->offset, dlen);
+ break;
+
+ /* [DYN]RUBIN support required! */
+
+ default:
+ fprintf(stderr, "Unsupported compression method!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ *rsize = n->isize;
+}
+
+/* adds/removes directory node into dir struct. */
+/* reading all valid nodes in version order reconstructs the directory. */
+
+/*
+ dd - directory struct being processed
+ n - node
+
+ return value: directory struct value replacing dd
+ */
+
+struct dir *putdir(struct dir *dd, struct jffs2_raw_dirent *n)
+{
+ struct dir *o, *d, *p;
+
+ o = dd;
+
+ if (n->ino) {
+ if (dd == NULL) {
+ d = malloc(sizeof(struct dir));
+ d->type = n->type;
+ memcpy(d->name, n->name, n->nsize);
+ d->nsize = n->nsize;
+ d->ino = n->ino;
+ d->next = NULL;
+
+ return d;
+ }
+
+ while (1) {
+ if (n->nsize == dd->nsize &&
+ !memcmp(n->name, dd->name, n->nsize)) {
+ dd->type = n->type;
+ dd->ino = n->ino;
+
+ return o;
+ }
+
+ if (dd->next == NULL) {
+ dd->next = malloc(sizeof(struct dir));
+ dd->next->type = n->type;
+ memcpy(dd->next->name, n->name, n->nsize);
+ dd->next->nsize = n->nsize;
+ dd->next->ino = n->ino;
+ dd->next->next = NULL;
+
+ return o;
+ }
+
+ dd = dd->next;
+ }
+ } else {
+ if (dd == NULL)
+ return NULL;
+
+ if (n->nsize == dd->nsize && !memcmp(n->name, dd->name, n->nsize)) {
+ d = dd->next;
+ free(dd);
+ return d;
+ }
+
+ while (1) {
+ p = dd;
+ dd = dd->next;
+
+ if (dd == NULL)
+ return o;
+
+ if (n->nsize == dd->nsize &&
+ !memcmp(n->name, dd->name, n->nsize)) {
+ p->next = dd->next;
+ free(dd);
+
+ return o;
+ }
+ }
+ }
+}
+
+
+#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
+#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
+
+/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
+static const mode_t SBIT[] = {
+ 0, 0, S_ISUID,
+ 0, 0, S_ISGID,
+ 0, 0, S_ISVTX
+};
+
+/* The 9 mode bits to test */
+static const mode_t MBIT[] = {
+ S_IRUSR, S_IWUSR, S_IXUSR,
+ S_IRGRP, S_IWGRP, S_IXGRP,
+ S_IROTH, S_IWOTH, S_IXOTH
+};
+
+static const char MODE1[] = "rwxrwxrwx";
+static const char MODE0[] = "---------";
+static const char SMODE1[] = "..s..s..t";
+static const char SMODE0[] = "..S..S..T";
+
+/*
+ * Return the standard ls-like mode string from a file mode.
+ * This is static and so is overwritten on each call.
+ */
+const char *mode_string(int mode)
+{
+ static char buf[12];
+
+ int i;
+
+ buf[0] = TYPECHAR(mode);
+ for (i = 0; i < 9; i++) {
+ if (mode & SBIT[i])
+ buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
+ else
+ buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
+ }
+ return buf;
+}
+
+/* prints contents of directory structure */
+
+/*
+ d - dir struct
+ */
+
+void printdir(char *o, size_t size, struct dir *d, char *path, int recurse)
+{
+ char m;
+ char *filetime;
+ time_t age;
+ struct jffs2_raw_inode *ri;
+
+ if (!path)
+ return;
+ if (strlen(path) == 1 && *path == '/')
+ path++;
+
+ while (d != NULL) {
+ switch (d->type) {
+ case DT_REG:
+ m = ' ';
+ break;
+
+ case DT_FIFO:
+ m = '|';
+ break;
+
+ case DT_CHR:
+ m = ' ';
+ break;
+
+ case DT_BLK:
+ m = ' ';
+ break;
+
+ case DT_DIR:
+ m = '/';
+ break;
+
+ case DT_LNK:
+ m = ' ';
+ break;
+
+ case DT_SOCK:
+ m = '=';
+ break;
+
+ default:
+ m = '?';
+ }
+ ri = find_raw_inode(o, size, d->ino);
+ if (!ri) {
+ fprintf(stderr, "bug: raw_inode missing!\n");
+ d = d->next;
+ continue;
+ }
+
+ filetime = ctime((const time_t *) &(ri->ctime));
+ age = time(NULL) - ri->ctime;
+ printf("%s %-4d %-8d %-8d ", mode_string(ri->mode),
+ 1, ri->uid, ri->gid);
+ if ( d->type==DT_BLK || d->type==DT_CHR ) {
+ dev_t rdev;
+ size_t devsize;
+ putblock((char*)&rdev, sizeof(rdev), &devsize, ri);
+ printf("%4d, %3d ", (int)MAJOR(rdev), (int)MINOR(rdev));
+ } else {
+ printf("%9ld ", (long)ri->dsize);
+ }
+ d->name[d->nsize]='\0';
+ if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) {
+ /* hh:mm if less than 6 months old */
+ printf("%6.6s %5.5s %s/%s%c", filetime + 4, filetime + 11, path, d->name, m);
+ } else {
+ printf("%6.6s %4.4s %s/%s%c", filetime + 4, filetime + 20, path, d->name, m);
+ }
+ if (d->type == DT_LNK) {
+ char symbuf[1024];
+ size_t symsize;
+ putblock(symbuf, sizeof(symbuf), &symsize, ri);
+ symbuf[symsize] = 0;
+ printf(" -> %s", symbuf);
+ }
+ printf("\n");
+
+ if (d->type == DT_DIR && recurse) {
+ char *tmp;
+ tmp = malloc(BUFSIZ);
+ if (!tmp) {
+ fprintf(stderr, "memory exhausted\n");
+ exit(EXIT_FAILURE);
+ }
+ sprintf(tmp, "%s/%s", path, d->name);
+ lsdir(o, size, tmp, recurse); /* Go recursive */
+ free(tmp);
+ }
+
+ d = d->next;
+ }
+}
+
+/* frees memory used by directory structure */
+
+/*
+ d - dir struct
+ */
+
+void freedir(struct dir *d)
+{
+ struct dir *t;
+
+ while (d != NULL) {
+ t = d->next;
+ free(d);
+ d = t;
+ }
+}
+
+/* collects directory/file nodes in version order. */
+
+/*
+ f - file flag.
+ if zero, collect file, compare ino to inode
+ otherwise, collect directory, compare ino to parent inode
+ o - filesystem image pointer
+ size - size of filesystem image
+ ino - inode to compare against. see f.
+
+ return value: a jffs2_raw_inode that corresponds the the specified
+ inode, or NULL
+ */
+
+struct jffs2_raw_inode *find_raw_inode(char *o, size_t size, uint32_t ino)
+{
+ /* aligned! */
+ union jffs2_node_union *n;
+ union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
+ union jffs2_node_union *lr; /* last block position */
+ union jffs2_node_union *mp = NULL; /* minimum position */
+
+ uint32_t vmin, vmint, vmaxt, vmax, vcur, v;
+
+ vmin = 0; /* next to read */
+ vmax = ~((uint32_t) 0); /* last to read */
+ vmint = ~((uint32_t) 0);
+ vmaxt = 0; /* found maximum */
+ vcur = 0; /* XXX what is smallest version number used? */
+ /* too low version number can easily result excess log rereading */
+
+ n = (union jffs2_node_union *) o;
+ lr = n;
+
+ do {
+ while (n < e && n->u.magic != JFFS2_MAGIC_BITMASK)
+ ((char *) n) += 4;
+
+ if (n < e && n->u.magic == JFFS2_MAGIC_BITMASK) {
+ if (n->u.nodetype == JFFS2_NODETYPE_INODE &&
+ n->i.ino == ino && (v = n->i.version) > vcur) {
+ /* XXX crc check */
+
+ if (vmaxt < v)
+ vmaxt = v;
+ if (vmint > v) {
+ vmint = v;
+ mp = n;
+ }
+
+ if (v == (vcur + 1))
+ return (&(n->i));
+ }
+
+ ((char *) n) += ((n->u.totlen + 3) & ~3);
+ } else
+ n = (union jffs2_node_union *) o; /* we're at the end, rewind to the beginning */
+
+ if (lr == n) { /* whole loop since last read */
+ vmax = vmaxt;
+ vmin = vmint;
+ vmint = ~((uint32_t) 0);
+
+ if (vcur < vmax && vcur < vmin)
+ return (&(mp->i));
+ }
+ } while (vcur < vmax);
+
+ return NULL;
+}
+
+/* collects dir struct for selected inode */
+
+/*
+ o - filesystem image pointer
+ size - size of filesystem image
+ pino - inode of the specified directory
+ d - input directory structure
+
+ return value: result directory structure, replaces d.
+ */
+
+struct dir *collectdir(char *o, size_t size, uint32_t ino, struct dir *d)
+{
+ /* aligned! */
+ union jffs2_node_union *n;
+ union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
+ union jffs2_node_union *lr; /* last block position */
+ union jffs2_node_union *mp = NULL; /* minimum position */
+
+ uint32_t vmin, vmint, vmaxt, vmax, vcur, v;
+
+ vmin = 0; /* next to read */
+ vmax = ~((uint32_t) 0); /* last to read */
+ vmint = ~((uint32_t) 0);
+ vmaxt = 0; /* found maximum */
+ vcur = 0; /* XXX what is smallest version number used? */
+ /* too low version number can easily result excess log rereading */
+
+ n = (union jffs2_node_union *) o;
+ lr = n;
+
+ do {
+ while (n < e && n->u.magic != JFFS2_MAGIC_BITMASK)
+ ((char *) n) += 4;
+
+ if (n < e && n->u.magic == JFFS2_MAGIC_BITMASK) {
+ if (n->u.nodetype == JFFS2_NODETYPE_DIRENT &&
+ n->d.pino == ino && (v = n->d.version) > vcur) {
+ /* XXX crc check */
+
+ if (vmaxt < v)
+ vmaxt = v;
+ if (vmint > v) {
+ vmint = v;
+ mp = n;
+ }
+
+ if (v == (vcur + 1)) {
+ d = putdir(d, &(n->d));
+
+ lr = n;
+ vcur++;
+ vmint = ~((uint32_t) 0);
+ }
+ }
+
+ ((char *) n) += ((n->u.totlen + 3) & ~3);
+ } else
+ n = (union jffs2_node_union *) o; /* we're at the end, rewind to the beginning */
+
+ if (lr == n) { /* whole loop since last read */
+ vmax = vmaxt;
+ vmin = vmint;
+ vmint = ~((uint32_t) 0);
+
+ if (vcur < vmax && vcur < vmin) {
+ d = putdir(d, &(mp->d));
+
+ lr = n =
+ (union jffs2_node_union *) (((char *) mp) +
+ ((mp->u.totlen + 3) & ~3));
+
+ vcur = vmin;
+ }
+ }
+ } while (vcur < vmax);
+
+ return d;
+}
+
+
+
+/* resolve dirent based on criteria */
+
+/*
+ o - filesystem image pointer
+ size - size of filesystem image
+ ino - if zero, ignore,
+ otherwise compare against dirent inode
+ pino - if zero, ingore,
+ otherwise compare against parent inode
+ and use name and nsize as extra criteria
+ name - name of wanted dirent, used if pino!=0
+ nsize - length of name of wanted dirent, used if pino!=0
+
+ return value: pointer to relevant dirent structure in
+ filesystem image or NULL
+ */
+
+struct jffs2_raw_dirent *resolvedirent(char *o, size_t size,
+ uint32_t ino, uint32_t pino,
+ char *name, uint8_t nsize)
+{
+ /* aligned! */
+ union jffs2_node_union *n;
+ union jffs2_node_union *e = (union jffs2_node_union *) (o + size);
+
+ struct jffs2_raw_dirent *dd = NULL;
+
+ uint32_t vmax, v;
+
+ if (!pino && ino <= 1)
+ return dd;
+
+ vmax = 0;
+
+ n = (union jffs2_node_union *) o;
+
+ do {
+ while (n < e && n->u.magic != JFFS2_MAGIC_BITMASK)
+ ((char *) n) += 4;
+
+ if (n < e && n->u.magic == JFFS2_MAGIC_BITMASK) {
+ if (n->u.nodetype == JFFS2_NODETYPE_DIRENT &&
+ (!ino || n->d.ino == ino) &&
+ (v = n->d.version) > vmax &&
+ (!pino || (n->d.pino == pino &&
+ nsize == n->d.nsize &&
+ !memcmp(name, n->d.name, nsize)))) {
+ /* XXX crc check */
+
+ if (vmax < v) {
+ vmax = v;
+ dd = &(n->d);
+ }
+ }
+
+ ((char *) n) += ((n->u.totlen + 3) & ~3);
+ } else
+ return dd;
+ } while (1);
+}
+
+/* resolve name under certain parent inode to dirent */
+
+/*
+ o - filesystem image pointer
+ size - size of filesystem image
+ pino - requested parent inode
+ name - name of wanted dirent
+ nsize - length of name of wanted dirent
+
+ return value: pointer to relevant dirent structure in
+ filesystem image or NULL
+ */
+
+struct jffs2_raw_dirent *resolvename(char *o, size_t size, uint32_t pino,
+ char *name, uint8_t nsize)
+{
+ return resolvedirent(o, size, 0, pino, name, nsize);
+}
+
+/* resolve inode to dirent */
+
+/*
+ o - filesystem image pointer
+ size - size of filesystem image
+ ino - compare against dirent inode
+
+ return value: pointer to relevant dirent structure in
+ filesystem image or NULL
+ */
+
+struct jffs2_raw_dirent *resolveinode(char *o, size_t size, uint32_t ino)
+{
+ return resolvedirent(o, size, ino, 0, NULL, 0);
+}
+
+/* resolve slash-style path into dirent and inode.
+ slash as first byte marks absolute path (root=inode 1).
+ . and .. are resolved properly, and symlinks are followed.
+ */
+
+/*
+ o - filesystem image pointer
+ size - size of filesystem image
+ ino - root inode, used if path is relative
+ p - path to be resolved
+ inos - result inode, zero if failure
+ recc - recursion count, to detect symlink loops
+
+ return value: pointer to dirent struct in file system image.
+ note that root directory doesn't have dirent struct
+ (return value is NULL), but it has inode (*inos=1)
+ */
+
+struct jffs2_raw_dirent *resolvepath0(char *o, size_t size, uint32_t ino,
+ char *p, uint32_t * inos, int recc)
+{
+ struct jffs2_raw_dirent *dir = NULL;
+
+ int d = 1;
+ uint32_t tino;
+
+ char *next;
+
+ char *path, *pp;
+
+ char symbuf[1024];
+ size_t symsize;
+
+ if (recc > 16) {
+ /* probably symlink loop */
+ *inos = 0;
+ return NULL;
+ }
+
+ pp = path = strdup(p);
+
+ if (*path == '/') {
+ path++;
+ ino = 1;
+ }
+
+ if (ino > 1) {
+ dir = resolveinode(o, size, ino);
+
+ ino = DIRENT_INO(dir);
+ }
+
+ next = path - 1;
+
+ while (ino && next != NULL && next[1] != 0 && d) {
+ path = next + 1;
+ next = strchr(path, '/');
+
+ if (next != NULL)
+ *next = 0;
+
+ if (*path == '.' && path[1] == 0)
+ continue;
+ if (*path == '.' && path[1] == '.' && path[2] == 0) {
+ if (DIRENT_PINO(dir) == 1) {
+ ino = 1;
+ dir = NULL;
+ } else {
+ dir = resolveinode(o, size, DIRENT_PINO(dir));
+ ino = DIRENT_INO(dir);
+ }
+
+ continue;
+ }
+
+ dir = resolvename(o, size, ino, path, (uint8_t) strlen(path));
+
+ if (DIRENT_INO(dir) == 0 ||
+ (next != NULL &&
+ !(dir->type == DT_DIR || dir->type == DT_LNK))) {
+ free(pp);
+
+ *inos = 0;
+
+ return NULL;
+ }
+
+ if (dir->type == DT_LNK) {
+ struct jffs2_raw_inode *ri;
+ ri = find_raw_inode(o, size, DIRENT_INO(dir));
+ putblock(symbuf, sizeof(symbuf), &symsize, ri);
+ symbuf[symsize] = 0;
+
+ tino = ino;
+ ino = 0;
+
+ dir = resolvepath0(o, size, tino, symbuf, &ino, ++recc);
+
+ if (dir != NULL && next != NULL &&
+ !(dir->type == DT_DIR || dir->type == DT_LNK)) {
+ free(pp);
+
+ *inos = 0;
+ return NULL;
+ }
+ }
+ if (dir != NULL)
+ ino = DIRENT_INO(dir);
+ }
+
+ free(pp);
+
+ *inos = ino;
+
+ return dir;
+}
+
+/* resolve slash-style path into dirent and inode.
+ slash as first byte marks absolute path (root=inode 1).
+ . and .. are resolved properly, and symlinks are followed.
+ */
+
+/*
+ o - filesystem image pointer
+ size - size of filesystem image
+ ino - root inode, used if path is relative
+ p - path to be resolved
+ inos - result inode, zero if failure
+
+ return value: pointer to dirent struct in file system image.
+ note that root directory doesn't have dirent struct
+ (return value is NULL), but it has inode (*inos=1)
+ */
+
+struct jffs2_raw_dirent *resolvepath(char *o, size_t size, uint32_t ino,
+ char *p, uint32_t * inos)
+{
+ return resolvepath0(o, size, ino, p, inos, 0);
+}
+
+/* lists files on directory specified by path */
+
+/*
+ o - filesystem image pointer
+ size - size of filesystem image
+ p - path to be resolved
+ */
+
+void lsdir(char *o, size_t size, char *path, int recurse)
+{
+ struct jffs2_raw_dirent *dd;
+ struct dir *d = NULL;
+
+ uint32_t ino;
+
+ dd = resolvepath(o, size, 1, path, &ino);
+
+ if (ino == 0 ||
+ (dd == NULL && ino == 0) || (dd != NULL && dd->type != DT_DIR)) {
+ fprintf(stderr, "jffs2reader: %s: No such file or directory\n",
+ path);
+ exit(EXIT_FAILURE);
+ }
+
+ d = collectdir(o, size, ino, d);
+ printdir(o, size, d, path, recurse);
+ freedir(d);
+}
+
+/* writes file specified by path to the buffer */
+
+/*
+ o - filesystem image pointer
+ size - size of filesystem image
+ p - path to be resolved
+ b - file buffer
+ bsize - file buffer size
+ rsize - file result size
+ */
+
+void catfile(char *o, size_t size, char *path, char *b, size_t bsize,
+ size_t * rsize)
+{
+ struct jffs2_raw_dirent *dd;
+ struct jffs2_raw_inode *ri;
+ uint32_t ino;
+
+ dd = resolvepath(o, size, 1, path, &ino);
+
+ if (ino == 0) {
+ fprintf(stderr, "%s: No such file or directory\n", path);
+ exit(EXIT_FAILURE);
+ }
+
+ if (dd == NULL || dd->type != DT_REG) {
+ fprintf(stderr, "%s: Not a regular file\n", path);
+ exit(EXIT_FAILURE);
+ }
+
+ ri = find_raw_inode(o, size, ino);
+ putblock(b, bsize, rsize, ri);
+
+ write(1, b, *rsize);
+}
+
+/* usage example */
+
+int main(int argc, char **argv)
+{
+ int fd, opt, recurse = 0;
+ struct stat st;
+
+ char *scratch, *dir = NULL, *file = NULL;
+ size_t ssize = 0;
+
+ char *buf;
+
+ while ((opt = getopt(argc, argv, "rd:f:")) > 0) {
+ switch (opt) {
+ case 'd':
+ dir = optarg;
+ break;
+ case 'f':
+ file = optarg;
+ break;
+ case 'r':
+ recurse++;
+ break;
+ default:
+ fprintf(stderr,
+ "Usage: jffs2reader <image> [-d|-f] < path > \n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ fd = open(argv[optind], O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "%s: %s\n", argv[optind], strerror(errno));
+ exit(2);
+ }
+
+ if (fstat(fd, &st)) {
+ fprintf(stderr, "%s: %s\n", argv[optind], strerror(errno));
+ exit(3);
+ }
+
+ buf = malloc((size_t) st.st_size);
+ if (buf == NULL) {
+ fprintf(stderr, "%s: memory exhausted\n", argv[optind]);
+ exit(4);
+ }
+
+ if (read(fd, buf, st.st_size) != (ssize_t) st.st_size) {
+ fprintf(stderr, "%s: %s\n", argv[optind], strerror(errno));
+ exit(5);
+ }
+
+ if (dir)
+ lsdir(buf, st.st_size, dir, recurse);
+
+ if (file) {
+ scratch = malloc(SCRATCH_SIZE);
+ if (scratch == NULL) {
+ fprintf(stderr, "%s: memory exhausted\n", argv[optind]);
+ exit(6);
+ }
+
+ catfile(buf, st.st_size, file, scratch, SCRATCH_SIZE, &ssize);
+ free(scratch);
+ }
+
+ if (!dir && !file)
+ lsdir(buf, st.st_size, "/", 1);
+
+
+ free(buf);
+ exit(EXIT_SUCCESS);
+}
diff --git a/drivers/mtd/mtd-utils/load_nandsim.sh b/drivers/mtd/mtd-utils/load_nandsim.sh
new file mode 100644
index 00000000000..bda3c790cf5
--- /dev/null
+++ b/drivers/mtd/mtd-utils/load_nandsim.sh
@@ -0,0 +1,123 @@
+#!/bin/bash
+
+#
+# This script inserts NAND simulator module to emulate NAND flash of specified
+# size.
+#
+# Author: Artem Bityutskiy
+#
+
+# Check if nandsim module is loaded
+function nandsim_loaded()
+{
+ local NANDSIM=`lsmod | grep nandsim`
+ if [ -n "$NANDSIM" ]; then
+ return 1
+ fi
+ return 0
+}
+
+nandsim_loaded
+if (( $? != 0 )); then
+ echo "Error: nandsim is already loaded"
+ exit 1
+fi
+
+if (( $# < 1 )); then
+ echo "Load NAND simulator to simulate flash of a specified size."
+ echo ""
+ echo "Usage: ./load_nandsim.sh <size in MiB> <eraseblock size in KiB>"
+ echo " <page size (512 or 2048)>"
+ echo ""
+ echo "Only the first parameter is mandatory. Default eraseblock size"
+ echo "is 16KiB, default NAND page size is 512 bytes."
+ echo ""
+ echo "Only the following combinations are supported:"
+ echo "--------------------------------------------------"
+ echo "| size (MiB) | EB size (KiB) | Page size (bytes) |"
+ echo "--------------------------------------------------"
+ echo "| 16 | 16 | 512 |"
+ echo "| 32 | 16 | 512 |"
+ echo "| 64 | 16 | 512 |"
+ echo "| 128 | 16 | 512 |"
+ echo "| 256 | 16 | 512 |"
+ echo "| 64 | 64 | 2048 |"
+ echo "| 64 | 128 | 2048 |"
+ echo "| 64 | 256 | 2048 |"
+ echo "| 64 | 512 | 2048 |"
+ echo "| 128 | 64 | 2048 |"
+ echo "| 128 | 128 | 2048 |"
+ echo "| 128 | 256 | 2048 |"
+ echo "| 128 | 512 | 2048 |"
+ echo "| 256 | 64 | 2048 |"
+ echo "| 256 | 128 | 2048 |"
+ echo "| 256 | 256 | 2048 |"
+ echo "| 256 | 512 | 2048 |"
+ echo "| 512 | 64 | 2048 |"
+ echo "| 512 | 128 | 2048 |"
+ echo "| 512 | 256 | 2048 |"
+ echo "| 512 | 512 | 2048 |"
+ echo "| 1024 | 64 | 2048 |"
+ echo "| 1024 | 128 | 2048 |"
+ echo "| 1024 | 256 | 2048 |"
+ echo "| 1024 | 512 | 2048 |"
+ echo "--------------------------------------------------"
+ exit 1
+fi
+
+SZ=$1
+EBSZ=$2
+PGSZ=$3
+if [[ $# == '1' ]]; then
+ EBSZ=16
+ PGSZ=512
+elif [[ $# == '2' ]]; then
+ PGSZ=512
+fi
+
+if (( $PGSZ == 512 && $EBSZ != 16 )); then
+ echo "Error: only 16KiB eraseblocks are possible in case of 512 bytes page"
+ exit 1
+fi
+
+if (( $PGSZ == 512 )); then
+ case $SZ in
+ 16) modprobe nandsim first_id_byte=0x20 second_id_byte=0x33 ;;
+ 32) modprobe nandsim first_id_byte=0x20 second_id_byte=0x35 ;;
+ 64) modprobe nandsim first_id_byte=0x20 second_id_byte=0x36 ;;
+ 128) modprobe nandsim first_id_byte=0x20 second_id_byte=0x78 ;;
+ 256) modprobe nandsim first_id_byte=0x20 second_id_byte=0x71 ;;
+ *) echo "Flash size ${SZ}MiB is not supported, try 16, 32, 64 or 256"
+ exit 1 ;;
+ esac
+elif (( $PGSZ == 2048 )); then
+ case $EBSZ in
+ 64) FOURTH=0x05 ;;
+ 128) FOURTH=0x15 ;;
+ 256) FOURTH=0x25 ;;
+ 512) FOURTH=0x35 ;;
+ *) echo "Eraseblock ${EBSZ}KiB is not supported"
+ exit 1
+ esac
+
+ case $SZ in
+ 64) modprobe nandsim first_id_byte=0x20 second_id_byte=0xa2 third_id_byte=0x00 fourth_id_byte=$FOURTH ;;
+ 128) modprobe nandsim first_id_byte=0xec second_id_byte=0xa1 third_id_byte=0x00 fourth_id_byte=$FOURTH ;;
+ 256) modprobe nandsim first_id_byte=0x20 second_id_byte=0xaa third_id_byte=0x00 fourth_id_byte=$FOURTH ;;
+ 512) modprobe nandsim first_id_byte=0x20 second_id_byte=0xac third_id_byte=0x00 fourth_id_byte=$FOURTH ;;
+ 1024) modprobe nandsim first_id_byte=0xec second_id_byte=0xd3 third_id_byte=0x51 fourth_id_byte=$FOURTH ;;
+ *) echo "Unable to emulate ${SZ}MiB flash with ${EBSZ}KiB eraseblock"
+ exit 1
+ esac
+else
+ echo "Error: bad NAND page size ${PGSZ}KiB, it has to be either 512 or 2048"
+ exit 1
+fi
+
+if (( $? != 0 )); then
+ echo "Error: cannot load nandsim"
+ exit 1
+fi
+
+echo "Loaded NAND simulator (${SZ}MiB, ${EBSZ}KiB eraseblock, $PGSZ bytes NAND page)"
+exit 0
diff --git a/drivers/mtd/mtd-utils/mcast_image.h b/drivers/mtd/mtd-utils/mcast_image.h
new file mode 100644
index 00000000000..07b6e316ebb
--- /dev/null
+++ b/drivers/mtd/mtd-utils/mcast_image.h
@@ -0,0 +1,54 @@
+#include <stdint.h>
+
+#define PKT_SIZE 2820
+
+struct image_pkt_hdr {
+ uint32_t resend;
+ uint32_t totcrc;
+ uint32_t nr_blocks;
+ uint32_t blocksize;
+ uint32_t block_crc;
+ uint32_t block_nr;
+ uint32_t pkt_sequence;
+ uint16_t pkt_nr;
+ uint16_t nr_pkts;
+ uint32_t thislen;
+ uint32_t thiscrc;
+};
+
+struct image_pkt {
+ struct image_pkt_hdr hdr;
+ unsigned char data[PKT_SIZE];
+};
+
+struct fec_parms;
+
+/* k - number of actual data packets
+ * n - total number of packets including data and redundant packets
+ * (actual packet size isn't relevant here) */
+struct fec_parms *fec_new(int k, int n);
+void fec_free(struct fec_parms *p);
+
+/* src - array of (n) pointers to data packets
+ * fec - buffer for packet to be generated
+ * index - index of packet to be generated (0 <= index < n)
+ * sz - data packet size
+ *
+ * _linear version just takes a pointer to the raw data; no
+ * mucking about with packet pointers.
+ */
+void fec_encode(struct fec_parms *code, unsigned char *src[],
+ unsigned char *fec, int index, int sz);
+void fec_encode_linear(struct fec_parms *code, unsigned char *src,
+ unsigned char *fec, int index, int sz);
+
+/* data - array of (k) pointers to data packets, in arbitrary order (see i)
+ * i - indices of (data) packets
+ * sz - data packet size
+ *
+ * Will never fail as long as you give it (k) individual data packets.
+ * Will re-order the (data) pointers but not the indices -- data packets
+ * are ordered on return.
+ */
+int fec_decode(struct fec_parms *code, unsigned char *data[],
+ int i[], int sz);
diff --git a/drivers/mtd/mtd-utils/mkfs.jffs2.1 b/drivers/mtd/mtd-utils/mkfs.jffs2.1
new file mode 100644
index 00000000000..4080032e429
--- /dev/null
+++ b/drivers/mtd/mtd-utils/mkfs.jffs2.1
@@ -0,0 +1,259 @@
+.TH MKFS.JFFS2 1
+.SH NAME
+mkfs.jffs2 \- Create a JFFS2 file system image from directory
+.SH SYNOPSIS
+.B mkfs.jffs2
+[
+.B -p,--pad[=SIZE]
+]
+[
+.B -r,-d,--root
+.I directory
+]
+[
+.B -s,--pagesize=SIZE
+]
+[
+.B -e,--eraseblock=SIZE
+]
+[
+.B -c,--cleanmarker=SIZE
+]
+[
+.B -n,--no-cleanmarkers
+]
+[
+.B -o,--output
+.I image.jffs2
+]
+[
+.B -l,--little-endian
+]
+[
+.B -b,--big-endian
+]
+[
+.B -D,--devtable=FILE
+]
+[
+.B -f,--faketime
+]
+[
+.B -q,--squash
+]
+[
+.B -U,--squash-uids
+]
+[
+.B -P,--squash-perms
+]
+[
+.B --with-xattr
+]
+[
+.B --with-selinux
+]
+[
+.B --with-posix-acl
+]
+[
+.B -m,--compression-mode=MODE
+]
+[
+.B -x,--disable-compressor=NAME
+]
+[
+.B -X,--enable-compressor=NAME
+]
+[
+.B -y,--compressor-priority=PRIORITY:NAME
+]
+[
+.B -L,--list-compressors
+]
+[
+.B -t,--test-compression
+]
+[
+.B -h,--help
+]
+[
+.B -v,--verbose
+]
+[
+.B -V,--version
+]
+[
+.B -i,--incremental
+.I image.jffs2
+]
+
+.SH DESCRIPTION
+The program
+.B mkfs.jffs2
+creates a JFFS2 (Second Journalling Flash File System) file system
+image and writes the resulting image to the file specified by the
+.B -o
+option or by default to the standard output, unless the standard
+output is a terminal device in which case mkfs.jffs2 will abort.
+
+The file system image is created using the files and directories
+contained in the directory specified by the option
+.B -r
+or the present directory, if the
+.B -r
+option is not specified.
+
+Each block of the files to be placed into the file system image
+are compressed using one of the avaiable compressors depending
+on the selected compression mode.
+
+File systems are created with the same endianness as the host,
+unless the
+.B -b
+or
+.B -l
+options are specified. JFFS2 driver in the 2.4 Linux kernel only
+supported images having the same endianness as the CPU. As of 2.5.48,
+the kernel can be changed with a #define to accept images of the
+non-native endianness. Full bi-endian support in the kernel is not
+planned.
+
+It is unlikely that JFFS2 images are useful except in conjuction
+with the MTD (Memory Technology Device) drivers in the Linux
+kernel, since the JFFS2 file system driver in the kernel requires
+MTD devices.
+.SH OPTIONS
+Options that take SIZE arguments can be specified as either
+decimal (e.g., 65536), octal (0200000), or hexidecimal (0x1000).
+.TP
+.B -p, --pad[=SIZE]
+Pad output to SIZE bytes with 0xFF. If SIZE is not specified,
+the output is padded to the end of the final erase block.
+.TP
+.B -r, -d, --root=DIR
+Build file system from directory DIR. The default is the current
+directory.
+.TP
+.B -s, --pagesize=SIZE
+Use page size SIZE. The default is 4 KiB. This size is the
+maximum size of a data node.
+.TP
+.B -e, --eraseblock=SIZE
+Use erase block size SIZE. The default is 64 KiB. If you use a erase
+block size different than the erase block size of the target MTD
+device, JFFS2 may not perform optimally. If the SIZE specified is
+below 4096, the units are assumed to be KiB.
+.TP
+.B -c, --cleanmarker=SIZE
+Write \'CLEANMARKER\' nodes with the size specified. It is not
+normally appropriate to specify a size other than the default 12
+bytes.
+.TP
+.B -n, --no-cleanmarkers
+Do not write \'CLEANMARKER\' nodes to the beginning of each erase
+block. This option can be useful for creating JFFS2 images for
+use on NAND flash, and for creating images which are to be used
+on a variety of hardware with differing eraseblock sizes.
+.TP
+.B -o, --output=FILE
+Write JFFS2 image to file FILE. Default is the standard output.
+.TP
+.B -l, --little-endian
+Create a little-endian JFFS2 image. Default is to make an image
+with the same endianness as the host.
+.TP
+.B -b, --big-endian
+Create a big-endian JFFS2 image. Default is to make an image
+with the same endianness as the host.
+.TP
+.B -D, --devtable=FILE
+Use the named FILE as a device table file, for including devices and
+changing permissions in the created image when the user does not have
+appropriate permissions to create them on the file system used as
+source.
+.TP
+.B -f, --faketime
+Change all file timestamps to \'0\' for regression testing.
+.TP
+.B -q, --squash
+Squash permissions and owners, making all files be owned by root and
+removing write permission for \'group\' and \'other\'.
+.TP
+.B -U, --squash-uids
+Squash owners making all files be owned by root.
+.TP
+.B -P, --squash-perms
+Squash permissions, removing write permission for \'group\' and \'other\'.
+.TP
+.B --with-xattr
+Enables xattr, stuff all xattr entries into jffs2 image file.
+.TP
+.B --with-selinux
+Enables xattr, stuff only SELinux Labels into jffs2 image file.
+.TP
+.B --with-posix-acl
+Enable xattr, stuff only POSIX ACL entries into jffs2 image file.
+.TP
+.B -m, --compression-mode=MODE
+Set the default compression mode. The default mode is
+.B priority
+which tries the compressors in a predefinied order and chooses the first
+successful one. The alternatives are:
+.B none
+(mkfs will not compress) and
+.B size
+(mkfs will try all compressor and chooses the one which have the smallest result).
+.TP
+.B -x, --disable-compressor=NAME
+Disable a compressor. Use
+.B -L
+to see the list of the avaiable compressors and their default states.
+.TP
+.B -X, --enable-compressor=NAME
+Enable a compressor. Use
+.B -L
+to see the list of the avaiable compressors and their default states.
+.TP
+.B -y, --compressor-priority=PRIORITY:NAME
+Set the priority of a compressor. Use
+.B -L
+to see the list of the avaiable compressors and their default priority.
+Priorities are used by priority compression mode.
+.TP
+.B -L, --list-compressors
+Show the list of the avaiable compressors and their states.
+.TP
+.B -t, --test-compression
+Call decompress after every compress - and compare the result with the original data -, and
+some other check.
+.TP
+.B -h, --help
+Display help text.
+.TP
+.B -v, --verbose
+Verbose operation.
+.TP
+.B -V, --version
+Display version information.
+.TP
+.B -i, --incremental=FILE
+Generate an appendage image for FILE. If FILE is written to flash and flash
+is appended with the output, then it seems as if it was one thing.
+
+.SH BUGS
+JFFS2 limits device major and minor numbers to 8 bits each. Some
+consider this a bug.
+
+.B mkfs.jffs2
+does not properly handle hard links in the input directory structure.
+Currently, hard linked files will be expanded to multiple identical
+files in the output image.
+.SH AUTHORS
+David Woodhouse
+.br
+Manual page written by David Schleef <ds@schleef.org>
+.SH SEE ALSO
+.BR mkfs (8),
+.BR mkfs.jffs (1),
+.BR fakeroot (1)
diff --git a/drivers/mtd/mtd-utils/mkfs.jffs2.c b/drivers/mtd/mtd-utils/mkfs.jffs2.c
new file mode 100644
index 00000000000..cdf2a5a834f
--- /dev/null
+++ b/drivers/mtd/mtd-utils/mkfs.jffs2.c
@@ -0,0 +1,1902 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Build a JFFS2 image in a file, from a given directory tree.
+ *
+ * Copyright 2001, 2002 Red Hat, Inc.
+ * 2001 David A. Schleef <ds@lineo.com>
+ * 2002 Axis Communications AB
+ * 2001, 2002 Erik Andersen <andersen@codepoet.org>
+ * 2004 University of Szeged, Hungary
+ * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Cross-endian support added by David Schleef <ds@schleef.org>.
+ *
+ * Major architectural rewrite by Erik Andersen <andersen@codepoet.org>
+ * to allow support for making hard links (though hard links support is
+ * not yet implemented), and for munging file permissions and ownership
+ * on the fly using --faketime, --squash, --devtable. And I plugged a
+ * few memory leaks, adjusted the error handling and fixed some little
+ * nits here and there.
+ *
+ * I also added a sample device table file. See device_table.txt
+ * -Erik, September 2001
+ *
+ * Cleanmarkers support added by Axis Communications AB
+ *
+ * Rewritten again. Cleanly separated host and target filsystem
+ * activities (mainly so I can reuse all the host handling stuff as I
+ * rewrite other mkfs utils). Added a verbose option to list types
+ * and attributes as files are added to the file system. Major cleanup
+ * and scrubbing of the code so it can be read, understood, and
+ * modified by mere mortals.
+ *
+ * -Erik, November 2002
+ */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <libgen.h>
+#include <ctype.h>
+#include <time.h>
+#include <getopt.h>
+#ifndef WITHOUT_XATTR
+#include <sys/xattr.h>
+#include <sys/acl.h>
+#endif
+#include <byteswap.h>
+#define crc32 __complete_crap
+#include <zlib.h>
+#undef crc32
+#include "crc32.h"
+#include "rbtree.h"
+
+/* Do not use the weird XPG version of basename */
+#undef basename
+
+//#define DMALLOC
+//#define mkfs_debug_msg error_msg
+#define mkfs_debug_msg(a...) { }
+#define min(x,y) ({ typeof((x)) _x = (x); typeof((y)) _y = (y); (_x>_y)?_y:_x; })
+
+#define PAD(x) (((x)+3)&~3)
+
+struct filesystem_entry {
+ char *name; /* Name of this directory (think basename) */
+ char *path; /* Path of this directory (think dirname) */
+ char *fullname; /* Full name of this directory (i.e. path+name) */
+ char *hostname; /* Full path to this file on the host filesystem */
+ uint32_t ino; /* Inode number of this file in JFFS2 */
+ struct stat sb; /* Stores directory permissions and whatnot */
+ char *link; /* Target a symlink points to. */
+ struct filesystem_entry *parent; /* Parent directory */
+ struct filesystem_entry *prev; /* Only relevant to non-directories */
+ struct filesystem_entry *next; /* Only relevant to non-directories */
+ struct filesystem_entry *files; /* Only relevant to directories */
+ struct rb_node hardlink_rb;
+};
+
+struct rb_root hardlinks;
+static int out_fd = -1;
+static int in_fd = -1;
+static char default_rootdir[] = ".";
+static char *rootdir = default_rootdir;
+static int verbose = 0;
+static int squash_uids = 0;
+static int squash_perms = 0;
+static int fake_times = 0;
+int target_endian = __BYTE_ORDER;
+static const char *const app_name = "mkfs.jffs2";
+static const char *const memory_exhausted = "memory exhausted";
+
+uint32_t find_hardlink(struct filesystem_entry *e)
+{
+ struct filesystem_entry *f;
+ struct rb_node **n = &hardlinks.rb_node;
+ struct rb_node *parent = NULL;
+
+ while (*n) {
+ parent = *n;
+ f = rb_entry(parent, struct filesystem_entry, hardlink_rb);
+
+ if ((f->sb.st_dev < e->sb.st_dev) ||
+ (f->sb.st_dev == e->sb.st_dev &&
+ f->sb.st_ino < e->sb.st_ino))
+ n = &parent->rb_left;
+ else if ((f->sb.st_dev > e->sb.st_dev) ||
+ (f->sb.st_dev == e->sb.st_dev &&
+ f->sb.st_ino > e->sb.st_ino)) {
+ n = &parent->rb_right;
+ } else
+ return f->ino;
+ }
+
+ rb_link_node(&e->hardlink_rb, parent, n);
+ rb_insert_color(&e->hardlink_rb, &hardlinks);
+ return 0;
+}
+
+static void verror_msg(const char *s, va_list p)
+{
+ fflush(stdout);
+ fprintf(stderr, "%s: ", app_name);
+ vfprintf(stderr, s, p);
+}
+static void error_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ verror_msg(s, p);
+ va_end(p);
+ putc('\n', stderr);
+}
+
+static void error_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ verror_msg(s, p);
+ va_end(p);
+ putc('\n', stderr);
+ exit(EXIT_FAILURE);
+}
+
+static void vperror_msg(const char *s, va_list p)
+{
+ int err = errno;
+
+ if (s == 0)
+ s = "";
+ verror_msg(s, p);
+ if (*s)
+ s = ": ";
+ fprintf(stderr, "%s%s\n", s, strerror(err));
+}
+
+static void perror_msg(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ vperror_msg(s, p);
+ va_end(p);
+}
+
+static void perror_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ vperror_msg(s, p);
+ va_end(p);
+ exit(EXIT_FAILURE);
+}
+
+#ifndef DMALLOC
+extern void *xmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+
+ if (ptr == NULL && size != 0)
+ error_msg_and_die(memory_exhausted);
+ return ptr;
+}
+
+extern void *xcalloc(size_t nmemb, size_t size)
+{
+ void *ptr = calloc(nmemb, size);
+
+ if (ptr == NULL && nmemb != 0 && size != 0)
+ error_msg_and_die(memory_exhausted);
+ return ptr;
+}
+
+extern void *xrealloc(void *ptr, size_t size)
+{
+ ptr = realloc(ptr, size);
+ if (ptr == NULL && size != 0)
+ error_msg_and_die(memory_exhausted);
+ return ptr;
+}
+
+extern char *xstrdup(const char *s)
+{
+ char *t;
+
+ if (s == NULL)
+ return NULL;
+ t = strdup(s);
+ if (t == NULL)
+ error_msg_and_die(memory_exhausted);
+ return t;
+}
+#endif
+
+extern char *xreadlink(const char *path)
+{
+ static const int GROWBY = 80; /* how large we will grow strings by */
+
+ char *buf = NULL;
+ int bufsize = 0, readsize = 0;
+
+ do {
+ buf = xrealloc(buf, bufsize += GROWBY);
+ readsize = readlink(path, buf, bufsize); /* 1st try */
+ if (readsize == -1) {
+ perror_msg("%s:%s", app_name, path);
+ return NULL;
+ }
+ }
+ while (bufsize < readsize + 1);
+
+ buf[readsize] = '\0';
+
+ return buf;
+}
+static FILE *xfopen(const char *path, const char *mode)
+{
+ FILE *fp;
+ if ((fp = fopen(path, mode)) == NULL)
+ perror_msg_and_die("%s", path);
+ return fp;
+}
+
+static struct filesystem_entry *find_filesystem_entry(
+ struct filesystem_entry *dir, char *fullname, uint32_t type)
+{
+ struct filesystem_entry *e = dir;
+
+ if (S_ISDIR(dir->sb.st_mode)) {
+ e = dir->files;
+ }
+ while (e) {
+ /* Only bother to do the expensive strcmp on matching file types */
+ if (type == (e->sb.st_mode & S_IFMT)) {
+ if (S_ISDIR(e->sb.st_mode)) {
+ int len = strlen(e->fullname);
+
+ /* Check if we are a parent of the correct path */
+ if (strncmp(e->fullname, fullname, len) == 0) {
+ /* Is this an _exact_ match? */
+ if (strcmp(fullname, e->fullname) == 0) {
+ return (e);
+ }
+ /* Looks like we found a parent of the correct path */
+ if (fullname[len] == '/') {
+ if (e->files) {
+ return (find_filesystem_entry (e, fullname, type));
+ } else {
+ return NULL;
+ }
+ }
+ }
+ } else {
+ if (strcmp(fullname, e->fullname) == 0) {
+ return (e);
+ }
+ }
+ }
+ e = e->next;
+ }
+ return (NULL);
+}
+
+static struct filesystem_entry *add_host_filesystem_entry(
+ char *name, char *path, unsigned long uid, unsigned long gid,
+ unsigned long mode, dev_t rdev, struct filesystem_entry *parent)
+{
+ int status;
+ char *tmp;
+ struct stat sb;
+ time_t timestamp = time(NULL);
+ struct filesystem_entry *entry;
+
+ memset(&sb, 0, sizeof(struct stat));
+ status = lstat(path, &sb);
+
+ if (status >= 0) {
+ /* It is ok for some types of files to not exit on disk (such as
+ * device nodes), but if they _do_ exist the specified mode had
+ * better match the actual file or strange things will happen.... */
+ if ((mode & S_IFMT) != (sb.st_mode & S_IFMT)) {
+ error_msg_and_die ("%s: file type does not match specified type!", path);
+ }
+ timestamp = sb.st_mtime;
+ } else {
+ /* If this is a regular file, it _must_ exist on disk */
+ if ((mode & S_IFMT) == S_IFREG) {
+ error_msg_and_die("%s: does not exist!", path);
+ }
+ }
+
+ /* Squash all permissions so files are owned by root, all
+ * timestamps are _right now_, and file permissions
+ * have group and other write removed */
+ if (squash_uids) {
+ uid = gid = 0;
+ }
+ if (squash_perms) {
+ if (!S_ISLNK(mode)) {
+ mode &= ~(S_IWGRP | S_IWOTH);
+ mode &= ~(S_ISUID | S_ISGID);
+ }
+ }
+ if (fake_times) {
+ timestamp = 0;
+ }
+
+ entry = xcalloc(1, sizeof(struct filesystem_entry));
+
+ entry->hostname = xstrdup(path);
+ entry->fullname = xstrdup(name);
+ tmp = xstrdup(name);
+ entry->name = xstrdup(basename(tmp));
+ free(tmp);
+ tmp = xstrdup(name);
+ entry->path = xstrdup(dirname(tmp));
+ free(tmp);
+
+ entry->sb.st_ino = sb.st_ino;
+ entry->sb.st_dev = sb.st_dev;
+ entry->sb.st_nlink = sb.st_nlink;
+
+ entry->sb.st_uid = uid;
+ entry->sb.st_gid = gid;
+ entry->sb.st_mode = mode;
+ entry->sb.st_rdev = rdev;
+ entry->sb.st_atime = entry->sb.st_ctime =
+ entry->sb.st_mtime = timestamp;
+ if (S_ISREG(mode)) {
+ entry->sb.st_size = sb.st_size;
+ }
+ if (S_ISLNK(mode)) {
+ entry->link = xreadlink(path);
+ entry->sb.st_size = strlen(entry->link);
+ }
+
+ /* This happens only for root */
+ if (!parent)
+ return (entry);
+
+ /* Hook the file into the parent directory */
+ entry->parent = parent;
+ if (!parent->files) {
+ parent->files = entry;
+ } else {
+ struct filesystem_entry *prev;
+ for (prev = parent->files; prev->next; prev = prev->next);
+ prev->next = entry;
+ entry->prev = prev;
+ }
+
+ return (entry);
+}
+
+static struct filesystem_entry *recursive_add_host_directory(
+ struct filesystem_entry *parent, char *targetpath, char *hostpath)
+{
+ int i, n;
+ struct stat sb;
+ char *hpath, *tpath;
+ struct dirent *dp, **namelist;
+ struct filesystem_entry *entry;
+
+
+ if (lstat(hostpath, &sb)) {
+ perror_msg_and_die("%s", hostpath);
+ }
+
+ entry = add_host_filesystem_entry(targetpath, hostpath,
+ sb.st_uid, sb.st_gid, sb.st_mode, 0, parent);
+
+ n = scandir(hostpath, &namelist, 0, alphasort);
+ if (n < 0) {
+ perror_msg_and_die("opening directory %s", hostpath);
+ }
+
+ for (i=0; i<n; i++)
+ {
+ dp = namelist[i];
+ if (dp->d_name[0] == '.' && (dp->d_name[1] == 0 ||
+ (dp->d_name[1] == '.' && dp->d_name[2] == 0)))
+ {
+ free(dp);
+ continue;
+ }
+
+ asprintf(&hpath, "%s/%s", hostpath, dp->d_name);
+ if (lstat(hpath, &sb)) {
+ perror_msg_and_die("%s", hpath);
+ }
+ if (strcmp(targetpath, "/") == 0) {
+ asprintf(&tpath, "%s%s", targetpath, dp->d_name);
+ } else {
+ asprintf(&tpath, "%s/%s", targetpath, dp->d_name);
+ }
+
+ switch (sb.st_mode & S_IFMT) {
+ case S_IFDIR:
+ recursive_add_host_directory(entry, tpath, hpath);
+ break;
+
+ case S_IFREG:
+ case S_IFSOCK:
+ case S_IFIFO:
+ case S_IFLNK:
+ case S_IFCHR:
+ case S_IFBLK:
+ add_host_filesystem_entry(tpath, hpath, sb.st_uid,
+ sb.st_gid, sb.st_mode, sb.st_rdev, entry);
+ break;
+
+ default:
+ error_msg("Unknown file type %o for %s", sb.st_mode, hpath);
+ break;
+ }
+ free(dp);
+ free(hpath);
+ free(tpath);
+ }
+ free(namelist);
+ return (entry);
+}
+
+/* the GNU C library has a wonderful scanf("%as", string) which will
+ allocate the string with the right size, good to avoid buffer overruns.
+ the following macros use it if available or use a hacky workaround...
+ */
+
+#ifdef __GNUC__
+#define SCANF_PREFIX "a"
+#define SCANF_STRING(s) (&s)
+#define GETCWD_SIZE 0
+#else
+#define SCANF_PREFIX "511"
+#define SCANF_STRING(s) (s = malloc(512))
+#define GETCWD_SIZE -1
+inline int snprintf(char *str, size_t n, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vsprintf(str, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+#endif
+
+/* device table entries take the form of:
+ <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
+ /dev/mem c 640 0 0 1 1 0 0 -
+
+ type can be one of:
+ f A regular file
+ d Directory
+ c Character special device file
+ b Block special device file
+ p Fifo (named pipe)
+
+ I don't bother with symlinks (permissions are irrelevant), hard
+ links (special cases of regular files), or sockets (why bother).
+
+ Regular files must exist in the target root directory. If a char,
+ block, fifo, or directory does not exist, it will be created.
+ */
+static int interpret_table_entry(struct filesystem_entry *root, char *line)
+{
+ char *hostpath;
+ char type, *name = NULL, *tmp, *dir;
+ unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;
+ unsigned long start = 0, increment = 1, count = 0;
+ struct filesystem_entry *parent, *entry;
+
+ if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",
+ SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,
+ &start, &increment, &count) < 0)
+ {
+ return 1;
+ }
+
+ if (!strcmp(name, "/")) {
+ error_msg_and_die("Device table entries require absolute paths");
+ }
+
+ asprintf(&hostpath, "%s%s", rootdir, name);
+
+ /* Check if this file already exists... */
+ switch (type) {
+ case 'd':
+ mode |= S_IFDIR;
+ break;
+ case 'f':
+ mode |= S_IFREG;
+ break;
+ case 'p':
+ mode |= S_IFIFO;
+ break;
+ case 'c':
+ mode |= S_IFCHR;
+ break;
+ case 'b':
+ mode |= S_IFBLK;
+ break;
+ default:
+ error_msg_and_die("Unsupported file type");
+ }
+ entry = find_filesystem_entry(root, name, mode);
+ if (entry) {
+ /* Ok, we just need to fixup the existing entry
+ * and we will be all done... */
+ entry->sb.st_uid = uid;
+ entry->sb.st_gid = gid;
+ entry->sb.st_mode = mode;
+ if (major && minor) {
+ entry->sb.st_rdev = makedev(major, minor);
+ }
+ } else {
+ /* If parent is NULL (happens with device table entries),
+ * try and find our parent now) */
+ tmp = strdup(name);
+ dir = dirname(tmp);
+ parent = find_filesystem_entry(root, dir, S_IFDIR);
+ free(tmp);
+ if (parent == NULL) {
+ error_msg ("skipping device_table entry '%s': no parent directory!", name);
+ free(name);
+ free(hostpath);
+ return 1;
+ }
+
+ switch (type) {
+ case 'd':
+ add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
+ break;
+ case 'f':
+ add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
+ break;
+ case 'p':
+ add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent);
+ break;
+ case 'c':
+ case 'b':
+ if (count > 0) {
+ dev_t rdev;
+ unsigned long i;
+ char *dname, *hpath;
+
+ for (i = start; i < count; i++) {
+ asprintf(&dname, "%s%lu", name, i);
+ asprintf(&hpath, "%s/%s%lu", rootdir, name, i);
+ rdev = makedev(major, minor + (i * increment - start));
+ add_host_filesystem_entry(dname, hpath, uid, gid,
+ mode, rdev, parent);
+ free(dname);
+ free(hpath);
+ }
+ } else {
+ dev_t rdev = makedev(major, minor);
+ add_host_filesystem_entry(name, hostpath, uid, gid,
+ mode, rdev, parent);
+ }
+ break;
+ default:
+ error_msg_and_die("Unsupported file type");
+ }
+ }
+ free(name);
+ free(hostpath);
+ return 0;
+}
+
+static int parse_device_table(struct filesystem_entry *root, FILE * file)
+{
+ char *line;
+ int status = 0;
+ size_t length = 0;
+
+ /* Turn off squash, since we must ensure that values
+ * entered via the device table are not squashed */
+ squash_uids = 0;
+ squash_perms = 0;
+
+ /* Looks ok so far. The general plan now is to read in one
+ * line at a time, check for leading comment delimiters ('#'),
+ * then try and parse the line as a device table. If we fail
+ * to parse things, try and help the poor fool to fix their
+ * device table with a useful error msg... */
+ line = NULL;
+ while (getline(&line, &length, file) != -1) {
+ /* First trim off any whitespace */
+ int len = strlen(line);
+
+ /* trim trailing whitespace */
+ while (len > 0 && isspace(line[len - 1]))
+ line[--len] = '\0';
+ /* trim leading whitespace */
+ memmove(line, &line[strspn(line, " \n\r\t\v")], len);
+
+ /* How long are we after trimming? */
+ len = strlen(line);
+
+ /* If this is NOT a comment line, try to interpret it */
+ if (len && *line != '#') {
+ if (interpret_table_entry(root, line))
+ status = 1;
+ }
+
+ free(line);
+ line = NULL;
+ }
+ fclose(file);
+
+ return status;
+}
+
+static void cleanup(struct filesystem_entry *dir)
+{
+ struct filesystem_entry *e, *prev;
+
+ e = dir->files;
+ while (e) {
+ if (e->name)
+ free(e->name);
+ if (e->path)
+ free(e->path);
+ if (e->fullname)
+ free(e->fullname);
+ e->next = NULL;
+ e->name = NULL;
+ e->path = NULL;
+ e->fullname = NULL;
+ e->prev = NULL;
+ prev = e;
+ if (S_ISDIR(e->sb.st_mode)) {
+ cleanup(e);
+ }
+ e = e->next;
+ free(prev);
+ }
+}
+
+/* Here is where we do the actual creation of the file system */
+#include "mtd/jffs2-user.h"
+
+#define JFFS2_MAX_FILE_SIZE 0xFFFFFFFF
+#ifndef JFFS2_MAX_SYMLINK_LEN
+#define JFFS2_MAX_SYMLINK_LEN 254
+#endif
+
+static uint32_t ino = 0;
+static uint8_t *file_buffer = NULL; /* file buffer contains the actual erase block*/
+static int out_ofs = 0;
+static int erase_block_size = 65536;
+static int pad_fs_size = 0;
+static int add_cleanmarkers = 1;
+static struct jffs2_unknown_node cleanmarker;
+static int cleanmarker_size = sizeof(cleanmarker);
+static unsigned char ffbuf[16] =
+{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+/* We set this at start of main() using sysconf(), -1 means we don't know */
+/* When building an fs for non-native systems, use --pagesize=SIZE option */
+int page_size = -1;
+
+#include "compr.h"
+
+static void full_write(int fd, const void *buf, int len)
+{
+ int ret;
+
+ while (len > 0) {
+ ret = write(fd, buf, len);
+
+ if (ret < 0)
+ perror_msg_and_die("write");
+
+ if (ret == 0)
+ perror_msg_and_die("write returned zero");
+
+ len -= ret;
+ buf += ret;
+ out_ofs += ret;
+ }
+}
+
+static void padblock(void)
+{
+ while (out_ofs % erase_block_size) {
+ full_write(out_fd, ffbuf, min(sizeof(ffbuf),
+ erase_block_size - (out_ofs % erase_block_size)));
+ }
+}
+
+static void pad(int req)
+{
+ while (req) {
+ if (req > sizeof(ffbuf)) {
+ full_write(out_fd, ffbuf, sizeof(ffbuf));
+ req -= sizeof(ffbuf);
+ } else {
+ full_write(out_fd, ffbuf, req);
+ req = 0;
+ }
+ }
+}
+
+static inline void padword(void)
+{
+ if (out_ofs % 4) {
+ full_write(out_fd, ffbuf, 4 - (out_ofs % 4));
+ }
+}
+
+static inline void pad_block_if_less_than(int req)
+{
+ if (add_cleanmarkers) {
+ if ((out_ofs % erase_block_size) == 0) {
+ full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
+ pad(cleanmarker_size - sizeof(cleanmarker));
+ padword();
+ }
+ }
+ if ((out_ofs % erase_block_size) + req > erase_block_size) {
+ padblock();
+ }
+ if (add_cleanmarkers) {
+ if ((out_ofs % erase_block_size) == 0) {
+ full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
+ pad(cleanmarker_size - sizeof(cleanmarker));
+ padword();
+ }
+ }
+}
+
+static void write_dirent(struct filesystem_entry *e)
+{
+ char *name = e->name;
+ struct jffs2_raw_dirent rd;
+ struct stat *statbuf = &(e->sb);
+ static uint32_t version = 0;
+
+ memset(&rd, 0, sizeof(rd));
+
+ rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+ rd.totlen = cpu_to_je32(sizeof(rd) + strlen(name));
+ rd.hdr_crc = cpu_to_je32(crc32(0, &rd,
+ sizeof(struct jffs2_unknown_node) - 4));
+ rd.pino = cpu_to_je32((e->parent) ? e->parent->ino : 1);
+ rd.version = cpu_to_je32(version++);
+ rd.ino = cpu_to_je32(e->ino);
+ rd.mctime = cpu_to_je32(statbuf->st_mtime);
+ rd.nsize = strlen(name);
+ rd.type = IFTODT(statbuf->st_mode);
+ //rd.unused[0] = 0;
+ //rd.unused[1] = 0;
+ rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd) - 8));
+ rd.name_crc = cpu_to_je32(crc32(0, name, strlen(name)));
+
+ pad_block_if_less_than(sizeof(rd) + rd.nsize);
+ full_write(out_fd, &rd, sizeof(rd));
+ full_write(out_fd, name, rd.nsize);
+ padword();
+}
+
+static unsigned int write_regular_file(struct filesystem_entry *e)
+{
+ int fd, len;
+ uint32_t ver;
+ unsigned int offset;
+ unsigned char *buf, *cbuf, *wbuf;
+ struct jffs2_raw_inode ri;
+ struct stat *statbuf;
+ unsigned int totcomp = 0;
+
+ statbuf = &(e->sb);
+ if (statbuf->st_size >= JFFS2_MAX_FILE_SIZE) {
+ error_msg("Skipping file \"%s\" too large.", e->path);
+ return -1;
+ }
+ fd = open(e->hostname, O_RDONLY);
+ if (fd == -1) {
+ perror_msg_and_die("%s: open file", e->hostname);
+ }
+
+ e->ino = ++ino;
+ mkfs_debug_msg("writing file '%s' ino=%lu parent_ino=%lu",
+ e->name, (unsigned long) e->ino,
+ (unsigned long) e->parent->ino);
+ write_dirent(e);
+
+ buf = xmalloc(page_size);
+ cbuf = NULL;
+
+ ver = 0;
+ offset = 0;
+
+ memset(&ri, 0, sizeof(ri));
+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+
+ ri.ino = cpu_to_je32(e->ino);
+ ri.mode = cpu_to_jemode(statbuf->st_mode);
+ ri.uid = cpu_to_je16(statbuf->st_uid);
+ ri.gid = cpu_to_je16(statbuf->st_gid);
+ ri.atime = cpu_to_je32(statbuf->st_atime);
+ ri.ctime = cpu_to_je32(statbuf->st_ctime);
+ ri.mtime = cpu_to_je32(statbuf->st_mtime);
+ ri.isize = cpu_to_je32(statbuf->st_size);
+
+ while ((len = read(fd, buf, page_size))) {
+ unsigned char *tbuf = buf;
+
+ if (len < 0) {
+ perror_msg_and_die("read");
+ }
+
+ while (len) {
+ uint32_t dsize, space;
+ uint16_t compression;
+
+ pad_block_if_less_than(sizeof(ri) + JFFS2_MIN_DATA_LEN);
+
+ dsize = len;
+ space =
+ erase_block_size - (out_ofs % erase_block_size) -
+ sizeof(ri);
+ if (space > dsize)
+ space = dsize;
+
+ compression = jffs2_compress(tbuf, &cbuf, &dsize, &space);
+
+ ri.compr = compression & 0xff;
+ ri.usercompr = (compression >> 8) & 0xff;
+
+ if (ri.compr) {
+ wbuf = cbuf;
+ } else {
+ wbuf = tbuf;
+ dsize = space;
+ }
+
+ ri.totlen = cpu_to_je32(sizeof(ri) + space);
+ ri.hdr_crc = cpu_to_je32(crc32(0,
+ &ri, sizeof(struct jffs2_unknown_node) - 4));
+
+ ri.version = cpu_to_je32(++ver);
+ ri.offset = cpu_to_je32(offset);
+ ri.csize = cpu_to_je32(space);
+ ri.dsize = cpu_to_je32(dsize);
+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8));
+ ri.data_crc = cpu_to_je32(crc32(0, wbuf, space));
+
+ full_write(out_fd, &ri, sizeof(ri));
+ totcomp += sizeof(ri);
+ full_write(out_fd, wbuf, space);
+ totcomp += space;
+ padword();
+
+ if (tbuf != cbuf) {
+ free(cbuf);
+ cbuf = NULL;
+ }
+
+ tbuf += dsize;
+ len -= dsize;
+ offset += dsize;
+
+ }
+ }
+ if (!je32_to_cpu(ri.version)) {
+ /* Was empty file */
+ pad_block_if_less_than(sizeof(ri));
+
+ ri.version = cpu_to_je32(++ver);
+ ri.totlen = cpu_to_je32(sizeof(ri));
+ ri.hdr_crc = cpu_to_je32(crc32(0,
+ &ri, sizeof(struct jffs2_unknown_node) - 4));
+ ri.csize = cpu_to_je32(0);
+ ri.dsize = cpu_to_je32(0);
+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8));
+
+ full_write(out_fd, &ri, sizeof(ri));
+ padword();
+ }
+ free(buf);
+ close(fd);
+ return totcomp;
+}
+
+static void write_symlink(struct filesystem_entry *e)
+{
+ int len;
+ struct stat *statbuf;
+ struct jffs2_raw_inode ri;
+
+ statbuf = &(e->sb);
+ e->ino = ++ino;
+ mkfs_debug_msg("writing symlink '%s' ino=%lu parent_ino=%lu",
+ e->name, (unsigned long) e->ino,
+ (unsigned long) e->parent->ino);
+ write_dirent(e);
+
+ len = strlen(e->link);
+ if (len > JFFS2_MAX_SYMLINK_LEN) {
+ error_msg("symlink too large. Truncated to %d chars.",
+ JFFS2_MAX_SYMLINK_LEN);
+ len = JFFS2_MAX_SYMLINK_LEN;
+ }
+
+ memset(&ri, 0, sizeof(ri));
+
+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+ ri.totlen = cpu_to_je32(sizeof(ri) + len);
+ ri.hdr_crc = cpu_to_je32(crc32(0,
+ &ri, sizeof(struct jffs2_unknown_node) - 4));
+
+ ri.ino = cpu_to_je32(e->ino);
+ ri.mode = cpu_to_jemode(statbuf->st_mode);
+ ri.uid = cpu_to_je16(statbuf->st_uid);
+ ri.gid = cpu_to_je16(statbuf->st_gid);
+ ri.atime = cpu_to_je32(statbuf->st_atime);
+ ri.ctime = cpu_to_je32(statbuf->st_ctime);
+ ri.mtime = cpu_to_je32(statbuf->st_mtime);
+ ri.isize = cpu_to_je32(statbuf->st_size);
+ ri.version = cpu_to_je32(1);
+ ri.csize = cpu_to_je32(len);
+ ri.dsize = cpu_to_je32(len);
+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8));
+ ri.data_crc = cpu_to_je32(crc32(0, e->link, len));
+
+ pad_block_if_less_than(sizeof(ri) + len);
+ full_write(out_fd, &ri, sizeof(ri));
+ full_write(out_fd, e->link, len);
+ padword();
+}
+
+static void write_pipe(struct filesystem_entry *e)
+{
+ struct stat *statbuf;
+ struct jffs2_raw_inode ri;
+
+ statbuf = &(e->sb);
+ e->ino = ++ino;
+ if (S_ISDIR(statbuf->st_mode)) {
+ mkfs_debug_msg("writing dir '%s' ino=%lu parent_ino=%lu",
+ e->name, (unsigned long) e->ino,
+ (unsigned long) (e->parent) ? e->parent->ino : 1);
+ }
+ write_dirent(e);
+
+ memset(&ri, 0, sizeof(ri));
+
+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+ ri.totlen = cpu_to_je32(sizeof(ri));
+ ri.hdr_crc = cpu_to_je32(crc32(0,
+ &ri, sizeof(struct jffs2_unknown_node) - 4));
+
+ ri.ino = cpu_to_je32(e->ino);
+ ri.mode = cpu_to_jemode(statbuf->st_mode);
+ ri.uid = cpu_to_je16(statbuf->st_uid);
+ ri.gid = cpu_to_je16(statbuf->st_gid);
+ ri.atime = cpu_to_je32(statbuf->st_atime);
+ ri.ctime = cpu_to_je32(statbuf->st_ctime);
+ ri.mtime = cpu_to_je32(statbuf->st_mtime);
+ ri.isize = cpu_to_je32(0);
+ ri.version = cpu_to_je32(1);
+ ri.csize = cpu_to_je32(0);
+ ri.dsize = cpu_to_je32(0);
+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8));
+ ri.data_crc = cpu_to_je32(0);
+
+ pad_block_if_less_than(sizeof(ri));
+ full_write(out_fd, &ri, sizeof(ri));
+ padword();
+}
+
+static void write_special_file(struct filesystem_entry *e)
+{
+ jint16_t kdev;
+ struct stat *statbuf;
+ struct jffs2_raw_inode ri;
+
+ statbuf = &(e->sb);
+ e->ino = ++ino;
+ write_dirent(e);
+
+ kdev = cpu_to_je16((major(statbuf->st_rdev) << 8) +
+ minor(statbuf->st_rdev));
+
+ memset(&ri, 0, sizeof(ri));
+
+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+ ri.totlen = cpu_to_je32(sizeof(ri) + sizeof(kdev));
+ ri.hdr_crc = cpu_to_je32(crc32(0,
+ &ri, sizeof(struct jffs2_unknown_node) - 4));
+
+ ri.ino = cpu_to_je32(e->ino);
+ ri.mode = cpu_to_jemode(statbuf->st_mode);
+ ri.uid = cpu_to_je16(statbuf->st_uid);
+ ri.gid = cpu_to_je16(statbuf->st_gid);
+ ri.atime = cpu_to_je32(statbuf->st_atime);
+ ri.ctime = cpu_to_je32(statbuf->st_ctime);
+ ri.mtime = cpu_to_je32(statbuf->st_mtime);
+ ri.isize = cpu_to_je32(statbuf->st_size);
+ ri.version = cpu_to_je32(1);
+ ri.csize = cpu_to_je32(sizeof(kdev));
+ ri.dsize = cpu_to_je32(sizeof(kdev));
+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8));
+ ri.data_crc = cpu_to_je32(crc32(0, &kdev, sizeof(kdev)));
+
+ pad_block_if_less_than(sizeof(ri) + sizeof(kdev));
+ full_write(out_fd, &ri, sizeof(ri));
+ full_write(out_fd, &kdev, sizeof(kdev));
+ padword();
+}
+
+#ifndef WITHOUT_XATTR
+typedef struct xattr_entry {
+ struct xattr_entry *next;
+ uint32_t xid;
+ int xprefix;
+ char *xname;
+ char *xvalue;
+ int name_len;
+ int value_len;
+} xattr_entry_t;
+
+#define XATTR_BUFFER_SIZE (64 * 1024) /* 64KB */
+static uint32_t enable_xattr = 0;
+static uint32_t highest_xid = 0;
+static uint32_t highest_xseqno = 0;
+
+static struct {
+ int xprefix;
+ char *string;
+ int length;
+} xprefix_tbl[] = {
+ { JFFS2_XPREFIX_USER, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN },
+ { JFFS2_XPREFIX_SECURITY, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
+ { JFFS2_XPREFIX_ACL_ACCESS, POSIX_ACL_XATTR_ACCESS, POSIX_ACL_XATTR_ACCESS_LEN },
+ { JFFS2_XPREFIX_ACL_DEFAULT, POSIX_ACL_XATTR_DEFAULT, POSIX_ACL_XATTR_DEFAULT_LEN },
+ { JFFS2_XPREFIX_TRUSTED, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN },
+ { 0, NULL, 0 }
+};
+
+static void formalize_posix_acl(void *xvalue, int *value_len)
+{
+ struct posix_acl_xattr_header *pacl_header;
+ struct posix_acl_xattr_entry *pent, *plim;
+ struct jffs2_acl_header *jacl_header;
+ struct jffs2_acl_entry *jent;
+ struct jffs2_acl_entry_short *jent_s;
+ char buffer[XATTR_BUFFER_SIZE];
+ int offset = 0;
+
+ pacl_header = xvalue;;
+ pent = pacl_header->a_entries;
+ plim = xvalue + *value_len;
+
+ jacl_header = (struct jffs2_acl_header *)buffer;
+ offset += sizeof(struct jffs2_acl_header);
+ jacl_header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
+
+ while (pent < plim) {
+ switch(le16_to_cpu(pent->e_tag)) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ jent_s = (struct jffs2_acl_entry_short *)(buffer + offset);
+ offset += sizeof(struct jffs2_acl_entry_short);
+ jent_s->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
+ jent_s->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
+ break;
+ case ACL_USER:
+ case ACL_GROUP:
+ jent = (struct jffs2_acl_entry *)(buffer + offset);
+ offset += sizeof(struct jffs2_acl_entry);
+ jent->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
+ jent->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
+ jent->e_id = cpu_to_je32(le32_to_cpu(pent->e_id));
+ break;
+ default:
+ printf("%04x : Unknown XATTR entry tag.\n", le16_to_cpu(pent->e_tag));
+ exit(1);
+ }
+ pent++;
+ }
+ if (offset > *value_len) {
+ printf("Length of JFFS2 ACL expression(%u) is longer than general one(%u).\n",
+ offset, *value_len);
+ exit(1);
+ }
+ memcpy(xvalue, buffer, offset);
+ *value_len = offset;
+}
+
+static xattr_entry_t *create_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
+{
+ xattr_entry_t *xe;
+ struct jffs2_raw_xattr rx;
+ int name_len;
+
+ /* create xattr entry */
+ name_len = strlen(xname);
+ xe = xcalloc(1, sizeof(xattr_entry_t) + name_len + 1 + value_len);
+ xe->next = NULL;
+ xe->xid = ++highest_xid;
+ xe->xprefix = xprefix;
+ xe->xname = ((char *)xe) + sizeof(xattr_entry_t);
+ xe->xvalue = xe->xname + name_len + 1;
+ xe->name_len = name_len;
+ xe->value_len = value_len;
+ strcpy(xe->xname, xname);
+ memcpy(xe->xvalue, xvalue, value_len);
+
+ /* write xattr node */
+ memset(&rx, 0, sizeof(rx));
+ rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
+ rx.totlen = cpu_to_je32(PAD(sizeof(rx) + xe->name_len + 1 + xe->value_len));
+ rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
+
+ rx.xid = cpu_to_je32(xe->xid);
+ rx.version = cpu_to_je32(1); /* initial version */
+ rx.xprefix = xprefix;
+ rx.name_len = xe->name_len;
+ rx.value_len = cpu_to_je16(xe->value_len);
+ rx.data_crc = cpu_to_je32(crc32(0, xe->xname, xe->name_len + 1 + xe->value_len));
+ rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(rx) - 4));
+
+ pad_block_if_less_than(sizeof(rx) + xe->name_len + 1 + xe->value_len);
+ full_write(out_fd, &rx, sizeof(rx));
+ full_write(out_fd, xe->xname, xe->name_len + 1 + xe->value_len);
+ padword();
+
+ return xe;
+}
+
+#define XATTRENTRY_HASHSIZE 57
+static xattr_entry_t *find_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
+{
+ static xattr_entry_t **xentry_hash = NULL;
+ xattr_entry_t *xe;
+ int index, name_len;
+
+ /* create hash table */
+ if (!xentry_hash)
+ xentry_hash = xcalloc(1, sizeof(xe) * XATTRENTRY_HASHSIZE);
+
+ if (xprefix == JFFS2_XPREFIX_ACL_ACCESS
+ || xprefix == JFFS2_XPREFIX_ACL_DEFAULT)
+ formalize_posix_acl(xvalue, &value_len);
+
+ name_len = strlen(xname);
+ index = (crc32(0, xname, name_len) ^ crc32(0, xvalue, value_len)) % XATTRENTRY_HASHSIZE;
+ for (xe = xentry_hash[index]; xe; xe = xe->next) {
+ if (xe->xprefix == xprefix
+ && xe->value_len == value_len
+ && !strcmp(xe->xname, xname)
+ && !memcmp(xe->xvalue, xvalue, value_len))
+ break;
+ }
+ if (!xe) {
+ xe = create_xattr_entry(xprefix, xname, xvalue, value_len);
+ xe->next = xentry_hash[index];
+ xentry_hash[index] = xe;
+ }
+ return xe;
+}
+
+static void write_xattr_entry(struct filesystem_entry *e)
+{
+ struct jffs2_raw_xref ref;
+ struct xattr_entry *xe;
+ char xlist[XATTR_BUFFER_SIZE], xvalue[XATTR_BUFFER_SIZE];
+ char *xname, *prefix_str;
+ int i, xprefix, prefix_len;
+ int list_sz, offset, name_len, value_len;
+
+ if (!enable_xattr)
+ return;
+
+ list_sz = llistxattr(e->hostname, xlist, XATTR_BUFFER_SIZE);
+ if (list_sz < 0) {
+ if (verbose)
+ printf("llistxattr('%s') = %d : %s\n",
+ e->hostname, errno, strerror(errno));
+ return;
+ }
+
+ for (offset = 0; offset < list_sz; offset += name_len) {
+ xname = xlist + offset;
+ name_len = strlen(xname) + 1;
+
+ for (i = 0; (xprefix = xprefix_tbl[i].xprefix); i++) {
+ prefix_str = xprefix_tbl[i].string;
+ prefix_len = xprefix_tbl[i].length;
+ if (prefix_str[prefix_len - 1] == '.') {
+ if (!strncmp(xname, prefix_str, prefix_len - 1))
+ break;
+ } else {
+ if (!strcmp(xname, prefix_str))
+ break;
+ }
+ }
+ if (!xprefix) {
+ if (verbose)
+ printf("%s: xattr '%s' is not supported.\n",
+ e->hostname, xname);
+ continue;
+ }
+ if ((enable_xattr & (1 << xprefix)) == 0)
+ continue;
+
+ value_len = lgetxattr(e->hostname, xname, xvalue, XATTR_BUFFER_SIZE);
+ if (value_len < 0) {
+ if (verbose)
+ printf("lgetxattr('%s', '%s') = %d : %s\n",
+ e->hostname, xname, errno, strerror(errno));
+ continue;
+ }
+ xe = find_xattr_entry(xprefix, xname + prefix_len, xvalue, value_len);
+ if (!xe) {
+ if (verbose)
+ printf("%s : xattr '%s' was ignored.\n",
+ e->hostname, xname);
+ continue;
+ }
+
+ memset(&ref, 0, sizeof(ref));
+ ref.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ ref.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF);
+ ref.totlen = cpu_to_je32(sizeof(ref));
+ ref.hdr_crc = cpu_to_je32(crc32(0, &ref, sizeof(struct jffs2_unknown_node) - 4));
+ ref.ino = cpu_to_je32(e->ino);
+ ref.xid = cpu_to_je32(xe->xid);
+ ref.xseqno = cpu_to_je32(highest_xseqno += 2);
+ ref.node_crc = cpu_to_je32(crc32(0, &ref, sizeof(ref) - 4));
+
+ pad_block_if_less_than(sizeof(ref));
+ full_write(out_fd, &ref, sizeof(ref));
+ padword();
+ }
+}
+
+#else /* WITHOUT_XATTR */
+#define write_xattr_entry(x)
+#endif
+
+static void recursive_populate_directory(struct filesystem_entry *dir)
+{
+ struct filesystem_entry *e;
+ unsigned int wrote;
+
+ if (verbose) {
+ printf("%s\n", dir->fullname);
+ }
+ write_xattr_entry(dir); /* for '/' */
+
+ e = dir->files;
+ while (e) {
+ if (e->sb.st_nlink >= 1 &&
+ (e->ino = find_hardlink(e))) {
+
+ write_dirent(e);
+ if (verbose) {
+ printf("\tL %04o %9lu %5d:%-3d %s\n",
+ e->sb.st_mode & ~S_IFMT, (unsigned long) e->ino,
+ (int) (e->sb.st_uid), (int) (e->sb.st_gid),
+ e->name);
+ }
+ } else switch (e->sb.st_mode & S_IFMT) {
+ case S_IFDIR:
+ if (verbose) {
+ printf("\td %04o %9lu %5d:%-3d %s\n",
+ e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+ (int) (e->sb.st_uid), (int) (e->sb.st_gid),
+ e->name);
+ }
+ write_pipe(e);
+ write_xattr_entry(e);
+ break;
+ case S_IFSOCK:
+ if (verbose) {
+ printf("\ts %04o %9lu %5d:%-3d %s\n",
+ e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+ (int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
+ }
+ write_pipe(e);
+ write_xattr_entry(e);
+ break;
+ case S_IFIFO:
+ if (verbose) {
+ printf("\tp %04o %9lu %5d:%-3d %s\n",
+ e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+ (int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
+ }
+ write_pipe(e);
+ write_xattr_entry(e);
+ break;
+ case S_IFCHR:
+ if (verbose) {
+ printf("\tc %04o %4d,%4d %5d:%-3d %s\n",
+ e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev),
+ minor(e->sb.st_rdev), (int) e->sb.st_uid,
+ (int) e->sb.st_gid, e->name);
+ }
+ write_special_file(e);
+ write_xattr_entry(e);
+ break;
+ case S_IFBLK:
+ if (verbose) {
+ printf("\tb %04o %4d,%4d %5d:%-3d %s\n",
+ e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev),
+ minor(e->sb.st_rdev), (int) e->sb.st_uid,
+ (int) e->sb.st_gid, e->name);
+ }
+ write_special_file(e);
+ write_xattr_entry(e);
+ break;
+ case S_IFLNK:
+ if (verbose) {
+ printf("\tl %04o %9lu %5d:%-3d %s -> %s\n",
+ e->sb.st_mode & ~S_IFMT, e->sb.st_size,
+ (int) e->sb.st_uid, (int) e->sb.st_gid, e->name,
+ e->link);
+ }
+ write_symlink(e);
+ write_xattr_entry(e);
+ break;
+ case S_IFREG:
+ wrote = write_regular_file(e);
+ write_xattr_entry(e);
+ if (verbose) {
+ printf("\tf %04o %9lu (%9u) %5d:%-3d %s\n",
+ e->sb.st_mode & ~S_IFMT, e->sb.st_size, wrote,
+ (int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
+ }
+ break;
+ default:
+ error_msg("Unknown mode %o for %s", e->sb.st_mode,
+ e->fullname);
+ break;
+ }
+ e = e->next;
+ }
+
+ e = dir->files;
+ while (e) {
+ if (S_ISDIR(e->sb.st_mode)) {
+ if (e->files) {
+ recursive_populate_directory(e);
+ } else if (verbose) {
+ printf("%s\n", e->fullname);
+ }
+ }
+ e = e->next;
+ }
+}
+
+static void create_target_filesystem(struct filesystem_entry *root)
+{
+ cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
+ cleanmarker.totlen = cpu_to_je32(cleanmarker_size);
+ cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
+
+ if (ino == 0)
+ ino = 1;
+
+ root->ino = 1;
+ recursive_populate_directory(root);
+
+ if (pad_fs_size == -1) {
+ padblock();
+ } else {
+ if (pad_fs_size && add_cleanmarkers){
+ padblock();
+ while (out_ofs < pad_fs_size) {
+ full_write(out_fd, &cleanmarker, sizeof(cleanmarker));
+ pad(cleanmarker_size - sizeof(cleanmarker));
+ padblock();
+ }
+ } else {
+ while (out_ofs < pad_fs_size) {
+ full_write(out_fd, ffbuf, min(sizeof(ffbuf), pad_fs_size - out_ofs));
+ }
+
+ }
+ }
+}
+
+static struct option long_options[] = {
+ {"pad", 2, NULL, 'p'},
+ {"root", 1, NULL, 'r'},
+ {"pagesize", 1, NULL, 's'},
+ {"eraseblock", 1, NULL, 'e'},
+ {"output", 1, NULL, 'o'},
+ {"help", 0, NULL, 'h'},
+ {"verbose", 0, NULL, 'v'},
+ {"version", 0, NULL, 'V'},
+ {"big-endian", 0, NULL, 'b'},
+ {"little-endian", 0, NULL, 'l'},
+ {"no-cleanmarkers", 0, NULL, 'n'},
+ {"cleanmarker", 1, NULL, 'c'},
+ {"squash", 0, NULL, 'q'},
+ {"squash-uids", 0, NULL, 'U'},
+ {"squash-perms", 0, NULL, 'P'},
+ {"faketime", 0, NULL, 'f'},
+ {"devtable", 1, NULL, 'D'},
+ {"compression-mode", 1, NULL, 'm'},
+ {"disable-compressor", 1, NULL, 'x'},
+ {"test-compression", 0, NULL, 't'},
+ {"compressor-priority", 1, NULL, 'y'},
+ {"incremental", 1, NULL, 'i'},
+#ifndef WITHOUT_XATTR
+ {"with-xattr", 0, NULL, 1000 },
+ {"with-selinux", 0, NULL, 1001 },
+ {"with-posix-acl", 0, NULL, 1002 },
+#endif
+ {NULL, 0, NULL, 0}
+};
+
+static char *helptext =
+"Usage: mkfs.jffs2 [OPTIONS]\n"
+"Make a JFFS2 file system image from an existing directory tree\n\n"
+"Options:\n"
+" -p, --pad[=SIZE] Pad output to SIZE bytes with 0xFF. If SIZE is\n"
+" not specified, the output is padded to the end of\n"
+" the final erase block\n"
+" -r, -d, --root=DIR Build file system from directory DIR (default: cwd)\n"
+" -s, --pagesize=SIZE Use page size (max data node size) SIZE (default: 4KiB)\n"
+" -e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB)\n"
+" -c, --cleanmarker=SIZE Size of cleanmarker (default 12)\n"
+" -m, --compr-mode=MODE Select compression mode (default: priortiry)\n"
+" -x, --disable-compressor=COMPRESSOR_NAME\n"
+" Disable a compressor\n"
+" -X, --enable-compressor=COMPRESSOR_NAME\n"
+" Enable a compressor\n"
+" -y, --compressor-priority=PRIORITY:COMPRESSOR_NAME\n"
+" Set the priority of a compressor\n"
+" -L, --list-compressors Show the list of the avaiable compressors\n"
+" -t, --test-compression Call decompress and compare with the original (for test)\n"
+" -n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock\n"
+" -o, --output=FILE Output to FILE (default: stdout)\n"
+" -l, --little-endian Create a little-endian filesystem\n"
+" -b, --big-endian Create a big-endian filesystem\n"
+" -D, --devtable=FILE Use the named FILE as a device table file\n"
+" -f, --faketime Change all file times to '0' for regression testing\n"
+" -q, --squash Squash permissions and owners making all files be owned by root\n"
+" -U, --squash-uids Squash owners making all files be owned by root\n"
+" -P, --squash-perms Squash permissions on all files\n"
+#ifndef WITHOUT_XATTR
+" --with-xattr stuff all xattr entries into image\n"
+" --with-selinux stuff only SELinux Labels into jffs2 image\n"
+" --with-posix-acl stuff only POSIX ACL entries into jffs2 image\n"
+#endif
+" -h, --help Display this help text\n"
+" -v, --verbose Verbose operation\n"
+" -V, --version Display version information\n"
+" -i, --incremental=FILE Parse FILE and generate appendage output for it\n\n";
+
+static char *revtext = "1.60";
+
+int load_next_block() {
+
+ int ret;
+ ret = read(in_fd, file_buffer, erase_block_size);
+
+ if(verbose)
+ printf("Load next block : %d bytes read\n",ret);
+
+ return ret;
+}
+
+void process_buffer(int inp_size) {
+ uint8_t *p = file_buffer;
+ union jffs2_node_union *node;
+ uint16_t type;
+ int bitchbitmask = 0;
+ int obsolete;
+
+ char name[256];
+
+ while ( p < (file_buffer + inp_size)) {
+
+ node = (union jffs2_node_union *) p;
+
+ /* Skip empty space */
+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+ p += 4;
+ continue;
+ }
+
+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
+ if (!bitchbitmask++)
+ printf ("Wrong bitmask at 0x%08x, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic));
+ p += 4;
+ continue;
+ }
+
+ bitchbitmask = 0;
+
+ type = je16_to_cpu(node->u.nodetype);
+ if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+ obsolete = 1;
+ type |= JFFS2_NODE_ACCURATE;
+ } else
+ obsolete = 0;
+
+ node->u.nodetype = cpu_to_je16(type);
+
+ switch(je16_to_cpu(node->u.nodetype)) {
+
+ case JFFS2_NODETYPE_INODE:
+ if(verbose)
+ printf ("%8s Inode node at 0x%08x, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+ je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize),
+ je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+ if ( je32_to_cpu (node->i.ino) > ino )
+ ino = je32_to_cpu (node->i.ino);
+
+ p += PAD(je32_to_cpu (node->i.totlen));
+ break;
+
+ case JFFS2_NODETYPE_DIRENT:
+ memcpy (name, node->d.name, node->d.nsize);
+ name [node->d.nsize] = 0x0;
+
+ if(verbose)
+ printf ("%8s Dirent node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+ je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
+ node->d.nsize, name);
+
+ p += PAD(je32_to_cpu (node->d.totlen));
+ break;
+
+ case JFFS2_NODETYPE_CLEANMARKER:
+ if (verbose) {
+ printf ("%8s Cleanmarker at 0x%08x, totlen 0x%08x\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->u.totlen));
+ }
+
+ p += PAD(je32_to_cpu (node->u.totlen));
+ break;
+
+ case JFFS2_NODETYPE_PADDING:
+ if (verbose) {
+ printf ("%8s Padding node at 0x%08x, totlen 0x%08x\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->u.totlen));
+ }
+
+ p += PAD(je32_to_cpu (node->u.totlen));
+ break;
+
+ case 0xffff:
+ p += 4;
+ break;
+
+ default:
+ if (verbose) {
+ printf ("%8s Unknown node at 0x%08x, totlen 0x%08x\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->u.totlen));
+ }
+
+ p += PAD(je32_to_cpu (node->u.totlen));
+ }
+ }
+}
+
+void parse_image(){
+ int ret;
+
+ file_buffer = malloc(erase_block_size);
+
+ if (!file_buffer) {
+ perror("out of memory");
+ close (in_fd);
+ close (out_fd);
+ exit(1);
+ }
+
+ while ((ret = load_next_block())) {
+ process_buffer(ret);
+ }
+
+ if (file_buffer)
+ free(file_buffer);
+
+ close(in_fd);
+}
+
+int main(int argc, char **argv)
+{
+ int c, opt;
+ char *cwd;
+ struct stat sb;
+ FILE *devtable = NULL;
+ struct filesystem_entry *root;
+ char *compr_name = NULL;
+ int compr_prior = -1;
+ int warn_page_size = 0;
+
+ page_size = sysconf(_SC_PAGESIZE);
+ if (page_size < 0) /* System doesn't know so ... */
+ page_size = 4096; /* ... we make an educated guess */
+ if (page_size != 4096)
+ warn_page_size = 1; /* warn user if page size not 4096 */
+
+ jffs2_compressors_init();
+
+ while ((opt = getopt_long(argc, argv,
+ "D:d:r:s:o:qUPfh?vVe:lbp::nc:m:x:X:Lty:i:", long_options, &c)) >= 0)
+ {
+ switch (opt) {
+ case 'D':
+ devtable = xfopen(optarg, "r");
+ if (fstat(fileno(devtable), &sb) < 0)
+ perror_msg_and_die(optarg);
+ if (sb.st_size < 10)
+ error_msg_and_die("%s: not a proper device table file", optarg);
+ break;
+
+ case 'r':
+ case 'd': /* for compatibility with mkfs.jffs, genext2fs, etc... */
+ if (rootdir != default_rootdir) {
+ error_msg_and_die("root directory specified more than once");
+ }
+ rootdir = xstrdup(optarg);
+ break;
+
+ case 's':
+ page_size = strtol(optarg, NULL, 0);
+ warn_page_size = 0; /* set by user, so don't need to warn */
+ break;
+
+ case 'o':
+ if (out_fd != -1) {
+ error_msg_and_die("output filename specified more than once");
+ }
+ out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
+ if (out_fd == -1) {
+ perror_msg_and_die("open output file");
+ }
+ break;
+
+ case 'q':
+ squash_uids = 1;
+ squash_perms = 1;
+ break;
+
+ case 'U':
+ squash_uids = 1;
+ break;
+
+ case 'P':
+ squash_perms = 1;
+ break;
+
+ case 'f':
+ fake_times = 1;
+ break;
+
+ case 'h':
+ case '?':
+ error_msg_and_die(helptext);
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ case 'V':
+ error_msg_and_die("revision %s\n", revtext);
+
+ case 'e': {
+ char *next;
+ unsigned units = 0;
+ erase_block_size = strtol(optarg, &next, 0);
+ if (!erase_block_size)
+ error_msg_and_die("Unrecognisable erase size\n");
+
+ if (*next) {
+ if (!strcmp(next, "KiB")) {
+ units = 1024;
+ } else if (!strcmp(next, "MiB")) {
+ units = 1024 * 1024;
+ } else {
+ error_msg_and_die("Unknown units in erasesize\n");
+ }
+ } else {
+ if (erase_block_size < 0x1000)
+ units = 1024;
+ else
+ units = 1;
+ }
+ erase_block_size *= units;
+
+ /* If it's less than 8KiB, they're not allowed */
+ if (erase_block_size < 0x2000) {
+ fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n",
+ erase_block_size);
+ erase_block_size = 0x2000;
+ }
+ break;
+ }
+
+ case 'l':
+ target_endian = __LITTLE_ENDIAN;
+ break;
+
+ case 'b':
+ target_endian = __BIG_ENDIAN;
+ break;
+
+ case 'p':
+ if (optarg)
+ pad_fs_size = strtol(optarg, NULL, 0);
+ else
+ pad_fs_size = -1;
+ break;
+ case 'n':
+ add_cleanmarkers = 0;
+ break;
+ case 'c':
+ cleanmarker_size = strtol(optarg, NULL, 0);
+ if (cleanmarker_size < sizeof(cleanmarker)) {
+ error_msg_and_die("cleanmarker size must be >= 12");
+ }
+ if (cleanmarker_size >= erase_block_size) {
+ error_msg_and_die("cleanmarker size must be < eraseblock size");
+ }
+ break;
+ case 'm':
+ if (jffs2_set_compression_mode_name(optarg)) {
+ error_msg_and_die("Unknown compression mode %s", optarg);
+ }
+ break;
+ case 'x':
+ if (jffs2_disable_compressor_name(optarg)) {
+ error_msg_and_die("Unknown compressor name %s",optarg);
+ }
+ break;
+ case 'X':
+ if (jffs2_enable_compressor_name(optarg)) {
+ error_msg_and_die("Unknown compressor name %s",optarg);
+ }
+ break;
+ case 'L':
+ error_msg_and_die("\n%s",jffs2_list_compressors());
+ break;
+ case 't':
+ jffs2_compression_check_set(1);
+ break;
+ case 'y':
+ compr_name = malloc(strlen(optarg));
+ sscanf(optarg,"%d:%s",&compr_prior,compr_name);
+ if ((compr_prior>=0)&&(compr_name)) {
+ if (jffs2_set_compressor_priority(compr_name, compr_prior))
+ exit(EXIT_FAILURE);
+ }
+ else {
+ error_msg_and_die("Cannot parse %s",optarg);
+ }
+ free(compr_name);
+ break;
+ case 'i':
+ if (in_fd != -1) {
+ error_msg_and_die("(incremental) filename specified more than once");
+ }
+ in_fd = open(optarg, O_RDONLY);
+ if (in_fd == -1) {
+ perror_msg_and_die("cannot open (incremental) file");
+ }
+ break;
+#ifndef WITHOUT_XATTR
+ case 1000: /* --with-xattr */
+ enable_xattr |= (1 << JFFS2_XPREFIX_USER)
+ | (1 << JFFS2_XPREFIX_SECURITY)
+ | (1 << JFFS2_XPREFIX_ACL_ACCESS)
+ | (1 << JFFS2_XPREFIX_ACL_DEFAULT)
+ | (1 << JFFS2_XPREFIX_TRUSTED);
+ break;
+ case 1001: /* --with-selinux */
+ enable_xattr |= (1 << JFFS2_XPREFIX_SECURITY);
+ break;
+ case 1002: /* --with-posix-acl */
+ enable_xattr |= (1 << JFFS2_XPREFIX_ACL_ACCESS)
+ | (1 << JFFS2_XPREFIX_ACL_DEFAULT);
+ break;
+#endif
+ }
+ }
+ if (warn_page_size) {
+ error_msg("Page size for this system is by default %d", page_size);
+ error_msg("Use the --pagesize=SIZE option if this is not what you want");
+ }
+ if (out_fd == -1) {
+ if (isatty(1)) {
+ error_msg_and_die(helptext);
+ }
+ out_fd = 1;
+ }
+ if (lstat(rootdir, &sb)) {
+ perror_msg_and_die("%s", rootdir);
+ }
+ if (chdir(rootdir))
+ perror_msg_and_die("%s", rootdir);
+
+ if (!(cwd = getcwd(0, GETCWD_SIZE)))
+ perror_msg_and_die("getcwd failed");
+
+ if(in_fd != -1)
+ parse_image();
+
+ root = recursive_add_host_directory(NULL, "/", cwd);
+
+ if (devtable)
+ parse_device_table(root, devtable);
+
+ create_target_filesystem(root);
+
+ cleanup(root);
+
+ if (rootdir != default_rootdir)
+ free(rootdir);
+
+ close(out_fd);
+
+ if (verbose) {
+ char *s = jffs2_stats();
+ fprintf(stderr,"\n\n%s",s);
+ free(s);
+ }
+ if ((verbose)||(jffs2_compression_check_get()&&(jffs2_compression_check_errorcnt_get()))) {
+ fprintf(stderr,"Compression errors: %d\n",jffs2_compression_check_errorcnt_get());
+ }
+
+ jffs2_compressors_exit();
+
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/mtd-utils.spec b/drivers/mtd/mtd-utils/mtd-utils.spec
new file mode 100644
index 00000000000..606a6a21145
--- /dev/null
+++ b/drivers/mtd/mtd-utils/mtd-utils.spec
@@ -0,0 +1,40 @@
+Summary: Tools for maintaining Memory Technology Devices
+Name: mtd-utils
+Version: 1.0
+Release: 1
+License: GPL
+Group: Applications/System
+URL: http://www.linux-mtd.infradead.org/
+Source0: %{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
+
+%description
+This package contains tools for erasing and formatting flash devices,
+including JFFS2, M-Systems DiskOnChip devices, etc.
+
+%prep
+%setup -q
+
+%build
+make -C util
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make DESTDIR=$RPM_BUILD_ROOT -C util install
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%defattr(-,root,root,-)
+/usr/sbin
+/usr/man/man1/mkfs.jffs2.1.gz
+/usr/include/mtd
+%doc
+
+
+%changelog
+* Wed May 5 2004 <dwmw2@infradead.org> - 1.0
+- Initial build.
+
diff --git a/drivers/mtd/mtd-utils/mtd_debug.c b/drivers/mtd/mtd-utils/mtd_debug.c
new file mode 100644
index 00000000000..85d48e92497
--- /dev/null
+++ b/drivers/mtd/mtd-utils/mtd_debug.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2d3D, Inc.
+ * Written by Abraham vd Merwe <abraham@2d3d.co.za>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <mtd/mtd-user.h>
+
+/*
+ * MEMGETINFO
+ */
+static int getmeminfo (int fd,struct mtd_info_user *mtd)
+{
+ return (ioctl (fd,MEMGETINFO,mtd));
+}
+
+/*
+ * MEMERASE
+ */
+static int memerase (int fd,struct erase_info_user *erase)
+{
+ return (ioctl (fd,MEMERASE,erase));
+}
+
+/*
+ * MEMGETREGIONCOUNT
+ * MEMGETREGIONINFO
+ */
+static int getregions (int fd,struct region_info_user *regions,int *n)
+{
+ int i,err;
+ err = ioctl (fd,MEMGETREGIONCOUNT,n);
+ if (err) return (err);
+ for (i = 0; i < *n; i++)
+ {
+ regions[i].regionindex = i;
+ err = ioctl (fd,MEMGETREGIONINFO,&regions[i]);
+ if (err) return (err);
+ }
+ return (0);
+}
+
+int erase_flash (int fd,u_int32_t offset,u_int32_t bytes)
+{
+ int err;
+ struct erase_info_user erase;
+ erase.start = offset;
+ erase.length = bytes;
+ err = memerase (fd,&erase);
+ if (err < 0)
+ {
+ perror ("MEMERASE");
+ return (1);
+ }
+ fprintf (stderr,"Erased %d bytes from address 0x%.8x in flash\n",bytes,offset);
+ return (0);
+}
+
+void printsize (u_int32_t x)
+{
+ int i;
+ static const char *flags = "KMGT";
+ printf ("%u ",x);
+ for (i = 0; x >= 1024 && flags[i] != '\0'; i++) x /= 1024;
+ i--;
+ if (i >= 0) printf ("(%u%c)",x,flags[i]);
+}
+
+int flash_to_file (int fd,u_int32_t offset,size_t len,const char *filename)
+{
+ u_int8_t *buf = NULL;
+ int outfd,err;
+ int size = len * sizeof (u_int8_t);
+ int n = len;
+
+ if (offset != lseek (fd,offset,SEEK_SET))
+ {
+ perror ("lseek()");
+ goto err0;
+ }
+ outfd = creat (filename,O_WRONLY);
+ if (outfd < 0)
+ {
+ perror ("creat()");
+ goto err1;
+ }
+
+retry:
+ if ((buf = (u_int8_t *) malloc (size)) == NULL)
+ {
+#define BUF_SIZE (64 * 1024 * sizeof (u_int8_t))
+ fprintf (stderr, "%s: malloc(%#x)\n", __FUNCTION__, size);
+ if (size != BUF_SIZE) {
+ size = BUF_SIZE;
+ fprintf (stderr, "%s: trying buffer size %#x\n", __FUNCTION__, size);
+ goto retry;
+ }
+ perror ("malloc()");
+ goto err0;
+ }
+ do {
+ if (n <= size)
+ size = n;
+ err = read (fd,buf,size);
+ if (err < 0)
+ {
+ fprintf (stderr, "%s: read, size %#x, n %#x\n", __FUNCTION__, size, n);
+ perror ("read()");
+ goto err2;
+ }
+ err = write (outfd,buf,size);
+ if (err < 0)
+ {
+ fprintf (stderr, "%s: write, size %#x, n %#x\n", __FUNCTION__, size, n);
+ perror ("write()");
+ goto err2;
+ }
+ if (err != size)
+ {
+ fprintf (stderr,"Couldn't copy entire buffer to %s. (%d/%d bytes copied)\n",filename,err,size);
+ goto err2;
+ }
+ n -= size;
+ } while (n > 0);
+
+ if (buf != NULL)
+ free (buf);
+ close (outfd);
+ printf ("Copied %d bytes from address 0x%.8x in flash to %s\n",len,offset,filename);
+ return (0);
+
+err2:
+ close (outfd);
+err1:
+ if (buf != NULL)
+ free (buf);
+err0:
+ return (1);
+}
+
+int file_to_flash (int fd,u_int32_t offset,u_int32_t len,const char *filename)
+{
+ u_int8_t *buf = NULL;
+ FILE *fp;
+ int err;
+ int size = len * sizeof (u_int8_t);
+ int n = len;
+
+ if (offset != lseek (fd,offset,SEEK_SET))
+ {
+ perror ("lseek()");
+ return (1);
+ }
+ if ((fp = fopen (filename,"r")) == NULL)
+ {
+ perror ("fopen()");
+ return (1);
+ }
+retry:
+ if ((buf = (u_int8_t *) malloc (size)) == NULL)
+ {
+ fprintf (stderr, "%s: malloc(%#x) failed\n", __FUNCTION__, size);
+ if (size != BUF_SIZE) {
+ size = BUF_SIZE;
+ fprintf (stderr, "%s: trying buffer size %#x\n", __FUNCTION__, size);
+ goto retry;
+ }
+ perror ("malloc()");
+ fclose (fp);
+ return (1);
+ }
+ do {
+ if (n <= size)
+ size = n;
+ if (fread (buf,size,1,fp) != 1 || ferror (fp))
+ {
+ fprintf (stderr, "%s: fread, size %#x, n %#x\n", __FUNCTION__, size, n);
+ perror ("fread()");
+ free (buf);
+ fclose (fp);
+ return (1);
+ }
+ err = write (fd,buf,size);
+ if (err < 0)
+ {
+ fprintf (stderr, "%s: write, size %#x, n %#x\n", __FUNCTION__, size, n);
+ perror ("write()");
+ free (buf);
+ fclose (fp);
+ return (1);
+ }
+ n -= size;
+ } while (n > 0);
+
+ if (buf != NULL)
+ free (buf);
+ fclose (fp);
+ printf ("Copied %d bytes from %s to address 0x%.8x in flash\n",len,filename,offset);
+ return (0);
+}
+
+int showinfo (int fd)
+{
+ int i,err,n;
+ struct mtd_info_user mtd;
+ static struct region_info_user region[1024];
+
+ err = getmeminfo (fd,&mtd);
+ if (err < 0)
+ {
+ perror ("MEMGETINFO");
+ return (1);
+ }
+
+ err = getregions (fd,region,&n);
+ if (err < 0)
+ {
+ perror ("MEMGETREGIONCOUNT");
+ return (1);
+ }
+
+ printf ("mtd.type = ");
+ switch (mtd.type)
+ {
+ case MTD_ABSENT:
+ printf ("MTD_ABSENT");
+ break;
+ case MTD_RAM:
+ printf ("MTD_RAM");
+ break;
+ case MTD_ROM:
+ printf ("MTD_ROM");
+ break;
+ case MTD_NORFLASH:
+ printf ("MTD_NORFLASH");
+ break;
+ case MTD_NANDFLASH:
+ printf ("MTD_NANDFLASH");
+ break;
+ case MTD_DATAFLASH:
+ printf ("MTD_DATAFLASH");
+ break;
+ case MTD_UBIVOLUME:
+ printf ("MTD_UBIVOLUME");
+ default:
+ printf ("(unknown type - new MTD API maybe?)");
+ }
+
+ printf ("\nmtd.flags = ");
+ if (mtd.flags == MTD_CAP_ROM)
+ printf ("MTD_CAP_ROM");
+ else if (mtd.flags == MTD_CAP_RAM)
+ printf ("MTD_CAP_RAM");
+ else if (mtd.flags == MTD_CAP_NORFLASH)
+ printf ("MTD_CAP_NORFLASH");
+ else if (mtd.flags == MTD_CAP_NANDFLASH)
+ printf ("MTD_CAP_NANDFLASH");
+ else if (mtd.flags == MTD_WRITEABLE)
+ printf ("MTD_WRITEABLE");
+ else
+ {
+ int first = 1;
+ static struct
+ {
+ const char *name;
+ int value;
+ } flags[] =
+ {
+ { "MTD_WRITEABLE", MTD_WRITEABLE },
+ { "MTD_BIT_WRITEABLE", MTD_BIT_WRITEABLE },
+ { "MTD_NO_ERASE", MTD_NO_ERASE },
+ { "MTD_STUPID_LOCK", MTD_STUPID_LOCK },
+ { NULL, -1 }
+ };
+ for (i = 0; flags[i].name != NULL; i++)
+ if (mtd.flags & flags[i].value)
+ {
+ if (first)
+ {
+ printf (flags[i].name);
+ first = 0;
+ }
+ else printf (" | %s",flags[i].name);
+ }
+ }
+
+ printf ("\nmtd.size = ");
+ printsize (mtd.size);
+
+ printf ("\nmtd.erasesize = ");
+ printsize (mtd.erasesize);
+
+ printf ("\nmtd.writesize = ");
+ printsize (mtd.writesize);
+
+ printf ("\nmtd.oobsize = ");
+ printsize (mtd.oobsize);
+
+ printf ("\n"
+ "regions = %d\n"
+ "\n",
+ n);
+
+ for (i = 0; i < n; i++)
+ {
+ printf ("region[%d].offset = 0x%.8x\n"
+ "region[%d].erasesize = ",
+ i,region[i].offset,i);
+ printsize (region[i].erasesize);
+ printf ("\nregion[%d].numblocks = %d\n"
+ "region[%d].regionindex = %d\n",
+ i,region[i].numblocks,
+ i,region[i].regionindex);
+ }
+ return (0);
+}
+
+void showusage (const char *progname)
+{
+ fprintf (stderr,
+ "usage: %s info <device>\n"
+ " %s read <device> <offset> <len> <dest-filename>\n"
+ " %s write <device> <offset> <len> <source-filename>\n"
+ " %s erase <device> <offset> <len>\n",
+ progname,
+ progname,
+ progname,
+ progname);
+ exit (1);
+}
+
+#define OPT_INFO 1
+#define OPT_READ 2
+#define OPT_WRITE 3
+#define OPT_ERASE 4
+
+int main (int argc,char *argv[])
+{
+ const char *progname;
+ int err = 0,fd,option = OPT_INFO;
+ int open_flag;
+ (progname = strrchr (argv[0],'/')) ? progname++ : (progname = argv[0]);
+
+ /* parse command-line options */
+ if (argc == 3 && !strcmp (argv[1],"info"))
+ option = OPT_INFO;
+ else if (argc == 6 && !strcmp (argv[1],"read"))
+ option = OPT_READ;
+ else if (argc == 6 && !strcmp (argv[1],"write"))
+ option = OPT_WRITE;
+ else if (argc == 5 && !strcmp (argv[1],"erase"))
+ option = OPT_ERASE;
+ else
+ showusage (progname);
+
+ /* open device */
+ open_flag = (option==OPT_INFO || option==OPT_READ) ? O_RDONLY : O_RDWR;
+ if ((fd = open (argv[2],O_SYNC | open_flag)) < 0)
+ {
+ perror ("open()");
+ exit (1);
+ }
+
+ switch (option)
+ {
+ case OPT_INFO:
+ showinfo (fd);
+ break;
+ case OPT_READ:
+ err = flash_to_file (fd,strtol (argv[3],NULL,0),strtol (argv[4],NULL,0),argv[5]);
+ break;
+ case OPT_WRITE:
+ err = file_to_flash (fd,strtol (argv[3],NULL,0),strtol (argv[4],NULL,0),argv[5]);
+ break;
+ case OPT_ERASE:
+ err = erase_flash (fd,strtol (argv[3],NULL,0),strtol (argv[4],NULL,0));
+ break;
+ }
+
+ /* close device */
+ if (close (fd) < 0)
+ perror ("close()");
+
+ exit (err);
+}
+
diff --git a/drivers/mtd/mtd-utils/nanddump.c b/drivers/mtd/mtd-utils/nanddump.c
new file mode 100644
index 00000000000..46f81f4fc1c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/nanddump.c
@@ -0,0 +1,403 @@
+/*
+ * nanddump.c
+ *
+ * Copyright (C) 2000 David Woodhouse (dwmw2@infradead.org)
+ * Steven J. Hill (sjhill@realitydiluted.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Overview:
+ * This utility dumps the contents of raw NAND chips or NAND
+ * chips contained in DoC devices.
+ */
+
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+
+#define PROGRAM "nanddump"
+#define VERSION "$Revision: 1.1.1.1 $"
+
+struct nand_oobinfo none_oobinfo = {
+ .useecc = MTD_NANDECC_OFF,
+};
+
+void display_help (void)
+{
+ printf("Usage: nanddump [OPTIONS] MTD-device\n"
+ "Dumps the contents of a nand mtd partition.\n"
+ "\n"
+ " --help display this help and exit\n"
+ " --version output version information and exit\n"
+ "-f file --file=file dump to file\n"
+ "-i --ignoreerrors ignore errors\n"
+ "-l length --length=length length\n"
+ "-n --noecc read without error correction\n"
+ "-o --omitoob omit oob data\n"
+ "-b --omitbad omit bad blocks from the dump\n"
+ "-p --prettyprint print nice (hexdump)\n"
+ "-s addr --startaddress=addr start address\n");
+ exit(0);
+}
+
+void display_version (void)
+{
+ printf(PROGRAM " " VERSION "\n"
+ "\n"
+ PROGRAM " comes with NO WARRANTY\n"
+ "to the extent permitted by law.\n"
+ "\n"
+ "You may redistribute copies of " PROGRAM "\n"
+ "under the terms of the GNU General Public Licence.\n"
+ "See the file `COPYING' for more information.\n");
+ exit(0);
+}
+
+// Option variables
+
+int ignoreerrors; // ignore errors
+int pretty_print; // print nice in ascii
+int noecc; // don't error correct
+int omitoob; // omit oob data
+unsigned long start_addr; // start address
+unsigned long length; // dump length
+char *mtddev; // mtd device name
+char *dumpfile; // dump file name
+int omitbad;
+
+void process_options (int argc, char *argv[])
+{
+ int error = 0;
+
+ for (;;) {
+ int option_index = 0;
+ static const char *short_options = "bs:f:il:opn";
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 0},
+ {"version", no_argument, 0, 0},
+ {"file", required_argument, 0, 'f'},
+ {"ignoreerrors", no_argument, 0, 'i'},
+ {"prettyprint", no_argument, 0, 'p'},
+ {"omitoob", no_argument, 0, 'o'},
+ {"omitbad", no_argument, 0, 'b'},
+ {"startaddress", required_argument, 0, 's'},
+ {"length", required_argument, 0, 'l'},
+ {"noecc", no_argument, 0, 'n'},
+ {0, 0, 0, 0},
+ };
+
+ int c = getopt_long(argc, argv, short_options,
+ long_options, &option_index);
+ if (c == EOF) {
+ break;
+ }
+
+ switch (c) {
+ case 0:
+ switch (option_index) {
+ case 0:
+ display_help();
+ break;
+ case 1:
+ display_version();
+ break;
+ }
+ break;
+ case 'b':
+ omitbad = 1;
+ break;
+ case 's':
+ start_addr = strtol(optarg, NULL, 0);
+ break;
+ case 'f':
+ if (!(dumpfile = strdup(optarg))) {
+ perror("stddup");
+ exit(1);
+ }
+ break;
+ case 'i':
+ ignoreerrors = 1;
+ break;
+ case 'l':
+ length = strtol(optarg, NULL, 0);
+ break;
+ case 'o':
+ omitoob = 1;
+ break;
+ case 'p':
+ pretty_print = 1;
+ break;
+ case 'n':
+ noecc = 1;
+ break;
+ case '?':
+ error = 1;
+ break;
+ }
+ }
+
+ if ((argc - optind) != 1 || error)
+ display_help ();
+
+ mtddev = argv[optind];
+}
+
+/*
+ * Buffers for reading data from flash
+ */
+unsigned char readbuf[8192];
+unsigned char oobbuf[256];
+
+/*
+ * Main program
+ */
+int main(int argc, char **argv)
+{
+ unsigned long ofs, end_addr = 0;
+ unsigned long long blockstart = 1;
+ int ret, i, fd, ofd, bs, badblock = 0;
+ struct mtd_oob_buf oob = {0, 16, oobbuf};
+ mtd_info_t meminfo;
+ char pretty_buf[80];
+ int oobinfochanged = 0 ;
+ struct nand_oobinfo old_oobinfo;
+ struct mtd_ecc_stats stat1, stat2;
+ int eccstats = 0;
+
+ process_options(argc, argv);
+
+ /* Open MTD device */
+ if ((fd = open(mtddev, O_RDONLY)) == -1) {
+ perror("open flash");
+ exit (1);
+ }
+
+ /* Fill in MTD device capability structure */
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ perror("MEMGETINFO");
+ close(fd);
+ exit (1);
+ }
+
+ /* Make sure device page sizes are valid */
+ if (!(meminfo.oobsize == 256 && meminfo.writesize == 8192) &&
+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096) &&
+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
+ !(meminfo.oobsize == 32 && meminfo.writesize == 1024) &&
+ !(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
+ !(meminfo.oobsize == 8 && meminfo.writesize == 256)) {
+ fprintf(stderr, "Unknown flash (not normal NAND)\n");
+ close(fd);
+ exit(1);
+ }
+ /* Read the real oob length */
+ oob.length = meminfo.oobsize;
+
+ if (noecc) {
+ ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW);
+ if (ret == 0) {
+ oobinfochanged = 2;
+ } else {
+ switch (errno) {
+ case ENOTTY:
+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMGETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ oobinfochanged = 1;
+ break;
+ default:
+ perror ("MTDFILEMODE");
+ close (fd);
+ exit (1);
+ }
+ }
+ } else {
+
+ /* check if we can read ecc stats */
+ if (!ioctl(fd, ECCGETSTATS, &stat1)) {
+ eccstats = 1;
+ fprintf(stderr, "ECC failed: %d\n", stat1.failed);
+ fprintf(stderr, "ECC corrected: %d\n", stat1.corrected);
+ fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks);
+ fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks);
+ } else
+ perror("No ECC status information available");
+ }
+
+ /* Open output file for writing. If file name is "-", write to standard
+ * output. */
+ if (!dumpfile) {
+ ofd = STDOUT_FILENO;
+ } else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) {
+ perror ("open outfile");
+ close(fd);
+ exit(1);
+ }
+
+ /* Initialize start/end addresses and block size */
+ if (length)
+ end_addr = start_addr + length;
+ if (!length || end_addr > meminfo.size)
+ end_addr = meminfo.size;
+
+ bs = meminfo.writesize;
+
+ /* Print informative message */
+ fprintf(stderr, "Block size %u, page size %u, OOB size %u\n",
+ meminfo.erasesize, meminfo.writesize, meminfo.oobsize);
+ fprintf(stderr,
+ "Dumping data starting at 0x%08x and ending at 0x%08x...\n",
+ (unsigned int) start_addr, (unsigned int) end_addr);
+
+ /* Dump the flash contents */
+ for (ofs = start_addr; ofs < end_addr ; ofs+=bs) {
+
+ // new eraseblock , check for bad block
+ if (blockstart != (ofs & (~meminfo.erasesize + 1))) {
+ blockstart = ofs & (~meminfo.erasesize + 1);
+ if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) {
+ perror("ioctl(MEMGETBADBLOCK)");
+ goto closeall;
+ }
+ }
+
+ if (badblock) {
+ if (omitbad)
+ continue;
+ memset (readbuf, 0xff, bs);
+ } else {
+ /* Read page data and exit on failure */
+ if (pread(fd, readbuf, bs, ofs) != bs) {
+ perror("pread");
+ goto closeall;
+ }
+ }
+
+ /* ECC stats available ? */
+ if (eccstats) {
+ if (ioctl(fd, ECCGETSTATS, &stat2)) {
+ perror("ioctl(ECCGETSTATS)");
+ goto closeall;
+ }
+ if (stat1.failed != stat2.failed)
+ fprintf(stderr, "ECC: %d uncorrectable bitflip(s)"
+ " at offset 0x%08lx\n",
+ stat2.failed - stat1.failed, ofs);
+ if (stat1.corrected != stat2.corrected)
+ fprintf(stderr, "ECC: %d corrected bitflip(s) at"
+ " offset 0x%08lx\n",
+ stat2.corrected - stat1.corrected, ofs);
+ stat1 = stat2;
+ }
+
+ /* Write out page data */
+ if (pretty_print) {
+ for (i = 0; i < bs; i += 16) {
+ sprintf(pretty_buf,
+ "0x%08x: %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ (unsigned int) (ofs + i), readbuf[i],
+ readbuf[i+1], readbuf[i+2],
+ readbuf[i+3], readbuf[i+4],
+ readbuf[i+5], readbuf[i+6],
+ readbuf[i+7], readbuf[i+8],
+ readbuf[i+9], readbuf[i+10],
+ readbuf[i+11], readbuf[i+12],
+ readbuf[i+13], readbuf[i+14],
+ readbuf[i+15]);
+ write(ofd, pretty_buf, 60);
+ }
+ } else
+ write(ofd, readbuf, bs);
+
+
+
+ if (omitoob)
+ continue;
+
+ if (badblock) {
+ memset (readbuf, 0xff, meminfo.oobsize);
+ } else {
+ /* Read OOB data and exit on failure */
+ oob.start = ofs;
+ if (ioctl(fd, MEMREADOOB, &oob) != 0) {
+ perror("ioctl(MEMREADOOB)");
+ goto closeall;
+ }
+ }
+
+ /* Write out OOB data */
+ if (pretty_print) {
+ if (meminfo.oobsize < 16) {
+ sprintf(pretty_buf, " OOB Data: %02x %02x %02x %02x %02x %02x "
+ "%02x %02x\n",
+ oobbuf[0], oobbuf[1], oobbuf[2],
+ oobbuf[3], oobbuf[4], oobbuf[5],
+ oobbuf[6], oobbuf[7]);
+ write(ofd, pretty_buf, 48);
+ continue;
+ }
+
+ for (i = 0; i < meminfo.oobsize; i += 16) {
+ sprintf(pretty_buf, " OOB Data: %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ oobbuf[i], oobbuf[i+1], oobbuf[i+2],
+ oobbuf[i+3], oobbuf[i+4], oobbuf[i+5],
+ oobbuf[i+6], oobbuf[i+7], oobbuf[i+8],
+ oobbuf[i+9], oobbuf[i+10], oobbuf[i+11],
+ oobbuf[i+12], oobbuf[i+13], oobbuf[i+14],
+ oobbuf[i+15]);
+ write(ofd, pretty_buf, 60);
+ }
+ } else
+ write(ofd, oobbuf, meminfo.oobsize);
+ }
+
+ /* reset oobinfo */
+ if (oobinfochanged == 1) {
+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close(fd);
+ close(ofd);
+ return 1;
+ }
+ }
+ /* Close the output file and MTD device */
+ close(fd);
+ close(ofd);
+
+ /* Exit happy */
+ return 0;
+
+closeall:
+ /* The new mode change is per file descriptor ! */
+ if (oobinfochanged == 1) {
+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ }
+ }
+ close(fd);
+ close(ofd);
+ exit(1);
+}
diff --git a/drivers/mtd/mtd-utils/nanddump_vfat.c b/drivers/mtd/mtd-utils/nanddump_vfat.c
new file mode 100644
index 00000000000..812d3f94ba6
--- /dev/null
+++ b/drivers/mtd/mtd-utils/nanddump_vfat.c
@@ -0,0 +1,365 @@
+/*
+ * nanddump.c
+ *
+ * Copyright (C) 2000 David Woodhouse (dwmw2@infradead.org)
+ * Steven J. Hill (sjhill@realitydiluted.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Overview:
+ * This utility dumps the contents of raw NAND chips or NAND
+ * chips contained in DoC devices.
+ */
+
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+
+#define PROGRAM "nanddump"
+#define VERSION "$Revision: 1.1.1.1 $"
+
+struct nand_oobinfo none_oobinfo = {
+ .useecc = MTD_NANDECC_OFF,
+};
+
+void display_help (void)
+{
+ printf("Usage: nanddump [OPTIONS] MTD-device\n"
+ "Dumps the contents of a nand mtd partition.\n"
+ "\n"
+ " --help display this help and exit\n"
+ " --version output version information and exit\n"
+ "-f file --file=file dump to file\n"
+ "-i --ignoreerrors ignore errors\n"
+ "-l length --length=length length\n"
+ "-n --noecc read without error correction\n"
+ "-o --omitoob omit oob data\n"
+ "-b --omitbad omit bad blocks from the dump\n"
+ "-p --prettyprint print nice (hexdump)\n"
+ "-s addr --startaddress=addr start address\n");
+ exit(0);
+}
+
+void display_version (void)
+{
+ printf(PROGRAM " " VERSION "\n"
+ "\n"
+ PROGRAM " comes with NO WARRANTY\n"
+ "to the extent permitted by law.\n"
+ "\n"
+ "You may redistribute copies of " PROGRAM "\n"
+ "under the terms of the GNU General Public Licence.\n"
+ "See the file `COPYING' for more information.\n");
+ exit(0);
+}
+
+// Option variables
+
+int ignoreerrors; // ignore errors
+int pretty_print; // print nice in ascii
+int noecc; // don't error correct
+int omitoob; // omit oob data
+unsigned long start_addr; // start address
+unsigned long length; // dump length
+char *mtddev; // mtd device name
+char *dumpfile; // dump file name
+int omitbad;
+
+void process_options (int argc, char *argv[])
+{
+ int error = 0;
+
+ for (;;) {
+ int option_index = 0;
+ static const char *short_options = "bs:f:il:opn";
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 0},
+ {"version", no_argument, 0, 0},
+ {"file", required_argument, 0, 'f'},
+ {"ignoreerrors", no_argument, 0, 'i'},
+ {"prettyprint", no_argument, 0, 'p'},
+ {"omitoob", no_argument, 0, 'o'},
+ {"omitbad", no_argument, 0, 'b'},
+ {"startaddress", required_argument, 0, 's'},
+ {"length", required_argument, 0, 'l'},
+ {"noecc", no_argument, 0, 'n'},
+ {0, 0, 0, 0},
+ };
+
+ int c = getopt_long(argc, argv, short_options,
+ long_options, &option_index);
+ if (c == EOF) {
+ break;
+ }
+
+ switch (c) {
+ case 0:
+ switch (option_index) {
+ case 0:
+ display_help();
+ break;
+ case 1:
+ display_version();
+ break;
+ }
+ break;
+ case 'b':
+ omitbad = 1;
+ break;
+ case 's':
+ start_addr = strtol(optarg, NULL, 0);
+ break;
+ case 'f':
+ if (!(dumpfile = strdup(optarg))) {
+ perror("stddup");
+ exit(1);
+ }
+ break;
+ case 'i':
+ ignoreerrors = 1;
+ break;
+ case 'l':
+ length = strtol(optarg, NULL, 0);
+ break;
+ case 'o':
+ omitoob = 1;
+ break;
+ case 'p':
+ pretty_print = 1;
+ break;
+ case 'n':
+ noecc = 1;
+ break;
+ case '?':
+ error = 1;
+ break;
+ }
+ }
+
+ if ((argc - optind) != 1 || error)
+ display_help ();
+
+ mtddev = argv[optind];
+}
+
+/*
+ * Buffers for reading data from flash
+ */
+unsigned char readbuf[8192];
+unsigned char oobbuf[256];
+
+/*
+ * Main program
+ */
+int main(int argc, char **argv)
+{
+ unsigned long ofs, end_addr = 0;
+ unsigned long long blockstart = 1;
+ int ret, fd, ofd, bs, badblock = 0;
+ struct mtd_oob_buf oob = {0, 16, oobbuf};
+ mtd_info_t meminfo;
+ int oobinfochanged = 0 ;
+ struct nand_oobinfo old_oobinfo;
+ struct mtd_ecc_stats stat1, stat2;
+ int eccstats = 0;
+
+ process_options(argc, argv);
+
+ /* Open MTD device */
+ if ((fd = open(mtddev, O_RDONLY)) == -1) {
+ perror("open flash");
+ exit (1);
+ }
+
+ /* Fill in MTD device capability structure */
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ perror("MEMGETINFO");
+ close(fd);
+ exit (1);
+ }
+
+ /* Make sure device page sizes are valid */
+ if (!(meminfo.oobsize == 256 && meminfo.writesize == 8192) &&
+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096) &&
+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
+ !(meminfo.oobsize == 32 && meminfo.writesize == 1024) &&
+ !(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
+ !(meminfo.oobsize == 8 && meminfo.writesize == 256)) {
+ fprintf(stderr, "Unknown flash (not normal NAND)\n");
+ close(fd);
+ exit(1);
+ }
+ /* Read the real oob length */
+ oob.length = meminfo.oobsize;
+
+ if (noecc) {
+ ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW);
+ if (ret == 0) {
+ oobinfochanged = 2;
+ } else {
+ switch (errno) {
+ case ENOTTY:
+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMGETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ oobinfochanged = 1;
+ break;
+ default:
+ perror ("MTDFILEMODE");
+ close (fd);
+ exit (1);
+ }
+ }
+ } else {
+
+ /* check if we can read ecc stats */
+ if (!ioctl(fd, ECCGETSTATS, &stat1)) {
+ eccstats = 1;
+ fprintf(stderr, "ECC failed: %d\n", stat1.failed);
+ fprintf(stderr, "ECC corrected: %d\n", stat1.corrected);
+ fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks);
+ fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks);
+ } else
+ perror("No ECC status information available");
+ }
+
+ /* Open output file for writing. If file name is "-", write to standard
+ * output. */
+ if (!dumpfile) {
+ ofd = STDOUT_FILENO;
+ } else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) {
+ perror ("open outfile");
+ close(fd);
+ exit(1);
+ }
+
+ /* Initialize start/end addresses and block size */
+ if (length)
+ end_addr = start_addr + length;
+ if (!length || end_addr > meminfo.size)
+ end_addr = meminfo.size;
+
+ bs = meminfo.writesize;
+
+ /* Print informative message */
+ fprintf(stderr, "Block size %u, page size %u, OOB size %u\n",
+ meminfo.erasesize, meminfo.writesize, meminfo.oobsize);
+ fprintf(stderr,
+ "Dumping data starting at 0x%08x and ending at 0x%08x...\n",
+ (unsigned int) start_addr, (unsigned int) end_addr);
+
+ /* Dump the flash contents */
+ for (ofs = start_addr; ofs < end_addr ; ofs+=bs) {
+
+ // new eraseblock , check for bad block
+ if (blockstart != (ofs & (~meminfo.erasesize + 1))) {
+ blockstart = ofs & (~meminfo.erasesize + 1);
+ if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) {
+ perror("ioctl(MEMGETBADBLOCK)");
+ goto closeall;
+ }
+ }
+
+ if (badblock) {
+ //skip bad block;
+ ofs += meminfo.erasesize - bs;
+ continue;
+ } else {
+ /* Read page data and exit on failure */
+ if (pread(fd, readbuf, bs, ofs) != bs) {
+ perror("pread");
+ goto closeall;
+ }
+ }
+
+ /* ECC stats available ? */
+ if (eccstats) {
+ if (ioctl(fd, ECCGETSTATS, &stat2)) {
+ perror("ioctl(ECCGETSTATS)");
+ goto closeall;
+ }
+ if (stat1.failed != stat2.failed)
+ fprintf(stderr, "ECC: %d uncorrectable bitflip(s)"
+ " at offset 0x%08lx\n",
+ stat2.failed - stat1.failed, ofs);
+ if (stat1.corrected != stat2.corrected)
+ fprintf(stderr, "ECC: %d corrected bitflip(s) at"
+ " offset 0x%08lx\n",
+ stat2.corrected - stat1.corrected, ofs);
+ stat1 = stat2;
+ }
+
+ if (badblock) {
+ memset (readbuf, 0xff, meminfo.oobsize);
+ } else {
+ /* Read OOB data and exit on failure */
+ oob.start = ofs;
+ if (ioctl(fd, MEMREADOOB, &oob) != 0) {
+ perror("ioctl(MEMREADOOB)");
+ goto closeall;
+ }
+ if(oobbuf[2]==0xff && oobbuf[3]==0xff && oobbuf[4]==0xff && oobbuf[5]==0xff){
+ //skip free block;
+ ofs += meminfo.erasesize - bs;
+ continue;
+ }
+ }
+
+ /* Write out page data */
+ write(ofd, readbuf, bs);
+
+ if (omitoob)
+ continue;
+
+ /* Write out OOB data */
+ write(ofd, oobbuf, meminfo.oobsize);
+ }
+
+ /* reset oobinfo */
+ if (oobinfochanged == 1) {
+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close(fd);
+ close(ofd);
+ return 1;
+ }
+ }
+ /* Close the output file and MTD device */
+ close(fd);
+ close(ofd);
+
+ /* Exit happy */
+ return 0;
+
+closeall:
+ /* The new mode change is per file descriptor ! */
+ if (oobinfochanged == 1) {
+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ }
+ }
+ close(fd);
+ close(ofd);
+ exit(1);
+}
diff --git a/drivers/mtd/mtd-utils/nandtest.c b/drivers/mtd/mtd-utils/nandtest.c
new file mode 100644
index 00000000000..05804020763
--- /dev/null
+++ b/drivers/mtd/mtd-utils/nandtest.c
@@ -0,0 +1,284 @@
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <getopt.h>
+
+#include <asm/types.h>
+#include "mtd/mtd-user.h"
+
+void usage(void)
+{
+ fprintf(stderr, "usage: nandtest [OPTIONS] <device>\n\n"
+ " -h, --help Display this help output\n"
+ " -m, --markbad Mark blocks bad if they appear so\n"
+ " -s, --seed Supply random seed\n"
+ " -p, --passes Number of passes\n"
+ " -o, --offset Start offset on flash\n"
+ " -l, --length Length of flash to test\n"
+ " -k, --keep Restore existing contents after test\n"
+ "Warning: it is just used for SLC NAND!\n");
+
+ exit(1);
+}
+
+struct mtd_info_user meminfo;
+struct mtd_ecc_stats oldstats, newstats;
+int fd;
+int markbad=0;
+int seed;
+
+int erase_and_write(loff_mtd_t ofs, unsigned char *data, unsigned char *rbuf)
+{
+ struct erase_info_user er;
+ ssize_t len;
+ int i;
+
+ printf("\r%09llx: erasing... ", (loff_mtd_t)ofs);
+ fflush(stdout);
+
+ er.start = ofs;
+ er.length = meminfo.erasesize;
+
+ if (ioctl(fd, MEMERASE, &er)) {
+ perror("MEMERASE");
+ if (markbad) {
+ printf("Mark block bad at %09llx\n", (loff_mtd_t)ofs);
+ ioctl(fd, MEMSETBADBLOCK, &ofs);
+ }
+ return 1;
+ }
+
+ printf("\r%09llx: writing...", (loff_mtd_t)ofs);
+ fflush(stdout);
+
+ len = pwrite(fd, data, meminfo.erasesize, ofs);
+ if (len < 0) {
+ printf("\n");
+ perror("write");
+ if (markbad) {
+ printf("Mark block bad at %09llx\n", (loff_mtd_t)ofs);
+ ioctl(fd, MEMSETBADBLOCK, &ofs);
+ }
+ return 1;
+ }
+ if (len < meminfo.erasesize) {
+ printf("\n");
+ fprintf(stderr, "Short write (%d bytes)\n", len);
+ exit(1);
+ }
+
+ printf("\r%09llx: reading...", (loff_mtd_t)ofs);
+ fflush(stdout);
+
+ len = pread(fd, rbuf, meminfo.erasesize, ofs);
+ if (len < meminfo.erasesize) {
+ printf("\n");
+ if (len)
+ fprintf(stderr, "Short read (%d bytes)\n", len);
+ else
+ perror("read");
+ exit(1);
+ }
+
+ if (ioctl(fd, ECCGETSTATS, &newstats)) {
+ printf("\n");
+ perror("ECCGETSTATS");
+ close(fd);
+ exit(1);
+ }
+
+ if (newstats.corrected > oldstats.corrected) {
+ printf("\nECC corrected at %09llx\n", (loff_mtd_t) ofs);
+ oldstats.corrected = newstats.corrected;
+ }
+ if (newstats.failed > oldstats.failed) {
+ printf("\nECC failed at %09llx\n", (loff_mtd_t) ofs);
+ oldstats.corrected = newstats.corrected;
+ }
+ if (len < meminfo.erasesize)
+ exit(1);
+
+ printf("\r%09llx: checking...", (loff_mtd_t)ofs);
+ fflush(stdout);
+
+ if (memcmp(data, rbuf, meminfo.erasesize)) {
+ printf("\n");
+ fprintf(stderr, "compare failed. seed %d\n", seed);
+ for (i=0; i<meminfo.erasesize; i++) {
+ if (data[i] != rbuf[i])
+ printf("Byte 0x%x is %02x should be %02x\n",
+ i, rbuf[i], data[i]);
+ }
+ exit(1);
+ }
+ return 0;
+}
+
+
+/*
+ * Main program
+ */
+int main(int argc, char **argv)
+{
+ int i;
+ unsigned char *wbuf, *rbuf, *kbuf;
+ int pass;
+ int nr_passes = 1;
+ int keep_contents = 0;
+ uint64_t offset = 0;
+ uint64_t length = -1;
+
+ for (;;) {
+ static const char *short_options="hkl:mo:p:s:";
+ static const struct option long_options[] = {
+ { "help", no_argument, 0, 'h' },
+ { "markbad", no_argument, 0, 'm' },
+ { "seed", required_argument, 0, 's' },
+ { "passes", required_argument, 0, 'p' },
+ { "offset", required_argument, 0, 'o' },
+ { "length", required_argument, 0, 'l' },
+ { "keep", no_argument, 0, 'k' },
+ {0, 0, 0, 0},
+ };
+ int option_index = 0;
+ int c = getopt_long(argc, argv, short_options, long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c) {
+ case 'h':
+ case '?':
+ usage();
+ break;
+
+ case 'm':
+ markbad = 1;
+ break;
+
+ case 'k':
+ keep_contents = 1;
+ break;
+
+ case 's':
+ seed = atol(optarg);
+ break;
+
+ case 'p':
+ nr_passes = atol(optarg);
+ break;
+
+ case 'o':
+ offset = atol(optarg);
+ break;
+
+ case 'l':
+ length = strtol(optarg, NULL, 0);
+ break;
+
+ }
+ }
+ if (argc - optind != 1)
+ usage();
+
+ fd = open(argv[optind], O_RDWR);
+ if (fd < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ if (ioctl(fd, MEMGETINFO, &meminfo)) {
+ perror("MEMGETINFO");
+ close(fd);
+ exit(1);
+ }
+
+ if (length == -1)
+ length = meminfo.size;
+
+ if (offset % meminfo.erasesize) {
+ fprintf(stderr, "Offset %09llx not multiple of erase size %x\n",
+ offset, meminfo.erasesize);
+ exit(1);
+ }
+ if (length % meminfo.erasesize) {
+ fprintf(stderr, "Length %09llx not multiple of erase size %x\n",
+ length, meminfo.erasesize);
+ exit(1);
+ }
+
+ if (length + offset > meminfo.size) {
+ fprintf(stderr, "Length %09llx + offset %09llx exceeds device size %09llx\n",
+ length, offset, meminfo.size);
+ exit(1);
+ }
+
+ wbuf = malloc(meminfo.erasesize * 3);
+ if (!wbuf) {
+ fprintf(stderr, "Could not allocate %d bytes for buffer\n",
+ meminfo.erasesize * 2);
+ exit(1);
+ }
+ rbuf = wbuf + meminfo.erasesize;
+ kbuf = rbuf + meminfo.erasesize;
+
+ if (ioctl(fd, ECCGETSTATS, &oldstats)) {
+ perror("ECCGETSTATS");
+ close(fd);
+ exit(1);
+ }
+
+ printf("ECC corrections: %d\n", oldstats.corrected);
+ printf("ECC failures : %d\n", oldstats.failed);
+ printf("Bad blocks : %d\n", oldstats.badblocks);
+ printf("BBT blocks : %d\n", oldstats.bbtblocks);
+
+ for (pass = 0; pass < nr_passes; pass++) {
+ loff_mtd_t test_ofs;
+
+ for (test_ofs = offset; test_ofs < offset+length; test_ofs += meminfo.erasesize) {
+ ssize_t len;
+
+ seed = rand();
+ srand(seed);
+
+ if (ioctl(fd, MEMGETBADBLOCK, &test_ofs)) {
+ printf("\rBad block at 0x%09llx\n", test_ofs);
+ continue;
+ }
+
+ for (i=0; i<meminfo.erasesize; i++)
+ wbuf[i] = rand();
+
+ if (keep_contents) {
+ printf("\r%09llx: reading... ", test_ofs);
+ fflush(stdout);
+
+ len = pread(fd, rbuf, meminfo.erasesize, test_ofs);
+ if (len < meminfo.erasesize) {
+ printf("\n");
+ if (len)
+ fprintf(stderr, "Short read (%d bytes)\n", len);
+ else
+ perror("read");
+ exit(1);
+ }
+ }
+ if (erase_and_write(test_ofs, wbuf, rbuf))
+ continue;
+ if (keep_contents)
+ erase_and_write(test_ofs, kbuf, rbuf);
+ }
+ printf("\nFinished pass %d successfully\n", pass+1);
+ }
+ /* Return happy */
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/nandwrite.c b/drivers/mtd/mtd-utils/nandwrite.c
new file mode 100644
index 00000000000..75edfe30ab5
--- /dev/null
+++ b/drivers/mtd/mtd-utils/nandwrite.c
@@ -0,0 +1,525 @@
+/*
+ * nandwrite.c
+ *
+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ * 2003 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Overview:
+ * This utility writes a binary image directly to a NAND flash
+ * chip or NAND chips contained in DoC devices. This is the
+ * "inverse operation" of nanddump.
+ *
+ * tglx: Major rewrite to handle bad blocks, write data with or without ECC
+ * write oob data only on request
+ *
+ * Bug/ToDo:
+ */
+
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <getopt.h>
+
+#include <asm/types.h>
+#include "mtd/mtd-user.h"
+
+#define PROGRAM "nandwrite"
+#define VERSION "$Revision: 1.1.1.1 $"
+
+#define MAX_PAGE_SIZE 4096
+#define MAX_OOB_SIZE 128
+
+/*
+ * Buffer array used for writing data
+ */
+unsigned char writebuf[MAX_PAGE_SIZE];
+unsigned char oobbuf[MAX_OOB_SIZE];
+unsigned char oobreadbuf[MAX_OOB_SIZE];
+
+// oob layouts to pass into the kernel as default
+struct nand_oobinfo none_oobinfo = {
+ .useecc = MTD_NANDECC_OFF,
+};
+
+struct nand_oobinfo jffs2_oobinfo = {
+ .useecc = MTD_NANDECC_PLACE,
+ .eccbytes = 6,
+ .eccpos = { 0, 1, 2, 3, 6, 7 }
+};
+
+struct nand_oobinfo yaffs_oobinfo = {
+ .useecc = MTD_NANDECC_PLACE,
+ .eccbytes = 6,
+ .eccpos = { 8, 9, 10, 13, 14, 15}
+};
+
+struct nand_oobinfo autoplace_oobinfo = {
+ .useecc = MTD_NANDECC_AUTOPLACE
+};
+
+void display_help (void)
+{
+ printf("Usage: nandwrite [OPTION] MTD_DEVICE INPUTFILE\n"
+ "Writes to the specified MTD device.\n"
+ "\n"
+ " -a, --autoplace Use auto oob layout\n"
+ " -j, --jffs2 force jffs2 oob layout (legacy support)\n"
+ " -y, --yaffs force yaffs oob layout (legacy support)\n"
+ " -f, --forcelegacy force legacy support on autoplacement enabled mtd device\n"
+ " -m, --markbad mark blocks bad if write fails\n"
+ " -n, --noecc write without ecc\n"
+ " -o, --oob image contains oob data\n"
+ " -s addr, --start=addr set start address (default is 0)\n"
+ " -p, --pad pad to page size\n"
+ " -b, --blockalign=1|2|4 set multiple of eraseblocks to align to\n"
+ " -q, --quiet don't display progress messages\n"
+ " --help display this help and exit\n"
+ " --version output version information and exit\n");
+ exit(0);
+}
+
+void display_version (void)
+{
+ printf(PROGRAM " " VERSION "\n"
+ "\n"
+ "Copyright (C) 2003 Thomas Gleixner \n"
+ "\n"
+ PROGRAM " comes with NO WARRANTY\n"
+ "to the extent permitted by law.\n"
+ "\n"
+ "You may redistribute copies of " PROGRAM "\n"
+ "under the terms of the GNU General Public Licence.\n"
+ "See the file `COPYING' for more information.\n");
+ exit(0);
+}
+
+char *mtd_device, *img;
+int mtdoffset = 0;
+int quiet = 0;
+int writeoob = 0;
+int markbad = 0;
+int autoplace = 0;
+int forcejffs2 = 0;
+int forceyaffs = 0;
+int forcelegacy = 0;
+int noecc = 0;
+int pad = 0;
+int blockalign = 1; /*default to using 16K block size */
+
+void process_options (int argc, char *argv[])
+{
+ int error = 0;
+
+ for (;;) {
+ int option_index = 0;
+ static const char *short_options = "ab:fjmnopqs:y";
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 0},
+ {"version", no_argument, 0, 0},
+ {"autoplace", no_argument, 0, 'a'},
+ {"blockalign", required_argument, 0, 'b'},
+ {"forcelegacy", no_argument, 0, 'f'},
+ {"jffs2", no_argument, 0, 'j'},
+ {"markbad", no_argument, 0, 'm'},
+ {"noecc", no_argument, 0, 'n'},
+ {"oob", no_argument, 0, 'o'},
+ {"pad", no_argument, 0, 'p'},
+ {"quiet", no_argument, 0, 'q'},
+ {"start", required_argument, 0, 's'},
+ {"yaffs", no_argument, 0, 'y'},
+ {0, 0, 0, 0},
+ };
+
+ int c = getopt_long(argc, argv, short_options,
+ long_options, &option_index);
+ if (c == EOF) {
+ break;
+ }
+
+ switch (c) {
+ case 0:
+ switch (option_index) {
+ case 0:
+ display_help();
+ break;
+ case 1:
+ display_version();
+ break;
+ }
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'a':
+ autoplace = 1;
+ break;
+ case 'j':
+ forcejffs2 = 1;
+ break;
+ case 'y':
+ forceyaffs = 1;
+ break;
+ case 'f':
+ forcelegacy = 1;
+ break;
+ case 'n':
+ noecc = 1;
+ break;
+ case 'm':
+ markbad = 1;
+ break;
+ case 'o':
+ writeoob = 1;
+ break;
+ case 'p':
+ pad = 1;
+ break;
+ case 's':
+ mtdoffset = strtol (optarg, NULL, 0);
+ break;
+ case 'b':
+ blockalign = atoi (optarg);
+ break;
+ case '?':
+ error = 1;
+ break;
+ }
+ }
+
+ if ((argc - optind) != 2 || error)
+ display_help ();
+
+ mtd_device = argv[optind++];
+ img = argv[optind];
+}
+
+/*
+ * Main program
+ */
+int main(int argc, char **argv)
+{
+ int cnt, fd, ifd, imglen = 0, pagelen, baderaseblock, blockstart = -1;
+ struct mtd_info_user meminfo;
+ struct mtd_oob_buf oob;
+ loff_mtd_t offs;
+ int ret, readlen;
+ int oobinfochanged = 0;
+ struct nand_oobinfo old_oobinfo;
+
+ printf("Warning: nandwrite_mlc instead of nandwrite is used for MLC NAND!\n");
+
+ process_options(argc, argv);
+
+ memset(oobbuf, 0xff, sizeof(oobbuf));
+
+ if (pad && writeoob) {
+ fprintf(stderr, "Can't pad when oob data is present.\n");
+ exit(1);
+ }
+
+ /* Open the device */
+ if ((fd = open(mtd_device, O_RDWR)) == -1) {
+ perror("open flash");
+ exit(1);
+ }
+
+ /* Fill in MTD device capability structure */
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ perror("MEMGETINFO");
+ close(fd);
+ exit(1);
+ }
+
+ /* Set erasesize to specified number of blocks - to match jffs2
+ * (virtual) block size */
+ meminfo.erasesize *= blockalign;
+
+ /* Make sure device page sizes are valid */
+ if (!(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
+ !(meminfo.oobsize == 8 && meminfo.writesize == 256) &&
+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096)) {
+ fprintf(stderr, "Unknown flash (not normal NAND)\n");
+ close(fd);
+ exit(1);
+ }
+
+ if (autoplace) {
+ /* Read the current oob info */
+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMGETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+
+ // autoplace ECC ?
+ if (autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
+
+ if (ioctl (fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ oobinfochanged = 1;
+ }
+ }
+
+ if (noecc) {
+ ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW);
+ if (ret == 0) {
+ oobinfochanged = 2;
+ } else {
+ switch (errno) {
+ case ENOTTY:
+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMGETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ oobinfochanged = 1;
+ break;
+ default:
+ perror ("MTDFILEMODE");
+ close (fd);
+ exit (1);
+ }
+ }
+ }
+
+ /*
+ * force oob layout for jffs2 or yaffs ?
+ * Legacy support
+ */
+ if (forcejffs2 || forceyaffs) {
+ struct nand_oobinfo *oobsel = forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
+
+ if (autoplace) {
+ fprintf(stderr, "Autoplacement is not possible for legacy -j/-y options\n");
+ goto restoreoob;
+ }
+ if ((old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) && !forcelegacy) {
+ fprintf(stderr, "Use -f option to enforce legacy placement on autoplacement enabled mtd device\n");
+ goto restoreoob;
+ }
+ if (meminfo.oobsize == 8) {
+ if (forceyaffs) {
+ fprintf (stderr, "YAFSS cannot operate on 256 Byte page size");
+ goto restoreoob;
+ }
+ /* Adjust number of ecc bytes */
+ jffs2_oobinfo.eccbytes = 3;
+ }
+
+ if (ioctl (fd, MEMSETOOBSEL, oobsel) != 0) {
+ perror ("MEMSETOOBSEL");
+ goto restoreoob;
+ }
+ }
+
+ oob.length = meminfo.oobsize;
+ oob.ptr = noecc ? oobreadbuf : oobbuf;
+
+ /* Open the input file */
+ if ((ifd = open(img, O_RDONLY)) == -1) {
+ perror("open input file");
+ goto restoreoob;
+ }
+
+ // get image length
+ imglen = lseek(ifd, 0, SEEK_END);
+ lseek (ifd, 0, SEEK_SET);
+
+ pagelen = meminfo.writesize + ((writeoob == 1) ? meminfo.oobsize : 0);
+
+ // Check, if file is pagealigned
+ if ((!pad) && ((imglen % pagelen) != 0)) {
+ fprintf (stderr, "Input file is not page aligned\n");
+ goto closeall;
+ }
+
+ // Check, if length fits into device
+ if ( ((imglen / pagelen) * meminfo.writesize) > (meminfo.size - mtdoffset)) {
+ fprintf (stderr, "Image %d bytes, NAND page %d bytes, OOB area %u bytes, device size %llu bytes\n",
+ imglen, pagelen, meminfo.writesize, meminfo.size);
+ perror ("Input file does not fit into device");
+ goto closeall;
+ }
+
+ /* Get data from input and write to the device */
+ while (imglen && (mtdoffset < meminfo.size)) {
+ // new eraseblock , check for bad block(s)
+ // Stay in the loop to be sure if the mtdoffset changes because
+ // of a bad block, that the next block that will be written to
+ // is also checked. Thus avoiding errors if the block(s) after the
+ // skipped block(s) is also bad (number of blocks depending on
+ // the blockalign
+ while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) {
+ blockstart = mtdoffset & (~meminfo.erasesize + 1);
+ offs = blockstart;
+ baderaseblock = 0;
+ if (!quiet)
+ fprintf (stdout, "Writing data to block %x\n", blockstart);
+
+ /* Check all the blocks in an erase block for bad blocks */
+ do {
+ if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) {
+ perror("ioctl(MEMGETBADBLOCK)");
+ goto closeall;
+ }
+
+ if (ret == 1) {
+ baderaseblock = 1;
+ if (!quiet)
+ fprintf (stderr, "Bad block at %x, %u block(s) "
+ "from %x will be skipped\n",
+ (int) offs, blockalign, blockstart);
+ }
+
+ if (baderaseblock) {
+ mtdoffset = blockstart + meminfo.erasesize;
+ }
+ offs += meminfo.erasesize / blockalign ;
+ } while ( offs < blockstart + meminfo.erasesize );
+
+ }
+
+ readlen = meminfo.writesize;
+ if (pad && (imglen < readlen))
+ {
+ readlen = imglen;
+ memset(writebuf + readlen, 0xff, meminfo.writesize - readlen);
+ }
+
+ /* Read Page Data from input file */
+ if ((cnt = read(ifd, writebuf, readlen)) != readlen) {
+ if (cnt == 0) // EOF
+ break;
+ perror ("File I/O error on input file");
+ goto closeall;
+ }
+
+ if (writeoob) {
+ /* Read OOB data from input file, exit on failure */
+ if ((cnt = read(ifd, oobreadbuf, meminfo.oobsize)) != meminfo.oobsize) {
+ perror ("File I/O error on input file");
+ goto closeall;
+ }
+ if (!noecc) {
+ int i, start, len;
+ /*
+ * We use autoplacement and have the oobinfo with the autoplacement
+ * information from the kernel available
+ *
+ * Modified to support out of order oobfree segments,
+ * such as the layout used by diskonchip.c
+ */
+ if (!oobinfochanged && (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE)) {
+ for (i = 0;old_oobinfo.oobfree[i][1]; i++) {
+ /* Set the reserved bytes to 0xff */
+ start = old_oobinfo.oobfree[i][0];
+ len = old_oobinfo.oobfree[i][1];
+ memcpy(oobbuf + start,
+ oobreadbuf + start,
+ len);
+ }
+ } else {
+ /* Set at least the ecc byte positions to 0xff */
+ start = old_oobinfo.eccbytes;
+ len = meminfo.oobsize - start;
+ memcpy(oobbuf + start,
+ oobreadbuf + start,
+ len);
+ }
+ }
+ /* Write OOB data first, as ecc will be placed in there*/
+ oob.start = mtdoffset;
+ if (ioctl(fd, MEMWRITEOOB, &oob) != 0) {
+ perror ("ioctl(MEMWRITEOOB)");
+ goto closeall;
+ }
+ imglen -= meminfo.oobsize;
+ }
+
+ /* Write out the Page data */
+ if (pwrite(fd, writebuf, meminfo.writesize, mtdoffset) != meminfo.writesize) {
+ int rewind_blocks;
+ off_t rewind_bytes;
+ erase_info_t erase;
+
+ perror ("pwrite");
+ /* Must rewind to blockstart if we can */
+ rewind_blocks = (mtdoffset - blockstart) / meminfo.writesize; /* Not including the one we just attempted */
+ rewind_bytes = (rewind_blocks * meminfo.writesize) + readlen;
+ if (writeoob)
+ rewind_bytes += (rewind_blocks + 1) * meminfo.oobsize;
+ if (lseek(ifd, -rewind_bytes, SEEK_CUR) == -1) {
+ perror("lseek");
+ fprintf(stderr, "Failed to seek backwards to recover from write error\n");
+ goto closeall;
+ }
+ erase.start = blockstart;
+ erase.length = meminfo.erasesize;
+ fprintf(stderr, "Erasing failed write from 0x%09llx-0x%09llx\n",
+ erase.start, erase.start+erase.length-1);
+ if (ioctl(fd, MEMERASE, &erase) != 0) {
+ perror("MEMERASE");
+ goto closeall;
+ }
+
+ if (markbad) {
+ loff_mtd_t bad_addr = mtdoffset & (~(meminfo.erasesize / blockalign) + 1);
+ fprintf(stderr, "Marking block at %09llx bad\n", (long long)bad_addr);
+ if (ioctl(fd, MEMSETBADBLOCK, &bad_addr)) {
+ perror("MEMSETBADBLOCK");
+ /* But continue anyway */
+ }
+ }
+ mtdoffset = blockstart + meminfo.erasesize;
+ imglen += rewind_blocks * meminfo.writesize;
+
+ continue;
+ }
+ imglen -= readlen;
+ mtdoffset += meminfo.writesize;
+ }
+
+closeall:
+ close(ifd);
+
+restoreoob:
+ if (oobinfochanged == 1) {
+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ }
+
+ close(fd);
+
+ if (imglen > 0) {
+ perror ("Data was only partially written due to error\n");
+ exit (1);
+ }
+
+ /* Return happy */
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/nandwrite_mlc.c b/drivers/mtd/mtd-utils/nandwrite_mlc.c
new file mode 100644
index 00000000000..52f5b18e02b
--- /dev/null
+++ b/drivers/mtd/mtd-utils/nandwrite_mlc.c
@@ -0,0 +1,446 @@
+/*
+ * nandwrite.c
+ *
+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ * 2003 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Overview:
+ * This utility writes a binary image directly to a NAND flash
+ * chip or NAND chips contained in DoC devices. This is the
+ * "inverse operation" of nanddump.
+ *
+ * tglx: Major rewrite to handle bad blocks, write data with or without ECC
+ * write oob data only on request
+ *
+ * Bug/ToDo:
+ */
+
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <getopt.h>
+
+#include <asm/types.h>
+#include "mtd/mtd-user.h"
+
+#define PROGRAM "nandwrite"
+#define VERSION "$Revision: 1.1.1.1 $"
+
+#define MAX_PAGE_SIZE 8192
+#define MAX_OOB_SIZE 256
+/*
+ * Buffer array used for writing data
+ */
+unsigned char writebuf[MAX_PAGE_SIZE];
+unsigned char oobreadbuf[MAX_OOB_SIZE];
+
+// oob layouts to pass into the kernel as default
+struct nand_oobinfo none_oobinfo = {
+ .useecc = MTD_NANDECC_OFF,
+};
+
+struct nand_oobinfo jffs2_oobinfo = {
+ .useecc = MTD_NANDECC_PLACE,
+ .eccbytes = 6,
+ .eccpos = { 0, 1, 2, 3, 6, 7 }
+};
+
+struct nand_oobinfo yaffs_oobinfo = {
+ .useecc = MTD_NANDECC_PLACE,
+ .eccbytes = 6,
+ .eccpos = { 8, 9, 10, 13, 14, 15}
+};
+
+struct nand_oobinfo autoplace_oobinfo = {
+ .useecc = MTD_NANDECC_AUTOPLACE,
+ .eccbytes = 36
+};
+
+void display_help (void)
+{
+ printf("Usage: nandwrite [OPTION] MTD_DEVICE INPUTFILE\n"
+ "Writes to the specified MTD device.\n"
+ "\n"
+ " -a, --autoplace Use auto oob layout\n"
+ " -j, --jffs2 force jffs2 oob layout (legacy support)\n"
+ " -y, --yaffs force yaffs oob layout (legacy support)\n"
+ " -f, --forcelegacy force legacy support on autoplacement enabled mtd device\n"
+ " -m, --markbad mark blocks bad if write fails\n"
+ " -n, --noecc write without ecc\n"
+ " -o, --oob image contains oob data\n"
+ " -s addr, --start=addr set start address (default is 0)\n"
+ " -p, --pad pad to page size\n"
+ " -b, --blockalign=1|2|4 set multiple of eraseblocks to align to\n"
+ " -q, --quiet don't display progress messages\n"
+ " --help display this help and exit\n"
+ " --version output version information and exit\n");
+ exit(0);
+}
+
+void display_version (void)
+{
+ printf(PROGRAM " " VERSION "\n"
+ "\n"
+ "Copyright (C) 2003 Thomas Gleixner \n"
+ "\n"
+ PROGRAM " comes with NO WARRANTY\n"
+ "to the extent permitted by law.\n"
+ "\n"
+ "You may redistribute copies of " PROGRAM "\n"
+ "under the terms of the GNU General Public Licence.\n"
+ "See the file `COPYING' for more information.\n");
+ exit(0);
+}
+
+char *mtd_device, *img;
+unsigned long long mtdoffset = 0;
+int quiet = 0;
+int writeoob = 0;
+int markbad = 1;
+int autoplace = 0;
+int forcejffs2 = 0;
+int forceyaffs = 0;
+int forcelegacy = 0;
+int noecc = 0;
+int pad = 0;
+int blockalign = 1; /*default to using 16K block size */
+
+void process_options (int argc, char *argv[])
+{
+ int error = 0;
+
+ for (;;) {
+ int option_index = 0;
+ static const char *short_options = "ab:fjmnopqs:y";
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 0},
+ {"version", no_argument, 0, 0},
+ {"autoplace", no_argument, 0, 'a'},
+ {"blockalign", required_argument, 0, 'b'},
+ {"forcelegacy", no_argument, 0, 'f'},
+ {"jffs2", no_argument, 0, 'j'},
+ {"markbad", no_argument, 0, 'm'},
+ {"noecc", no_argument, 0, 'n'},
+ {"oob", no_argument, 0, 'o'},
+ {"pad", no_argument, 0, 'p'},
+ {"quiet", no_argument, 0, 'q'},
+ {"start", required_argument, 0, 's'},
+ {"yaffs", no_argument, 0, 'y'},
+ {0, 0, 0, 0},
+ };
+
+ int c = getopt_long(argc, argv, short_options,
+ long_options, &option_index);
+ if (c == EOF) {
+ break;
+ }
+
+ switch (c) {
+ case 0:
+ switch (option_index) {
+ case 0:
+ display_help();
+ break;
+ case 1:
+ display_version();
+ break;
+ }
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'a':
+ autoplace = 1;
+ break;
+ case 'j':
+ forcejffs2 = 1;
+ break;
+ case 'y':
+ forceyaffs = 1;
+ break;
+ case 'f':
+ forcelegacy = 1;
+ break;
+ case 'n':
+ noecc = 1;
+ break;
+ case 'm':
+ markbad = 1;
+ break;
+ case 'o':
+ writeoob = 1;
+ break;
+ case 'p':
+ pad = 1;
+ break;
+ case 's':
+ mtdoffset = strtol (optarg, NULL, 0);
+ break;
+ case 'b':
+ blockalign = atoi (optarg);
+ break;
+ case '?':
+ error = 1;
+ break;
+ }
+ }
+
+ if ((argc - optind) != 2 || error)
+ display_help ();
+
+ mtd_device = argv[optind++];
+ img = argv[optind];
+}
+
+/*
+ * Main program
+ */
+int main(int argc, char **argv)
+{
+ int cnt, fd, ifd, imglen = 0, pagelen, baderaseblock, blockstart = -1;
+ struct mtd_info_user meminfo;
+ struct mtd_page_buf oob;
+ loff_mtd_t offs;
+ int ret, readlen;
+ int oobinfochanged = 0;
+ struct nand_oobinfo old_oobinfo;
+ int i;
+
+ process_options(argc, argv);
+
+ if (pad && writeoob) {
+ fprintf(stderr, "Can't pad when oob data is present.\n");
+ exit(1);
+ }
+
+ /* Open the device */
+ if ((fd = open(mtd_device, O_RDWR)) == -1) {
+ perror("open flash");
+ exit(1);
+ }
+
+ /* Fill in MTD device capability structure */
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ perror("MEMGETINFO");
+ close(fd);
+ exit(1);
+ }
+
+ /* Set erasesize to specified number of blocks - to match jffs2
+ * (virtual) block size */
+ meminfo.erasesize *= blockalign;
+
+ /* Make sure device page sizes are valid */
+ if (!(meminfo.oobsize == 16 && meminfo.writesize == 512) &&
+ !(meminfo.oobsize == 8 && meminfo.writesize == 256) &&
+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) &&
+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096) &&
+ !(meminfo.oobsize == 256 && meminfo.writesize == 8192)) {
+ fprintf(stderr, "Unknown flash (not normal NAND)\n");
+ close(fd);
+ exit(1);
+ }
+
+ if (autoplace) {
+ /* Read the current oob info */
+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMGETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+
+ // autoplace ECC ?
+ if (autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
+
+ if (ioctl (fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ oobinfochanged = 1;
+ }
+ }
+
+ memset(oobreadbuf, 0xff, MAX_OOB_SIZE);
+
+ if (autoplace) {
+ oob.ooblength = meminfo.oobsize-old_oobinfo.eccbytes; /* Get ooblength from kernel */
+ printf("oobsize=%d eccbytes=%d\n", meminfo.oobsize, old_oobinfo.eccbytes);
+ } else {
+ oob.ooblength = meminfo.oobsize-autoplace_oobinfo.eccbytes;
+ printf("oobsize=%d eccbytes=%d\n", meminfo.oobsize, autoplace_oobinfo.eccbytes);
+ }
+
+ oob.oobptr = oobreadbuf;
+ oob.datptr = writebuf;
+
+ /* Open the input file */
+ if ((ifd = open(img, O_RDONLY)) == -1) {
+ perror("open input file");
+ goto restoreoob;
+ }
+
+ // get image length
+ imglen = lseek(ifd, 0, SEEK_END);
+ lseek (ifd, 0, SEEK_SET);
+
+ pagelen = meminfo.writesize + ((writeoob == 1) ? meminfo.oobsize : 0);
+
+ // Check, if file is pagealigned
+ if ((!pad) && ((imglen % pagelen) != 0)) {
+ fprintf (stderr, "Input file is not page aligned\n");
+ goto closeall;
+ }
+
+ // Check, if length fits into device
+ if ( ((imglen / pagelen) * meminfo.writesize) > (meminfo.size - mtdoffset)) {
+ fprintf (stderr, "Image %d bytes, NAND page %d bytes, OOB area %u bytes, device size %lld bytes\n",
+ imglen, pagelen, meminfo.writesize, meminfo.size);
+ perror ("Input file does not fit into device");
+ goto closeall;
+ }
+
+ /* Get data from input and write to the device */
+ while (imglen && (mtdoffset < meminfo.size)) {
+ // new eraseblock , check for bad block(s)
+ // Stay in the loop to be sure if the mtdoffset changes because
+ // of a bad block, that the next block that will be written to
+ // is also checked. Thus avoiding errors if the block(s) after the
+ // skipped block(s) is also bad (number of blocks depending on
+ // the blockalign
+ while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) {
+ blockstart = mtdoffset & (~meminfo.erasesize + 1);
+ offs = blockstart;
+ baderaseblock = 0;
+ i=0;
+ if (!quiet)
+ fprintf (stdout, "Writing data to block 0x%x\n", blockstart);
+
+ /* Check all the blocks in an erase block for bad blocks */
+ do {
+ if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) {
+ perror("ioctl(MEMGETBADBLOCK)");
+ goto closeall;
+ }
+ if (ret == 1) {
+ baderaseblock = 1;
+ if (!quiet)
+ fprintf (stderr, "Bad block at 0x%llx, %u block(s) "
+ "from 0x%x will be skipped\n",
+ offs, blockalign, blockstart);
+ }
+
+ if (baderaseblock) {
+ mtdoffset = blockstart + meminfo.erasesize;
+ }
+ offs += meminfo.erasesize / blockalign ;
+ } while ( offs < blockstart + meminfo.erasesize );
+
+ }
+
+ readlen = meminfo.writesize;
+ if (pad && (imglen < readlen))
+ {
+ readlen = imglen;
+ memset(writebuf + readlen, 0xff, meminfo.writesize - readlen);
+ }
+
+ /* Read Page Data from input file */
+ if ((cnt = read(ifd, writebuf, readlen)) != readlen) {
+ if (cnt == 0) // EOF
+ break;
+ perror ("File I/O error 1 on input file");
+ goto closeall;
+ }
+
+ /* Read OOB data from input file, exit on failure */
+ if(writeoob) {
+ if ((cnt = read(ifd, oobreadbuf, meminfo.oobsize)) != meminfo.oobsize) {
+ perror ("File I/O error 2 on input file");
+ goto closeall;
+ }
+ }
+ oob.start = mtdoffset;
+
+ // write a page include its oob to nand
+ ioctl(fd, MEMWRITEPAGE, &oob);
+ if(oob.datlength != meminfo.writesize){
+ perror ("ioctl(MEMWRITEPAGE)");
+
+ int rewind_blocks;
+ off_t rewind_bytes;
+ erase_info_t erase;
+
+ /* Must rewind to blockstart if we can */
+ rewind_blocks = (mtdoffset - blockstart) / meminfo.writesize; /* Not including the one we just attempted */
+ rewind_bytes = (rewind_blocks * meminfo.writesize) + readlen;
+ if (writeoob)
+ rewind_bytes += (rewind_blocks + 1) * meminfo.oobsize;
+ if (lseek(ifd, -rewind_bytes, SEEK_CUR) == -1) {
+ perror("lseek");
+ fprintf(stderr, "Failed to seek backwards to recover from write error\n");
+ goto closeall;
+ }
+ erase.start = blockstart;
+ erase.length = meminfo.erasesize;
+ fprintf(stderr, "Erasing failed write from 0x%09llx-0x%09llx\n",
+ erase.start, erase.start+erase.length-1);
+ if (ioctl(fd, MEMERASE, &erase) != 0) {
+ perror("MEMERASE");
+ goto closeall;
+ }
+
+ if (markbad) {
+ loff_mtd_t bad_addr = mtdoffset & (~(meminfo.erasesize / blockalign) + 1);
+ fprintf(stderr, "Marking block at %09llx bad\n", (long long)bad_addr);
+ if (ioctl(fd, MEMSETBADBLOCK, &bad_addr)) {
+ perror("MEMSETBADBLOCK");
+ /* But continue anyway */
+ }
+ }
+ mtdoffset = blockstart + meminfo.erasesize;
+ imglen += rewind_blocks * meminfo.writesize;
+
+ continue;
+ }
+ if(writeoob)
+ imglen -= meminfo.oobsize;
+ imglen -= readlen;
+ mtdoffset += meminfo.writesize;
+ }
+
+closeall:
+ close(ifd);
+
+restoreoob:
+ if (oobinfochanged == 1) {
+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
+ perror ("MEMSETOOBSEL");
+ close (fd);
+ exit (1);
+ }
+ }
+
+ close(fd);
+
+ if (imglen > 0) {
+ perror ("Data was only partially written due to error\n");
+ exit (1);
+ }
+
+ /* Return happy */
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/nftl_format.c b/drivers/mtd/mtd-utils/nftl_format.c
new file mode 100644
index 00000000000..42949a0393e
--- /dev/null
+++ b/drivers/mtd/mtd-utils/nftl_format.c
@@ -0,0 +1,419 @@
+/*
+ * nftl_format.c: Creating a NFTL/INFTL partition on an MTD device
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ToDo:
+ * 1. UnitSizeFactor != 0xFF cases
+ * 2. test, test, and test !!!
+ */
+
+#define _XOPEN_SOURCE 500 /* for pread/pwrite */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <string.h>
+
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+#include <mtd/nftl-user.h>
+#include <mtd/inftl-user.h>
+#include <mtd_swab.h>
+
+unsigned char BadUnitTable[MAX_ERASE_ZONES];
+unsigned char *readbuf;
+unsigned char *writebuf[4];
+
+mtd_info_t meminfo;
+erase_info_t erase;
+int fd;
+struct NFTLMediaHeader *NFTLhdr;
+struct INFTLMediaHeader *INFTLhdr;
+
+static int do_oobcheck = 1;
+static int do_rwecheck = 1;
+
+static unsigned char check_block_1(unsigned long block)
+{
+ unsigned char oobbuf[16];
+ struct mtd_oob_buf oob = { 0, 16, oobbuf };
+
+ oob.start = block * meminfo.erasesize;
+ if (ioctl(fd, MEMREADOOB, &oob))
+ return ZONE_BAD_ORIGINAL;
+
+ if(oobbuf[5] == 0)
+ return ZONE_BAD_ORIGINAL;
+
+ oob.start = block * meminfo.erasesize + 512 /* FIXME */;
+ if (ioctl(fd, MEMREADOOB, &oob))
+ return ZONE_BAD_ORIGINAL;
+
+ if(oobbuf[5] == 0)
+ return ZONE_BAD_ORIGINAL;
+
+ return ZONE_GOOD;
+}
+
+static unsigned char check_block_2(unsigned long block)
+{
+ unsigned long ofs = block * meminfo.erasesize;
+ unsigned long blockofs;
+
+ /* Erase test */
+ erase.start = ofs;
+
+ for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
+ pread(fd, readbuf, 512, ofs + blockofs);
+ if (memcmp(readbuf, writebuf[0], 512)) {
+ /* Block wasn't 0xff after erase */
+ printf(": Block not 0xff after erase\n");
+ return ZONE_BAD_ORIGINAL;
+ }
+
+ pwrite(fd, writebuf[1], 512, blockofs + ofs);
+ pread(fd, readbuf, 512, blockofs + ofs);
+ if (memcmp(readbuf, writebuf[1], 512)) {
+ printf(": Block not zero after clearing\n");
+ return ZONE_BAD_ORIGINAL;
+ }
+ }
+
+ /* Write test */
+ if (ioctl(fd, MEMERASE, &erase) != 0) {
+ printf(": Second erase failed (%s)\n", strerror(errno));
+ return ZONE_BAD_ORIGINAL;
+ }
+ for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
+ pwrite(fd, writebuf[2], 512, blockofs + ofs);
+ pread(fd, readbuf, 512, blockofs + ofs);
+ if (memcmp(readbuf, writebuf[2], 512)) {
+ printf(": Block not 0x5a after writing\n");
+ return ZONE_BAD_ORIGINAL;
+ }
+ }
+
+ if (ioctl(fd, MEMERASE, &erase) != 0) {
+ printf(": Third erase failed (%s)\n", strerror(errno));
+ return ZONE_BAD_ORIGINAL;
+ }
+ for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
+ pwrite(fd, writebuf[3], 512, blockofs + ofs);
+ pread(fd, readbuf, 512, blockofs + ofs);
+ if (memcmp(readbuf, writebuf[3], 512)) {
+ printf(": Block not 0xa5 after writing\n");
+ return ZONE_BAD_ORIGINAL;
+ }
+ }
+ if (ioctl(fd, MEMERASE, &erase) != 0) {
+ printf(": Fourth erase failed (%s)\n", strerror(errno));
+ return ZONE_BAD_ORIGINAL;
+ }
+ return ZONE_GOOD;
+}
+
+static unsigned char erase_block(unsigned long block)
+{
+ unsigned char status;
+ int ret;
+
+ status = (do_oobcheck) ? check_block_1(block) : ZONE_GOOD;
+ erase.start = block * meminfo.erasesize;
+
+ if (status != ZONE_GOOD) {
+ printf("\rSkipping bad zone (factory marked) #%ld @ 0x%x\n", block, erase.start);
+ fflush(stdout);
+ return status;
+ }
+
+ printf("\r\t Erasing Zone #%ld @ 0x%x", block, erase.start);
+ fflush(stdout);
+
+ if ((ret=ioctl(fd, MEMERASE, &erase)) != 0) {
+ printf(": Erase failed (%s)\n", strerror(errno));
+ return ZONE_BAD_ORIGINAL;
+ }
+
+ if (do_rwecheck) {
+ printf("\r\tChecking Zone #%ld @ 0x%x", block, erase.start);
+ fflush(stdout);
+ status = check_block_2(block);
+ if (status != ZONE_GOOD) {
+ printf("\rSkipping bad zone (RWE test failed) #%ld @ 0x%x\n", block, erase.start);
+ fflush(stdout);
+ }
+ }
+ return status;
+}
+
+static int checkbbt(void)
+{
+ unsigned char bbt[512];
+ unsigned char bits;
+ int i, addr;
+
+ if (pread(fd, bbt, 512, 0x800) < 0) {
+ printf("nftl_format: failed to read BBT, errno=%d\n", errno);
+ return (-1);
+ }
+
+
+ for (i = 0; (i < 512); i++) {
+ addr = i / 4;
+ bits = 0x3 << ((i % 4) * 2);
+ if ((bbt[addr] & bits) == 0) {
+ BadUnitTable[i] = ZONE_BAD_ORIGINAL;
+ }
+ }
+
+ return (0);
+}
+
+void usage(int rc)
+{
+ fprintf(stderr, "Usage: nftl_format [-ib] <mtddevice> [<start offset> [<size>]]\n");
+ exit(rc);
+}
+
+int main(int argc, char **argv)
+{
+ unsigned long startofs = 0, part_size = 0;
+ unsigned long ezones = 0, ezone = 0, bad_zones = 0;
+ unsigned char unit_factor = 0xFF;
+ long MediaUnit1 = -1, MediaUnit2 = -1;
+ long MediaUnitOff1 = 0, MediaUnitOff2 = 0;
+ unsigned char oobbuf[16];
+ struct mtd_oob_buf oob = {0, 16, oobbuf};
+ char *mtddevice, *nftl;
+ int c, do_inftl = 0, do_bbt = 0;
+
+
+ printf("version 1.24 2005/11/07 11:15:13 gleixner\n");
+
+ if (argc < 2)
+ usage(1);
+
+ nftl = "NFTL";
+
+ while ((c = getopt(argc, argv, "?hib")) > 0) {
+ switch (c) {
+ case 'i':
+ nftl = "INFTL";
+ do_inftl = 1;
+ break;
+ case 'b':
+ do_bbt = 1;
+ break;
+ case 'h':
+ case '?':
+ usage(0);
+ break;
+ default:
+ usage(1);
+ break;
+ }
+ }
+
+ mtddevice = argv[optind++];
+ if (argc > optind) {
+ startofs = strtoul(argv[optind++], NULL, 0);
+ }
+ if (argc > optind) {
+ part_size = strtoul(argv[optind++], NULL, 0);
+ }
+
+ // Open and size the device
+ if ((fd = open(mtddevice, O_RDWR)) < 0) {
+ perror("Open flash device");
+ return 1;
+ }
+
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ perror("ioctl(MEMGETINFO)");
+ close(fd);
+ return 1;
+ }
+
+ switch (meminfo.erasesize) {
+ case 0x1000:
+ case 0x2000:
+ case 0x4000:
+ case 0x8000:
+ break;
+ default:
+ printf("Unrecognized Erase size, 0x%x - I'm confused\n",
+ meminfo.erasesize);
+ close(fd);
+ return 1;
+ }
+ writebuf[0] = malloc(meminfo.erasesize * 5);
+ if (!writebuf[0]) {
+ printf("Malloc failed\n");
+ close(fd);
+ return 1;
+ }
+ writebuf[1] = writebuf[0] + meminfo.erasesize;
+ writebuf[2] = writebuf[1] + meminfo.erasesize;
+ writebuf[3] = writebuf[2] + meminfo.erasesize;
+ readbuf = writebuf[3] + meminfo.erasesize;
+ memset(writebuf[0], 0xff, meminfo.erasesize);
+ memset(writebuf[1], 0x00, meminfo.erasesize);
+ memset(writebuf[2], 0x5a, meminfo.erasesize);
+ memset(writebuf[3], 0xa5, meminfo.erasesize);
+ memset(BadUnitTable, ZONE_GOOD, MAX_ERASE_ZONES);
+
+ if (part_size == 0 || (part_size > meminfo.size - startofs))
+ /* the user doest not or incorrectly specify NFTL partition size */
+ part_size = meminfo.size - startofs;
+
+ erase.length = meminfo.erasesize;
+ ezones = part_size / meminfo.erasesize;
+
+ if (ezones > MAX_ERASE_ZONES) {
+ /* Ought to change the UnitSizeFactor. But later. */
+ part_size = meminfo.erasesize * MAX_ERASE_ZONES;
+ ezones = MAX_ERASE_ZONES;
+ unit_factor = 0xFF;
+ }
+
+ /* If using device BBT then parse that now */
+ if (do_bbt) {
+ checkbbt();
+ do_oobcheck = 0;
+ do_rwecheck = 0;
+ }
+
+ /* Phase 1. Erasing and checking each erase zones in the NFTL partition.
+ N.B. Erase Zones not used by the NFTL partition are untouched and marked ZONE_GOOD */
+ printf("Phase 1. Checking and erasing Erase Zones from 0x%08lx to 0x%08lx\n",
+ startofs, startofs + part_size);
+ for (ezone = startofs / meminfo.erasesize;
+ ezone < (ezones + startofs / meminfo.erasesize); ezone++) {
+ if (BadUnitTable[ezone] != ZONE_GOOD)
+ continue;
+ if ((BadUnitTable[ezone] = erase_block(ezone)) == ZONE_GOOD) {
+ if (MediaUnit1 == -1) {
+ MediaUnit1 = ezone;
+ } else if (MediaUnit2 == -1) {
+ MediaUnit2 = ezone;
+ }
+ } else {
+ bad_zones++;
+ }
+ }
+ printf("\n");
+
+ /* N.B. from dump of M-System original chips, NumEraseUnits counts the 2 Erase Unit used
+ by MediaHeader and the FirstPhysicalEUN starts from the MediaHeader */
+ if (do_inftl) {
+ unsigned long maxzones, pezstart, pezend, numvunits;
+
+ INFTLhdr = (struct INFTLMediaHeader *) (writebuf[0]);
+ strcpy(INFTLhdr->bootRecordID, "BNAND");
+ INFTLhdr->NoOfBootImageBlocks = cpu_to_le32(0);
+ INFTLhdr->NoOfBinaryPartitions = cpu_to_le32(0);
+ INFTLhdr->NoOfBDTLPartitions = cpu_to_le32(1);
+ INFTLhdr->BlockMultiplierBits = cpu_to_le32(0);
+ INFTLhdr->FormatFlags = cpu_to_le32(0);
+ INFTLhdr->OsakVersion = cpu_to_le32(OSAK_VERSION);
+ INFTLhdr->PercentUsed = cpu_to_le32(PERCENTUSED);
+ /*
+ * Calculate number of virtual units we will have to work
+ * with. I am calculating out the known bad units here, not
+ * sure if that is what M-Systems do...
+ */
+ MediaUnit2 = MediaUnit1;
+ MediaUnitOff2 = 4096;
+ maxzones = meminfo.size / meminfo.erasesize;
+ pezstart = startofs / meminfo.erasesize + 1;
+ pezend = startofs / meminfo.erasesize + ezones - 1;
+ numvunits = (ezones - 2) * PERCENTUSED / 100;
+ for (ezone = pezstart; ezone < maxzones; ezone++) {
+ if (BadUnitTable[ezone] != ZONE_GOOD) {
+ if (numvunits > 1)
+ numvunits--;
+ }
+ }
+
+ INFTLhdr->Partitions[0].virtualUnits = cpu_to_le32(numvunits);
+ INFTLhdr->Partitions[0].firstUnit = cpu_to_le32(pezstart);
+ INFTLhdr->Partitions[0].lastUnit = cpu_to_le32(pezend);
+ INFTLhdr->Partitions[0].flags = cpu_to_le32(INFTL_BDTL);
+ INFTLhdr->Partitions[0].spareUnits = cpu_to_le32(0);
+ INFTLhdr->Partitions[0].Reserved0 = INFTLhdr->Partitions[0].firstUnit;
+ INFTLhdr->Partitions[0].Reserved1 = cpu_to_le32(0);
+
+ } else {
+
+ NFTLhdr = (struct NFTLMediaHeader *) (writebuf[0]);
+ strcpy(NFTLhdr->DataOrgID, "ANAND");
+ NFTLhdr->NumEraseUnits = cpu_to_le16(part_size / meminfo.erasesize);
+ NFTLhdr->FirstPhysicalEUN = cpu_to_le16(MediaUnit1);
+ /* N.B. we reserve 2 more Erase Units for "folding" of Virtual Unit Chain */
+ NFTLhdr->FormattedSize = cpu_to_le32(part_size - ( (5+bad_zones) * meminfo.erasesize));
+ NFTLhdr->UnitSizeFactor = unit_factor;
+ }
+
+ /* Phase 2. Writing NFTL Media Headers and Bad Unit Table */
+ printf("Phase 2.a Writing %s Media Header and Bad Unit Table\n", nftl);
+ pwrite(fd, writebuf[0], 512, MediaUnit1 * meminfo.erasesize + MediaUnitOff1);
+ for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
+ pwrite(fd, BadUnitTable + ezone, 512,
+ (MediaUnit1 * meminfo.erasesize) + 512 * (1 + ezone / 512));
+ }
+
+#if 0
+ printf(" MediaHeader contents:\n");
+ printf(" NumEraseUnits: %d\n", le16_to_cpu(NFTLhdr->NumEraseUnits));
+ printf(" FirstPhysicalEUN: %d\n", le16_to_cpu(NFTLhdr->FirstPhysicalEUN));
+ printf(" FormattedSize: %d (%d sectors)\n", le32_to_cpu(NFTLhdr->FormattedSize),
+ le32_to_cpu(NFTLhdr->FormattedSize)/512);
+#endif
+ printf("Phase 2.b Writing Spare %s Media Header and Spare Bad Unit Table\n", nftl);
+ pwrite(fd, writebuf[0], 512, MediaUnit2 * meminfo.erasesize + MediaUnitOff2);
+ for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
+ pwrite(fd, BadUnitTable + ezone, 512,
+ (MediaUnit2 * meminfo.erasesize + MediaUnitOff2) + 512 * (1 + ezone / 512));
+ }
+
+ /* UCI #1 for newly erased Erase Unit */
+ memset(oobbuf, 0xff, 16);
+ oobbuf[11] = oobbuf[10] = oobbuf[9] = 0;
+ oobbuf[8] = (do_inftl) ? 0x00 : 0x03;
+ oobbuf[12] = oobbuf[14] = 0x69;
+ oobbuf[13] = oobbuf[15] = 0x3c;
+
+ /* N.B. The Media Header and Bad Erase Unit Table are considered as Free Erase Unit
+ by M-System i.e. their Virtual Unit Number == 0xFFFF in the Unit Control Information #0,
+ but their Block Status is BLOCK_USED (0x5555) in their Block Control Information */
+ /* Phase 3. Writing Unit Control Information for each Erase Unit */
+ printf("Phase 3. Writing Unit Control Information to each Erase Unit\n");
+ for (ezone = MediaUnit1; ezone < (ezones + startofs / meminfo.erasesize); ezone++) {
+ /* write UCI #1 to each Erase Unit */
+ if (BadUnitTable[ezone] != ZONE_GOOD)
+ continue;
+ oob.start = (ezone * meminfo.erasesize) + 512 + (do_inftl * 512);
+ if (ioctl(fd, MEMWRITEOOB, &oob))
+ printf("MEMWRITEOOB at %lx: %s\n", (unsigned long)oob.start, strerror(errno));
+ }
+
+ exit(0);
+}
diff --git a/drivers/mtd/mtd-utils/nftldump.c b/drivers/mtd/mtd-utils/nftldump.c
new file mode 100644
index 00000000000..6d72acd7bef
--- /dev/null
+++ b/drivers/mtd/mtd-utils/nftldump.c
@@ -0,0 +1,281 @@
+/*
+ * nftldump.c: Dumping the content of NFTL partitions on a "Physical Disk"
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ToDo:
+ * 1. UnitSizeFactor != 0xFF cases
+ * 2. test, test, and test !!!
+ */
+
+#define _XOPEN_SOURCE 500 /* For pread */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <asm/types.h>
+#include <mtd/mtd-user.h>
+#include <mtd/nftl-user.h>
+#include <mtd_swab.h>
+
+static struct NFTLMediaHeader MedHead[2];
+static mtd_info_t meminfo;
+
+static struct nftl_oob oobbuf;
+static struct mtd_oob_buf oob = {0, 16, (unsigned char *)&oobbuf};
+
+static int fd, ofd = -1;;
+static int NumMedHeads;
+
+static unsigned char BadUnitTable[MAX_ERASE_ZONES];
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define SWAP16(x) do { ; } while(0)
+#define SWAP32(x) do { ; } while(0)
+#else
+#define SWAP16(x) do { x = swab16(x); } while(0)
+#define SWAP32(x) do { x = swab32(x); } while(0)
+#endif
+
+/* VUCtable, store the Erase Unit Number of the first Erase Unit in the chain */
+static unsigned short *VUCtable;
+
+/* FixMe: make this dynamic allocated */
+#define ERASESIZE 0x2000
+#define NUMVUNITS ((40*1024*1024) / ERASESIZE)
+static union nftl_uci UCItable[NUMVUNITS][3];
+
+static unsigned short nextEUN(unsigned short curEUN)
+{
+ return UCItable[curEUN][0].a.ReplUnitNum;
+}
+
+static unsigned int find_media_headers(void)
+{
+ int i;
+ static unsigned long ofs = 0;
+
+ NumMedHeads = 0;
+ while (ofs < meminfo.size) {
+ pread(fd, &MedHead[NumMedHeads], sizeof(struct NFTLMediaHeader), ofs);
+ if (!strncmp(MedHead[NumMedHeads].DataOrgID, "ANAND", 6)) {
+ SWAP16(MedHead[NumMedHeads].NumEraseUnits);
+ SWAP16(MedHead[NumMedHeads].FirstPhysicalEUN);
+ SWAP32(MedHead[NumMedHeads].FormattedSize);
+
+ if (NumMedHeads == 0) {
+ printf("NFTL Media Header found at offset 0x%08lx:\n", ofs);
+ printf("NumEraseUnits: %d\n",
+ MedHead[NumMedHeads].NumEraseUnits);
+ printf("FirstPhysicalEUN: %d\n",
+ MedHead[NumMedHeads].FirstPhysicalEUN);
+ printf("Formatted Size: %d\n",
+ MedHead[NumMedHeads].FormattedSize);
+ printf("UnitSizeFactor: 0x%x\n",
+ MedHead[NumMedHeads].UnitSizeFactor);
+
+ /* read BadUnitTable, I don't know why pread() does not work for
+ larger (7680 bytes) chunks */
+ for (i = 0; i < MAX_ERASE_ZONES; i += 512)
+ pread(fd, &BadUnitTable[i], 512, ofs + 512 + i);
+ } else
+ printf("Second NFTL Media Header found at offset 0x%08lx\n",ofs);
+ NumMedHeads++;
+ }
+
+ ofs += meminfo.erasesize;
+ if (NumMedHeads == 2) {
+ if (strncmp((char *)&MedHead[0], (char *)&MedHead[1], sizeof(struct NFTLMediaHeader)) != 0) {
+ printf("warning: NFTL Media Header is not consistent with "
+ "Spare NFTL Media Header\n");
+ }
+ break;
+ }
+ }
+
+ /* allocate Virtual Unit Chain table for this NFTL partition */
+ VUCtable = calloc(MedHead[0].NumEraseUnits, sizeof(unsigned short));
+ return NumMedHeads;
+}
+
+static void dump_erase_units(void)
+{
+ int i, j;
+ unsigned long ofs;
+
+ for (i = MedHead[0].FirstPhysicalEUN; i < MedHead[0].FirstPhysicalEUN +
+ MedHead[0].NumEraseUnits; i++) {
+ /* For each Erase Unit */
+ ofs = i * meminfo.erasesize;
+
+ /* read the Unit Control Information */
+ for (j = 0; j < 3; j++) {
+ oob.start = ofs + (j * 512);
+ if (ioctl(fd, MEMREADOOB, &oob))
+ printf("MEMREADOOB at %lx: %s\n",
+ (unsigned long) oob.start, strerror(errno));
+ memcpy(&UCItable[i][j], &oobbuf.u, 8);
+ }
+ if (UCItable[i][1].b.EraseMark != cpu_to_le16(0x3c69)) {
+ printf("EraseMark not present in unit %d: %x\n",
+ i, UCItable[i][1].b.EraseMark);
+ } else {
+ /* a properly formatted unit */
+ SWAP16(UCItable[i][0].a.VirtUnitNum);
+ SWAP16(UCItable[i][0].a.ReplUnitNum);
+ SWAP16(UCItable[i][0].a.SpareVirtUnitNum);
+ SWAP16(UCItable[i][0].a.SpareReplUnitNum);
+ SWAP32(UCItable[i][1].b.WearInfo);
+ SWAP16(UCItable[i][1].b.EraseMark);
+ SWAP16(UCItable[i][1].b.EraseMark1);
+ SWAP16(UCItable[i][2].c.FoldMark);
+ SWAP16(UCItable[i][2].c.FoldMark1);
+
+ if (!(UCItable[i][0].a.VirtUnitNum & 0x8000)) {
+ /* If this is the first in a chain, store the EUN in the VUC table */
+ if (VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]) {
+ printf("Duplicate start of chain for VUC %d: "
+ "Unit %d replaces Unit %d\n",
+ UCItable[i][0].a.VirtUnitNum & 0x7fff,
+ i, VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]);
+ }
+ VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff] = i;
+ }
+ }
+
+ switch (BadUnitTable[i]) {
+ case ZONE_BAD_ORIGINAL:
+ printf("Unit %d is marked as ZONE_BAD_ORIGINAL\n", i);
+ continue;
+ case ZONE_BAD_MARKED:
+ printf("Unit %d is marked as ZONE_BAD_MARKED\n", i);
+ continue;
+ }
+
+ /* ZONE_GOOD */
+ if (UCItable[i][0].a.VirtUnitNum == 0xffff)
+ printf("Unit %d is free\n", i);
+ else
+ printf("Unit %d is in chain %d and %s a replacement\n", i,
+ UCItable[i][0].a.VirtUnitNum & 0x7fff,
+ UCItable[i][0].a.VirtUnitNum & 0x8000 ? "is" : "is not");
+ }
+}
+
+static void dump_virtual_units(void)
+{
+ int i, j;
+ char readbuf[512];
+
+ for (i = 0; i < (MedHead[0].FormattedSize / meminfo.erasesize); i++) {
+ unsigned short curEUN = VUCtable[i];
+
+ printf("Virtual Unit #%d: ", i);
+ if (!curEUN) {
+ printf("Not present\n");
+ continue;
+ }
+ printf("%d", curEUN);
+
+ /* walk through the Virtual Unit Chain */
+ while ((curEUN = nextEUN(curEUN)) != 0xffff) {
+ printf(", %d", curEUN & 0x7fff);
+ }
+ printf("\n");
+
+ if (ofd != -1) {
+ /* Actually write out the data */
+ for (j = 0; j < meminfo.erasesize / 512; j++) {
+ /* For each sector in the block */
+ unsigned short lastgoodEUN = 0xffff, thisEUN = VUCtable[i];
+ unsigned int status;
+
+ if (thisEUN == 0xffff) thisEUN = 0;
+
+ while (thisEUN && (thisEUN & 0x7fff) != 0x7fff) {
+ oob.start = (thisEUN * ERASESIZE) + (j * 512);
+ ioctl(fd, MEMREADOOB, &oob);
+ status = oobbuf.b.Status | oobbuf.b.Status1;
+
+ switch (status) {
+ case SECTOR_FREE:
+ /* This is still free. Don't look any more */
+ thisEUN = 0;
+ break;
+
+ case SECTOR_USED:
+ /* SECTOR_USED. This is a good one. */
+ lastgoodEUN = thisEUN;
+ break;
+ }
+
+ /* Find the next erase unit in this chain, if any */
+ if (thisEUN)
+ thisEUN = nextEUN(thisEUN) & 0x7fff;
+ }
+
+ if (lastgoodEUN == 0xffff)
+ memset(readbuf, 0, 512);
+ else
+ pread(fd, readbuf, 512,
+ (lastgoodEUN * ERASESIZE) + (j * 512));
+
+ write(ofd, readbuf, 512);
+ }
+
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ if (argc < 2) {
+ printf("Usage: %s <device> [<outfile>]\n", argv[0]);
+ exit(1);
+ }
+ fd = open(argv[1], O_RDONLY);
+ if (fd == -1) {
+ perror("open flash");
+ exit (1);
+ }
+
+ if (argc > 2) {
+ ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644);
+ if (ofd == -1)
+ perror ("open outfile");
+ }
+
+ /* get size information of the MTD device */
+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
+ perror("ioctl(MEMGETINFO)");
+ close(fd);
+ return 1;
+ }
+
+ while (find_media_headers() != 0) {
+ dump_erase_units();
+ dump_virtual_units();
+ free(VUCtable);
+ }
+
+ exit(0);
+}
diff --git a/drivers/mtd/mtd-utils/rbtree.c b/drivers/mtd/mtd-utils/rbtree.c
new file mode 100644
index 00000000000..dd50134b21c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/rbtree.c
@@ -0,0 +1,390 @@
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
+ (C) 2002 David Woodhouse <dwmw2@infradead.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ linux/lib/rbtree.c
+*/
+
+#include <stdlib.h>
+#include "rbtree.h"
+
+static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *right = node->rb_right;
+ struct rb_node *parent = rb_parent(node);
+
+ if ((node->rb_right = right->rb_left))
+ rb_set_parent(right->rb_left, node);
+ right->rb_left = node;
+
+ rb_set_parent(right, parent);
+
+ if (parent)
+ {
+ if (node == parent->rb_left)
+ parent->rb_left = right;
+ else
+ parent->rb_right = right;
+ }
+ else
+ root->rb_node = right;
+ rb_set_parent(node, right);
+}
+
+static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *left = node->rb_left;
+ struct rb_node *parent = rb_parent(node);
+
+ if ((node->rb_left = left->rb_right))
+ rb_set_parent(left->rb_right, node);
+ left->rb_right = node;
+
+ rb_set_parent(left, parent);
+
+ if (parent)
+ {
+ if (node == parent->rb_right)
+ parent->rb_right = left;
+ else
+ parent->rb_left = left;
+ }
+ else
+ root->rb_node = left;
+ rb_set_parent(node, left);
+}
+
+void rb_insert_color(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *parent, *gparent;
+
+ while ((parent = rb_parent(node)) && rb_is_red(parent))
+ {
+ gparent = rb_parent(parent);
+
+ if (parent == gparent->rb_left)
+ {
+ {
+ register struct rb_node *uncle = gparent->rb_right;
+ if (uncle && rb_is_red(uncle))
+ {
+ rb_set_black(uncle);
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ node = gparent;
+ continue;
+ }
+ }
+
+ if (parent->rb_right == node)
+ {
+ register struct rb_node *tmp;
+ __rb_rotate_left(parent, root);
+ tmp = parent;
+ parent = node;
+ node = tmp;
+ }
+
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ __rb_rotate_right(gparent, root);
+ } else {
+ {
+ register struct rb_node *uncle = gparent->rb_left;
+ if (uncle && rb_is_red(uncle))
+ {
+ rb_set_black(uncle);
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ node = gparent;
+ continue;
+ }
+ }
+
+ if (parent->rb_left == node)
+ {
+ register struct rb_node *tmp;
+ __rb_rotate_right(parent, root);
+ tmp = parent;
+ parent = node;
+ node = tmp;
+ }
+
+ rb_set_black(parent);
+ rb_set_red(gparent);
+ __rb_rotate_left(gparent, root);
+ }
+ }
+
+ rb_set_black(root->rb_node);
+}
+
+static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
+ struct rb_root *root)
+{
+ struct rb_node *other;
+
+ while ((!node || rb_is_black(node)) && node != root->rb_node)
+ {
+ if (parent->rb_left == node)
+ {
+ other = parent->rb_right;
+ if (rb_is_red(other))
+ {
+ rb_set_black(other);
+ rb_set_red(parent);
+ __rb_rotate_left(parent, root);
+ other = parent->rb_right;
+ }
+ if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+ (!other->rb_right || rb_is_black(other->rb_right)))
+ {
+ rb_set_red(other);
+ node = parent;
+ parent = rb_parent(node);
+ }
+ else
+ {
+ if (!other->rb_right || rb_is_black(other->rb_right))
+ {
+ struct rb_node *o_left;
+ if ((o_left = other->rb_left))
+ rb_set_black(o_left);
+ rb_set_red(other);
+ __rb_rotate_right(other, root);
+ other = parent->rb_right;
+ }
+ rb_set_color(other, rb_color(parent));
+ rb_set_black(parent);
+ if (other->rb_right)
+ rb_set_black(other->rb_right);
+ __rb_rotate_left(parent, root);
+ node = root->rb_node;
+ break;
+ }
+ }
+ else
+ {
+ other = parent->rb_left;
+ if (rb_is_red(other))
+ {
+ rb_set_black(other);
+ rb_set_red(parent);
+ __rb_rotate_right(parent, root);
+ other = parent->rb_left;
+ }
+ if ((!other->rb_left || rb_is_black(other->rb_left)) &&
+ (!other->rb_right || rb_is_black(other->rb_right)))
+ {
+ rb_set_red(other);
+ node = parent;
+ parent = rb_parent(node);
+ }
+ else
+ {
+ if (!other->rb_left || rb_is_black(other->rb_left))
+ {
+ register struct rb_node *o_right;
+ if ((o_right = other->rb_right))
+ rb_set_black(o_right);
+ rb_set_red(other);
+ __rb_rotate_left(other, root);
+ other = parent->rb_left;
+ }
+ rb_set_color(other, rb_color(parent));
+ rb_set_black(parent);
+ if (other->rb_left)
+ rb_set_black(other->rb_left);
+ __rb_rotate_right(parent, root);
+ node = root->rb_node;
+ break;
+ }
+ }
+ }
+ if (node)
+ rb_set_black(node);
+}
+
+void rb_erase(struct rb_node *node, struct rb_root *root)
+{
+ struct rb_node *child, *parent;
+ int color;
+
+ if (!node->rb_left)
+ child = node->rb_right;
+ else if (!node->rb_right)
+ child = node->rb_left;
+ else
+ {
+ struct rb_node *old = node, *left;
+
+ node = node->rb_right;
+ while ((left = node->rb_left) != NULL)
+ node = left;
+ child = node->rb_right;
+ parent = rb_parent(node);
+ color = rb_color(node);
+
+ if (child)
+ rb_set_parent(child, parent);
+ if (parent == old) {
+ parent->rb_right = child;
+ parent = node;
+ } else
+ parent->rb_left = child;
+
+ node->rb_parent_color = old->rb_parent_color;
+ node->rb_right = old->rb_right;
+ node->rb_left = old->rb_left;
+
+ if (rb_parent(old))
+ {
+ if (rb_parent(old)->rb_left == old)
+ rb_parent(old)->rb_left = node;
+ else
+ rb_parent(old)->rb_right = node;
+ } else
+ root->rb_node = node;
+
+ rb_set_parent(old->rb_left, node);
+ if (old->rb_right)
+ rb_set_parent(old->rb_right, node);
+ goto color;
+ }
+
+ parent = rb_parent(node);
+ color = rb_color(node);
+
+ if (child)
+ rb_set_parent(child, parent);
+ if (parent)
+ {
+ if (parent->rb_left == node)
+ parent->rb_left = child;
+ else
+ parent->rb_right = child;
+ }
+ else
+ root->rb_node = child;
+
+ color:
+ if (color == RB_BLACK)
+ __rb_erase_color(child, parent, root);
+}
+
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct rb_node *rb_first(struct rb_root *root)
+{
+ struct rb_node *n;
+
+ n = root->rb_node;
+ if (!n)
+ return NULL;
+ while (n->rb_left)
+ n = n->rb_left;
+ return n;
+}
+
+struct rb_node *rb_last(struct rb_root *root)
+{
+ struct rb_node *n;
+
+ n = root->rb_node;
+ if (!n)
+ return NULL;
+ while (n->rb_right)
+ n = n->rb_right;
+ return n;
+}
+
+struct rb_node *rb_next(struct rb_node *node)
+{
+ struct rb_node *parent;
+
+ if (rb_parent(node) == node)
+ return NULL;
+
+ /* If we have a right-hand child, go down and then left as far
+ as we can. */
+ if (node->rb_right) {
+ node = node->rb_right;
+ while (node->rb_left)
+ node=node->rb_left;
+ return node;
+ }
+
+ /* No right-hand children. Everything down and left is
+ smaller than us, so any 'next' node must be in the general
+ direction of our parent. Go up the tree; any time the
+ ancestor is a right-hand child of its parent, keep going
+ up. First time it's a left-hand child of its parent, said
+ parent is our 'next' node. */
+ while ((parent = rb_parent(node)) && node == parent->rb_right)
+ node = parent;
+
+ return parent;
+}
+
+struct rb_node *rb_prev(struct rb_node *node)
+{
+ struct rb_node *parent;
+
+ if (rb_parent(node) == node)
+ return NULL;
+
+ /* If we have a left-hand child, go down and then right as far
+ as we can. */
+ if (node->rb_left) {
+ node = node->rb_left;
+ while (node->rb_right)
+ node=node->rb_right;
+ return node;
+ }
+
+ /* No left-hand children. Go up till we find an ancestor which
+ is a right-hand child of its parent */
+ while ((parent = rb_parent(node)) && node == parent->rb_left)
+ node = parent;
+
+ return parent;
+}
+
+void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+ struct rb_root *root)
+{
+ struct rb_node *parent = rb_parent(victim);
+
+ /* Set the surrounding nodes to point to the replacement */
+ if (parent) {
+ if (victim == parent->rb_left)
+ parent->rb_left = new;
+ else
+ parent->rb_right = new;
+ } else {
+ root->rb_node = new;
+ }
+ if (victim->rb_left)
+ rb_set_parent(victim->rb_left, new);
+ if (victim->rb_right)
+ rb_set_parent(victim->rb_right, new);
+
+ /* Copy the pointers/colour from the victim to the replacement */
+ *new = *victim;
+}
diff --git a/drivers/mtd/mtd-utils/rbtree.h b/drivers/mtd/mtd-utils/rbtree.h
new file mode 100644
index 00000000000..9597b10e2f3
--- /dev/null
+++ b/drivers/mtd/mtd-utils/rbtree.h
@@ -0,0 +1,168 @@
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ linux/include/linux/rbtree.h
+
+ To use rbtrees you'll have to implement your own insert and search cores.
+ This will avoid us to use callbacks and to drop drammatically performances.
+ I know it's not the cleaner way, but in C (not in C++) to get
+ performances and genericity...
+
+ Some example of insert and search follows here. The search is a plain
+ normal search over an ordered tree. The insert instead must be implemented
+ int two steps: as first thing the code must insert the element in
+ order as a red leaf in the tree, then the support library function
+ rb_insert_color() must be called. Such function will do the
+ not trivial work to rebalance the rbtree if necessary.
+
+-----------------------------------------------------------------------
+static inline struct page * rb_search_page_cache(struct inode * inode,
+ unsigned long offset)
+{
+ struct rb_node * n = inode->i_rb_page_cache.rb_node;
+ struct page * page;
+
+ while (n)
+ {
+ page = rb_entry(n, struct page, rb_page_cache);
+
+ if (offset < page->offset)
+ n = n->rb_left;
+ else if (offset > page->offset)
+ n = n->rb_right;
+ else
+ return page;
+ }
+ return NULL;
+}
+
+static inline struct page * __rb_insert_page_cache(struct inode * inode,
+ unsigned long offset,
+ struct rb_node * node)
+{
+ struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
+ struct rb_node * parent = NULL;
+ struct page * page;
+
+ while (*p)
+ {
+ parent = *p;
+ page = rb_entry(parent, struct page, rb_page_cache);
+
+ if (offset < page->offset)
+ p = &(*p)->rb_left;
+ else if (offset > page->offset)
+ p = &(*p)->rb_right;
+ else
+ return page;
+ }
+
+ rb_link_node(node, parent, p);
+
+ return NULL;
+}
+
+static inline struct page * rb_insert_page_cache(struct inode * inode,
+ unsigned long offset,
+ struct rb_node * node)
+{
+ struct page * ret;
+ if ((ret = __rb_insert_page_cache(inode, offset, node)))
+ goto out;
+ rb_insert_color(node, &inode->i_rb_page_cache);
+ out:
+ return ret;
+}
+-----------------------------------------------------------------------
+*/
+
+#ifndef _LINUX_RBTREE_H
+#define _LINUX_RBTREE_H
+
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+
+struct rb_node
+{
+ unsigned long rb_parent_color;
+#define RB_RED 0
+#define RB_BLACK 1
+ struct rb_node *rb_right;
+ struct rb_node *rb_left;
+} __attribute__((aligned(sizeof(long))));
+ /* The alignment might seem pointless, but allegedly CRIS needs it */
+
+struct rb_root
+{
+ struct rb_node *rb_node;
+};
+
+
+#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
+#define rb_color(r) ((r)->rb_parent_color & 1)
+#define rb_is_red(r) (!rb_color(r))
+#define rb_is_black(r) rb_color(r)
+#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
+#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
+
+static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
+{
+ rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
+}
+static inline void rb_set_color(struct rb_node *rb, int color)
+{
+ rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
+}
+
+#define RB_ROOT (struct rb_root) { NULL, }
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define rb_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
+#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
+#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
+
+extern void rb_insert_color(struct rb_node *, struct rb_root *);
+extern void rb_erase(struct rb_node *, struct rb_root *);
+
+/* Find logical next and previous nodes in a tree */
+extern struct rb_node *rb_next(struct rb_node *);
+extern struct rb_node *rb_prev(struct rb_node *);
+extern struct rb_node *rb_first(struct rb_root *);
+extern struct rb_node *rb_last(struct rb_root *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+ struct rb_root *root);
+
+static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
+ struct rb_node ** rb_link)
+{
+ node->rb_parent_color = (unsigned long )parent;
+ node->rb_left = node->rb_right = NULL;
+
+ *rb_link = node;
+}
+
+#endif /* _LINUX_RBTREE_H */
diff --git a/drivers/mtd/mtd-utils/recv_image.c b/drivers/mtd/mtd-utils/recv_image.c
new file mode 100644
index 00000000000..3b793040122
--- /dev/null
+++ b/drivers/mtd/mtd-utils/recv_image.c
@@ -0,0 +1,484 @@
+
+#define _XOPEN_SOURCE 500
+#define _USE_MISC
+
+#include <errno.h>
+#include <error.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include "crc32.h"
+#include "mtd/mtd-user.h"
+#include "mcast_image.h"
+
+#define min(x,y) ( (x)>(y)?(y):(x) )
+
+#define WBUF_SIZE 4096
+struct eraseblock {
+ uint32_t flash_offset;
+ unsigned char wbuf[WBUF_SIZE];
+ int wbuf_ofs;
+ int nr_pkts;
+ int *pkt_indices;
+ uint32_t crc;
+};
+
+int main(int argc, char **argv)
+{
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ struct addrinfo *runp;
+ int ret;
+ int sock;
+ size_t len;
+ int flfd;
+ struct mtd_info_user meminfo;
+ unsigned char *eb_buf, *decode_buf, **src_pkts;
+ int nr_blocks = 0;
+ int pkts_per_block;
+ int block_nr = -1;
+ uint32_t image_crc;
+ int total_pkts = 0;
+ int ignored_pkts = 0;
+ loff_t mtdoffset = 0;
+ int badcrcs = 0;
+ int duplicates = 0;
+ int file_mode = 0;
+ struct fec_parms *fec;
+ int i;
+ struct eraseblock *eraseblocks = NULL;
+ uint32_t start_seq;
+ struct timeval start, now;
+ unsigned long fec_time = 0, flash_time = 0, crc_time = 0,
+ rflash_time = 0, erase_time = 0, net_time = 0;
+
+ if (argc != 4) {
+ fprintf(stderr, "usage: %s <host> <port> <mtddev>\n",
+ (strrchr(argv[0], '/')?:argv[0]-1)+1);
+ exit(1);
+ }
+ /* Open the device */
+ flfd = open(argv[3], O_RDWR);
+
+ if (flfd >= 0) {
+ /* Fill in MTD device capability structure */
+ if (ioctl(flfd, MEMGETINFO, &meminfo) != 0) {
+ perror("MEMGETINFO");
+ close(flfd);
+ flfd = -1;
+ } else {
+ printf("Receive to MTD device %s with erasesize %d\n",
+ argv[3], meminfo.erasesize);
+ }
+ }
+ if (flfd == -1) {
+ /* Try again, as if it's a file */
+ flfd = open(argv[3], O_CREAT|O_TRUNC|O_RDWR, 0644);
+ if (flfd < 0) {
+ perror("open");
+ exit(1);
+ }
+ meminfo.erasesize = 131072;
+ file_mode = 1;
+ printf("Receive to file %s with (assumed) erasesize %d\n",
+ argv[3], meminfo.erasesize);
+ }
+
+ pkts_per_block = (meminfo.erasesize + PKT_SIZE - 1) / PKT_SIZE;
+
+ eb_buf = malloc(pkts_per_block * PKT_SIZE);
+ decode_buf = malloc(pkts_per_block * PKT_SIZE);
+ if (!eb_buf && !decode_buf) {
+ fprintf(stderr, "No memory for eraseblock buffer\n");
+ exit(1);
+ }
+ src_pkts = malloc(sizeof(unsigned char *) * pkts_per_block);
+ if (!src_pkts) {
+ fprintf(stderr, "No memory for decode packet pointers\n");
+ exit(1);
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_ADDRCONFIG;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ ret = getaddrinfo(argv[1], argv[2], &hints, &ai);
+ if (ret) {
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
+ exit(1);
+ }
+ runp = ai;
+ for (runp = ai; runp; runp = runp->ai_next) {
+ sock = socket(runp->ai_family, runp->ai_socktype,
+ runp->ai_protocol);
+ if (sock == -1) {
+ perror("socket");
+ continue;
+ }
+ if (runp->ai_family == AF_INET &&
+ IN_MULTICAST( ntohl(((struct sockaddr_in *)runp->ai_addr)->sin_addr.s_addr))) {
+ struct ip_mreq rq;
+ rq.imr_multiaddr = ((struct sockaddr_in *)runp->ai_addr)->sin_addr;
+ rq.imr_interface.s_addr = INADDR_ANY;
+ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &rq, sizeof(rq))) {
+ perror("IP_ADD_MEMBERSHIP");
+ close(sock);
+ continue;
+ }
+
+ } else if (runp->ai_family == AF_INET6 &&
+ ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr.s6_addr[0] == 0xff) {
+ struct ipv6_mreq rq;
+ rq.ipv6mr_multiaddr = ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr;
+ rq.ipv6mr_interface = 0;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &rq, sizeof(rq))) {
+ perror("IPV6_ADD_MEMBERSHIP");
+ close(sock);
+ continue;
+ }
+ }
+ if (bind(sock, runp->ai_addr, runp->ai_addrlen)) {
+ perror("bind");
+ close(sock);
+ continue;
+ }
+ break;
+ }
+ if (!runp)
+ exit(1);
+
+ while (1) {
+ struct image_pkt thispkt;
+
+ len = read(sock, &thispkt, sizeof(thispkt));
+
+ if (len < 0) {
+ perror("read socket");
+ break;
+ }
+ if (len < sizeof(thispkt)) {
+ fprintf(stderr, "Wrong length %d bytes (expected %d)\n",
+ len, sizeof(thispkt));
+ continue;
+ }
+ if (!eraseblocks) {
+ image_crc = thispkt.hdr.totcrc;
+ start_seq = ntohl(thispkt.hdr.pkt_sequence);
+
+ if (meminfo.erasesize != ntohl(thispkt.hdr.blocksize)) {
+ fprintf(stderr, "Erasesize mismatch (0x%x not 0x%x)\n",
+ ntohl(thispkt.hdr.blocksize), meminfo.erasesize);
+ exit(1);
+ }
+ nr_blocks = ntohl(thispkt.hdr.nr_blocks);
+
+ fec = fec_new(pkts_per_block, ntohs(thispkt.hdr.nr_pkts));
+
+ eraseblocks = malloc(nr_blocks * sizeof(*eraseblocks));
+ if (!eraseblocks) {
+ fprintf(stderr, "No memory for block map\n");
+ exit(1);
+ }
+ for (i = 0; i < nr_blocks; i++) {
+ eraseblocks[i].pkt_indices = malloc(sizeof(int) * pkts_per_block);
+ if (!eraseblocks[i].pkt_indices) {
+ fprintf(stderr, "Failed to allocate packet indices\n");
+ exit(1);
+ }
+ eraseblocks[i].nr_pkts = 0;
+ if (!file_mode) {
+ if (mtdoffset >= meminfo.size) {
+ fprintf(stderr, "Run out of space on flash\n");
+ exit(1);
+ }
+#if 1 /* Deliberately use bad blocks... test write failures */
+ while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
+ printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
+ mtdoffset += meminfo.erasesize;
+ }
+#endif
+ }
+ eraseblocks[i].flash_offset = mtdoffset;
+ mtdoffset += meminfo.erasesize;
+ eraseblocks[i].wbuf_ofs = 0;
+ }
+ gettimeofday(&start, NULL);
+ }
+ if (image_crc != thispkt.hdr.totcrc) {
+ fprintf(stderr, "\nImage CRC changed from 0x%x to 0x%x. Aborting\n",
+ ntohl(image_crc), ntohl(thispkt.hdr.totcrc));
+ exit(1);
+ }
+
+ block_nr = ntohl(thispkt.hdr.block_nr);
+ if (block_nr >= nr_blocks) {
+ fprintf(stderr, "\nErroneous block_nr %d (> %d)\n",
+ block_nr, nr_blocks);
+ exit(1);
+ }
+ for (i=0; i<eraseblocks[block_nr].nr_pkts; i++) {
+ if (eraseblocks[block_nr].pkt_indices[i] == ntohs(thispkt.hdr.pkt_nr)) {
+// printf("Discarding duplicate packet at %08x pkt %d\n",
+// block_nr * meminfo.erasesize, eraseblocks[block_nr].pkt_indices[i]);
+ duplicates++;
+ break;
+ }
+ }
+ if (i < eraseblocks[block_nr].nr_pkts) {
+ continue;
+ }
+
+ if (eraseblocks[block_nr].nr_pkts >= pkts_per_block) {
+ /* We have a block which we didn't really need */
+ eraseblocks[block_nr].nr_pkts++;
+ ignored_pkts++;
+ continue;
+ }
+
+ if (crc32(-1, thispkt.data, PKT_SIZE) != ntohl(thispkt.hdr.thiscrc)) {
+ printf("\nDiscard %08x pkt %d with bad CRC (%08x not %08x)\n",
+ block_nr * meminfo.erasesize, ntohs(thispkt.hdr.pkt_nr),
+ crc32(-1, thispkt.data, PKT_SIZE),
+ ntohl(thispkt.hdr.thiscrc));
+ badcrcs++;
+ continue;
+ }
+ pkt_again:
+ eraseblocks[block_nr].pkt_indices[eraseblocks[block_nr].nr_pkts++] =
+ ntohs(thispkt.hdr.pkt_nr);
+ total_pkts++;
+ if (!(total_pkts % 50) || total_pkts == pkts_per_block * nr_blocks) {
+ uint32_t pkts_sent = ntohl(thispkt.hdr.pkt_sequence) - start_seq + 1;
+ long time_msec;
+ gettimeofday(&now, NULL);
+
+ time_msec = ((now.tv_usec - start.tv_usec) / 1000) +
+ (now.tv_sec - start.tv_sec) * 1000;
+
+ printf("\rReceived %d/%d (%d%%) in %lds @%ldKiB/s, %d lost (%d%%), %d dup/xs ",
+ total_pkts, nr_blocks * pkts_per_block,
+ total_pkts * 100 / nr_blocks / pkts_per_block,
+ time_msec / 1000,
+ total_pkts * PKT_SIZE / 1024 * 1000 / time_msec,
+ pkts_sent - total_pkts - duplicates - ignored_pkts,
+ (pkts_sent - total_pkts - duplicates - ignored_pkts) * 100 / pkts_sent,
+ duplicates + ignored_pkts);
+ fflush(stdout);
+ }
+
+ if (eraseblocks[block_nr].wbuf_ofs + PKT_SIZE < WBUF_SIZE) {
+ /* New packet doesn't full the wbuf */
+ memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs,
+ thispkt.data, PKT_SIZE);
+ eraseblocks[block_nr].wbuf_ofs += PKT_SIZE;
+ } else {
+ int fits = WBUF_SIZE - eraseblocks[block_nr].wbuf_ofs;
+ ssize_t wrotelen;
+ static int faked = 1;
+
+ memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs,
+ thispkt.data, fits);
+ wrotelen = pwrite(flfd, eraseblocks[block_nr].wbuf, WBUF_SIZE,
+ eraseblocks[block_nr].flash_offset);
+
+ if (wrotelen < WBUF_SIZE || (block_nr == 5 && eraseblocks[block_nr].nr_pkts == 5 && !faked)) {
+ faked = 1;
+ if (wrotelen < 0)
+ perror("\npacket write");
+ else
+ fprintf(stderr, "\nshort write of packet wbuf\n");
+
+ if (!file_mode) {
+ struct erase_info_user erase;
+ /* FIXME: Perhaps we should store pkt crcs and try
+ to recover data from the offending eraseblock */
+
+ /* We have increased nr_pkts but not yet flash_offset */
+ erase.start = eraseblocks[block_nr].flash_offset &
+ ~(meminfo.erasesize - 1);
+ erase.length = meminfo.erasesize;
+
+ printf("Will erase at %08lx len %08lx (bad write was at %08lx)\n",
+ erase.start, erase.length, eraseblocks[block_nr].flash_offset);
+ if (ioctl(flfd, MEMERASE, &erase)) {
+ perror("MEMERASE");
+ exit(1);
+ }
+ if (mtdoffset >= meminfo.size) {
+ fprintf(stderr, "Run out of space on flash\n");
+ exit(1);
+ }
+ while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
+ printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
+ mtdoffset += meminfo.erasesize;
+ if (mtdoffset >= meminfo.size) {
+ fprintf(stderr, "Run out of space on flash\n");
+ exit(1);
+ }
+ }
+ eraseblocks[block_nr].flash_offset = mtdoffset;
+ printf("Block #%d will now be at %08lx\n", block_nr, (long)mtdoffset);
+ total_pkts -= eraseblocks[block_nr].nr_pkts;
+ eraseblocks[block_nr].nr_pkts = 0;
+ eraseblocks[block_nr].wbuf_ofs = 0;
+ mtdoffset += meminfo.erasesize;
+ goto pkt_again;
+ }
+ else /* Usually nothing we can do in file mode */
+ exit(1);
+ }
+ eraseblocks[block_nr].flash_offset += WBUF_SIZE;
+ /* Copy the remainder into the wbuf */
+ memcpy(eraseblocks[block_nr].wbuf, &thispkt.data[fits], PKT_SIZE - fits);
+ eraseblocks[block_nr].wbuf_ofs = PKT_SIZE - fits;
+ }
+
+ if (eraseblocks[block_nr].nr_pkts == pkts_per_block) {
+ eraseblocks[block_nr].crc = ntohl(thispkt.hdr.block_crc);
+
+ if (total_pkts == nr_blocks * pkts_per_block)
+ break;
+ }
+ }
+ printf("\n");
+ gettimeofday(&now, NULL);
+ net_time = (now.tv_usec - start.tv_usec) / 1000;
+ net_time += (now.tv_sec - start.tv_sec) * 1000;
+ close(sock);
+ for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
+ ssize_t rwlen;
+ gettimeofday(&start, NULL);
+ eraseblocks[block_nr].flash_offset -= meminfo.erasesize;
+ rwlen = pread(flfd, eb_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset);
+
+ gettimeofday(&now, NULL);
+ rflash_time += (now.tv_usec - start.tv_usec) / 1000;
+ rflash_time += (now.tv_sec - start.tv_sec) * 1000;
+ if (rwlen < 0) {
+ perror("read");
+ /* Argh. Perhaps we could go back and try again, but if the flash is
+ going to fail to read back what we write to it, and the whole point
+ in this program is to write to it, what's the point? */
+ fprintf(stderr, "Packets we wrote to flash seem to be unreadable. Aborting\n");
+ exit(1);
+ }
+
+ memcpy(eb_buf + meminfo.erasesize, eraseblocks[block_nr].wbuf,
+ eraseblocks[block_nr].wbuf_ofs);
+
+ for (i=0; i < pkts_per_block; i++)
+ src_pkts[i] = &eb_buf[i * PKT_SIZE];
+
+ gettimeofday(&start, NULL);
+ if (fec_decode(fec, src_pkts, eraseblocks[block_nr].pkt_indices, PKT_SIZE)) {
+ /* Eep. This cannot happen */
+ printf("The world is broken. fec_decode() returned error\n");
+ exit(1);
+ }
+ gettimeofday(&now, NULL);
+ fec_time += (now.tv_usec - start.tv_usec) / 1000;
+ fec_time += (now.tv_sec - start.tv_sec) * 1000;
+
+ for (i=0; i < pkts_per_block; i++)
+ memcpy(&decode_buf[i*PKT_SIZE], src_pkts[i], PKT_SIZE);
+
+ /* Paranoia */
+ gettimeofday(&start, NULL);
+ if (crc32(-1, decode_buf, meminfo.erasesize) != eraseblocks[block_nr].crc) {
+ printf("\nCRC mismatch for block #%d: want %08x got %08x\n",
+ block_nr, eraseblocks[block_nr].crc,
+ crc32(-1, decode_buf, meminfo.erasesize));
+ exit(1);
+ }
+ gettimeofday(&now, NULL);
+ crc_time += (now.tv_usec - start.tv_usec) / 1000;
+ crc_time += (now.tv_sec - start.tv_sec) * 1000;
+ start = now;
+
+ if (!file_mode) {
+ struct erase_info_user erase;
+
+ erase.start = eraseblocks[block_nr].flash_offset;
+ erase.length = meminfo.erasesize;
+
+ printf("\rErasing block at %08x...", erase.start);
+
+ if (ioctl(flfd, MEMERASE, &erase)) {
+ perror("MEMERASE");
+ /* This block has dirty data on it. If the erase failed, we're screwed */
+ fprintf(stderr, "Erase to clean FEC data from flash failed. Aborting\n");
+ exit(1);
+ }
+ gettimeofday(&now, NULL);
+ erase_time += (now.tv_usec - start.tv_usec) / 1000;
+ erase_time += (now.tv_sec - start.tv_sec) * 1000;
+ start = now;
+ }
+ else printf("\r");
+ write_again:
+ rwlen = pwrite(flfd, decode_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset);
+ if (rwlen < meminfo.erasesize) {
+ if (rwlen < 0) {
+ perror("\ndecoded data write");
+ } else
+ fprintf(stderr, "\nshort write of decoded data\n");
+
+ if (!file_mode) {
+ struct erase_info_user erase;
+ erase.start = eraseblocks[block_nr].flash_offset;
+ erase.length = meminfo.erasesize;
+
+ printf("Erasing failed block at %08x\n",
+ eraseblocks[block_nr].flash_offset);
+
+ if (ioctl(flfd, MEMERASE, &erase)) {
+ perror("MEMERASE");
+ exit(1);
+ }
+ if (mtdoffset >= meminfo.size) {
+ fprintf(stderr, "Run out of space on flash\n");
+ exit(1);
+ }
+ while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) {
+ printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset);
+ mtdoffset += meminfo.erasesize;
+ if (mtdoffset >= meminfo.size) {
+ fprintf(stderr, "Run out of space on flash\n");
+ exit(1);
+ }
+ }
+ printf("Will try again at %08lx...", (long)mtdoffset);
+ eraseblocks[block_nr].flash_offset = mtdoffset;
+
+ goto write_again;
+ }
+ else /* Usually nothing we can do in file mode */
+ exit(1);
+ }
+ gettimeofday(&now, NULL);
+ flash_time += (now.tv_usec - start.tv_usec) / 1000;
+ flash_time += (now.tv_sec - start.tv_sec) * 1000;
+
+ printf("wrote image block %08x (%d pkts) ",
+ block_nr * meminfo.erasesize, eraseblocks[block_nr].nr_pkts);
+ fflush(stdout);
+ }
+ close(flfd);
+ printf("Net rx %ld.%03lds\n", net_time / 1000, net_time % 1000);
+ printf("flash rd %ld.%03lds\n", rflash_time / 1000, rflash_time % 1000);
+ printf("FEC time %ld.%03lds\n", fec_time / 1000, fec_time % 1000);
+ printf("CRC time %ld.%03lds\n", crc_time / 1000, crc_time % 1000);
+ printf("flash wr %ld.%03lds\n", flash_time / 1000, flash_time % 1000);
+ printf("flash er %ld.%03lds\n", erase_time / 1000, erase_time % 1000);
+
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/rfddump.c b/drivers/mtd/mtd-utils/rfddump.c
new file mode 100644
index 00000000000..73b0ecab814
--- /dev/null
+++ b/drivers/mtd/mtd-utils/rfddump.c
@@ -0,0 +1,336 @@
+/*
+ * rfddump.c
+ *
+ * Copyright (C) 2005 Sean Young <sean@mess.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#define _XOPEN_SOURCE 500 /* For pread */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include <mtd/mtd-user.h>
+#include <linux/types.h>
+#include <mtd_swab.h>
+
+/* next is an array of mapping for each corresponding sector */
+#define RFD_MAGIC 0x9193
+#define HEADER_MAP_OFFSET 3
+#define SECTOR_DELETED 0x0000
+#define SECTOR_ZERO 0xfffe
+#define SECTOR_FREE 0xffff
+
+#define SECTOR_SIZE 512
+
+#define SECTORS_PER_TRACK 63
+
+
+struct rfd {
+ int block_size;
+ int block_count;
+ int header_sectors;
+ int data_sectors;
+ int header_size;
+ uint16_t *header;
+ int sector_count;
+ int *sector_map;
+ const char *mtd_filename;
+ const char *out_filename;
+ int verbose;
+};
+
+#define PROGRAM "rfddump"
+#define VERSION "$Revision 1.0 $"
+
+void display_help(void)
+{
+ printf("Usage: " PROGRAM " [OPTIONS] MTD-device filename\n"
+ "Dumps the contents of a resident flash disk\n"
+ "\n"
+ "-h --help display this help and exit\n"
+ "-V --version output version information and exit\n"
+ "-v --verbose Be verbose\n"
+ "-b size --blocksize Block size (defaults to erase unit)\n");
+ exit(0);
+}
+
+void display_version(void)
+{
+ printf(PROGRAM " " VERSION "\n"
+ "\n"
+ "This is free software; see the source for copying conditions. There is NO\n"
+ "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+
+ exit(0);
+}
+
+void process_options(int argc, char *argv[], struct rfd *rfd)
+{
+ int error = 0;
+
+ rfd->block_size = 0;
+ rfd->verbose = 0;
+
+ for (;;) {
+ int option_index = 0;
+ static const char *short_options = "hvVb:";
+ static const struct option long_options[] = {
+ { "help", no_argument, 0, 'h' },
+ { "version", no_argument, 0, 'V', },
+ { "blocksize", required_argument, 0, 'b' },
+ { "verbose", no_argument, 0, 'v' },
+ { NULL, 0, 0, 0 }
+ };
+
+ int c = getopt_long(argc, argv, short_options,
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c) {
+ case 'h':
+ display_help();
+ break;
+ case 'V':
+ display_version();
+ break;
+ case 'v':
+ rfd->verbose = 1;
+ break;
+ case 'b':
+ rfd->block_size = atoi(optarg);
+ break;
+ case '?':
+ error = 1;
+ break;
+ }
+ }
+
+ if ((argc - optind) != 2 || error)
+ display_help();
+
+ rfd->mtd_filename = argv[optind];
+ rfd->out_filename = argv[optind + 1];
+}
+
+int build_block_map(struct rfd *rfd, int fd, int block)
+{
+ int i;
+ int sectors;
+
+ if (pread(fd, rfd->header, rfd->header_size, block * rfd->block_size)
+ != rfd->header_size) {
+ return -1;
+ }
+
+ if (le16_to_cpu(rfd->header[0]) != RFD_MAGIC) {
+ if (rfd->verbose)
+ printf("Block #%02d: Magic missing\n", block);
+
+ return 0;
+ }
+
+ sectors = 0;
+ for (i=0; i<rfd->data_sectors; i++) {
+ uint16_t entry = le16_to_cpu(rfd->header[i + HEADER_MAP_OFFSET]);
+
+ if (entry == SECTOR_FREE || entry == SECTOR_DELETED)
+ continue;
+
+ if (entry == SECTOR_ZERO)
+ entry = 0;
+
+ if (entry >= rfd->sector_count) {
+ fprintf(stderr, "%s: warning: sector %d out of range\n",
+ rfd->mtd_filename, entry);
+ continue;
+ }
+
+ if (rfd->sector_map[entry] != -1) {
+ fprintf(stderr, "%s: warning: more than one entry "
+ "for sector %d\n", rfd->mtd_filename, entry);
+ continue;
+ }
+
+ rfd->sector_map[entry] = rfd->block_size * block +
+ (i + rfd->header_sectors) * SECTOR_SIZE;
+ sectors++;
+ }
+
+ if (rfd->verbose)
+ printf("Block #%02d: %d sectors\n", block, sectors);
+
+ return 1;
+}
+
+int main(int argc, char *argv[])
+{
+ int fd, sectors_per_block;
+ mtd_info_t mtd_info;
+ struct rfd rfd;
+ int i, blocks_found;
+ int out_fd = 0;
+ uint8_t sector[512];
+ int blank, rc, cylinders;
+
+ process_options(argc, argv, &rfd);
+
+ fd = open(rfd.mtd_filename, O_RDONLY);
+ if (fd == -1) {
+ perror(rfd.mtd_filename);
+ return 1;
+ }
+
+ if (rfd.block_size == 0) {
+ if (ioctl(fd, MEMGETINFO, &mtd_info)) {
+ perror(rfd.mtd_filename);
+ close(fd);
+ return 1;
+ }
+
+ if (mtd_info.type != MTD_NORFLASH) {
+ fprintf(stderr, "%s: wrong type\n", rfd.mtd_filename);
+ close(fd);
+ return 2;
+ }
+
+ sectors_per_block = mtd_info.erasesize / SECTOR_SIZE;
+
+ rfd.block_size = mtd_info.erasesize;
+ rfd.block_count = mtd_info.size / mtd_info.erasesize;
+ } else {
+ struct stat st;
+
+ if (fstat(fd, &st) == -1) {
+ perror(rfd.mtd_filename);
+ close(fd);
+ return 1;
+ }
+
+ if (st.st_size % SECTOR_SIZE)
+ fprintf(stderr, "%s: warning: not a multiple of sectors (512 bytes)\n", rfd.mtd_filename);
+
+ sectors_per_block = rfd.block_size / SECTOR_SIZE;
+
+ if (st.st_size % rfd.block_size)
+ fprintf(stderr, "%s: warning: not a multiple of block size\n", rfd.mtd_filename);
+
+ rfd.block_count = st.st_size / rfd.block_size;
+
+ if (!rfd.block_count) {
+ fprintf(stderr, "%s: not large enough for one block\n", rfd.mtd_filename);
+ close(fd);
+ return 2;
+ }
+ }
+
+ rfd.header_sectors =
+ ((HEADER_MAP_OFFSET + sectors_per_block) *
+ sizeof(uint16_t) + SECTOR_SIZE - 1) / SECTOR_SIZE;
+ rfd.data_sectors = sectors_per_block - rfd.header_sectors;
+ cylinders = ((rfd.block_count - 1) * rfd.data_sectors - 1)
+ / SECTORS_PER_TRACK;
+ rfd.sector_count = cylinders * SECTORS_PER_TRACK;
+ rfd.header_size =
+ (HEADER_MAP_OFFSET + rfd.data_sectors) * sizeof(uint16_t);
+
+ rfd.header = malloc(rfd.header_size);
+ if (!rfd.header) {
+ perror(PROGRAM);
+ close(fd);
+ return 2;
+ }
+ rfd.sector_map = malloc(rfd.sector_count * sizeof(int));
+ if (!rfd.sector_map) {
+ perror(PROGRAM);
+ close(fd);
+ free(rfd.sector_map);
+ return 2;
+ }
+
+ rfd.mtd_filename = rfd.mtd_filename;
+
+ for (i=0; i<rfd.sector_count; i++)
+ rfd.sector_map[i] = -1;
+
+ for (blocks_found=i=0; i<rfd.block_count; i++) {
+ rc = build_block_map(&rfd, fd, i);
+ if (rc > 0)
+ blocks_found++;
+ if (rc < 0)
+ goto err;
+ }
+
+ if (!blocks_found) {
+ fprintf(stderr, "%s: no RFD blocks found\n", rfd.mtd_filename);
+ goto err;
+ }
+
+ for (i=0; i<rfd.sector_count; i++) {
+ if (rfd.sector_map[i] != -1)
+ break;
+ }
+
+ if (i == rfd.sector_count) {
+ fprintf(stderr, "%s: no sectors found\n", rfd.mtd_filename);
+ goto err;
+ }
+
+ out_fd = open(rfd.out_filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+ if (out_fd == -1) {
+ perror(rfd.out_filename);
+ goto err;
+ }
+
+ blank = 0;
+ for (i=0; i<rfd.sector_count; i++) {
+ if (rfd.sector_map[i] == -1) {
+ memset(sector, 0, SECTOR_SIZE);
+ blank++;
+ } else {
+ if (pread(fd, sector, SECTOR_SIZE, rfd.sector_map[i])
+ != SECTOR_SIZE) {
+ perror(rfd.mtd_filename);
+ goto err;
+ }
+ }
+
+ if (write(out_fd, sector, SECTOR_SIZE) != SECTOR_SIZE) {
+ perror(rfd.out_filename);
+ goto err;
+ }
+ }
+
+ if (rfd.verbose)
+ printf("Copied %d sectors (%d blank)\n", rfd.sector_count, blank);
+
+ close(out_fd);
+ close(fd);
+ free(rfd.header);
+ free(rfd.sector_map);
+
+ return 0;
+
+err:
+ if (out_fd)
+ close(out_fd);
+
+ close(fd);
+ free(rfd.header);
+ free(rfd.sector_map);
+
+ return 2;
+}
+
diff --git a/drivers/mtd/mtd-utils/rfdformat.c b/drivers/mtd/mtd-utils/rfdformat.c
new file mode 100644
index 00000000000..d2637a1cb85
--- /dev/null
+++ b/drivers/mtd/mtd-utils/rfdformat.c
@@ -0,0 +1,158 @@
+/*
+ * rfdformat.c
+ *
+ * Copyright (C) 2005 Sean Young <sean@mess.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is very easy: just erase all the blocks and put the magic at
+ * the beginning of each block.
+ */
+
+#define _XOPEN_SOURCE 500 /* For pread/pwrite */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include <mtd/mtd-user.h>
+#include <linux/types.h>
+
+#define PROGRAM "rfdformat"
+#define VERSION "$Revision 1.0 $"
+
+void display_help(void)
+{
+ printf("Usage: " PROGRAM " [OPTIONS] MTD-device\n"
+ "Formats NOR flash for resident flash disk\n"
+ "\n"
+ "-h --help display this help and exit\n"
+ "-V --version output version information and exit\n");
+ exit(0);
+}
+
+void display_version(void)
+{
+ printf(PROGRAM " " VERSION "\n"
+ "\n"
+ "This is free software; see the source for copying conditions. There is NO\n"
+ "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+
+ exit(0);
+}
+
+void process_options(int argc, char *argv[], const char **mtd_filename)
+{
+ int error = 0;
+
+ for (;;) {
+ int option_index = 0;
+ static const char *short_options = "hV";
+ static const struct option long_options[] = {
+ { "help", no_argument, 0, 'h' },
+ { "version", no_argument, 0, 'V', },
+ { NULL, 0, 0, 0 }
+ };
+
+ int c = getopt_long(argc, argv, short_options,
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c) {
+ case 'h':
+ display_help();
+ break;
+ case 'V':
+ display_version();
+ break;
+ case '?':
+ error = 1;
+ break;
+ }
+ }
+
+ if ((argc - optind) != 1 || error)
+ display_help();
+
+ *mtd_filename = argv[optind];
+}
+
+int main(int argc, char *argv[])
+{
+ static const uint8_t magic[] = { 0x93, 0x91 };
+ int fd, block_count, i;
+ struct mtd_info_user mtd_info;
+ char buf[512];
+ const char *mtd_filename;
+
+ process_options(argc, argv, &mtd_filename);
+
+ fd = open(mtd_filename, O_RDWR);
+ if (fd == -1) {
+ perror(mtd_filename);
+ return 1;
+ }
+
+ if (ioctl(fd, MEMGETINFO, &mtd_info)) {
+ perror(mtd_filename);
+ close(fd);
+ return 1;
+ }
+
+ if (mtd_info.type != MTD_NORFLASH) {
+ fprintf(stderr, "%s: not NOR flash\n", mtd_filename);
+ close(fd);
+ return 2;
+ }
+
+ if (mtd_info.size > 32*1024*1024) {
+ fprintf(stderr, "%s: flash larger than 32MiB not supported\n",
+ mtd_filename);
+ close(fd);
+ return 2;
+ }
+
+ block_count = mtd_info.size / mtd_info.erasesize;
+
+ if (block_count < 2) {
+ fprintf(stderr, "%s: at least two erase units required\n",
+ mtd_filename);
+ close(fd);
+ return 2;
+ }
+
+ for (i=0; i<block_count; i++) {
+ struct erase_info_user erase_info;
+
+ erase_info.start = i * mtd_info.erasesize;
+ erase_info.length = mtd_info.erasesize;
+
+ if (ioctl(fd, MEMERASE, &erase_info) != 0) {
+ snprintf(buf, sizeof(buf), "%s: erase", mtd_filename);
+ perror(buf);
+ close(fd);
+ return 2;
+ }
+
+ if (pwrite(fd, magic, sizeof(magic), i * mtd_info.erasesize)
+ != sizeof(magic)) {
+ snprintf(buf, sizeof(buf), "%s: write", mtd_filename);
+ perror(buf);
+ close(fd);
+ return 2;
+ }
+ }
+
+ close(fd);
+
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/serve_image.c b/drivers/mtd/mtd-utils/serve_image.c
new file mode 100644
index 00000000000..adb4869bf71
--- /dev/null
+++ b/drivers/mtd/mtd-utils/serve_image.c
@@ -0,0 +1,299 @@
+#define _POSIX_C_SOURCE 199309
+
+#include <time.h>
+
+#include <errno.h>
+#include <error.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include "crc32.h"
+#include "mcast_image.h"
+
+int tx_rate = 80000;
+int pkt_delay;
+
+#undef RANDOMDROP
+
+int main(int argc, char **argv)
+{
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ struct addrinfo *runp;
+ int ret;
+ int sock;
+ struct image_pkt pktbuf;
+ int rfd;
+ struct stat st;
+ int writeerrors = 0;
+ uint32_t erasesize;
+ unsigned char *image, *blockptr = NULL;
+ uint32_t block_nr, pkt_nr;
+ int nr_blocks;
+ struct timeval then, now, nextpkt;
+ long time_msecs;
+ int pkts_per_block;
+ int total_pkts_per_block;
+ struct fec_parms *fec;
+ unsigned char *last_block;
+ uint32_t *block_crcs;
+ long tosleep;
+ uint32_t sequence = 0;
+
+ if (argc == 6) {
+ tx_rate = atol(argv[5]) * 1024;
+ if (tx_rate < PKT_SIZE || tx_rate > 20000000) {
+ fprintf(stderr, "Bogus TX rate %d KiB/s\n", tx_rate);
+ exit(1);
+ }
+ argc = 5;
+ }
+ if (argc != 5) {
+ fprintf(stderr, "usage: %s <host> <port> <image> <erasesize> [<tx_rate>]\n",
+ (strrchr(argv[0], '/')?:argv[0]-1)+1);
+ exit(1);
+ }
+ pkt_delay = (sizeof(pktbuf) * 1000000) / tx_rate;
+ printf("Inter-packet delay (avg): %dµs\n", pkt_delay);
+ printf("Transmit rate: %d KiB/s\n", tx_rate / 1024);
+
+ erasesize = atol(argv[4]);
+ if (!erasesize) {
+ fprintf(stderr, "erasesize cannot be zero\n");
+ exit(1);
+ }
+
+ pkts_per_block = (erasesize + PKT_SIZE - 1) / PKT_SIZE;
+ total_pkts_per_block = pkts_per_block * 3 / 2;
+
+ /* We have to pad it with zeroes, so can't use it in-place */
+ last_block = malloc(pkts_per_block * PKT_SIZE);
+ if (!last_block) {
+ fprintf(stderr, "Failed to allocate last-block buffer\n");
+ exit(1);
+ }
+
+ fec = fec_new(pkts_per_block, total_pkts_per_block);
+ if (!fec) {
+ fprintf(stderr, "Error initialising FEC\n");
+ exit(1);
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_ADDRCONFIG;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ ret = getaddrinfo(argv[1], argv[2], &hints, &ai);
+ if (ret) {
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
+ exit(1);
+ }
+ runp = ai;
+ for (runp = ai; runp; runp = runp->ai_next) {
+ sock = socket(runp->ai_family, runp->ai_socktype,
+ runp->ai_protocol);
+ if (sock == -1) {
+ perror("socket");
+ continue;
+ }
+ if (connect(sock, runp->ai_addr, runp->ai_addrlen) == 0)
+ break;
+ perror("connect");
+ close(sock);
+ }
+ if (!runp)
+ exit(1);
+
+ rfd = open(argv[3], O_RDONLY);
+ if (rfd < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ if (fstat(rfd, &st)) {
+ perror("fstat");
+ exit(1);
+ }
+
+ if (st.st_size % erasesize) {
+ fprintf(stderr, "Image size %ld bytes is not a multiple of erasesize %d bytes\n",
+ st.st_size, erasesize);
+ exit(1);
+ }
+ image = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, rfd, 0);
+ if (image == MAP_FAILED) {
+ perror("mmap");
+ exit(1);
+ }
+
+ nr_blocks = st.st_size / erasesize;
+
+ block_crcs = malloc(nr_blocks * sizeof(uint32_t));
+ if (!block_crcs) {
+ fprintf(stderr, "Failed to allocate memory for CRCs\n");
+ exit(1);
+ }
+
+ memcpy(last_block, image + (nr_blocks - 1) * erasesize, erasesize);
+ memset(last_block + erasesize, 0, (PKT_SIZE * pkts_per_block) - erasesize);
+
+ printf("Checking CRC....");
+ fflush(stdout);
+
+ pktbuf.hdr.resend = 0;
+ pktbuf.hdr.totcrc = htonl(crc32(-1, image, st.st_size));
+ pktbuf.hdr.nr_blocks = htonl(nr_blocks);
+ pktbuf.hdr.blocksize = htonl(erasesize);
+ pktbuf.hdr.thislen = htonl(PKT_SIZE);
+ pktbuf.hdr.nr_pkts = htons(total_pkts_per_block);
+
+ printf("%08x\n", ntohl(pktbuf.hdr.totcrc));
+ printf("Checking block CRCs....");
+ fflush(stdout);
+ for (block_nr=0; block_nr < nr_blocks; block_nr++) {
+ printf("\rChecking block CRCS.... %d/%d",
+ block_nr + 1, nr_blocks);
+ fflush(stdout);
+ block_crcs[block_nr] = crc32(-1, image + (block_nr * erasesize), erasesize);
+ }
+
+ printf("\nImage size %ld KiB (0x%08lx). %d blocks at %d pkts/block\n"
+ "Estimated transmit time per cycle: %ds\n",
+ (long)st.st_size / 1024, (long) st.st_size,
+ nr_blocks, pkts_per_block,
+ nr_blocks * pkts_per_block * pkt_delay / 1000000);
+ gettimeofday(&then, NULL);
+ nextpkt = then;
+
+#ifdef RANDOMDROP
+ srand((unsigned)then.tv_usec);
+ printf("Random seed %u\n", (unsigned)then.tv_usec);
+#endif
+ while (1) for (pkt_nr=0; pkt_nr < total_pkts_per_block; pkt_nr++) {
+
+ if (blockptr && pkt_nr == 0) {
+ unsigned long amt_sent = total_pkts_per_block * nr_blocks * sizeof(pktbuf);
+ gettimeofday(&now, NULL);
+
+ time_msecs = (now.tv_sec - then.tv_sec) * 1000;
+ time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
+ printf("\n%ld KiB sent in %ldms (%ld KiB/s)\n",
+ amt_sent / 1024, time_msecs,
+ amt_sent / 1024 * 1000 / time_msecs);
+ then = now;
+ }
+
+ for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
+
+ int actualpkt;
+
+ /* Calculating the redundant FEC blocks is expensive;
+ the first $pkts_per_block are cheap enough though
+ because they're just copies. So alternate between
+ simple and complex stuff, so that we don't start
+ to choke and fail to keep up with the expected
+ bitrate in the second half of the sequence */
+ if (block_nr & 1)
+ actualpkt = pkt_nr;
+ else
+ actualpkt = total_pkts_per_block - 1 - pkt_nr;
+
+ blockptr = image + (erasesize * block_nr);
+ if (block_nr == nr_blocks - 1)
+ blockptr = last_block;
+
+ fec_encode_linear(fec, blockptr, pktbuf.data, actualpkt, PKT_SIZE);
+
+ pktbuf.hdr.thiscrc = htonl(crc32(-1, pktbuf.data, PKT_SIZE));
+ pktbuf.hdr.block_crc = htonl(block_crcs[block_nr]);
+ pktbuf.hdr.block_nr = htonl(block_nr);
+ pktbuf.hdr.pkt_nr = htons(actualpkt);
+ pktbuf.hdr.pkt_sequence = htonl(sequence++);
+
+ printf("\rSending data block %08x packet %3d/%d",
+ block_nr * erasesize,
+ pkt_nr, total_pkts_per_block);
+
+ if (pkt_nr && !block_nr) {
+ unsigned long amt_sent = pkt_nr * nr_blocks * sizeof(pktbuf);
+
+ gettimeofday(&now, NULL);
+
+ time_msecs = (now.tv_sec - then.tv_sec) * 1000;
+ time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
+ printf(" (%ld KiB/s) ",
+ amt_sent / 1024 * 1000 / time_msecs);
+ }
+
+ fflush(stdout);
+
+#ifdef RANDOMDROP
+ if ((rand() % 1000) < 20) {
+ printf("\nDropping packet %d of block %08x\n", pkt_nr+1, block_nr * erasesize);
+ continue;
+ }
+#endif
+ gettimeofday(&now, NULL);
+#if 1
+ tosleep = nextpkt.tv_usec - now.tv_usec +
+ (1000000 * (nextpkt.tv_sec - now.tv_sec));
+
+ /* We need hrtimers for this to actually work */
+ if (tosleep > 0) {
+ struct timespec req;
+
+ req.tv_nsec = (tosleep % 1000000) * 1000;
+ req.tv_sec = tosleep / 1000000;
+
+ nanosleep(&req, NULL);
+ }
+#else
+ while (now.tv_sec < nextpkt.tv_sec ||
+ (now.tv_sec == nextpkt.tv_sec &&
+ now.tv_usec < nextpkt.tv_usec)) {
+ gettimeofday(&now, NULL);
+ }
+#endif
+ nextpkt.tv_usec += pkt_delay;
+ if (nextpkt.tv_usec >= 1000000) {
+ nextpkt.tv_sec += nextpkt.tv_usec / 1000000;
+ nextpkt.tv_usec %= 1000000;
+ }
+
+ /* If the time for the next packet has already
+ passed (by some margin), then we've lost time
+ Adjust our expected timings accordingly. If
+ we're only a little way behind, don't slip yet */
+ if (now.tv_usec > (now.tv_usec + (5 * pkt_delay) +
+ 1000000 * (nextpkt.tv_sec - now.tv_sec))) {
+ nextpkt = now;
+ }
+
+ if (write(sock, &pktbuf, sizeof(pktbuf)) < 0) {
+ perror("write");
+ writeerrors++;
+ if (writeerrors > 10) {
+ fprintf(stderr, "Too many consecutive write errors\n");
+ exit(1);
+ }
+ } else
+ writeerrors = 0;
+
+
+
+ }
+ }
+ munmap(image, st.st_size);
+ close(rfd);
+ close(sock);
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/summary.h b/drivers/mtd/mtd-utils/summary.h
new file mode 100644
index 00000000000..95f25c62b66
--- /dev/null
+++ b/drivers/mtd/mtd-utils/summary.h
@@ -0,0 +1,178 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ * Zoltan Sogor <weth@inf.u-szeged.hu>,
+ * Patrik Kluba <pajko@halom.u-szeged.hu>,
+ * University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ */
+
+#ifndef JFFS2_SUMMARY_H
+#define JFFS2_SUMMARY_H
+
+#include <linux/uio.h>
+#include <linux/jffs2.h>
+
+#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
+ c->free_size -= _x; c->dirty_size += _x; \
+ jeb->free_size -= _x ; jeb->dirty_size += _x; \
+}while(0)
+#define USED_SPACE(x) do { typeof(x) _x = (x); \
+ c->free_size -= _x; c->used_size += _x; \
+ jeb->free_size -= _x ; jeb->used_size += _x; \
+}while(0)
+#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
+ c->free_size -= _x; c->wasted_size += _x; \
+ jeb->free_size -= _x ; jeb->wasted_size += _x; \
+}while(0)
+#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
+ c->free_size -= _x; c->unchecked_size += _x; \
+ jeb->free_size -= _x ; jeb->unchecked_size += _x; \
+}while(0)
+
+#define BLK_STATE_ALLFF 0
+#define BLK_STATE_CLEAN 1
+#define BLK_STATE_PARTDIRTY 2
+#define BLK_STATE_CLEANMARKER 3
+#define BLK_STATE_ALLDIRTY 4
+#define BLK_STATE_BADBLOCK 5
+
+#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
+#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
+#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
+#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash))
+#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash))
+
+/* Summary structures used on flash */
+
+struct jffs2_sum_unknown_flash
+{
+ jint16_t nodetype; /* node type */
+} __attribute__((packed));
+
+struct jffs2_sum_inode_flash
+{
+ jint16_t nodetype; /* node type */
+ jint32_t inode; /* inode number */
+ jint32_t version; /* inode version */
+ jint32_t offset; /* offset on jeb */
+ jint32_t totlen; /* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_flash
+{
+ jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
+ jint32_t totlen; /* record length */
+ jint32_t offset; /* ofset on jeb */
+ jint32_t pino; /* parent inode */
+ jint32_t version; /* dirent version */
+ jint32_t ino; /* == zero for unlink */
+ uint8_t nsize; /* dirent name size */
+ uint8_t type; /* dirent type */
+ uint8_t name[0]; /* dirent name */
+} __attribute__((packed));
+
+struct jffs2_sum_xattr_flash
+{
+ jint16_t nodetype; /* == JFFS2_NODETYPE_XATR */
+ jint32_t xid; /* xattr identifier */
+ jint32_t version; /* version number */
+ jint32_t offset; /* offset on jeb */
+ jint32_t totlen; /* node length */
+} __attribute__((packed));
+
+struct jffs2_sum_xref_flash
+{
+ jint16_t nodetype; /* == JFFS2_NODETYPE_XREF */
+ jint32_t offset; /* offset on jeb */
+} __attribute__((packed));
+
+union jffs2_sum_flash
+{
+ struct jffs2_sum_unknown_flash u;
+ struct jffs2_sum_inode_flash i;
+ struct jffs2_sum_dirent_flash d;
+ struct jffs2_sum_xattr_flash x;
+ struct jffs2_sum_xref_flash r;
+};
+
+/* Summary structures used in the memory */
+
+struct jffs2_sum_unknown_mem
+{
+ union jffs2_sum_mem *next;
+ jint16_t nodetype; /* node type */
+} __attribute__((packed));
+
+struct jffs2_sum_inode_mem
+{
+ union jffs2_sum_mem *next;
+ jint16_t nodetype; /* node type */
+ jint32_t inode; /* inode number */
+ jint32_t version; /* inode version */
+ jint32_t offset; /* offset on jeb */
+ jint32_t totlen; /* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_mem
+{
+ union jffs2_sum_mem *next;
+ jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
+ jint32_t totlen; /* record length */
+ jint32_t offset; /* ofset on jeb */
+ jint32_t pino; /* parent inode */
+ jint32_t version; /* dirent version */
+ jint32_t ino; /* == zero for unlink */
+ uint8_t nsize; /* dirent name size */
+ uint8_t type; /* dirent type */
+ uint8_t name[0]; /* dirent name */
+} __attribute__((packed));
+
+struct jffs2_sum_xattr_mem
+{
+ union jffs2_sum_mem *next;
+ jint16_t nodetype;
+ jint32_t xid;
+ jint32_t version;
+ jint32_t offset;
+ jint32_t totlen;
+} __attribute__((packed));
+
+struct jffs2_sum_xref_mem
+{
+ union jffs2_sum_mem *next;
+ jint16_t nodetype;
+ jint32_t offset;
+} __attribute__((packed));
+
+union jffs2_sum_mem
+{
+ struct jffs2_sum_unknown_mem u;
+ struct jffs2_sum_inode_mem i;
+ struct jffs2_sum_dirent_mem d;
+ struct jffs2_sum_xattr_mem x;
+ struct jffs2_sum_xref_mem r;
+};
+
+struct jffs2_summary
+{
+ uint32_t sum_size;
+ uint32_t sum_num;
+ uint32_t sum_padded;
+ union jffs2_sum_mem *sum_list_head;
+ union jffs2_sum_mem *sum_list_tail;
+};
+
+/* Summary marker is stored at the end of every sumarized erase block */
+
+struct jffs2_sum_marker
+{
+ jint32_t offset; /* offset of the summary node in the jeb */
+ jint32_t magic; /* == JFFS2_SUM_MAGIC */
+};
+
+#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker))
+
+#endif
diff --git a/drivers/mtd/mtd-utils/sumtool.c b/drivers/mtd/mtd-utils/sumtool.c
new file mode 100644
index 00000000000..2e3d94dd086
--- /dev/null
+++ b/drivers/mtd/mtd-utils/sumtool.c
@@ -0,0 +1,951 @@
+/*
+ * sumtool.c
+ *
+ * Copyright (C) 2004 Zoltan Sogor <weth@inf.u-szeged.hu>,
+ * Ferenc Havasi <havasi@inf.u-szeged.hu>
+ * University of Szeged, Hungary
+ * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Overview:
+ * This is a utility insert summary information into JFFS2 image for
+ * faster mount time
+ *
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <asm/types.h>
+#include <dirent.h>
+#include <mtd/jffs2-user.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <getopt.h>
+#include "crc32.h"
+#include "summary.h"
+
+#define PAD(x) (((x)+3)&~3)
+
+static const char *const app_name = "sumtool";
+
+static struct jffs2_summary *sum_collected = NULL;
+
+static int verbose = 0;
+static int padto = 0; /* pad the output with 0xFF to the end of the final eraseblock */
+static int add_cleanmarkers = 1; /* add cleanmarker to output */
+static int use_input_cleanmarker_size = 1; /* use input file's cleanmarker size (default) */
+static int found_cleanmarkers = 0; /* cleanmarker found in input file */
+static struct jffs2_unknown_node cleanmarker;
+static int cleanmarker_size = sizeof(cleanmarker);
+static const char *short_options = "o:i:e:hvVblnc:p";
+static int erase_block_size = 65536;
+static int out_fd = -1;
+static int in_fd = -1;
+
+static uint8_t *data_buffer = NULL; /* buffer for inodes */
+static unsigned int data_ofs = 0; /* inode buffer offset */
+
+static uint8_t *file_buffer = NULL; /* file buffer contains the actual erase block*/
+static unsigned int file_ofs = 0; /* position in the buffer */
+
+int target_endian = __BYTE_ORDER;
+
+static struct option long_options[] = {
+ {"output", 1, NULL, 'o'},
+ {"input", 1, NULL, 'i'},
+ {"eraseblock", 1, NULL, 'e'},
+ {"help", 0, NULL, 'h'},
+ {"verbose", 0, NULL, 'v'},
+ {"version", 0, NULL, 'V'},
+ {"bigendian", 0, NULL, 'b'},
+ {"littleendian", 0, NULL, 'l'},
+ {"no-cleanmarkers", 0, NULL, 'n'},
+ {"cleanmarker", 1, NULL, 'c'},
+ {"pad", 0, NULL, 'p'},
+ {NULL, 0, NULL, 0}
+};
+
+static char *helptext =
+"Usage: sumtool [OPTIONS] -i inputfile -o outputfile\n\n"
+"Convert the input JFFS2 image to a summarized JFFS2 image\n"
+"Summary makes mounting faster - if summary support enabled in your kernel\n\n"
+"Options:\n"
+" -e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB)\n"
+" (usually 16KiB on NAND)\n"
+" -c, --cleanmarker=SIZE Size of cleanmarker (default 12).\n"
+" (usually 16 bytes on NAND, and will be set to\n"
+" this value if left at the default 12). Will be\n"
+" stored in OOB after each physical page composing\n"
+" a physical eraseblock.\n"
+" -n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock\n"
+" -o, --output=FILE Output to FILE \n"
+" -i, --input=FILE Input from FILE \n"
+" -b, --bigendian Image is big endian\n"
+" -l --littleendian Image is little endian\n"
+" -h, --help Display this help text\n"
+" -v, --verbose Verbose operation\n"
+" -V, --version Display version information\n"
+" -p, --pad Pad the OUTPUT with 0xFF to the end of the final\n"
+" eraseblock\n\n";
+
+
+static char *revtext = "$Revision: 1.1.1.1 $";
+
+static unsigned char ffbuf[16] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static void verror_msg(const char *s, va_list p)
+{
+ fflush(stdout);
+ fprintf(stderr, "%s: ", app_name);
+ vfprintf(stderr, s, p);
+}
+
+static void error_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ verror_msg(s, p);
+ va_end(p);
+ putc('\n', stderr);
+ exit(EXIT_FAILURE);
+}
+
+static void vperror_msg(const char *s, va_list p)
+{
+ int err = errno;
+
+ if (s == 0)
+ s = "";
+ verror_msg(s, p);
+ if (*s)
+ s = ": ";
+ fprintf(stderr, "%s%s\n", s, strerror(err));
+}
+
+static void perror_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ vperror_msg(s, p);
+ va_end(p);
+ exit(EXIT_FAILURE);
+}
+
+
+
+static void full_write(void *target_buff, const void *buf, int len);
+
+void setup_cleanmarker()
+{
+ cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
+ cleanmarker.totlen = cpu_to_je32(cleanmarker_size);
+ cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
+}
+
+void process_options (int argc, char **argv)
+{
+ int opt,c;
+
+ while ((opt = getopt_long(argc, argv, short_options, long_options, &c)) >= 0) {
+ switch (opt) {
+ case 'o':
+ if (out_fd != -1)
+ error_msg_and_die("output filename specified more than once");
+ out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
+ if (out_fd == -1)
+ perror_msg_and_die("open output file");
+ break;
+
+ case 'i':
+ if (in_fd != -1)
+ error_msg_and_die("input filename specified more than once");
+ in_fd = open(optarg, O_RDONLY);
+ if (in_fd == -1)
+ perror_msg_and_die("open input file");
+ break;
+ case 'b':
+ target_endian = __BIG_ENDIAN;
+ break;
+ case 'l':
+ target_endian = __LITTLE_ENDIAN;
+ break;
+ case 'h':
+ case '?':
+ error_msg_and_die(helptext);
+ case 'v':
+ verbose = 1;
+ break;
+
+ case 'V':
+ error_msg_and_die("revision %.*s\n",
+ (int) strlen(revtext) - 13, revtext + 11);
+
+ case 'e': {
+ char *next;
+ unsigned units = 0;
+ erase_block_size = strtol(optarg, &next, 0);
+ if (!erase_block_size)
+ error_msg_and_die("Unrecognisable erase size\n");
+
+ if (*next) {
+ if (!strcmp(next, "KiB")) {
+ units = 1024;
+ } else if (!strcmp(next, "MiB")) {
+ units = 1024 * 1024;
+ } else {
+ error_msg_and_die("Unknown units in erasesize\n");
+ }
+ } else {
+ if (erase_block_size < 0x1000)
+ units = 1024;
+ else
+ units = 1;
+ }
+ erase_block_size *= units;
+
+ /* If it's less than 8KiB, they're not allowed */
+ if (erase_block_size < 0x2000) {
+ fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n",
+ erase_block_size);
+ erase_block_size = 0x2000;
+ }
+ break;
+ }
+
+ case 'n':
+ add_cleanmarkers = 0;
+ break;
+ case 'c':
+ cleanmarker_size = strtol(optarg, NULL, 0);
+
+ if (cleanmarker_size < sizeof(cleanmarker)) {
+ error_msg_and_die("cleanmarker size must be >= 12");
+ }
+ if (cleanmarker_size >= erase_block_size) {
+ error_msg_and_die("cleanmarker size must be < eraseblock size");
+ }
+
+ use_input_cleanmarker_size = 0;
+ found_cleanmarkers = 1;
+ setup_cleanmarker();
+
+ break;
+ case 'p':
+ padto = 1;
+ break;
+ }
+ }
+}
+
+
+void init_buffers()
+{
+ data_buffer = malloc(erase_block_size);
+
+ if (!data_buffer) {
+ perror("out of memory");
+ close (in_fd);
+ close (out_fd);
+ exit(1);
+ }
+
+ file_buffer = malloc(erase_block_size);
+
+ if (!file_buffer) {
+ perror("out of memory");
+ close (in_fd);
+ close (out_fd);
+ exit(1);
+ }
+}
+
+void init_sumlist()
+{
+ sum_collected = (struct jffs2_summary *) malloc (sizeof(struct jffs2_summary));
+
+ if (!sum_collected)
+ error_msg_and_die("Can't allocate memory for jffs2_summary!\n");
+
+ memset(sum_collected, 0, sizeof(struct jffs2_summary));
+}
+
+void clean_buffers()
+{
+ if (data_buffer)
+ free(data_buffer);
+ if (file_buffer)
+ free(file_buffer);
+}
+
+void clean_sumlist()
+{
+ union jffs2_sum_mem *temp;
+
+ if (sum_collected) {
+
+ while (sum_collected->sum_list_head) {
+ temp = sum_collected->sum_list_head;
+ sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
+ free(temp);
+ sum_collected->sum_num--;
+ }
+
+ if (sum_collected->sum_num != 0)
+ printf("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
+
+ free(sum_collected);
+ }
+}
+
+int load_next_block()
+{
+ int ret;
+ ret = read(in_fd, file_buffer, erase_block_size);
+ file_ofs = 0;
+
+ if (verbose)
+ printf("Load next block : %d bytes read\n",ret);
+
+ return ret;
+}
+
+void write_buff_to_file()
+{
+ int ret;
+ int len = data_ofs;
+
+ uint8_t *buf = NULL;
+
+ buf = data_buffer;
+ while (len > 0) {
+ ret = write(out_fd, buf, len);
+
+ if (ret < 0)
+ perror_msg_and_die("write");
+
+ if (ret == 0)
+ perror_msg_and_die("write returned zero");
+
+ len -= ret;
+ buf += ret;
+ }
+
+ data_ofs = 0;
+}
+
+void dump_sum_records()
+{
+
+ struct jffs2_raw_summary isum;
+ struct jffs2_sum_marker *sm;
+ union jffs2_sum_mem *temp;
+ jint32_t offset;
+ jint32_t *tpage;
+ void *wpage;
+ int datasize, infosize, padsize;
+ jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
+
+ if (!sum_collected->sum_num || !sum_collected->sum_list_head)
+ return;
+
+ datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker);
+ infosize = sizeof(struct jffs2_raw_summary) + datasize;
+ padsize = erase_block_size - data_ofs - infosize;
+ infosize += padsize; datasize += padsize;
+ offset = cpu_to_je32(data_ofs);
+
+ tpage = (jint32_t *) malloc(datasize);
+
+ if(!tpage)
+ error_msg_and_die("Can't allocate memory to dump summary information!\n");
+
+ memset(tpage, 0xff, datasize);
+ memset(&isum, 0, sizeof(isum));
+
+ isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
+ isum.totlen = cpu_to_je32(infosize);
+ isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
+ isum.padded = cpu_to_je32(0);
+
+ if (add_cleanmarkers && found_cleanmarkers) {
+ isum.cln_mkr = cpu_to_je32(cleanmarker_size);
+ } else {
+ isum.cln_mkr = cpu_to_je32(0);
+ }
+
+ isum.sum_num = cpu_to_je32(sum_collected->sum_num);
+ wpage = tpage;
+
+ while (sum_collected->sum_num) {
+ switch(je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) {
+
+ case JFFS2_NODETYPE_INODE : {
+ struct jffs2_sum_inode_flash *sino_ptr = wpage;
+
+ sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype;
+ sino_ptr->inode = sum_collected->sum_list_head->i.inode;
+ sino_ptr->version = sum_collected->sum_list_head->i.version;
+ sino_ptr->offset = sum_collected->sum_list_head->i.offset;
+ sino_ptr->totlen = sum_collected->sum_list_head->i.totlen;
+
+ wpage += JFFS2_SUMMARY_INODE_SIZE;
+ break;
+ }
+
+ case JFFS2_NODETYPE_DIRENT : {
+ struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
+
+ sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype;
+ sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen;
+ sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset;
+ sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino;
+ sdrnt_ptr->version = sum_collected->sum_list_head->d.version;
+ sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino;
+ sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize;
+ sdrnt_ptr->type = sum_collected->sum_list_head->d.type;
+
+ memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name,
+ sum_collected->sum_list_head->d.nsize);
+
+ wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize);
+ break;
+ }
+
+ case JFFS2_NODETYPE_XATTR: {
+ struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
+
+ sxattr_ptr->nodetype = sum_collected->sum_list_head->x.nodetype;
+ sxattr_ptr->xid = sum_collected->sum_list_head->x.xid;
+ sxattr_ptr->version = sum_collected->sum_list_head->x.version;
+ sxattr_ptr->offset = sum_collected->sum_list_head->x.offset;
+ sxattr_ptr->totlen = sum_collected->sum_list_head->x.totlen;
+
+ wpage += JFFS2_SUMMARY_XATTR_SIZE;
+ break;
+ }
+
+ case JFFS2_NODETYPE_XREF: {
+ struct jffs2_sum_xref_flash *sxref_ptr = wpage;
+
+ sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype;
+ sxref_ptr->offset = sum_collected->sum_list_head->r.offset;
+
+ wpage += JFFS2_SUMMARY_XREF_SIZE;
+ break;
+ }
+
+ default : {
+ printf("Unknown node type!\n");
+ }
+ }
+
+ temp = sum_collected->sum_list_head;
+ sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
+ free(temp);
+
+ sum_collected->sum_num--;
+ }
+
+ sum_collected->sum_size = 0;
+ sum_collected->sum_num = 0;
+ sum_collected->sum_list_tail = NULL;
+
+ wpage += padsize;
+
+ sm = wpage;
+ sm->offset = offset;
+ sm->magic = magic;
+
+ isum.sum_crc = cpu_to_je32(crc32(0, tpage, datasize));
+ isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8));
+
+ full_write(data_buffer + data_ofs, &isum, sizeof(isum));
+ full_write(data_buffer + data_ofs, tpage, datasize);
+
+ free(tpage);
+}
+
+static void full_write(void *target_buff, const void *buf, int len)
+{
+ memcpy(target_buff, buf, len);
+ data_ofs += len;
+}
+
+static void pad(int req)
+{
+ while (req) {
+ if (req > sizeof(ffbuf)) {
+ full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf));
+ req -= sizeof(ffbuf);
+ } else {
+ full_write(data_buffer + data_ofs, ffbuf, req);
+ req = 0;
+ }
+ }
+}
+
+static inline void padword()
+{
+ if (data_ofs % 4)
+ full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4));
+}
+
+
+static inline void pad_block_if_less_than(int req,int plus)
+{
+
+ int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
+ datasize += (4 - (datasize % 4)) % 4;
+
+ if (data_ofs + req > erase_block_size - datasize) {
+ dump_sum_records();
+ write_buff_to_file();
+ }
+
+ if (add_cleanmarkers && found_cleanmarkers) {
+ if (!data_ofs) {
+ full_write(data_buffer, &cleanmarker, sizeof(cleanmarker));
+ pad(cleanmarker_size - sizeof(cleanmarker));
+ padword();
+ }
+ }
+}
+
+void flush_buffers()
+{
+
+ if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */
+ if (data_ofs != cleanmarker_size) { /* INODE BUFFER */
+
+ int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
+ datasize += (4 - (datasize % 4)) % 4;
+
+ /* If we have a full inode buffer, then write out inode and summary data */
+ if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
+ dump_sum_records();
+ write_buff_to_file();
+ } else { /* else just write out inode data */
+ if (padto)
+ pad(erase_block_size - data_ofs);
+ write_buff_to_file();
+ }
+ }
+ } else { /* NO CLEANMARKER */
+ if (data_ofs != 0) { /* INODE BUFFER */
+
+ int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
+ datasize += (4 - (datasize % 4)) % 4;
+
+ /* If we have a full inode buffer, then write out inode and summary data */
+ if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
+ dump_sum_records();
+ write_buff_to_file();
+ } else { /* Else just write out inode data */
+ if(padto)
+ pad(erase_block_size - data_ofs);
+ write_buff_to_file();
+ }
+ }
+ }
+}
+
+int add_sum_mem(union jffs2_sum_mem *item)
+{
+
+ if (!sum_collected->sum_list_head)
+ sum_collected->sum_list_head = (union jffs2_sum_mem *) item;
+ if (sum_collected->sum_list_tail)
+ sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
+ sum_collected->sum_list_tail = (union jffs2_sum_mem *) item;
+
+ switch (je16_to_cpu(item->u.nodetype)) {
+ case JFFS2_NODETYPE_INODE:
+ sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE;
+ sum_collected->sum_num++;
+ break;
+
+ case JFFS2_NODETYPE_DIRENT:
+ sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
+ sum_collected->sum_num++;
+ break;
+
+ case JFFS2_NODETYPE_XATTR:
+ sum_collected->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
+ sum_collected->sum_num++;
+ break;
+
+ case JFFS2_NODETYPE_XREF:
+ sum_collected->sum_size += JFFS2_SUMMARY_XREF_SIZE;
+ sum_collected->sum_num++;
+ break;
+
+ default:
+ error_msg_and_die("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype));
+ }
+ return 0;
+}
+
+void add_sum_inode_mem(union jffs2_node_union *node)
+{
+ struct jffs2_sum_inode_mem *temp = (struct jffs2_sum_inode_mem *) malloc(sizeof(struct jffs2_sum_inode_mem));
+
+ if (!temp)
+ error_msg_and_die("Can't allocate memory for summary information!\n");
+
+ temp->nodetype = node->i.nodetype;
+ temp->inode = node->i.ino;
+ temp->version = node->i.version;
+ temp->offset = cpu_to_je32(data_ofs);
+ temp->totlen = node->i.totlen;
+ temp->next = NULL;
+
+ add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void add_sum_dirent_mem(union jffs2_node_union *node)
+{
+ struct jffs2_sum_dirent_mem *temp = (struct jffs2_sum_dirent_mem *)
+ malloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize);
+
+ if (!temp)
+ error_msg_and_die("Can't allocate memory for summary information!\n");
+
+ temp->nodetype = node->d.nodetype;
+ temp->totlen = node->d.totlen;
+ temp->offset = cpu_to_je32(data_ofs);
+ temp->pino = node->d.pino;
+ temp->version = node->d.version;
+ temp->ino = node->d.ino;
+ temp->nsize = node->d.nsize;
+ temp->type = node->d.type;
+ temp->next = NULL;
+
+ memcpy(temp->name,node->d.name,node->d.nsize);
+ add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void add_sum_xattr_mem(union jffs2_node_union *node)
+{
+ struct jffs2_sum_xattr_mem *temp = (struct jffs2_sum_xattr_mem *)
+ malloc(sizeof(struct jffs2_sum_xattr_mem));
+ if (!temp)
+ error_msg_and_die("Can't allocate memory for summary information!\n");
+
+ temp->nodetype = node->x.nodetype;
+ temp->xid = node->x.xid;
+ temp->version = node->x.version;
+ temp->offset = cpu_to_je32(data_ofs);
+ temp->totlen = node->x.totlen;
+ temp->next = NULL;
+
+ add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void add_sum_xref_mem(union jffs2_node_union *node)
+{
+ struct jffs2_sum_xref_mem *temp = (struct jffs2_sum_xref_mem *)
+ malloc(sizeof(struct jffs2_sum_xref_mem));
+ if (!temp)
+ error_msg_and_die("Can't allocate memory for summary information!\n");
+
+ temp->nodetype = node->r.nodetype;
+ temp->offset = cpu_to_je32(data_ofs);
+ temp->next = NULL;
+
+ add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void write_dirent_to_buff(union jffs2_node_union *node)
+{
+ pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize));
+ add_sum_dirent_mem(node);
+ full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen));
+ padword();
+}
+
+
+void write_inode_to_buff(union jffs2_node_union *node)
+{
+ pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE);
+ add_sum_inode_mem(node); /* Add inode summary mem to summary list */
+ full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen)); /* Write out the inode to inode_buffer */
+ padword();
+}
+
+void write_xattr_to_buff(union jffs2_node_union *node)
+{
+ pad_block_if_less_than(je32_to_cpu(node->x.totlen), JFFS2_SUMMARY_XATTR_SIZE);
+ add_sum_xattr_mem(node); /* Add xdatum summary mem to summary list */
+ full_write(data_buffer + data_ofs, &(node->x), je32_to_cpu(node->x.totlen));
+ padword();
+}
+
+void write_xref_to_buff(union jffs2_node_union *node)
+{
+ pad_block_if_less_than(je32_to_cpu(node->r.totlen), JFFS2_SUMMARY_XREF_SIZE);
+ add_sum_xref_mem(node); /* Add xref summary mem to summary list */
+ full_write(data_buffer + data_ofs, &(node->r), je32_to_cpu(node->r.totlen));
+ padword();
+}
+
+void create_summed_image(int inp_size)
+{
+ uint8_t *p = file_buffer;
+ union jffs2_node_union *node;
+ uint32_t crc, length;
+ uint16_t type;
+ int bitchbitmask = 0;
+ int obsolete;
+ char name[256];
+
+ while ( p < (file_buffer + inp_size)) {
+
+ node = (union jffs2_node_union *) p;
+
+ /* Skip empty space */
+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+ p += 4;
+ continue;
+ }
+
+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
+ if (!bitchbitmask++)
+ printf ("Wrong bitmask at 0x%08x, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic));
+ p += 4;
+ continue;
+ }
+
+ bitchbitmask = 0;
+
+ type = je16_to_cpu(node->u.nodetype);
+ if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+ obsolete = 1;
+ type |= JFFS2_NODE_ACCURATE;
+ } else {
+ obsolete = 0;
+ }
+
+ node->u.nodetype = cpu_to_je16(type);
+
+ crc = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+ if (crc != je32_to_cpu (node->u.hdr_crc)) {
+ printf ("Wrong hdr_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc);
+ p += 4;
+ continue;
+ }
+
+ switch(je16_to_cpu(node->u.nodetype)) {
+ case JFFS2_NODETYPE_INODE:
+ if (verbose)
+ printf ("%8s Inode node at 0x%08x, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+ je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize),
+ je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+ crc = crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
+ if (crc != je32_to_cpu (node->i.node_crc)) {
+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->i.node_crc), crc);
+ p += PAD(je32_to_cpu (node->i.totlen));
+ continue;
+ }
+
+ crc = crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
+ if (crc != je32_to_cpu(node->i.data_crc)) {
+ printf ("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->i.data_crc), crc);
+ p += PAD(je32_to_cpu (node->i.totlen));
+ continue;
+ }
+
+ write_inode_to_buff(node);
+
+ p += PAD(je32_to_cpu (node->i.totlen));
+ break;
+
+ case JFFS2_NODETYPE_DIRENT:
+ memcpy (name, node->d.name, node->d.nsize);
+ name [node->d.nsize] = 0x0;
+
+ if (verbose)
+ printf ("%8s Dirent node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+ je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
+ node->d.nsize, name);
+
+ crc = crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
+ if (crc != je32_to_cpu (node->d.node_crc)) {
+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->d.node_crc), crc);
+ p += PAD(je32_to_cpu (node->d.totlen));
+ continue;
+ }
+
+ crc = crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
+ if (crc != je32_to_cpu(node->d.name_crc)) {
+ printf ("Wrong name_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->d.name_crc), crc);
+ p += PAD(je32_to_cpu (node->d.totlen));
+ continue;
+ }
+
+ write_dirent_to_buff(node);
+
+ p += PAD(je32_to_cpu (node->d.totlen));
+ break;
+
+ case JFFS2_NODETYPE_XATTR:
+ if (je32_to_cpu(node->x.node_crc) == 0xffffffff)
+ obsolete = 1;
+ if (verbose)
+ printf("%8s Xdatum node at 0x%08x, totlen 0x%08x, "
+ "#xid %5u, version %5u\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->x.totlen),
+ je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version));
+ crc = crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4);
+ if (crc != je32_to_cpu(node->x.node_crc)) {
+ printf("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu(node->x.node_crc), crc);
+ p += PAD(je32_to_cpu (node->x.totlen));
+ continue;
+ }
+ length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len);
+ crc = crc32(0, node->x.data, length);
+ if (crc != je32_to_cpu(node->x.data_crc)) {
+ printf("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu(node->x.data_crc), crc);
+ p += PAD(je32_to_cpu (node->x.totlen));
+ continue;
+ }
+
+ write_xattr_to_buff(node);
+ p += PAD(je32_to_cpu (node->x.totlen));
+ break;
+
+ case JFFS2_NODETYPE_XREF:
+ if (je32_to_cpu(node->r.node_crc) == 0xffffffff)
+ obsolete = 1;
+ if (verbose)
+ printf("%8s Xref node at 0x%08x, totlen 0x%08x, "
+ "#ino %5u, xid %5u\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu(node->r.totlen),
+ je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid));
+ crc = crc32(0, node, sizeof (struct jffs2_raw_xref) - 4);
+ if (crc != je32_to_cpu(node->r.node_crc)) {
+ printf("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu(node->r.node_crc), crc);
+ p += PAD(je32_to_cpu (node->r.totlen));
+ continue;
+ }
+
+ write_xref_to_buff(node);
+ p += PAD(je32_to_cpu (node->r.totlen));
+ break;
+
+ case JFFS2_NODETYPE_CLEANMARKER:
+ if (verbose) {
+ printf ("%8s Cleanmarker at 0x%08x, totlen 0x%08x\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->u.totlen));
+ }
+
+ if (!found_cleanmarkers) {
+ found_cleanmarkers = 1;
+
+ if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1){
+ cleanmarker_size = je32_to_cpu (node->u.totlen);
+ setup_cleanmarker();
+ }
+ }
+
+ p += PAD(je32_to_cpu (node->u.totlen));
+ break;
+
+ case JFFS2_NODETYPE_PADDING:
+ if (verbose) {
+ printf ("%8s Padding node at 0x%08x, totlen 0x%08x\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->u.totlen));
+ }
+ p += PAD(je32_to_cpu (node->u.totlen));
+ break;
+
+ case 0xffff:
+ p += 4;
+ break;
+
+ default:
+ if (verbose) {
+ printf ("%8s Unknown node at 0x%08x, totlen 0x%08x\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->u.totlen));
+ }
+
+ p += PAD(je32_to_cpu (node->u.totlen));
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ process_options(argc,argv);
+
+ if ((in_fd == -1) || (out_fd == -1)) {
+ if(in_fd != -1)
+ close(in_fd);
+ if(out_fd != -1)
+ close(out_fd);
+ fprintf(stderr,helptext);
+ error_msg_and_die("You must specify input and output files!\n");
+ }
+
+ init_buffers();
+ init_sumlist();
+
+ while ((ret = load_next_block())) {
+ create_summed_image(ret);
+ }
+
+ flush_buffers();
+ clean_buffers();
+ clean_sumlist();
+
+ if (in_fd != -1)
+ close(in_fd);
+ if (out_fd != -1)
+ close(out_fd);
+
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/checkfs/Makefile b/drivers/mtd/mtd-utils/tests/checkfs/Makefile
new file mode 100644
index 00000000000..ac94dde8c5b
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/checkfs/Makefile
@@ -0,0 +1,14 @@
+
+all: checkfs makefiles
+
+checkfs: checkfs.c Makefile common.h comm.o
+ gcc -g -Wall checkfs.c comm.o -o checkfs
+
+comm.o: comm.c Makefile
+ gcc -g -Wall -c comm.c -o comm.o
+
+makefiles: makefiles.c Makefile common.h
+ gcc -g -Wall makefiles.c -o makefiles
+
+clean:
+ rm -f makefiles checkfs *~ *.o
diff --git a/drivers/mtd/mtd-utils/tests/checkfs/README b/drivers/mtd/mtd-utils/tests/checkfs/README
new file mode 100644
index 00000000000..f817c0f3ede
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/checkfs/README
@@ -0,0 +1,173 @@
+$Id: README,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+$Log: not supported by cvs2svn $
+Revision 1.2 2001/06/21 23:07:06 dwmw2
+Initial import to MTD CVS
+
+Revision 1.1 2001/06/11 19:34:40 vipin
+Added README file to dir.
+
+
+This is the README file for the "checkfs" power fail test program.
+By: Vipin Malik
+
+NOTE: This program requires an external "power cycling box"
+connected to one of the com ports of the system under test.
+This power cycling box should wait for a random amount of time
+after it receives a "ok to power me down" message over the
+serial port, and then yank power to the system under test.
+(The box that I rigged up tested with waits anywhere from
+0 to ~40 seconds).
+
+
+It should then restore power after a few seconds and wait for the
+message again.
+
+
+ABOUT:
+
+This program's primary purpose it to test the reliiability
+of various file systems under Linux.
+
+SETUP:
+
+You need to setup the file system you want to test and run the
+"makefiles" program ONCE. This creates a set of files that are
+required by the "checkfs" program.
+
+Also copy the "checkfs" executable program to the same dir.
+
+Then you need to make sure that the program "checkfs" is called
+automatically on startup. You can customise the operation of
+the "checkfs" program by passing it various cmd line arguments.
+run "checkfs -?" for more details.
+
+****NOTE*******
+Make sure that you call the checkfs program only after you have
+mounted the file system you want to test (this is obvious), but
+also after you have run any "scan" utilities to check for and
+fix any file systems errors. The e2fsck is one utility for the
+ext2 file system. For an automated setup you of course need to
+provide these scan programs to run in standalone mode (-f -y
+flags for e2fsck for example).
+
+File systems like JFFS and JFFS2 do not have any such external
+utilities and you may call "checkfs" right after you have mounted
+the respective file system under test.
+
+There are two ways you can mount the file system under test:
+
+1. Mount your root fs on a "standard" fs like ext2 and then
+mount the file system under test (which may be ext2 on another
+partition or device) and then run "checkfs" on this mounted
+partition OR
+
+2. Make your fs AND device that you have put this fs as your
+root fs and run "checkfs" on the root device (i.e. "/").
+You can of course still run checkfs under a separate dir
+under your "/" root dir.
+
+I have found the second method to be a particularly stringent
+arrangement (and thus preferred when you are trying to break
+something).
+
+Using this arrangement I was able to find that JFFS clobbered
+some "sister" files on the root fs even though "checkfs" would
+run fine through all its own check files.
+
+(I found this out when one of the clobbered sister file happened
+to be /bin/bash. The system refused to run rc.local thus
+preventing my "checkfs" program from being launched :)
+
+"checkfs":
+
+The "formatting" reliability of the fs as well as the file data integrity
+of files on the fs can be checked using this program.
+
+"formatiing" reliability can only be checked via an indirect method.
+If there is severe formatting reliability issues with the file system,
+it will most likely cause other system failures that will prevent this
+program from running successfully on a power up. This will prevent
+a "ok to power me down" message from going out to the power cycling
+black box and prevent power being turned off again.
+
+File data reliability is checked more directly. A fixed number of
+files are created in the current dir (using the program "makefiles").
+
+Each file has a random number of bytes in it (set by using the
+-s cmd line flag). The number of "ints" in the file is stored as the
+first "int" in it (note: 0 length files are not allowed). Each file
+is then filled with random data and a 16 bit CRC appended at the end.
+
+When "checkfs" is run, it runs through all files (with predetermined
+file names)- one at a time- and checks for the number of "int's"
+in it as well as the ending CRC.
+
+The program exits if the numbers of files that are corrupt are greater
+that a user specified parameter (set by using the -e cmd line flag).
+
+If the number of corrupt files is less than this parameter, the corrupt
+files are repaired and operation resumes as explained below.
+
+The idea behind allowing a user specified amount of corrupt files is as
+follows:
+
+If you are testing for "formatting" reliability of a fs, and for
+the data reliability of "other" files present of the fs, use -e 1.
+"other" files are defined as sister files on the fs, not being written to
+by the "checkfs" test program.
+
+As mentioned, in this case you would set -e 1, or allow at most 1 file
+to be corrupt each time after a power fail. This would be the file
+that was probably being written to when power failed (and CRC was not
+updated to reflect the new data being written). You would check file
+systems like ext2 etc. with such a configuration.
+(As you have no hope that these file systems provide for either your
+new data or old data to be present in the file if power failed during
+the write. This is called "roll back and recover".)
+
+With JFFS2 I tested for such "roll back and recover" file data reliability
+by setting -e 0 and making sure that all writes to the file being
+updated are done in a *single* write().
+
+This is how I found that JFFS2 (yet) does NOT support this functionality.
+(There was a great debate if this was a bug or a feature that was lacking
+or even an issue at all. See the mtd archives for more details).
+
+In other words, JFFS2 will partially update a file on FLASH even before
+the write() command has completed, thus leaving part old data part new
+data in your file if power failed in the middle of a write().
+
+This is bad functionality if you are updating a binary structure or a
+CRC protected file (as in our case).
+
+
+If All Files Check Out OK:
+
+On the startup scan, if there are less errors than specified by the "-e flag"
+a "ok to power me down message" is sent via the specified com port.
+
+The actual format of this message will depend on the format expected
+by the power cycling box that will receive this message. One may customise
+the actual message that goes out in the "do_pwr_dn)" routine in "comm.c".
+
+This file is called with an open file descriptor to the comm port that
+this message needs to go out over and the count of the current power
+cycle (in case your power cycling box can display/log this count).
+
+After this message has been sent out, the checkfs program goes into
+a while(1) loop of writing new data (with CRC), one at a time, into
+all the "check files" in the dir.
+
+Its life comes to a sudden end when power is asynchronously pulled from
+under its feet (by your external power cycling box).
+
+It comes back to life when power is restored and the system boots and
+checkfs is called from the rc.local script file.
+
+The cycle then repeats till a problem is detected, at which point
+the "ok to power me down" message is not sent and the cycle stops
+waiting for the user to examine the system.
+
+
+
+
diff --git a/drivers/mtd/mtd-utils/tests/checkfs/checkfs.c b/drivers/mtd/mtd-utils/tests/checkfs/checkfs.c
new file mode 100644
index 00000000000..795794649df
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/checkfs/checkfs.c
@@ -0,0 +1,695 @@
+/*
+
+ * Copyright Daniel Industries.
+ *
+ * Created by: Vipin Malik (vipin.malik@daniel.com)
+ *
+ * This code is released under the GPL version 2. See the file COPYING
+ * for more details.
+ *
+ * Software distributed under the Licence is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing rights and
+ * limitations under the Licence.
+
+ This program opens files in progression (file00001, file00002 etc),
+ upto MAX_NUM_FILES and checks their CRC. If a file is not found or the
+ CRC does not match it stops it's operation.
+
+ Everything is logged in a logfile called './logfile'.
+
+ If everything is ok this program sends a signal, via com1, to the remote
+ power control box to power cycle this computer.
+
+ This program then proceeds to create new files file0....file<MAX_NUM_FILES>
+ in a endless loop and checksum each before closing them.
+
+ STRUCTURE OF THE FILES:
+ The fist int is the size of the file in bytes.
+ The last 2 bytes are the CRC for the entire file.
+ There is random data in between.
+
+ The files are opened in the current dir.
+
+ $Id: checkfs.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ $Log: not supported by cvs2svn $
+ Revision 1.8 2005/11/07 11:15:17 gleixner
+ [MTD / JFFS2] Clean up trailing white spaces
+
+ Revision 1.7 2001/06/21 23:04:17 dwmw2
+ Initial import to MTD CVS
+
+ Revision 1.6 2001/06/08 22:26:05 vipin
+ Split the modbus comm part of the program (that sends the ok to pwr me down
+ message) into another file "comm.c"
+
+ Revision 1.5 2001/06/08 21:29:56 vipin
+ fixed small issue with write() checking for < 0 instead of < (bytes to be written).
+ Now it does the latter (as it should).
+
+ Revision 1.4 2001/05/11 22:29:40 vipin
+ Added a test to check and err out if the first int in file (which tells us
+ how many bytes there are in the file) is zero. This will prevent a corrupt
+ file with zero's in it from passing the crc test.
+
+ Revision 1.3 2001/05/11 21:33:54 vipin
+ Changed to use write() rather than fwrite() when creating new file. Additionally,
+ and more important, it now does a single write() for the entire data. This will
+ enable us to use this program to test for power fail *data* reliability when
+ writing over an existing file, specially on powr fail "safe" file systems as
+ jffs/jffs2. Also added a new cmdline parameter "-e" that specifies the max # of
+ errors that can be tolerated. This should be set to ZERO to test for the above,
+ as old data should be reliabily maintained if the newer write never "took" before
+ power failed. If the write did succeed, then the newer data will have its own
+ CRC in place when it gets checked => hence no error. In theory at least!
+
+
+ Revision 1.2 2001/05/11 19:27:33 vipin
+ Added cmd line args to change serial port, and specify max size of
+ random files created. Some cleanup. Added -Wall to Makefile.
+
+ Revision 1.1 2001/05/11 16:06:28 vipin
+ Importing checkfs (the power fail test program) into CVS. This was
+ originally done for NEWS. NEWS had a lot of version, this is
+ based off the last one done for NEWS. The "makefiles" program
+ is run once initially to create the files in the current dir.
+ "checkfs" is then run on every powerup to check consistancy
+ of the files. See checkfs.c for more details.
+
+
+*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include "common.h"
+
+
+
+extern int do_pwr_dn(int fd, int cycleCnt);
+
+#define CMDLINE_PORT "-p"
+#define CMDLINE_MAXFILEBYTES "-s"
+#define CMDLINE_MAXERROR "-e"
+#define CMDLINE_HELPSHORT "-?"
+#define CMDLINE_HELPLONG "--help"
+
+
+int CycleCount;
+
+char SerialDevice[255] = "/dev/ttyS0"; /* default, can be changed
+ through cmd line. */
+
+#define MAX_INTS_ALLOW 100000 /* max # of int's in the file written.
+ Statis limit to size struct. */
+float FileSizeMax = 1024.0; /*= (file size in bytes), MUST be float*/
+
+int MaxErrAllowed = 1; /* default, can ge changed thru cmd line*/
+
+
+/* Needed for CRC generation/checking */
+static const unsigned short crc_ccitt_table[] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+
+/*
+ Set's up the Linux serial port. Must be passed string to device to
+ open. Parameters are fixed to 9600,e,1
+
+ [A possible enhancement to this program would be to pass these
+ parameters via the command line.]
+
+ Returns file descriptor to open port. Use this fd to write to port
+ and close it later, when done.
+*/
+int setupSerial (const char *dev) {
+ int i, fd;
+ struct termios tios;
+
+ fd = open(dev,O_RDWR | O_NDELAY );
+ if (fd < 0) {
+ fprintf(stderr, "%s: %s\n", dev, sys_errlist[errno]);
+ exit(1);
+ }
+ if (tcgetattr(fd, &tios) < 0) {
+ fprintf(stderr,"Could not get terminal attributes: %s",sys_errlist[errno]);
+ exit(1);
+ }
+
+ tios.c_cflag =
+ CS7 |
+ CREAD | // Enable Receiver
+ HUPCL | // Hangup after close
+ CLOCAL | // Ignore modem control lines
+ PARENB; // Enable parity (even by default)
+
+
+
+ tios.c_iflag = IGNBRK; // Ignore break
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ for(i = 0; i < NCCS; i++) {
+ tios.c_cc[i] = '\0'; // no special characters
+ }
+ tios.c_cc[VMIN] = 1;
+ tios.c_cc[VTIME] = 0;
+
+ cfsetospeed (&tios, B9600);
+ cfsetispeed (&tios, B9600);
+
+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
+ fprintf(stderr,"Could not set attributes: ,%s",sys_errlist[errno]);
+ exit(1);
+ }
+ return fd;
+}
+
+
+
+
+
+//A portion of this code was taken from the AX.25 HDLC packet driver
+//in LINUX. Once I test and have a better understanding of what
+//it is doing, it will be better commented.
+
+//For now one can speculate that the CRC routine always expects the
+//CRC to calculate out to 0xf0b8 (the hardcoded value at the end)
+//and returns TRUE if it is and FALSE if it doesn't.
+//Why don't people document better!!!!
+int check_crc_ccitt(char *filename)
+{
+ FILE *fp;
+ FILE *logfp;
+ unsigned short crc = 0xffff;
+ int len;
+ char dataByte;
+ int retry;
+ char done;
+
+ fp = fopen(filename,"rb");
+ if(!fp){
+ logfp = fopen("logfile","a"); /*open for appending only.*/
+ fprintf(logfp, "Verify checksum:Error! Cannot open filename passed for verify checksum: %s\n",filename);
+ fclose(logfp);
+ return FALSE;
+ }
+
+
+ /*the first int contains an int that is the length of the file in long.*/
+ if(fread(&len, sizeof(int), 1, fp) != 1){
+ logfp = fopen("logfile","a"); /*open for appending only.*/
+ fprintf(logfp, "verify checksum:Error reading from file: %s\n", filename);
+ fclose(fp);
+ fclose(logfp);
+ return FALSE;
+ }
+
+ /* printf("Checking %i bytes for CRC in \"%s\".\n", len, filename); */
+
+ /* Make sure that we did not read 0 as the number of bytes in file. This
+ check prevents a corrupt file with zero's in it from passing the
+ CRC test. A good file will always have some data in it. */
+ if(len == 0)
+ {
+
+ logfp = fopen("logfile","a"); /*open for appending only.*/
+ fprintf(logfp, "verify checksum: first int claims there are 0 data in file. Error!: %s\n", filename);
+ fclose(fp);
+ fclose(logfp);
+ return FALSE;
+ }
+
+
+ rewind(fp);
+ len+=2; /*the file has two extra bytes at the end, it's checksum. Those
+ two MUST also be included in the checksum calculation.
+ */
+
+ for (;len>0;len--){
+ retry=5; /*retry 5 times*/
+ done = FALSE;
+ while(!done){
+ if(fread(&dataByte, sizeof(char), 1, fp) != 1){
+ retry--;
+ }else{
+ done = TRUE;
+ }
+ if(retry == 0){
+ done = TRUE;
+ }
+ }
+ if(!retry){
+ logfp = fopen("logfile","a"); /*open for appending only.*/
+ fprintf(logfp, "Unexpected end of file: %s\n", filename);
+ fprintf(logfp, "...bytes left to be read %i.\n",len);
+ fclose(logfp);
+ fclose(fp);
+ return FALSE;
+ }
+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ dataByte) & 0xff];
+ }
+ fclose(fp);
+ if( (crc & 0xffff) != 0xf0b8){
+ /*printf("The CRC of read file:%x\n", crc); */
+ return FALSE;
+ }
+ return TRUE;
+}/*end check_crc_ccitt() */
+
+
+
+/*
+ Sends "OK to power me down" message to the remote
+ power cycling box, via the serial port.
+ Also updates the num power cycle count in a local
+ file.
+ This file "./cycleCnt" must be present. This is
+ initially (and once) created by the separate "makefiles.c"
+ program.
+*/
+void send_pwrdn_ok(void){
+
+ int fd;
+ FILE *cyclefp;
+ int cycle_fd;
+
+ cyclefp = fopen("cycleCnt","rb");
+ if(!cyclefp){
+ printf("expecting file \"cycleCnt\". Cannot continue.\n");
+ exit(1);
+ }
+ if(fread(&CycleCount, sizeof(CycleCount),1,cyclefp) != 1){
+ fprintf(stderr, "Error! Unexpected end of file cycleCnt.\n");
+ exit(1);
+ }
+ fclose(cyclefp);
+
+ CycleCount++;
+
+ /*now write this puppy back*/
+ cyclefp = fopen("cycleCnt","wb");
+ cycle_fd = fileno(cyclefp);
+ if(!cyclefp){
+ fprintf(stderr, "Error! cannot open file for write:\"cycleCnt\". Cannot continue.\n");
+ exit(1);
+ }
+ if(fwrite(&CycleCount, sizeof(CycleCount), 1,cyclefp) !=1){
+ fprintf(stderr, "Error writing to file cycleCnt. Cannot continue.\n");
+ exit(1);
+ }
+ if(fdatasync(cycle_fd)){
+ fprintf(stderr, "Error! cannot sync file buffer with disk.\n");
+ exit(1);
+ }
+
+ fclose(cyclefp);
+ (void)sync();
+
+ printf("\n\n Sending Power down command to the remote box.\n");
+ fd = setupSerial(SerialDevice);
+
+ if(do_pwr_dn(fd, CycleCount) < 0)
+ {
+ fprintf(stderr, "Error sending power down command.\n");
+ exit(1);
+ }
+
+ close(fd);
+}//end send_pwrnd_ok()
+
+
+
+
+/*
+ Appends 16bit CRC at the end of numBytes long buffer.
+ Make sure buf, extends at least 2 bytes beyond.
+ */
+void appendChecksum(char *buf, int numBytes){
+
+ unsigned short crc = 0xffff;
+ int index = 0;
+
+ /* printf("Added CRC (2 bytes) to %i bytes.\n", numBytes); */
+
+ for (; numBytes > 0; numBytes--){
+
+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ buf[index++]) & 0xff];
+ }
+ crc ^= 0xffff;
+ /*printf("The CRC: %x\n\n", crc);*/
+
+ buf[index++] = crc;
+ buf[index++] = crc >> 8;
+
+
+
+}/*end checksum()*/
+
+
+
+
+
+/*
+ This guy make a new "random data file" with the filename
+ passed to it. This file is checksummed with the checksum
+ stored at the end. The first "int" in the file is the
+ number of int's in it (this is needed to know how much
+ data to read and checksum later).
+*/
+void make_new_file(char *filename){
+
+
+ int dfd; /* data file descriptor */
+ int rand_data;
+ int data_size;
+ int temp_size;
+ int dataIndex = 0;
+ int err;
+
+
+ struct {
+ int sizeInBytes; /* must be int */
+ int dataInt[MAX_INTS_ALLOW+1]; /* how many int's can we write? */
+ }__attribute((packed)) dataBuf;
+
+
+ fprintf(stderr, "Creating File:%s. ", filename);
+
+ if((dfd = open(filename, O_RDWR | O_CREAT | O_SYNC)) <= 0)
+ {
+ printf("Error! Cannot open file: %s\n",filename);
+ perror("Error");
+ exit(1);
+ }
+
+ /*now write a bunch of random binary data to the file*/
+ /*first figure out how much data to write. That is random also.*/
+
+ /*file should not be less than 5 ints long. (so that we have decent length files,
+ that's all)*/
+ while(
+ ((data_size = (int)(1+(int)((FileSizeMax/sizeof(int))*rand()/(RAND_MAX+1.0)))) < 5)
+ );
+
+ /* printf("Writing %i ints to the file.\n", data_size); */
+
+ temp_size = data_size * sizeof(int);
+
+ /* Make sure that all data is written in one go! This is important to
+ check for reliability of file systems like JFFS/JFFS that purport to
+ have "reliable" writes during powre fail.
+ */
+
+ dataBuf.sizeInBytes = temp_size;
+
+ data_size--; /*one alrady written*/
+ dataIndex = 0;
+
+ while(data_size--){
+ rand_data = (int)(1 + (int)(10000.0*rand()/(RAND_MAX+1.0)));
+
+ dataBuf.dataInt[dataIndex++] = rand_data;
+
+ }
+
+ /*now calculate the file checksum and append it to the end*/
+ appendChecksum((char *)&dataBuf, dataBuf.sizeInBytes);
+
+ /* Don't forget to increase the size of data written by the 2 chars of CRC at end.
+ These 2 bytes are NOT included in the sizeInBytes field. */
+ if((err = write(dfd, (void *)&dataBuf, dataBuf.sizeInBytes + sizeof(short))) <
+ (dataBuf.sizeInBytes + sizeof(short))
+ )
+ {
+ printf("Error writing data buffer to file. Written %i bytes rather than %i bytes.",
+ err, dataBuf.sizeInBytes);
+ perror("Error");
+ exit(1);
+ }
+
+ /* Now that the data is (hopefully) safely written. I can truncate the file to the new
+ length so that I can reclaim any unused space, if the older file was larger.
+ */
+ if(ftruncate(dfd, dataBuf.sizeInBytes + sizeof(short)) < 0)
+ {
+ perror("Error: Unable to truncate file.");
+ exit(1);
+ }
+
+
+ close(dfd);
+
+
+}//end make_new_file()
+
+
+
+/*
+ Show's help on stdout
+ */
+void printHelp(char **argv)
+{
+ printf("Usage:%s <options, defined below>\n", argv[0]);
+ printf("%s </dev/ttyS0,1,2...>: Set com port to send ok to pwr dn msg on\n",
+ CMDLINE_PORT);
+ printf("%s <n>: Set Max size in bytes of each file to be created.\n",
+ CMDLINE_MAXFILEBYTES);
+ printf("%s <n>: Set Max errors allowed when checking all files for CRC on start.\n",
+ CMDLINE_MAXERROR);
+ printf("%s or %s: This Help screen.\n", CMDLINE_HELPSHORT,
+ CMDLINE_HELPLONG);
+
+}/* end printHelp()*/
+
+
+
+void processCmdLine(int argc, char **argv)
+{
+
+ int cnt;
+
+ /* skip past name of this program, process rest */
+ for(cnt = 1; cnt < argc; cnt++)
+ {
+ if(strcmp(argv[cnt], CMDLINE_PORT) == 0)
+ {
+ strncpy(SerialDevice, argv[++cnt], sizeof(SerialDevice));
+ continue;
+ }else
+ if(strcmp(argv[cnt], CMDLINE_MAXFILEBYTES) == 0)
+ {
+ FileSizeMax = (float)atoi(argv[++cnt]);
+ if(FileSizeMax > (MAX_INTS_ALLOW*sizeof(int)))
+ {
+ printf("Max file size allowd is %i.\n",
+ MAX_INTS_ALLOW*sizeof(int));
+ exit(0);
+ }
+
+ continue;
+ }else
+ if(strcmp(argv[cnt], CMDLINE_HELPSHORT) == 0)
+ {
+ printHelp(argv);
+ exit(0);
+
+ }else
+ if(strcmp(argv[cnt], CMDLINE_HELPLONG) == 0)
+ {
+ printHelp(argv);
+ exit(0);
+ }else
+
+ if(strcmp(argv[cnt], CMDLINE_MAXERROR) == 0)
+ {
+ MaxErrAllowed = atoi(argv[++cnt]);
+ }
+ else
+ {
+ printf("Unknown cmd line option:%s\n", argv[cnt]);
+ printHelp(argv);
+ exit(0);
+
+ }
+ }
+
+
+}/* end processCmdLine() */
+
+
+
+
+
+int main(int argc, char **argv){
+
+ FILE *logfp;
+ int log_fd;
+ char filename[30];
+ short filenameCounter = 0;
+ unsigned short counter;
+ unsigned short numberFiles;
+ char error = FALSE;
+ short errorCnt = 0;
+ time_t timep;
+ char * time_string;
+ unsigned int seed;
+
+
+ numberFiles = MAX_NUM_FILES;
+
+ if(argc >= 1)
+ {
+ processCmdLine(argc, argv);
+ }
+
+
+ /*
+ First open MAX_NUM_FILES and make sure that the checksum is ok.
+ Also make an intry into the logfile.
+ */
+ /* timestamp! */
+ time(&timep);
+ time_string = (char *)ctime((time_t *)&timep);
+
+ /*start a new check, make a log entry and continue*/
+ logfp = fopen("logfile","a"); /*open for appending only.*/
+ log_fd = fileno(logfp);
+ fprintf(logfp,"%s", time_string);
+ fprintf(logfp,"Starting new check.\n");
+ if(fdatasync(log_fd) == -1){
+ fprintf(stderr,"Error! Cannot sync file data with disk.\n");
+ exit(1);
+ }
+
+ fclose(logfp);
+ (void)sync();
+
+ /*
+ Now check all random data files in this dir.
+ */
+ for(counter=0;counter<MAX_NUM_FILES;counter++){
+
+ fprintf(stderr, "%i.", counter);
+
+ /*create the filename in sequence. The number of files
+ to check and the algorithm to create the filename is
+ fixed and known in advance.*/
+ sprintf(filename,"file%i",filenameCounter++);
+
+ if(!check_crc_ccitt(filename)){
+ /*oops, checksum does not match. Make an entry into the log file
+ and decide if we can continue or not.*/
+ fprintf(stderr, "crcError:%s ", filename);
+ logfp = fopen("logfile","a"); /*open for appending only.*/
+ log_fd = fileno(logfp);
+ fprintf(logfp,"CRC error in file: %s\n", filename);
+ if(fdatasync(log_fd) == -1){
+ fprintf(stderr,"Error! Cannot sync file data with disk.\n");
+ exit(1);
+ }
+ fclose(logfp);
+ (void)sync();
+
+ error = TRUE;
+ errorCnt++;
+
+ if(errorCnt > MaxErrAllowed){
+ logfp = fopen("logfile","a"); /*open for appending only.*/
+ log_fd = fileno(logfp);
+ fprintf(logfp,"\nMax Error count exceed. Stopping!\n");
+ if(fdatasync(log_fd) == -1){
+ fprintf(stderr,"Error! Cannot sync file data with disk.\n");
+ exit(1);
+ }
+ fclose(logfp);
+ (void)sync();
+
+ fprintf(stderr, "Too many errors. See \"logfile\".\n");
+ exit(1);
+ }/* if too many errors */
+
+ /*we have decided to continue, however first repair this file
+ so that we do not cumulate errors across power cycles.*/
+ make_new_file(filename);
+ }
+ }//for
+
+ /*all files checked, make a log entry and continue*/
+ logfp = fopen("logfile","a"); /*open for appending only.*/
+ log_fd = fileno(logfp);
+ fprintf(logfp,"All files checked. Total errors found: %i\n\n", errorCnt);
+ if(fdatasync(log_fd)){
+ fprintf(stderr, "Error! cannot sync file buffer with disk.\n");
+ exit(1);
+ }
+
+ fclose(logfp);
+ (void)sync();
+
+ /*now send a message to the remote power box and have it start a random
+ pwer down timer after which power will be killed to this unit.
+ */
+ send_pwrdn_ok();
+
+ /*now go into a forever loop of writing to files and CRC'ing them on
+ a continious basis.*/
+
+ /*start from a random file #*/
+ /*seed rand based on the current time*/
+ seed = (unsigned int)time(NULL);
+ srand(seed);
+
+ filenameCounter=(int)(1+(int)((float)(MAX_NUM_FILES-1)*rand()/(RAND_MAX+1.0)));
+
+ while(1){
+
+ for(;filenameCounter<MAX_NUM_FILES;filenameCounter++){
+
+ /*create the filename in sequence*/
+ sprintf(filename,"file%i",filenameCounter);
+ make_new_file(filename);
+ }
+ filenameCounter = 0;
+ }
+
+ exit(0); /* though we will never reach here, but keeps the compiler happy*/
+}/*end main()*/
diff --git a/drivers/mtd/mtd-utils/tests/checkfs/comm.c b/drivers/mtd/mtd-utils/tests/checkfs/comm.c
new file mode 100644
index 00000000000..5d90017c7de
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/checkfs/comm.c
@@ -0,0 +1,67 @@
+/*
+ File: comm.c
+ Desc: This file implements the actual transmission portion
+ of the "ok to power me down" message to the remote
+ power cycling black box.
+
+ It's been sepatated into a separate file so that
+ it may be replaced by any other comm mechanism desired.
+
+ (including none or non serial mode at all)
+
+ $Id: comm.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ $Log: not supported by cvs2svn $
+ Revision 1.3 2005/11/07 11:15:17 gleixner
+ [MTD / JFFS2] Clean up trailing white spaces
+
+ Revision 1.2 2001/06/21 23:07:18 dwmw2
+ Initial import to MTD CVS
+
+ Revision 1.1 2001/06/08 22:26:05 vipin
+ Split the modbus comm part of the program (that sends the ok to pwr me down
+ message) into another file "comm.c"
+
+
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+
+/*
+ This is the routine that forms and
+ sends the "ok to pwr me down" message
+ to the remote power cycling "black box".
+
+ */
+int do_pwr_dn(int fd, int cycleCnt)
+{
+
+ char buf[200];
+
+ sprintf(buf, "ok to power me down!\nCount = %i\n", cycleCnt);
+
+ if(write(fd, buf, strlen(buf)) < strlen(buf))
+ {
+ perror("write error");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/drivers/mtd/mtd-utils/tests/checkfs/common.h b/drivers/mtd/mtd-utils/tests/checkfs/common.h
new file mode 100644
index 00000000000..cbac10766b1
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/checkfs/common.h
@@ -0,0 +1,7 @@
+/* $Id: common.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ */
+//this .h file is common to both the file creation utility and
+//the file checking utility.
+#define TRUE 1
+#define FALSE 0
+
+#define MAX_NUM_FILES 100
diff --git a/drivers/mtd/mtd-utils/tests/checkfs/makefiles.c b/drivers/mtd/mtd-utils/tests/checkfs/makefiles.c
new file mode 100644
index 00000000000..8589bbf744d
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/checkfs/makefiles.c
@@ -0,0 +1,264 @@
+/*
+
+ * Copyright Daniel Industries.
+
+ * Created by: Vipin Malik (vipin.malik@daniel.com)
+ *
+ * This is GPL code. See the file COPYING for more details
+ *
+ * Software distributed under the Licence is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing rights and
+ * limitations under the Licence.
+
+ * $Id: makefiles.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+
+This program creates MAX_NUM_FILES files (file00001, file00002 etc) and
+fills them with random numbers till they are a random length. Then it checksums
+the files (with the checksum as the last two bytes) and closes the file.
+
+The fist int is the size of the file in bytes.
+
+It then opens another file and the process continues.
+
+The files are opened in the current dir.
+
+*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "common.h"
+
+#define FILESIZE_MAX 20000.0 /* for each file in sizeof(int). Must be a float #
+ Hence, 20000.0 = 20000*4 = 80KB max file size
+ */
+
+static const unsigned short crc_ccitt_table[] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+//This code was taken from the AX.25 HDLC packet driver
+//in LINUX. Once I test and have a better understanding of what
+//it is doing, it will be better commented.
+
+//For now one can speculate that the CRC routine always expects the
+//CRC to calculate out to 0xf0b8 (the hardcoded value at the end)
+//and returns TRUE if it is and FALSE if it doesn't.
+//Why don't people document better!!!!
+void check_crc_ccitt(char *filename)
+{
+ FILE *fp;
+ unsigned short crc = 0xffff;
+ int len;
+ char dataByte;
+ int retry;
+
+ fp = fopen(filename,"rb");
+ if(!fp){
+ printf("Verify checksum:Error! Cannot open filename passed for verify checksum: %s\n",filename);
+ exit(1);
+ }
+ /*the first int contains an int that is the length of the file in long.*/
+ if(fread(&len, sizeof(int), 1, fp) != 1){
+ printf("verify checksum:Error reading from file: %s", filename);
+ fclose(fp);
+ exit(1);
+ }
+ rewind(fp);
+ len+=2; /*the file has two extra bytes at the end, it's checksum. Those
+ two MUST also be included in the checksum calculation.
+ */
+
+ for (;len>0;len--){
+ retry=5; /*retry 5 times*/
+ while(!fread(&dataByte, sizeof(char), 1, fp) && retry--);
+ if(!retry){
+ printf("Unexpected error reading from file: %s\n", filename);
+ printf("...bytes left to be read %i.\n\n",len);
+ fclose(fp);
+ exit(1);
+ }
+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ dataByte) & 0xff];
+ }
+ fclose(fp);
+ if( (crc & 0xffff) != 0xf0b8){
+ printf("Verify checksum: Error in file %s.\n\n",filename);
+ exit(1);
+ }
+}//end check_crc_ccitt()
+
+
+
+/*this routine opens a file 'filename' and checksumn's the entire
+ contents, and then appends the checksum at the end of the file,
+ closes the file and returns.
+*/
+void checksum(char *filename){
+
+ FILE *fp;
+ unsigned short crc = 0xffff;
+ int len;
+ char dataByte;
+ int retry;
+
+ fp = fopen(filename,"rb");
+ if(!fp){
+ printf("Error! Cannot open filename passed for checksum: %s\n",filename);
+ exit(1);
+ }
+ /*the first int contains an int that is the length of the file in longs.*/
+ if(fread(&len, sizeof(int), 1, fp) != 1){
+ printf("Error reading from file: %s", filename);
+ fclose(fp);
+ exit(1);
+ }
+ printf("Calculating checksum on %i bytes.\n",len);
+ rewind(fp); /*the # of bytes int is also included in the checksum.*/
+
+ for (;len>0;len--){
+ retry=5; /*retry 5 times*/
+ while(!fread(&dataByte, sizeof(char), 1, fp) && retry--);
+ if(!retry){
+ printf("Unexpected error reading from file: %s\n", filename);
+ printf("...bytes left to be read %i.\n\n",len);
+ fclose(fp);
+ exit(1);
+ }
+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ dataByte) & 0xff];
+ }
+ crc ^= 0xffff;
+ printf("The CRC: %x\n\n", crc);
+
+ /*the CRC has been calculated. now close the file and open it in append mode*/
+ fclose(fp);
+
+ fp = fopen(filename,"ab"); /*open in append mode. CRC goes at the end.*/
+ if(!fp){
+ printf("Error! Cannot open filename to update checksum: %s\n",filename);
+ exit(1);
+ }
+ if(fwrite(&crc, sizeof(crc), 1, fp) != 1){
+ printf("error! unable to update the file for checksum.\n");
+ fclose(fp);
+ exit(1);
+ }
+ fflush(fp);
+ fclose(fp);
+
+
+}/*end checksum()*/
+
+
+
+int main(void){
+
+ FILE *fp, *cyclefp;
+ int cycleCount;
+ int rand_data;
+ int data_size;
+ int temp_size;
+ char filename[30];
+ short filenameCounter = 0;
+ unsigned short counter;
+ unsigned short numberFiles;
+
+ numberFiles = MAX_NUM_FILES;
+
+ for(counter=0;counter<numberFiles;counter++){
+ /*create the filename in sequence*/
+ sprintf(filename,"file%i",filenameCounter++);
+ fp = fopen(filename,"wb");
+ if(!fp){
+ printf("Error! Cannot open file: %s\n",filename);
+ exit(1);
+ }
+ /*now write a bunch of random binary data to the file*/
+ /*first figure out how much data to write. That is random also.*/
+
+ while(
+ ((data_size = (int)(1 + (int)(FILESIZE_MAX*rand()/(RAND_MAX+1.0)))) < 100)
+ )/*file should not be less than 100 ints long. (so that we have decent length files, that's all)*/
+
+ printf("Writing %i ints to the file.\n", data_size);
+
+ temp_size = data_size * sizeof(int);
+
+ if(!fwrite(&temp_size, sizeof(int), 1, fp)){
+ printf("File write error!!.\n");
+ fclose(fp);
+ exit(1);
+ }
+ data_size--; /*one alrady written*/
+
+ while(data_size--){
+ rand_data = (int)(1 + (int)(10000.0*rand()/(RAND_MAX+1.0)));
+ if(!fwrite(&rand_data, sizeof(int), 1, fp)){
+ printf("File write error!!.\n");
+ fclose(fp);
+ exit(1);
+ }
+ }
+ fflush(fp);
+ fclose(fp);
+ /*now calculate the file checksum and append it to the end*/
+ checksum(filename);
+ /*this is just a test. Check the CRC to amek sure that it is OK.*/
+ check_crc_ccitt(filename);
+ }
+
+ /*now make a file called "cycleCnt" and put a binary (int)0 in it.
+ This file keeps count as to how many cycles have taken place!*/
+ cyclefp = fopen("cycleCnt","wb");
+ if(!cyclefp){
+ printf("cannot open file \"cycleCnt\". Cannot continue.\n");
+ exit(1);
+ }
+ cycleCount = 0;
+ if(fwrite(&cycleCount, sizeof(cycleCount), 1,cyclefp) !=1){
+ printf("Error writing to file cycleCnt. Cannot continue.\n");
+ exit(1);
+ }
+ fclose(cyclefp);
+ exit(0);
+
+}/*end main()*/
+
+
+
+
+
+
+
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/Makefile b/drivers/mtd/mtd-utils/tests/fs-tests/Makefile
new file mode 100644
index 00000000000..d188796cd1e
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/Makefile
@@ -0,0 +1,8 @@
+
+SUBDIRS = lib simple stress integrity utils
+
+all clean tests: $(SUBDIRS)
+
+.PHONY: $(SUBDIRS)
+$(SUBDIRS):
+ $(MAKE) -C $@ $(MAKECMDGOALS)
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/help_all.sh b/drivers/mtd/mtd-utils/tests/fs-tests/help_all.sh
new file mode 100644
index 00000000000..34b890b14db
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/help_all.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+echo -------------------------------------------------------------------------------
+./simple/test_1 -h
+echo -------------------------------------------------------------------------------
+./simple/test_2 -h
+echo -------------------------------------------------------------------------------
+./stress/atoms/stress_1 -h
+echo -------------------------------------------------------------------------------
+./stress/atoms/stress_2 -h
+echo -------------------------------------------------------------------------------
+./stress/atoms/stress_3 -h
+echo -------------------------------------------------------------------------------
+./stress/atoms/fwrite00 -h
+echo -------------------------------------------------------------------------------
+./stress/atoms/gcd_hupper -h
+echo -------------------------------------------------------------------------------
+./stress/atoms/pdfrun -h
+echo -------------------------------------------------------------------------------
+./stress/atoms/rmdir00 -h
+echo -------------------------------------------------------------------------------
+./stress/atoms/rndrm00 -h
+echo -------------------------------------------------------------------------------
+./stress/atoms/rndwrite00 -h
+echo -------------------------------------------------------------------------------
+./integrity/integck -h
+echo -------------------------------------------------------------------------------
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/integrity/Makefile b/drivers/mtd/mtd-utils/tests/fs-tests/integrity/Makefile
new file mode 100644
index 00000000000..a35f4d0d75c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/integrity/Makefile
@@ -0,0 +1,22 @@
+
+ifeq ($(origin CC),default)
+CC = gcc
+endif
+
+CFLAGS := $(CFLAGS) -Wall -g -O2 -I../lib
+
+LDFLAGS := $(LDFLAGS)
+
+TARGETS = integck
+
+all: $(TARGETS)
+
+$(TARGETS): ../lib/tests.o
+
+../lib/tests.o: ../lib/tests.h
+
+clean:
+ rm -f *.o $(TARGETS)
+
+tests: all
+ ./integck
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/integrity/integck.c b/drivers/mtd/mtd-utils/tests/fs-tests/integrity/integck.c
new file mode 100644
index 00000000000..753a3179b40
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/integrity/integck.c
@@ -0,0 +1,1422 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <dirent.h>
+
+#include "tests.h"
+
+/* Structures to store data written to the test file system,
+ so that we can check whether the file system is correct. */
+
+struct write_info /* Record of random data written into a file */
+{
+ struct write_info *next;
+ off_t offset; /* Where in the file the data was written */
+ size_t size; /* Number of bytes written */
+ unsigned random_seed; /* Seed for rand() to create random data */
+ off_t random_offset; /* Call rand() this number of times first */
+};
+
+struct file_info /* Each file has one of these */
+{
+ char *name;
+ struct dir_info *parent; /* Parent directory */
+ struct write_info *writes; /* Record accumulated writes to the file */
+ struct write_info *raw_writes;
+ /* Record in order all writes to the file */
+ struct fd_info *fds; /* All open file descriptors for this file */
+ off_t length;
+ int deleted; /* File has been deleted but is still open */
+ int no_space_error; /* File has incurred a ENOSPC error */
+};
+
+struct dir_info /* Each directory has one of these */
+{
+ char *name;
+ struct dir_info *parent; /* Parent directory or null
+ for our top directory */
+ unsigned number_of_entries;
+ struct dir_entry_info *first;
+};
+
+struct dir_entry_info /* Each entry in a directory has one of these */
+{
+ struct dir_entry_info *next;
+ char type; /* f => file, d=> dir */
+ int checked; /* Temporary flag used when checking */
+ union entry_
+ {
+ struct file_info *file;
+ struct dir_info *dir;
+ } entry;
+};
+
+struct fd_info /* We keep a number of files open */
+{
+ struct fd_info *next;
+ struct file_info *file;
+ int fd;
+};
+
+struct open_file_info /* We keep a list of open files */
+{
+ struct open_file_info *next;
+ struct fd_info *fdi;
+};
+
+static struct dir_info *top_dir = NULL; /* Our top directory */
+
+static struct open_file_info *open_files = NULL; /* We keep a list of
+ open files */
+static size_t open_files_count = 0;
+
+static int grow = 1; /* Should we try to grow files and directories */
+static int shrink = 0; /* Should we try to shrink files and directories */
+static int full = 0; /* Flag that the file system is full */
+static uint64_t operation_count = 0; /* Number of operations used to fill
+ up the file system */
+static uint64_t initial_free_space = 0; /* Free space on file system when
+ test starts */
+static unsigned log10_initial_free_space = 0; /* log10 of initial_free_space */
+
+static char *copy_string(const char *s)
+{
+ char *str;
+
+ if (!s)
+ return NULL;
+ str = (char *) malloc(strlen(s) + 1);
+ CHECK(str != NULL);
+ strcpy(str, s);
+ return str;
+}
+
+static char *cat_strings(const char *a, const char *b)
+{
+ char *str;
+ size_t sz;
+
+ if (a && !b)
+ return copy_string(a);
+ if (b && !a)
+ return copy_string(b);
+ if (!a && !b)
+ return NULL;
+ sz = strlen(a) + strlen(b) + 1;
+ str = (char *) malloc(sz);
+ CHECK(str != NULL);
+ strcpy(str, a);
+ strcat(str, b);
+ return str;
+}
+
+static char *cat_paths(const char *a, const char *b)
+{
+ char *str;
+ size_t sz;
+ int as, bs;
+ size_t na, nb;
+
+ if (a && !b)
+ return copy_string(a);
+ if (b && !a)
+ return copy_string(b);
+ if (!a && !b)
+ return NULL;
+
+ as = 0;
+ bs = 0;
+ na = strlen(a);
+ nb = strlen(b);
+ if (na && a[na - 1] == '/')
+ as = 1;
+ if (nb && b[0] == '/')
+ bs = 1;
+ if ((as && !bs) || (!as && bs))
+ return cat_strings(a, b);
+ if (as && bs)
+ return cat_strings(a, b + 1);
+
+ sz = na + nb + 2;
+ str = (char *) malloc(sz);
+ CHECK(str != NULL);
+ strcpy(str, a);
+ strcat(str, "/");
+ strcat(str, b);
+ return str;
+}
+
+static char *dir_path(struct dir_info *parent, const char *name)
+{
+ char *parent_path;
+ char *path;
+
+ if (!parent)
+ return cat_paths(tests_file_system_mount_dir, name);
+ parent_path = dir_path(parent->parent, parent->name);
+ path = cat_paths(parent_path, name);
+ free(parent_path);
+ return path;
+}
+
+static struct dir_entry_info *dir_entry_new(void)
+{
+ struct dir_entry_info *entry;
+ size_t sz;
+
+ sz = sizeof(struct dir_entry_info);
+ entry = (struct dir_entry_info *) malloc(sz);
+ CHECK(entry != NULL);
+ memset(entry, 0, sz);
+ return entry;
+}
+
+static void open_file_add(struct fd_info *fdi)
+{
+ struct open_file_info *ofi;
+ size_t sz;
+
+ sz = sizeof(struct open_file_info);
+ ofi = (struct open_file_info *) malloc(sz);
+ CHECK(ofi != NULL);
+ memset(ofi, 0, sz);
+ ofi->next = open_files;
+ ofi->fdi = fdi;
+ open_files = ofi;
+ open_files_count += 1;
+}
+
+static void open_file_remove(struct fd_info *fdi)
+{
+ struct open_file_info *ofi;
+ struct open_file_info **prev;
+
+ prev = &open_files;
+ for (ofi = open_files; ofi; ofi = ofi->next) {
+ if (ofi->fdi == fdi) {
+ *prev = ofi->next;
+ free(ofi);
+ open_files_count -= 1;
+ return;
+ }
+ prev = &ofi->next;
+ }
+ CHECK(0); /* We are trying to remove something that is not there */
+}
+
+static struct fd_info *fd_new(struct file_info *file, int fd)
+{
+ struct fd_info *fdi;
+ size_t sz;
+
+ sz = sizeof(struct fd_info);
+ fdi = (struct fd_info *) malloc(sz);
+ CHECK(fdi != NULL);
+ memset(fdi, 0, sz);
+ fdi->next = file->fds;
+ fdi->file = file;
+ fdi->fd = fd;
+ file->fds = fdi;
+ open_file_add(fdi);
+ return fdi;
+}
+
+static struct dir_info *dir_new(struct dir_info *parent, const char *name)
+{
+ struct dir_info *dir;
+ size_t sz;
+ char *path;
+
+ path = dir_path(parent, name);
+ if (mkdir(path, 0777) == -1) {
+ CHECK(errno == ENOSPC);
+ full = 1;
+ free(path);
+ return NULL;
+ }
+ free(path);
+
+ sz = sizeof(struct dir_info);
+ dir = (struct dir_info *) malloc(sz);
+ CHECK(dir != NULL);
+ memset(dir, 0, sz);
+ dir->name = copy_string(name);
+ dir->parent = parent;
+ if (parent) {
+ struct dir_entry_info *entry;
+
+ entry = dir_entry_new();
+ entry->type = 'd';
+ entry->entry.dir = dir;
+ entry->next = parent->first;
+ parent->first = entry;
+ parent->number_of_entries += 1;
+ }
+ return dir;
+}
+
+static void file_delete(struct file_info *file);
+
+static void dir_remove(struct dir_info *dir)
+{
+ char *path;
+ struct dir_entry_info *entry;
+ struct dir_entry_info **prev;
+ int found;
+
+ /* Remove directory contents */
+ while (dir->first) {
+ struct dir_entry_info *entry;
+
+ entry = dir->first;
+ if (entry->type == 'd')
+ dir_remove(entry->entry.dir);
+ else if (entry->type == 'f')
+ file_delete(entry->entry.file);
+ else
+ CHECK(0); /* Invalid struct dir_entry_info */
+ }
+ /* Remove entry from parent directory */
+ found = 0;
+ prev = &dir->parent->first;
+ for (entry = dir->parent->first; entry; entry = entry->next) {
+ if (entry->type == 'd' && entry->entry.dir == dir) {
+ dir->parent->number_of_entries -= 1;
+ *prev = entry->next;
+ free(entry);
+ found = 1;
+ break;
+ }
+ prev = &entry->next;
+ }
+ CHECK(found); /* Check the file is in the parent directory */
+ /* Remove directory itself */
+ path = dir_path(dir->parent, dir->name);
+ CHECK(rmdir(path) != -1);
+}
+
+static struct file_info *file_new(struct dir_info *parent, const char *name)
+{
+ struct file_info *file = NULL;
+ char *path;
+ mode_t mode;
+ int fd;
+ size_t sz;
+ struct dir_entry_info *entry;
+
+ CHECK(parent != NULL);
+
+ path = dir_path(parent, name);
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+ fd = open(path, O_CREAT | O_EXCL | O_RDWR, mode);
+ if (fd == -1) {
+ CHECK(errno == ENOSPC);
+ free(path);
+ full = 1;
+ return NULL;
+ }
+ free(path);
+
+ sz = sizeof(struct file_info);
+ file = (struct file_info *) malloc(sz);
+ CHECK(file != NULL);
+ memset(file, 0, sz);
+ file->name = copy_string(name);
+ file->parent = parent;
+
+ fd_new(file, fd);
+
+ entry = dir_entry_new();
+ entry->type = 'f';
+ entry->entry.file = file;
+ entry->next = parent->first;
+ parent->first = entry;
+ parent->number_of_entries += 1;
+
+ return file;
+}
+
+static void file_delete(struct file_info *file)
+{
+ char *path;
+ struct dir_entry_info *entry;
+ struct dir_entry_info **prev;
+ int found;
+
+ /* Remove file entry from parent directory */
+ found = 0;
+ prev = &file->parent->first;
+ for (entry = file->parent->first; entry; entry = entry->next) {
+ if (entry->type == 'f' && entry->entry.file == file) {
+ file->parent->number_of_entries -= 1;
+ *prev = entry->next;
+ free(entry);
+ found = 1;
+ break;
+ }
+ prev = &entry->next;
+ }
+ CHECK(found); /* Check the file is in the parent directory */
+
+ /* Delete the file */
+ path = dir_path(file->parent, file->name);
+ CHECK(unlink(path) != -1);
+ free(path);
+
+ /* Free struct file_info if file is not open */
+ if (!file->fds) {
+ struct write_info *w, *next;
+
+ free(file->name);
+ w = file->writes;
+ while (w) {
+ next = w->next;
+ free(w);
+ w = next;
+ }
+ free(file);
+ } else
+ file->deleted = 1;
+}
+
+static void file_info_display(struct file_info *file)
+{
+ struct write_info *w;
+ unsigned wcnt;
+
+ fprintf(stderr, "File Info:\n");
+ fprintf(stderr, " Name: %s\n", file->name);
+ fprintf(stderr, " Directory: %s\n", file->parent->name);
+ fprintf(stderr, " Length: %u\n", (unsigned) file->length);
+ fprintf(stderr, " File was open: %s\n",
+ (file->fds == NULL) ? "false" : "true");
+ fprintf(stderr, " File was deleted: %s\n",
+ (file->deleted == 0) ? "false" : "true");
+ fprintf(stderr, " File was out of space: %s\n",
+ (file->no_space_error == 0) ? "false" : "true");
+ fprintf(stderr, " Write Info:\n");
+ wcnt = 0;
+ w = file->writes;
+ while (w) {
+ fprintf(stderr, " Offset: %u Size: %u Seed: %u"
+ " R.Off: %u\n",
+ (unsigned) w->offset,
+ (unsigned) w->size,
+ (unsigned) w->random_seed,
+ (unsigned) w->random_offset);
+ wcnt += 1;
+ w = w->next;
+ }
+ fprintf(stderr, " %u writes\n", wcnt);
+ fprintf(stderr, " ============================================\n");
+ fprintf(stderr, " Raw Write Info:\n");
+ wcnt = 0;
+ w = file->raw_writes;
+ while (w) {
+ fprintf(stderr, " Offset: %u Size: %u Seed: %u"
+ " R.Off: %u\n",
+ (unsigned) w->offset,
+ (unsigned) w->size,
+ (unsigned) w->random_seed,
+ (unsigned) w->random_offset);
+ wcnt += 1;
+ w = w->next;
+ }
+ fprintf(stderr, " %u writes\n", wcnt);
+ fprintf(stderr, " ============================================\n");
+}
+
+static struct fd_info *file_open(struct file_info *file)
+{
+ int fd;
+ char *path;
+
+ path = dir_path(file->parent, file->name);
+ fd = open(path, O_RDWR);
+ CHECK(fd != -1);
+ free(path);
+ return fd_new(file, fd);
+}
+
+#define BUFFER_SIZE 32768
+
+static size_t file_write_data( struct file_info *file,
+ int fd,
+ off_t offset,
+ size_t size,
+ unsigned seed)
+{
+ size_t remains, actual, block;
+ ssize_t written;
+ char buf[BUFFER_SIZE];
+
+ srand(seed);
+ CHECK(lseek(fd, offset, SEEK_SET) != (off_t) -1);
+ remains = size;
+ actual = 0;
+ written = BUFFER_SIZE;
+ while (remains) {
+ /* Fill up buffer with random data */
+ if (written < BUFFER_SIZE)
+ memmove(buf, buf + written, BUFFER_SIZE - written);
+ else
+ written = 0;
+ for (; written < BUFFER_SIZE; ++written)
+ buf[written] = rand();
+ /* Write a block of data */
+ if (remains > BUFFER_SIZE)
+ block = BUFFER_SIZE;
+ else
+ block = remains;
+ written = write(fd, buf, block);
+ if (written < 0) {
+ CHECK(errno == ENOSPC); /* File system full */
+ full = 1;
+ file->no_space_error = 1;
+ break;
+ }
+ remains -= written;
+ actual += written;
+ }
+ return actual;
+}
+
+static void file_write_info(struct file_info *file,
+ off_t offset,
+ size_t size,
+ unsigned seed)
+{
+ struct write_info *new_write, *w, **prev, *tmp;
+ int inserted;
+ size_t sz;
+ off_t end, chg;
+
+ /* Create struct write_info */
+ sz = sizeof(struct write_info);
+ new_write = (struct write_info *) malloc(sz);
+ CHECK(new_write != NULL);
+ memset(new_write, 0, sz);
+ new_write->offset = offset;
+ new_write->size = size;
+ new_write->random_seed = seed;
+
+ w = (struct write_info *) malloc(sz);
+ CHECK(w != NULL);
+ memset(w, 0, sz);
+ w->next = file->raw_writes;
+ w->offset = offset;
+ w->size = size;
+ w->random_seed = seed;
+ file->raw_writes = w;
+
+ /* Insert it into file->writes */
+ inserted = 0;
+ end = offset + size;
+ w = file->writes;
+ prev = &file->writes;
+ while (w) {
+ if (w->offset >= end) {
+ /* w comes after new_write, so insert before it */
+ new_write->next = w;
+ *prev = new_write;
+ inserted = 1;
+ break;
+ }
+ /* w does not come after new_write */
+ if (w->offset + w->size > offset) {
+ /* w overlaps new_write */
+ if (w->offset < offset) {
+ /* w begins before new_write begins */
+ if (w->offset + w->size <= end)
+ /* w ends before new_write ends */
+ w->size = offset - w->offset;
+ else {
+ /* w ends after new_write ends */
+ /* Split w */
+ tmp = (struct write_info *) malloc(sz);
+ CHECK(tmp != NULL);
+ *tmp = *w;
+ chg = end - tmp->offset;
+ tmp->offset += chg;
+ tmp->random_offset += chg;
+ tmp->size -= chg;
+ w->size = offset - w->offset;
+ /* Insert new struct write_info */
+ w->next = new_write;
+ new_write->next = tmp;
+ inserted = 1;
+ break;
+ }
+ } else {
+ /* w begins after new_write begins */
+ if (w->offset + w->size <= end) {
+ /* w is completely overlapped,
+ so remove it */
+ *prev = w->next;
+ tmp = w;
+ w = w->next;
+ free(tmp);
+ continue;
+ }
+ /* w ends after new_write ends */
+ chg = end - w->offset;
+ w->offset += chg;
+ w->random_offset += chg;
+ w->size -= chg;
+ continue;
+ }
+ }
+ prev = &w->next;
+ w = w->next;
+ }
+ if (!inserted)
+ *prev = new_write;
+ /* Update file length */
+ if (end > file->length)
+ file->length = end;
+}
+
+/* Randomly select offset and and size to write in a file */
+static void get_offset_and_size(struct file_info *file,
+ off_t *offset,
+ size_t *size)
+{
+ size_t r, n;
+
+ r = tests_random_no(100);
+ if (r == 0 && grow)
+ /* 1 time in 100, when growing, write off the end of the file */
+ *offset = file->length + tests_random_no(10000000);
+ else if (r < 4)
+ /* 3 (or 4) times in 100, write at the beginning of file */
+ *offset = 0;
+ else if (r < 52 || !grow)
+ /* 48 times in 100, write into the file */
+ *offset = tests_random_no(file->length);
+ else
+ /* 48 times in 100, write at the end of the file */
+ *offset = file->length;
+ /* Distribute the size logarithmically */
+ if (tests_random_no(1000) == 0)
+ r = tests_random_no(log10_initial_free_space + 2);
+ else
+ r = tests_random_no(log10_initial_free_space);
+ n = 1;
+ while (r--)
+ n *= 10;
+ *size = tests_random_no(n);
+ if (!grow && *offset + *size > file->length)
+ *size = file->length - *offset;
+ if (*size == 0)
+ *size = 1;
+}
+
+static void file_truncate_info(struct file_info *file, size_t new_length);
+static void file_close(struct fd_info *fdi);
+
+static int file_ftruncate(struct file_info *file, int fd, off_t new_length)
+{
+ if (ftruncate(fd, new_length) == -1) {
+ CHECK(errno = ENOSPC);
+ file->no_space_error = 1;
+ /* Delete errored files */
+ if (!file->deleted) {
+ struct fd_info *fdi;
+
+ fdi = file->fds;
+ while (fdi) {
+ file_close(fdi);
+ fdi = file->fds;
+ }
+ file_delete(file);
+ }
+ return 0;
+ }
+ return 1;
+}
+
+static void file_write(struct file_info *file, int fd)
+{
+ off_t offset;
+ size_t size, actual;
+ unsigned seed;
+ int truncate = 0;
+
+ get_offset_and_size(file, &offset, &size);
+ seed = tests_random_no(10000000);
+ actual = file_write_data(file, fd, offset, size, seed);
+
+ if (offset + actual <= file->length && shrink)
+ /* 1 time in 100, when shrinking
+ truncate after the write */
+ if (tests_random_no(100) == 0)
+ truncate = 1;
+
+ if (actual != 0)
+ file_write_info(file, offset, actual, seed);
+
+ /* Delete errored files */
+ if (file->no_space_error) {
+ if (!file->deleted) {
+ struct fd_info *fdi;
+
+ fdi = file->fds;
+ while (fdi) {
+ file_close(fdi);
+ fdi = file->fds;
+ }
+ file_delete(file);
+ }
+ return;
+ }
+
+ if (truncate) {
+ size_t new_length = offset + actual;
+ if (file_ftruncate(file, fd, new_length))
+ file_truncate_info(file, new_length);
+ }
+}
+
+static void file_write_file(struct file_info *file)
+{
+ int fd;
+ char *path;
+
+ path = dir_path(file->parent, file->name);
+ fd = open(path, O_WRONLY);
+ CHECK(fd != -1);
+ file_write(file, fd);
+ CHECK(close(fd) != -1);
+ free(path);
+}
+
+static void file_truncate_info(struct file_info *file, size_t new_length)
+{
+ struct write_info *w, **prev, *tmp;
+
+ /* Remove / truncate file->writes */
+ w = file->writes;
+ prev = &file->writes;
+ while (w) {
+ if (w->offset >= new_length) {
+ /* w comes after eof, so remove it */
+ *prev = w->next;
+ tmp = w;
+ w = w->next;
+ free(tmp);
+ continue;
+ }
+ if (w->offset + w->size > new_length)
+ w->size = new_length - w->offset;
+ prev = &w->next;
+ w = w->next;
+ }
+ /* Update file length */
+ file->length = new_length;
+}
+
+static void file_truncate(struct file_info *file, int fd)
+{
+ size_t new_length;
+
+ new_length = tests_random_no(file->length);
+
+ if (file_ftruncate(file, fd, new_length))
+ file_truncate_info(file, new_length);
+}
+
+static void file_truncate_file(struct file_info *file)
+{
+ int fd;
+ char *path;
+
+ path = dir_path(file->parent, file->name);
+ fd = open(path, O_WRONLY);
+ CHECK(fd != -1);
+ file_truncate(file, fd);
+ CHECK(close(fd) != -1);
+ free(path);
+}
+
+static void file_close(struct fd_info *fdi)
+{
+ struct file_info *file;
+ struct fd_info *fdp;
+ struct fd_info **prev;
+
+ /* Close file */
+ CHECK(close(fdi->fd) != -1);
+ /* Remove struct fd_info */
+ open_file_remove(fdi);
+ file = fdi->file;
+ prev = &file->fds;
+ for (fdp = file->fds; fdp; fdp = fdp->next) {
+ if (fdp == fdi) {
+ *prev = fdi->next;
+ free(fdi);
+ if (file->deleted && !file->fds) {
+ /* Closing deleted file */
+ struct write_info *w, *next;
+
+ w = file->writes;
+ while (w) {
+ next = w->next;
+ free(w);
+ w = next;
+ }
+ free(file->name);
+ free(file);
+ }
+ return;
+ }
+ prev = &fdp->next;
+ }
+ CHECK(0); /* Didn't find struct fd_info */
+}
+
+static void file_rewrite_data(int fd, struct write_info *w, char *buf)
+{
+ size_t remains, block;
+ ssize_t written;
+ off_t r;
+
+ srand(w->random_seed);
+ for (r = 0; r < w->random_offset; ++r)
+ rand();
+ CHECK(lseek(fd, w->offset, SEEK_SET) != (off_t) -1);
+ remains = w->size;
+ written = BUFFER_SIZE;
+ while (remains) {
+ /* Fill up buffer with random data */
+ if (written < BUFFER_SIZE)
+ memmove(buf, buf + written, BUFFER_SIZE - written);
+ else
+ written = 0;
+ for (; written < BUFFER_SIZE; ++written)
+ buf[written] = rand();
+ /* Write a block of data */
+ if (remains > BUFFER_SIZE)
+ block = BUFFER_SIZE;
+ else
+ block = remains;
+ written = write(fd, buf, block);
+ CHECK(written == block);
+ remains -= written;
+ }
+}
+
+static void save_file(int fd, struct file_info *file)
+{
+ int w_fd;
+ struct write_info *w;
+ char buf[BUFFER_SIZE];
+ char name[256];
+
+ /* Open file to save contents to */
+ strcpy(name, "/tmp/");
+ strcat(name, file->name);
+ strcat(name, ".integ.sav.read");
+ fprintf(stderr, "Saving %s\n", name);
+ w_fd = open(name, O_CREAT | O_WRONLY, 0777);
+ CHECK(w_fd != -1);
+
+ /* Start at the beginning */
+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1);
+
+ for (;;) {
+ ssize_t r = read(fd, buf, BUFFER_SIZE);
+ CHECK(r != -1);
+ if (!r)
+ break;
+ CHECK(write(w_fd, buf, r) == r);
+ }
+ CHECK(close(w_fd) != -1);
+
+ /* Open file to save contents to */
+ strcpy(name, "/tmp/");
+ strcat(name, file->name);
+ strcat(name, ".integ.sav.written");
+ fprintf(stderr, "Saving %s\n", name);
+ w_fd = open(name, O_CREAT | O_WRONLY, 0777);
+ CHECK(w_fd != -1);
+
+ for (w = file->writes; w; w = w->next)
+ file_rewrite_data(w_fd, w, buf);
+
+ CHECK(close(w_fd) != -1);
+}
+
+static void file_check_hole( struct file_info *file,
+ int fd, off_t offset,
+ size_t size)
+{
+ size_t remains, block, i;
+ char buf[BUFFER_SIZE];
+
+ CHECK(lseek(fd, offset, SEEK_SET) != (off_t) -1);
+ remains = size;
+ while (remains) {
+ if (remains > BUFFER_SIZE)
+ block = BUFFER_SIZE;
+ else
+ block = remains;
+ CHECK(read(fd, buf, block) == block);
+ for (i = 0; i < block; ++i) {
+ if (buf[i] != 0) {
+ fprintf(stderr, "file_check_hole failed at %u "
+ "checking hole at %u size %u\n",
+ (unsigned) (size - remains + i),
+ (unsigned) offset,
+ (unsigned) size);
+ file_info_display(file);
+ save_file(fd, file);
+ }
+ CHECK(buf[i] == 0);
+ }
+ remains -= block;
+ }
+}
+
+static void file_check_data( struct file_info *file,
+ int fd,
+ struct write_info *w)
+{
+ size_t remains, block, i;
+ off_t r;
+ char buf[BUFFER_SIZE];
+
+ srand(w->random_seed);
+ for (r = 0; r < w->random_offset; ++r)
+ rand();
+ CHECK(lseek(fd, w->offset, SEEK_SET) != (off_t) -1);
+ remains = w->size;
+ while (remains) {
+ if (remains > BUFFER_SIZE)
+ block = BUFFER_SIZE;
+ else
+ block = remains;
+ CHECK(read(fd, buf, block) == block);
+ for (i = 0; i < block; ++i) {
+ char c = (char) rand();
+ if (buf[i] != c) {
+ fprintf(stderr, "file_check_data failed at %u "
+ "checking data at %u size %u\n",
+ (unsigned) (w->size - remains + i),
+ (unsigned) w->offset,
+ (unsigned) w->size);
+ file_info_display(file);
+ save_file(fd, file);
+ }
+ CHECK(buf[i] == c);
+ }
+ remains -= block;
+ }
+}
+
+static void file_check(struct file_info *file, int fd)
+{
+ int open_and_close = 0;
+ char *path = NULL;
+ off_t pos;
+ struct write_info *w;
+
+ /* Do not check files that have errored */
+ if (file->no_space_error)
+ return;
+ if (fd == -1)
+ open_and_close = 1;
+ if (open_and_close) {
+ /* Open file */
+ path = dir_path(file->parent, file->name);
+ fd = open(path, O_RDONLY);
+ CHECK(fd != -1);
+ }
+ /* Check length */
+ pos = lseek(fd, 0, SEEK_END);
+ if (pos != file->length) {
+ fprintf(stderr, "file_check failed checking length "
+ "expected %u actual %u\n",
+ (unsigned) file->length,
+ (unsigned) pos);
+ file_info_display(file);
+ save_file(fd, file);
+ }
+ CHECK(pos == file->length);
+ /* Check each write */
+ pos = 0;
+ for (w = file->writes; w; w = w->next) {
+ if (w->offset > pos)
+ file_check_hole(file, fd, pos, w->offset - pos);
+ file_check_data(file, fd, w);
+ pos = w->offset + w->size;
+ }
+ if (file->length > pos)
+ file_check_hole(file, fd, pos, file->length - pos);
+ if (open_and_close) {
+ CHECK(close(fd) != -1);
+ free(path);
+ }
+}
+
+static const char *dir_entry_name(const struct dir_entry_info *entry)
+{
+ CHECK(entry != NULL);
+ if (entry->type == 'd')
+ return entry->entry.dir->name;
+ else if (entry->type == 'f')
+ return entry->entry.file->name;
+ else {
+ CHECK(0);
+ return NULL;
+ }
+}
+
+static int search_comp(const void *pa, const void *pb)
+{
+ const struct dirent *a = (const struct dirent *) pa;
+ const struct dir_entry_info *b = * (const struct dir_entry_info **) pb;
+ return strcmp(a->d_name, dir_entry_name(b));
+}
+
+static void dir_entry_check(struct dir_entry_info **entry_array,
+ size_t number_of_entries,
+ struct dirent *ent)
+{
+ struct dir_entry_info **found;
+ struct dir_entry_info *entry;
+ size_t sz;
+
+ sz = sizeof(struct dir_entry_info *);
+ found = bsearch(ent, entry_array, number_of_entries, sz, search_comp);
+ CHECK(found != NULL);
+ entry = *found;
+ CHECK(!entry->checked);
+ entry->checked = 1;
+}
+
+static int sort_comp(const void *pa, const void *pb)
+{
+ const struct dir_entry_info *a = * (const struct dir_entry_info **) pa;
+ const struct dir_entry_info *b = * (const struct dir_entry_info **) pb;
+ return strcmp(dir_entry_name(a), dir_entry_name(b));
+}
+
+static void dir_check(struct dir_info *dir)
+{
+ struct dir_entry_info **entry_array, **p;
+ size_t sz, n;
+ struct dir_entry_info *entry;
+ DIR *d;
+ struct dirent *ent;
+ unsigned checked = 0;
+ char *path;
+
+ /* Create an array of entries */
+ sz = sizeof(struct dir_entry_info *);
+ n = dir->number_of_entries;
+ entry_array = (struct dir_entry_info **) malloc(sz * n);
+ CHECK(entry_array != NULL);
+
+ entry = dir->first;
+ p = entry_array;
+ while (entry) {
+ *p++ = entry;
+ entry->checked = 0;
+ entry = entry->next;
+ }
+
+ /* Sort it by name */
+ qsort(entry_array, n, sz, sort_comp);
+
+ /* Go through directory on file system checking entries match */
+ path = dir_path(dir->parent, dir->name);
+ d = opendir(path);
+ CHECK(d != NULL);
+ for (;;) {
+ errno = 0;
+ ent = readdir(d);
+ if (ent) {
+ if (strcmp(".",ent->d_name) != 0 &&
+ strcmp("..",ent->d_name) != 0) {
+ dir_entry_check(entry_array, n, ent);
+ checked += 1;
+ }
+ } else {
+ CHECK(errno == 0);
+ break;
+ }
+ }
+ CHECK(closedir(d) != -1);
+ CHECK(checked == dir->number_of_entries);
+ free(path);
+
+ /* Now check each entry */
+ entry = dir->first;
+ while (entry) {
+ if (entry->type == 'd')
+ dir_check(entry->entry.dir);
+ else if (entry->type == 'f')
+ file_check(entry->entry.file, -1);
+ else
+ CHECK(0);
+ entry = entry->next;
+ }
+
+ free(entry_array);
+}
+
+static void check_deleted_files(void)
+{
+ struct open_file_info *ofi;
+
+ for (ofi = open_files; ofi; ofi = ofi->next)
+ if (ofi->fdi->file->deleted)
+ file_check(ofi->fdi->file, ofi->fdi->fd);
+}
+
+static void close_open_files(void)
+{
+ struct open_file_info *ofi;
+
+ for (ofi = open_files; ofi; ofi = open_files)
+ file_close(ofi->fdi);
+}
+
+static char *make_name(struct dir_info *dir)
+{
+ static char name[256];
+ struct dir_entry_info *entry;
+ int found;
+
+ do {
+ found = 0;
+ sprintf(name, "%u", (unsigned) tests_random_no(1000000));
+ for (entry = dir->first; entry; entry = entry->next) {
+ if (strcmp(dir_entry_name(entry), name) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ } while (found);
+ return name;
+}
+
+static void operate_on_dir(struct dir_info *dir);
+static void operate_on_file(struct file_info *file);
+
+/* Randomly select something to do with a directory entry */
+static void operate_on_entry(struct dir_entry_info *entry)
+{
+ /* If shrinking, 1 time in 50, remove a directory */
+ if (entry->type == 'd') {
+ if (shrink && tests_random_no(50) == 0) {
+ dir_remove(entry->entry.dir);
+ return;
+ }
+ operate_on_dir(entry->entry.dir);
+ }
+ /* If shrinking, 1 time in 10, remove a file */
+ if (entry->type == 'f') {
+ if (shrink && tests_random_no(10) == 0) {
+ file_delete(entry->entry.file);
+ return;
+ }
+ operate_on_file(entry->entry.file);
+ }
+}
+
+/* Randomly select something to do with a directory */
+static void operate_on_dir(struct dir_info *dir)
+{
+ size_t r;
+ struct dir_entry_info *entry;
+
+ r = tests_random_no(12);
+ if (r == 0 && grow)
+ /* When growing, 1 time in 12 create a file */
+ file_new(dir, make_name(dir));
+ else if (r == 1 && grow)
+ /* When growing, 1 time in 12 create a directory */
+ dir_new(dir, make_name(dir));
+ else {
+ /* Otherwise randomly select an entry to operate on */
+ r = tests_random_no(dir->number_of_entries);
+ entry = dir->first;
+ while (entry && r) {
+ entry = entry->next;
+ --r;
+ }
+ if (entry)
+ operate_on_entry(entry);
+ }
+}
+
+/* Randomly select something to do with a file */
+static void operate_on_file(struct file_info *file)
+{
+ /* Try to keep at least 10 files open */
+ if (open_files_count < 10) {
+ file_open(file);
+ return;
+ }
+ /* Try to keep about 20 files open */
+ if (open_files_count < 20 && tests_random_no(2) == 0) {
+ file_open(file);
+ return;
+ }
+ /* Try to keep up to 40 files open */
+ if (open_files_count < 40 && tests_random_no(20) == 0) {
+ file_open(file);
+ return;
+ }
+ /* Occasionly truncate */
+ if (shrink && tests_random_no(100) == 0) {
+ file_truncate_file(file);
+ return;
+ }
+ /* Mostly just write */
+ file_write_file(file);
+}
+
+/* Randomly select something to do with an open file */
+static void operate_on_open_file(struct fd_info *fdi)
+{
+ size_t r;
+
+ r = tests_random_no(1000);
+ if (shrink && r == 0)
+ file_truncate(fdi->file, fdi->fd);
+ else if (r < 21)
+ file_close(fdi);
+ else if (shrink && r < 121 && !fdi->file->deleted)
+ file_delete(fdi->file);
+ else
+ file_write(fdi->file, fdi->fd);
+}
+
+/* Select an open file at random */
+static void operate_on_an_open_file(void)
+{
+ size_t r;
+ struct open_file_info *ofi;
+
+ /* Close any open files that have errored */
+ ofi = open_files;
+ while (ofi) {
+ if (ofi->fdi->file->no_space_error) {
+ struct fd_info *fdi;
+
+ fdi = ofi->fdi;
+ ofi = ofi->next;
+ file_close(fdi);
+ } else
+ ofi = ofi->next;
+ }
+ r = tests_random_no(open_files_count);
+ for (ofi = open_files; ofi; ofi = ofi->next, --r)
+ if (!r) {
+ operate_on_open_file(ofi->fdi);
+ return;
+ }
+}
+
+static void do_an_operation(void)
+{
+ /* Half the time operate on already open files */
+ if (tests_random_no(100) < 50)
+ operate_on_dir(top_dir);
+ else
+ operate_on_an_open_file();
+}
+
+static void create_test_data(void)
+{
+ uint64_t i;
+
+ grow = 1;
+ shrink = 0;
+ full = 0;
+ operation_count = 0;
+ while (!full) {
+ do_an_operation();
+ ++operation_count;
+ }
+ grow = 0;
+ shrink = 1;
+ /* Drop to less than 90% full */
+ for (;;) {
+ uint64_t free;
+ uint64_t total;
+ for (i = 0; i < 10; ++i)
+ do_an_operation();
+ free = tests_get_free_space();
+ total = tests_get_total_space();
+ if ((free * 100) / total >= 10)
+ break;
+ }
+ grow = 0;
+ shrink = 0;
+ full = 0;
+ for (i = 0; i < operation_count * 2; ++i)
+ do_an_operation();
+}
+
+static void update_test_data(void)
+{
+ uint64_t i;
+
+ grow = 1;
+ shrink = 0;
+ full = 0;
+ while (!full)
+ do_an_operation();
+ grow = 0;
+ shrink = 1;
+ /* Drop to less than 50% full */
+ for (;;) {
+ uint64_t free;
+ uint64_t total;
+ for (i = 0; i < 10; ++i)
+ do_an_operation();
+ free = tests_get_free_space();
+ total = tests_get_total_space();
+ if ((free * 100) / total >= 50)
+ break;
+ }
+ grow = 0;
+ shrink = 0;
+ full = 0;
+ for (i = 0; i < operation_count * 2; ++i)
+ do_an_operation();
+}
+
+void integck(void)
+{
+ pid_t pid;
+ int64_t rpt;
+ uint64_t z;
+ char dir_name[256];
+
+ /* Make our top directory */
+ pid = getpid();
+ printf("pid is %u\n", (unsigned) pid);
+ tests_cat_pid(dir_name, "integck_test_dir_", pid);
+ if (chdir(dir_name) != -1) {
+ /* Remove it if it is already there */
+ tests_clear_dir(".");
+ CHECK(chdir("..") != -1);
+ CHECK(rmdir(dir_name) != -1);
+ }
+ initial_free_space = tests_get_free_space();
+ log10_initial_free_space = 0;
+ for (z = initial_free_space; z >= 10; z /= 10)
+ ++log10_initial_free_space;
+ top_dir = dir_new(NULL, dir_name);
+
+ if (!top_dir)
+ return;
+
+ srand(pid);
+
+ create_test_data();
+
+ if (!tests_fs_is_rootfs()) {
+ close_open_files();
+ tests_remount(); /* Requires root access */
+ }
+
+ /* Check everything */
+ dir_check(top_dir);
+ check_deleted_files();
+
+ for (rpt = 0; tests_repeat_parameter == 0 ||
+ rpt < tests_repeat_parameter; ++rpt) {
+ update_test_data();
+
+ if (!tests_fs_is_rootfs()) {
+ close_open_files();
+ tests_remount(); /* Requires root access */
+ }
+
+ /* Check everything */
+ dir_check(top_dir);
+ check_deleted_files();
+ }
+
+ /* Tidy up by removing everything */
+ close_open_files();
+ tests_clear_dir(dir_name);
+ CHECK(rmdir(dir_name) != -1);
+}
+
+/* Title of this test */
+
+const char *integck_get_title(void)
+{
+ return "Test file system integrity";
+}
+
+/* Description of this test */
+
+const char *integck_get_description(void)
+{
+ return
+ "Create a directory named integck_test_dir_pid " \
+ "where pid is the process id. " \
+ "Randomly create and delete files and directories. " \
+ "Randomly write to and truncate files. " \
+ "Un-mount and re-mount test file " \
+ "system (if it is not the root file system ). " \
+ "Check data. Make more random changes. " \
+ "Un-mount and re-mount again. Check again. " \
+ "Repeat some number of times. "
+ "The repeat count is set by the -n or --repeat option, " \
+ "otherwise it defaults to 1. " \
+ "A repeat count of zero repeats forever.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test repetition */
+ tests_repeat_parameter = 1;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, integck_get_title(),
+ integck_get_description(), "n");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ integck();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile b/drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile
new file mode 100644
index 00000000000..8d57824069c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile
@@ -0,0 +1,18 @@
+
+ifeq ($(origin CC),default)
+CC = gcc
+endif
+
+CFLAGS := $(CFLAGS) -Wall -g -O2
+
+LDFLAGS := $(LDFLAGS)
+
+all: tests.o
+
+tests.o: tests.h
+
+clean:
+ rm -f *.o
+
+tests:
+ echo
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c b/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c
new file mode 100644
index 00000000000..9b8f4433054
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c
@@ -0,0 +1,1091 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/vfs.h>
+#include <sys/statvfs.h>
+#include <linux/jffs2.h>
+#include <libgen.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <limits.h>
+#include <sys/mount.h>
+#include <mntent.h>
+#include <time.h>
+
+#include "tests.h"
+
+char *tests_file_system_mount_dir = TESTS_DEFAULT_FILE_SYSTEM_MOUNT_DIR;
+
+char *tests_file_system_type = TESTS_DEFAULT_FILE_SYSTEM_TYPE;
+
+int tests_ok_to_sync = 0; /* Whether to use fsync */
+
+/* General purpose test parameter to specify some aspect of test size.
+ May be used by different tests in different ways or not at all.
+ Set by the -z or --size option. */
+int64_t tests_size_parameter = 0;
+
+/* General purpose test parameter to specify some aspect of test repetition.
+ May be used by different tests in different ways or not at all.
+ Set by the -n, --repeat options. */
+int64_t tests_repeat_parameter = 0;
+
+/* General purpose test parameter to specify some aspect of test sleeping.
+ May be used by different tests in different ways or not at all.
+ Set by the -p, --sleep options. */
+int64_t tests_sleep_parameter = 0;
+
+/* Program name from argv[0] */
+char *program_name = "unknown";
+
+/* General purpose test parameter to specify a file should be unlinked.
+ May be used by different tests in different ways or not at all. */
+int tests_unlink_flag = 0;
+
+/* General purpose test parameter to specify a file should be closed.
+ May be used by different tests in different ways or not at all. */
+int tests_close_flag = 0;
+
+/* General purpose test parameter to specify a file should be deleted.
+ May be used by different tests in different ways or not at all. */
+int tests_delete_flag = 0;
+
+/* General purpose test parameter to specify a file have a hole.
+ May be used by different tests in different ways or not at all. */
+int tests_hole_flag = 0;
+
+/* Whether it is ok to test on the root file system */
+static int rootok = 0;
+
+/* Function invoked by the CHECK macro */
+void tests_test(int test,const char *msg,const char *file,unsigned line)
+{
+ int eno;
+ time_t t;
+
+ if (test)
+ return;
+ eno = errno;
+ time(&t);
+ fprintf(stderr, "Test failed: %s on %s"
+ "Test failed: %s in %s at line %u\n",
+ program_name, ctime(&t), msg, file, line);
+ if (eno) {
+ fprintf(stderr,"errno = %d\n",eno);
+ fprintf(stderr,"strerror = %s\n",strerror(eno));
+ }
+ exit(1);
+}
+
+static int is_zero(const char *p)
+{
+ for (;*p;++p)
+ if (*p != '0')
+ return 0;
+ return 1;
+}
+
+static void fold(const char *text, int width)
+{
+ int pos, bpos = 0;
+ const char *p;
+ char line[1024];
+
+ if (width > 1023) {
+ printf("%s\n", text);
+ return;
+ }
+ p = text;
+ pos = 0;
+ while (p[pos]) {
+ while (!isspace(p[pos])) {
+ line[pos] = p[pos];
+ if (!p[pos])
+ break;
+ ++pos;
+ if (pos == width) {
+ line[pos] = '\0';
+ printf("%s\n", line);
+ p += pos;
+ pos = 0;
+ }
+ }
+ while (pos < width) {
+ line[pos] = p[pos];
+ if (!p[pos]) {
+ bpos = pos;
+ break;
+ }
+ if (isspace(p[pos]))
+ bpos = pos;
+ ++pos;
+ }
+ line[bpos] = '\0';
+ printf("%s\n", line);
+ p += bpos;
+ pos = 0;
+ while (p[pos] && isspace(p[pos]))
+ ++p;
+ }
+}
+
+/* Handle common program options */
+int tests_get_args(int argc,
+ char *argv[],
+ const char *title,
+ const char *desc,
+ const char *opts)
+{
+ int run_test = 0;
+ int display_help = 0;
+ int display_title = 0;
+ int display_description = 0;
+ int i;
+ char *s;
+
+ program_name = argv[0];
+
+ s = getenv("TEST_FILE_SYSTEM_MOUNT_DIR");
+ if (s)
+ tests_file_system_mount_dir = strdup(s);
+ s = getenv("TEST_FILE_SYSTEM_TYPE");
+ if (s)
+ tests_file_system_type = strdup(s);
+
+ run_test = 1;
+ rootok = 1;
+ for (i = 1; i < argc; ++i) {
+ if (strcmp(argv[i], "--help") == 0 ||
+ strcmp(argv[i], "-h") == 0)
+ display_help = 1;
+ else if (strcmp(argv[i], "--title") == 0 ||
+ strcmp(argv[i], "-t") == 0)
+ display_title = 1;
+ else if (strcmp(argv[i], "--description") == 0 ||
+ strcmp(argv[i], "-d") == 0)
+ display_description = 1;
+ else if (strcmp(argv[i], "--sync") == 0 ||
+ strcmp(argv[i], "-s") == 0)
+ tests_ok_to_sync = 1;
+ else if (strncmp(argv[i], "--size", 6) == 0 ||
+ strncmp(argv[i], "-z", 2) == 0) {
+ int64_t n;
+ char *p;
+ if (i+1 < argc && !isdigit(argv[i][strlen(argv[i])-1]))
+ ++i;
+ p = argv[i];
+ while (*p && !isdigit(*p))
+ ++p;
+ n = atoll(p);
+ if (n)
+ tests_size_parameter = n;
+ else {
+ int all_zero = 1;
+ for (; all_zero && *p; ++p)
+ if (*p != '0')
+ all_zero = 0;
+ if (all_zero)
+ tests_size_parameter = 0;
+ else
+ display_help = 1;
+ }
+ } else if (strncmp(argv[i], "--repeat", 8) == 0 ||
+ strncmp(argv[i], "-n", 2) == 0) {
+ int64_t n;
+ char *p;
+ if (i+1 < argc && !isdigit(argv[i][strlen(argv[i])-1]))
+ ++i;
+ p = argv[i];
+ while (*p && !isdigit(*p))
+ ++p;
+ n = atoll(p);
+ if (n || is_zero(p))
+ tests_repeat_parameter = n;
+ else
+ display_help = 1;
+ } else if (strncmp(argv[i], "--sleep", 7) == 0 ||
+ strncmp(argv[i], "-p", 2) == 0) {
+ int64_t n;
+ char *p;
+ if (i+1 < argc && !isdigit(argv[i][strlen(argv[i])-1]))
+ ++i;
+ p = argv[i];
+ while (*p && !isdigit(*p))
+ ++p;
+ n = atoll(p);
+ if (n || is_zero(p))
+ tests_sleep_parameter = n;
+ else
+ display_help = 1;
+ } else if (strcmp(argv[i], "--unlink") == 0 ||
+ strcmp(argv[i], "-u") == 0)
+ tests_unlink_flag = 1;
+ else if (strcmp(argv[i], "--hole") == 0 ||
+ strcmp(argv[i], "-o") == 0)
+ tests_hole_flag = 1;
+ else if (strcmp(argv[i], "--close") == 0 ||
+ strcmp(argv[i], "-c") == 0)
+ tests_close_flag = 1;
+ else if (strcmp(argv[i], "--delete") == 0 ||
+ strcmp(argv[i], "-e") == 0)
+ tests_delete_flag = 1;
+ else
+ display_help = 1;
+ }
+
+ if (display_help) {
+ run_test = 0;
+ display_title = 0;
+ display_description = 0;
+ if (!opts)
+ opts = "";
+ printf("File System Test Program\n\n");
+ printf("Test Title: %s\n\n", title);
+ printf("Usage is: %s [ options ]\n",argv[0]);
+ printf(" Options are:\n");
+ printf(" -h, --help ");
+ printf("Display this help\n");
+ printf(" -t, --title ");
+ printf("Display the test title\n");
+ printf(" -d, --description ");
+ printf("Display the test description\n");
+ if (strchr(opts, 's')) {
+ printf(" -s, --sync ");
+ printf("Make use of fsync\n");
+ }
+ if (strchr(opts, 'z')) {
+ printf(" -z, --size ");
+ printf("Set size parameter\n");
+ }
+ if (strchr(opts, 'n')) {
+ printf(" -n, --repeat ");
+ printf("Set repeat parameter\n");
+ }
+ if (strchr(opts, 'p')) {
+ printf(" -p, --sleep ");
+ printf("Set sleep parameter\n");
+ }
+ if (strchr(opts, 'u')) {
+ printf(" -u, --unlink ");
+ printf("Unlink file\n");
+ }
+ if (strchr(opts, 'o')) {
+ printf(" -o, --hole ");
+ printf("Create a hole in a file\n");
+ }
+ if (strchr(opts, 'c')) {
+ printf(" -c, --close ");
+ printf("Close file\n");
+ }
+ if (strchr(opts, 'e')) {
+ printf(" -e, --delete ");
+ printf("Delete file\n");
+ }
+ printf("\nBy default, testing is done in directory ");
+ printf("/mnt/test_file_system. To change this\nuse ");
+ printf("environmental variable ");
+ printf("TEST_FILE_SYSTEM_MOUNT_DIR. By default, ");
+ printf("the file\nsystem tested is jffs2. To change this ");
+ printf("set TEST_FILE_SYSTEM_TYPE.\n\n");
+ printf("Test Description:\n");
+ fold(desc, 80);
+ } else {
+ if (display_title)
+ printf("%s\n", title);
+ if (display_description)
+ printf("%s\n", desc);
+ if (display_title || display_description)
+ if (argc == 2 || (argc == 3 &&
+ display_title &&
+ display_description))
+ run_test = 0;
+ }
+ return run_test;
+}
+
+/* Return the number of files (or directories) in the given directory */
+unsigned tests_count_files_in_dir(const char *dir_name)
+{
+ DIR *dir;
+ struct dirent *entry;
+ unsigned count = 0;
+
+ dir = opendir(dir_name);
+ CHECK(dir != NULL);
+ for (;;) {
+ errno = 0;
+ entry = readdir(dir);
+ if (entry) {
+ if (strcmp(".",entry->d_name) != 0 &&
+ strcmp("..",entry->d_name) != 0)
+ ++count;
+ } else {
+ CHECK(errno == 0);
+ break;
+ }
+ }
+ CHECK(closedir(dir) != -1);
+ return count;
+}
+
+/* Change to the file system mount directory, check that it is empty,
+ matches the file system type, and is not the root file system */
+void tests_check_test_file_system(void)
+{
+ struct statfs fs_info;
+ struct stat f_info;
+ struct stat root_f_info;
+
+ if (chdir(tests_file_system_mount_dir) == -1 ||
+ statfs(tests_file_system_mount_dir, &fs_info) == -1) {
+ fprintf(stderr, "Invalid test file system mount directory:"
+ " %s\n", tests_file_system_mount_dir);
+ fprintf(stderr, "Use environment variable "
+ "TEST_FILE_SYSTEM_MOUNT_DIR\n");
+ CHECK(0);
+ }
+ if (strcmp(tests_file_system_type, "jffs2") == 0 &&
+ fs_info.f_type != JFFS2_SUPER_MAGIC) {
+ fprintf(stderr, "File system type is not jffs2\n");
+ CHECK(0);
+ }
+ /* Check that the test file system is not the root file system */
+ if (!rootok) {
+ CHECK(stat(tests_file_system_mount_dir, &f_info) != -1);
+ CHECK(stat("/", &root_f_info) != -1);
+ CHECK(f_info.st_dev != root_f_info.st_dev);
+ }
+}
+
+/* Get the free space for the file system of the current directory */
+uint64_t tests_get_free_space(void)
+{
+ struct statvfs fs_info;
+
+ CHECK(statvfs(tests_file_system_mount_dir, &fs_info) != -1);
+ return (uint64_t) fs_info.f_bavail * (uint64_t) fs_info.f_frsize;
+}
+
+/* Get the total space for the file system of the current directory */
+uint64_t tests_get_total_space(void)
+{
+ struct statvfs fs_info;
+
+ CHECK(statvfs(tests_file_system_mount_dir, &fs_info) != -1);
+ return (uint64_t) fs_info.f_blocks * (uint64_t) fs_info.f_frsize;
+}
+
+#define WRITE_BUFFER_SIZE 32768
+
+static char write_buffer[WRITE_BUFFER_SIZE];
+
+static void init_write_buffer()
+{
+ static int init = 0;
+
+ if (!init) {
+ int i, d;
+ uint64_t u;
+
+ u = RAND_MAX;
+ u += 1;
+ u /= 256;
+ d = (int) u;
+ srand(1);
+ for (i = 0; i < WRITE_BUFFER_SIZE; ++i)
+ write_buffer[i] = rand() / d;
+ init = 1;
+ }
+}
+
+/* Write size random bytes into file descriptor fd at the current position,
+ returning the number of bytes actually written */
+uint64_t tests_fill_file(int fd, uint64_t size)
+{
+ ssize_t written;
+ size_t sz;
+ unsigned start = 0, length;
+ uint64_t remains;
+ uint64_t actual_size = 0;
+
+ init_write_buffer();
+ remains = size;
+ while (remains > 0) {
+ length = WRITE_BUFFER_SIZE - start;
+ if (remains > length)
+ sz = length;
+ else
+ sz = (size_t) remains;
+ written = write(fd, write_buffer + start, sz);
+ if (written <= 0) {
+ CHECK(errno == ENOSPC); /* File system full */
+ errno = 0;
+ break;
+ }
+ remains -= written;
+ actual_size += written;
+ if (written == sz)
+ start = 0;
+ else
+ start += written;
+ }
+ tests_maybe_sync(fd);
+ return actual_size;
+}
+
+/* Write size random bytes into file descriptor fd at offset,
+ returning the number of bytes actually written */
+uint64_t tests_write_filled_file(int fd, off_t offset, uint64_t size)
+{
+ ssize_t written;
+ size_t sz;
+ unsigned start = 0, length;
+ uint64_t remains;
+ uint64_t actual_size = 0;
+
+ CHECK(lseek(fd, offset, SEEK_SET) == offset);
+
+ init_write_buffer();
+ remains = size;
+ start = offset % WRITE_BUFFER_SIZE;
+ while (remains > 0) {
+ length = WRITE_BUFFER_SIZE - start;
+ if (remains > length)
+ sz = length;
+ else
+ sz = (size_t) remains;
+ written = write(fd, write_buffer + start, sz);
+ if (written <= 0) {
+ CHECK(errno == ENOSPC); /* File system full */
+ errno = 0;
+ break;
+ }
+ remains -= written;
+ actual_size += written;
+ if (written == sz)
+ start = 0;
+ else
+ start += written;
+ }
+ tests_maybe_sync(fd);
+ return actual_size;
+}
+
+/* Check that a file written using tests_fill_file() and/or
+ tests_write_filled_file() and/or tests_create_file()
+ contains the expected random data */
+void tests_check_filled_file_fd(int fd)
+{
+ ssize_t sz;
+ char buf[WRITE_BUFFER_SIZE];
+
+ CHECK(lseek(fd, 0, SEEK_SET) == 0);
+ do {
+ sz = read(fd, buf, WRITE_BUFFER_SIZE);
+ CHECK(sz >= 0);
+ CHECK(memcmp(buf, write_buffer, sz) == 0);
+ } while (sz);
+}
+
+/* Check that a file written using tests_fill_file() and/or
+ tests_write_filled_file() and/or tests_create_file()
+ contains the expected random data */
+void tests_check_filled_file(const char *file_name)
+{
+ int fd;
+
+ fd = open(file_name, O_RDONLY);
+ CHECK(fd != -1);
+ tests_check_filled_file_fd(fd);
+ CHECK(close(fd) != -1);
+}
+
+void tests_sync_directory(const char *file_name)
+{
+ char *path;
+ char *dir;
+ int fd;
+
+ if (!tests_ok_to_sync)
+ return;
+
+ path = strdup(file_name);
+ dir = dirname(path);
+ fd = open(dir,O_RDONLY | tests_maybe_sync_flag());
+ CHECK(fd != -1);
+ CHECK(fsync(fd) != -1);
+ CHECK(close(fd) != -1);
+ free(path);
+}
+
+/* Delete a file */
+void tests_delete_file(const char *file_name)
+{
+ CHECK(unlink(file_name) != -1);
+ tests_sync_directory(file_name);
+}
+
+/* Create a file of size file_size */
+uint64_t tests_create_file(const char *file_name, uint64_t file_size)
+{
+ int fd;
+ int flags;
+ mode_t mode;
+ uint64_t actual_size; /* Less than size if the file system is full */
+
+ flags = O_CREAT | O_TRUNC | O_WRONLY | tests_maybe_sync_flag();
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+ fd = open(file_name, flags, mode);
+ if (fd == -1 && errno == ENOSPC) {
+ errno = 0;
+ return 0; /* File system full */
+ }
+ CHECK(fd != -1);
+ actual_size = tests_fill_file(fd, file_size);
+ CHECK(close(fd) != -1);
+ if (file_size != 0 && actual_size == 0)
+ tests_delete_file(file_name);
+ else
+ tests_sync_directory(file_name);
+ return actual_size;
+}
+
+/* Calculate: free_space * numerator / denominator */
+uint64_t tests_get_big_file_size(unsigned numerator, unsigned denominator)
+{
+ if (denominator == 0)
+ denominator = 1;
+ if (numerator > denominator)
+ numerator = denominator;
+ return numerator * (tests_get_free_space() / denominator);
+}
+
+/* Create file "fragment_n" where n is the file_number, and unlink it */
+int tests_create_orphan(unsigned file_number)
+{
+ int fd;
+ int flags;
+ mode_t mode;
+ char file_name[256];
+
+ sprintf(file_name, "fragment_%u", file_number);
+ flags = O_CREAT | O_TRUNC | O_RDWR | tests_maybe_sync_flag();
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+ fd = open(file_name, flags, mode);
+ if (fd == -1 && (errno == ENOSPC || errno == EMFILE))
+ return fd; /* File system full or too many open files */
+ CHECK(fd != -1);
+ tests_sync_directory(file_name);
+ CHECK(unlink(file_name) != -1);
+ return fd;
+}
+
+/* Write size bytes at offset to the file "fragment_n" where n is the
+ file_number and file_number also determines the random data written
+ i.e. seed for random numbers */
+unsigned tests_write_fragment_file(unsigned file_number,
+ int fd,
+ off_t offset,
+ unsigned size)
+{
+ int i, d;
+ uint64_t u;
+ ssize_t written;
+ off_t pos;
+ char buf[WRITE_BUFFER_SIZE];
+
+ if (size > WRITE_BUFFER_SIZE)
+ size = WRITE_BUFFER_SIZE;
+
+ pos = lseek(fd, 0, SEEK_END);
+ CHECK(pos != (off_t) -1);
+ if (offset > pos)
+ offset = pos;
+
+ pos = lseek(fd, offset, SEEK_SET);
+ CHECK(pos != (off_t) -1);
+ CHECK(pos == offset);
+
+ srand(file_number);
+ while (offset--)
+ rand();
+
+ u = RAND_MAX;
+ u += 1;
+ u /= 256;
+ d = (int) u;
+ for (i = 0; i < size; ++i)
+ buf[i] = rand() / d;
+
+ written = write(fd, buf, size);
+ if (written <= 0) {
+ CHECK(errno == ENOSPC); /* File system full */
+ errno = 0;
+ written = 0;
+ }
+ tests_maybe_sync(fd);
+ return (unsigned) written;
+}
+
+/* Write size bytes to the end of file descriptor fd using file_number
+ to determine the random data written i.e. seed for random numbers */
+unsigned tests_fill_fragment_file(unsigned file_number, int fd, unsigned size)
+{
+ off_t offset;
+
+ offset = lseek(fd, 0, SEEK_END);
+ CHECK(offset != (off_t) -1);
+
+ return tests_write_fragment_file(file_number, fd, offset, size);
+}
+
+/* Write size bytes to the end of file "fragment_n" where n is the file_number
+ and file_number also determines the random data written
+ i.e. seed for random numbers */
+unsigned tests_append_to_fragment_file(unsigned file_number,
+ unsigned size,
+ int create)
+{
+ int fd;
+ int flags;
+ mode_t mode;
+ unsigned actual_growth;
+ char file_name[256];
+
+ sprintf(file_name, "fragment_%u", file_number);
+ if (create)
+ flags = O_CREAT | O_EXCL | O_WRONLY | tests_maybe_sync_flag();
+ else
+ flags = O_WRONLY | tests_maybe_sync_flag();
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+ fd = open(file_name, flags, mode);
+ if (fd == -1 && errno == ENOSPC) {
+ errno = 0;
+ return 0; /* File system full */
+ }
+ CHECK(fd != -1);
+ actual_growth = tests_fill_fragment_file(file_number, fd, size);
+ CHECK(close(fd) != -1);
+ if (create && !actual_growth)
+ tests_delete_fragment_file(file_number);
+ return actual_growth;
+}
+
+/* Write size bytes at offset to the file "fragment_n" where n is the
+ file_number and file_number also determines the random data written
+ i.e. seed for random numbers */
+unsigned tests_overwite_fragment_file( unsigned file_number,
+ off_t offset,
+ unsigned size)
+{
+ int fd;
+ unsigned actual_size;
+ char file_name[256];
+
+ sprintf(file_name, "fragment_%u", file_number);
+ fd = open(file_name, O_RDWR | tests_maybe_sync_flag());
+ if (fd == -1 && errno == ENOSPC) {
+ errno = 0;
+ return 0; /* File system full */
+ }
+ CHECK(fd != -1);
+ actual_size = tests_write_fragment_file(file_number,
+ fd, offset, size);
+ CHECK(close(fd) != -1);
+ return actual_size;
+}
+
+/* Delete file "fragment_n" where n is the file_number */
+void tests_delete_fragment_file(unsigned file_number)
+{
+ char file_name[256];
+
+ sprintf(file_name, "fragment_%u", file_number);
+ tests_delete_file(file_name);
+}
+
+/* Check the random data in file "fragment_n" is what is expected */
+void tests_check_fragment_file_fd(unsigned file_number, int fd)
+{
+ ssize_t sz, i;
+ int d;
+ uint64_t u;
+ char buf[8192];
+
+ CHECK(lseek(fd, 0, SEEK_SET) == 0);
+ srand(file_number);
+ u = RAND_MAX;
+ u += 1;
+ u /= 256;
+ d = (int) u;
+ for (;;) {
+ sz = read(fd, buf, 8192);
+ if (sz == 0)
+ break;
+ CHECK(sz >= 0);
+ for (i = 0; i < sz; ++i)
+ CHECK(buf[i] == (char) (rand() / d));
+ }
+}
+
+/* Check the random data in file "fragment_n" is what is expected */
+void tests_check_fragment_file(unsigned file_number)
+{
+ int fd;
+ ssize_t sz, i;
+ int d;
+ uint64_t u;
+ char file_name[256];
+ char buf[8192];
+
+ sprintf(file_name, "fragment_%u", file_number);
+ fd = open(file_name, O_RDONLY);
+ CHECK(fd != -1);
+ srand(file_number);
+ u = RAND_MAX;
+ u += 1;
+ u /= 256;
+ d = (int) u;
+ for (;;) {
+ sz = read(fd, buf, 8192);
+ if (sz == 0)
+ break;
+ CHECK(sz >= 0);
+ for (i = 0; i < sz; ++i)
+ CHECK(buf[i] == (char) (rand() / d));
+ }
+ CHECK(close(fd) != -1);
+}
+
+/* Central point to decide whether to use fsync */
+void tests_maybe_sync(int fd)
+{
+ if (tests_ok_to_sync)
+ CHECK(fsync(fd) != -1);
+}
+
+/* Return O_SYNC if ok to sync otherwise return 0 */
+int tests_maybe_sync_flag(void)
+{
+ if (tests_ok_to_sync)
+ return O_SYNC;
+ return 0;
+}
+
+/* Return random number from 0 to n - 1 */
+size_t tests_random_no(size_t n)
+{
+ uint64_t a, b;
+
+ if (!n)
+ return 0;
+ if (n - 1 <= RAND_MAX) {
+ a = rand();
+ b = RAND_MAX;
+ b += 1;
+ } else {
+ const uint64_t u = 1 + (uint64_t) RAND_MAX;
+ a = rand();
+ a *= u;
+ a += rand();
+ b = u * u;
+ CHECK(n <= b);
+ }
+ if (RAND_MAX <= UINT32_MAX && n <= UINT32_MAX)
+ return a * n / b;
+ else /*if (RAND_MAX <= UINT64_MAX && n <= UINT64_MAX)*/ {
+ uint64_t x, y;
+ if (a < n) {
+ x = a;
+ y = n;
+ } else {
+ x = n;
+ y = a;
+ }
+ return (x * (y / b)) + ((x * (y % b)) / b);
+ }
+}
+
+/* Make a directory empty */
+void tests_clear_dir(const char *dir_name)
+{
+ DIR *dir;
+ struct dirent *entry;
+ char buf[4096];
+
+ dir = opendir(dir_name);
+ CHECK(dir != NULL);
+ CHECK(getcwd(buf, 4096) != NULL);
+ CHECK(chdir(dir_name) != -1);
+ for (;;) {
+ errno = 0;
+ entry = readdir(dir);
+ if (entry) {
+ if (strcmp(".",entry->d_name) != 0 &&
+ strcmp("..",entry->d_name) != 0) {
+ if (entry->d_type == DT_DIR) {
+ tests_clear_dir(entry->d_name);
+ CHECK(rmdir(entry->d_name) != -1);
+ } else
+ CHECK(unlink(entry->d_name) != -1);
+ }
+ } else {
+ CHECK(errno == 0);
+ break;
+ }
+ }
+ CHECK(chdir(buf) != -1);
+ CHECK(closedir(dir) != -1);
+}
+
+/* Create an empty sub-directory or small file in the current directory */
+int64_t tests_create_entry(char *return_name)
+{
+ int fd;
+ char name[256];
+
+ for (;;) {
+ sprintf(name, "%u", (unsigned) tests_random_no(10000000));
+ fd = open(name, O_RDONLY);
+ if (fd == -1)
+ break;
+ close(fd);
+ }
+ if (return_name)
+ strcpy(return_name, name);
+ if (tests_random_no(2)) {
+ return tests_create_file(name, tests_random_no(4096));
+ } else {
+ if (mkdir(name, 0777) == -1) {
+ CHECK(errno == ENOSPC);
+ errno = 0;
+ return 0;
+ }
+ return TESTS_EMPTY_DIR_SIZE;
+ }
+}
+
+/* Remove a random file of empty sub-directory from the current directory */
+int64_t tests_remove_entry(void)
+{
+ DIR *dir;
+ struct dirent *entry;
+ unsigned count = 0, pos;
+ int64_t result = 0;
+
+ dir = opendir(".");
+ CHECK(dir != NULL);
+ for (;;) {
+ errno = 0;
+ entry = readdir(dir);
+ if (entry) {
+ if (strcmp(".",entry->d_name) != 0 &&
+ strcmp("..",entry->d_name) != 0)
+ ++count;
+ } else {
+ CHECK(errno == 0);
+ break;
+ }
+ }
+ pos = tests_random_no(count);
+ count = 0;
+ rewinddir(dir);
+ for (;;) {
+ errno = 0;
+ entry = readdir(dir);
+ if (!entry) {
+ CHECK(errno == 0);
+ break;
+ }
+ if (strcmp(".",entry->d_name) != 0 &&
+ strcmp("..",entry->d_name) != 0) {
+ if (count == pos) {
+ if (entry->d_type == DT_DIR) {
+ tests_clear_dir(entry->d_name);
+ CHECK(rmdir(entry->d_name) != -1);
+ result = TESTS_EMPTY_DIR_SIZE;
+ } else {
+ struct stat st;
+ CHECK(stat(entry->d_name, &st) != -1);
+ result = st.st_size;
+ CHECK(unlink(entry->d_name) != -1);
+ }
+ }
+ ++count;
+ }
+ }
+ CHECK(closedir(dir) != -1);
+ return result;
+}
+
+/* Read mount information from /proc/mounts or /etc/mtab */
+int tests_get_mount_info(struct mntent *info)
+{
+ FILE *f;
+ struct mntent *entry;
+ int found = 0;
+
+ f = fopen("/proc/mounts", "rb");
+ if (!f)
+ f = fopen("/etc/mtab", "rb");
+ CHECK(f != NULL);
+ while (!found) {
+ entry = getmntent(f);
+ if (entry) {
+ if (strcmp(entry->mnt_dir,
+ tests_file_system_mount_dir) == 0) {
+ found = 1;
+ *info = *entry;
+ }
+ } else
+ break;
+ }
+ CHECK(fclose(f) == 0);
+ return found;
+}
+
+/* Un-mount and re-mount test file system */
+void tests_remount(void)
+{
+ struct mntent mount_info;
+ char *source;
+ char *target;
+ char *filesystemtype;
+ unsigned long mountflags;
+ void *data;
+ char cwd[4096];
+
+ CHECK(tests_get_mount_info(&mount_info));
+
+ if (strcmp(mount_info.mnt_dir,"/") == 0)
+ return;
+
+ CHECK(getcwd(cwd, 4096) != NULL);
+ CHECK(chdir("/") != -1);
+
+ CHECK(umount(tests_file_system_mount_dir) != -1);
+
+ source = mount_info.mnt_fsname;
+ target = tests_file_system_mount_dir;
+ filesystemtype = tests_file_system_type;
+ mountflags = 0;
+ data = NULL;
+
+ CHECK(mount(source, target, filesystemtype, mountflags, data) != -1);
+
+ CHECK(chdir(cwd) != -1);
+}
+
+/* Check whether the test file system is also the root file system */
+int tests_fs_is_rootfs(void)
+{
+ struct stat f_info;
+ struct stat root_f_info;
+
+ CHECK(stat(tests_file_system_mount_dir, &f_info) != -1);
+ CHECK(stat("/", &root_f_info) != -1);
+ if (f_info.st_dev == root_f_info.st_dev)
+ return 1;
+ else
+ return 0;
+}
+
+/* Try to make a directory empty */
+void tests_try_to_clear_dir(const char *dir_name)
+{
+ DIR *dir;
+ struct dirent *entry;
+ char buf[4096];
+
+ dir = opendir(dir_name);
+ if (dir == NULL)
+ return;
+ if (getcwd(buf, 4096) == NULL || chdir(dir_name) == -1) {
+ closedir(dir);
+ return;
+ }
+ for (;;) {
+ errno = 0;
+ entry = readdir(dir);
+ if (entry) {
+ if (strcmp(".",entry->d_name) != 0 &&
+ strcmp("..",entry->d_name) != 0) {
+ if (entry->d_type == DT_DIR) {
+ tests_try_to_clear_dir(entry->d_name);
+ rmdir(entry->d_name);
+ } else
+ unlink(entry->d_name);
+ }
+ } else {
+ CHECK(errno == 0);
+ break;
+ }
+ }
+ chdir(buf);
+ closedir(dir);
+}
+
+/* Check whether the test file system is also the current file system */
+int tests_fs_is_currfs(void)
+{
+ struct stat f_info;
+ struct stat curr_f_info;
+
+ CHECK(stat(tests_file_system_mount_dir, &f_info) != -1);
+ CHECK(stat(".", &curr_f_info) != -1);
+ if (f_info.st_dev == curr_f_info.st_dev)
+ return 1;
+ else
+ return 0;
+}
+
+#define PID_BUF_SIZE 64
+
+/* Concatenate a pid to a string in a signal safe way */
+void tests_cat_pid(char *buf, const char *name, pid_t pid)
+{
+ char *p;
+ unsigned x;
+ const char digits[] = "0123456789";
+ char pid_buf[PID_BUF_SIZE];
+
+ x = (unsigned) pid;
+ p = pid_buf + PID_BUF_SIZE;
+ *--p = '\0';
+ if (x)
+ while (x) {
+ *--p = digits[x % 10];
+ x /= 10;
+ }
+ else
+ *--p = '0';
+ buf[0] = '\0';
+ strcat(buf, name);
+ strcat(buf, p);
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h b/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h
new file mode 100644
index 00000000000..db08628aa79
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#ifndef included_tests_tests_h__
+#define included_tests_tests_h__
+
+#include <stdint.h>
+
+/* Main macro for testing */
+#define CHECK(x) tests_test((x),__func__,__FILE__,__LINE__)
+
+/* The default directory in which tests are conducted */
+#define TESTS_DEFAULT_FILE_SYSTEM_MOUNT_DIR "/mnt/test_file_system"
+
+/* The default file system type to test */
+#define TESTS_DEFAULT_FILE_SYSTEM_TYPE "jffs2"
+
+/* Estimated size of an empty directory */
+#define TESTS_EMPTY_DIR_SIZE 128
+
+/* Function invoked by the CHECK macro */
+void tests_test(int test,const char *msg,const char *file,unsigned line);
+
+/* Handle common program options */
+int tests_get_args(int argc,
+ char *argv[],
+ const char *title,
+ const char *desc,
+ const char *opts);
+
+/* Return the number of files (or directories) in the given directory */
+unsigned tests_count_files_in_dir(const char *dir_name);
+
+/* Change to the file system mount directory, check that it is empty,
+ matches the file system type, and is not the root file system */
+void tests_check_test_file_system(void);
+
+/* Get the free space for the file system of the current directory */
+uint64_t tests_get_free_space(void);
+
+/* Get the total space for the file system of the current directory */
+uint64_t tests_get_total_space(void);
+
+/* Write size random bytes into file descriptor fd at the current position,
+ returning the number of bytes actually written */
+uint64_t tests_fill_file(int fd, uint64_t size);
+
+/* Write size random bytes into file descriptor fd at offset,
+ returning the number of bytes actually written */
+uint64_t tests_write_filled_file(int fd, off_t offset, uint64_t size);
+
+/* Check that a file written using tests_fill_file() and/or
+ tests_write_filled_file() and/or tests_create_file()
+ contains the expected random data */
+void tests_check_filled_file_fd(int fd);
+
+/* Check that a file written using tests_fill_file() and/or
+ tests_write_filled_file() and/or tests_create_file()
+ contains the expected random data */
+void tests_check_filled_file(const char *file_name);
+
+/* Delete a file */
+void tests_delete_file(const char *file_name);
+
+/* Create a file of size file_size */
+uint64_t tests_create_file(const char *file_name, uint64_t file_size);
+
+/* Calculate: free_space * numerator / denominator */
+uint64_t tests_get_big_file_size(unsigned numerator, unsigned denominator);
+
+/* Create file "fragment_n" where n is the file_number, and unlink it */
+int tests_create_orphan(unsigned file_number);
+
+/* Write size bytes at offset to the file "fragment_n" where n is the
+ file_number and file_number also determines the random data written
+ i.e. seed for random numbers */
+unsigned tests_write_fragment_file(unsigned file_number,
+ int fd,
+ off_t offset,
+ unsigned size);
+
+/* Write size bytes to the end of file descriptor fd using file_number
+ to determine the random data written i.e. seed for random numbers */
+unsigned tests_fill_fragment_file(unsigned file_number,
+ int fd,
+ unsigned size);
+
+/* Write size bytes to the end of file "fragment_n" where n is the file_number
+ and file_number also determines the random data written
+ i.e. seed for random numbers */
+unsigned tests_append_to_fragment_file(unsigned file_number,
+ unsigned size,
+ int create);
+
+/* Write size bytes at offset to the file "fragment_n" where n is the
+ file_number and file_number also determines the random data written
+ i.e. seed for random numbers */
+unsigned tests_overwite_fragment_file( unsigned file_number,
+ off_t offset,
+ unsigned size);
+
+/* Delete file "fragment_n" where n is the file_number */
+void tests_delete_fragment_file(unsigned file_number);
+
+/* Check the random data in file "fragment_n" is what is expected */
+void tests_check_fragment_file_fd(unsigned file_number, int fd);
+
+/* Check the random data in file "fragment_n" is what is expected */
+void tests_check_fragment_file(unsigned file_number);
+
+/* Central point to decide whether to use fsync */
+void tests_maybe_sync(int fd);
+
+/* Return O_SYNC if ok to sync otherwise return 0 */
+int tests_maybe_sync_flag(void);
+
+/* Return random number from 0 to n - 1 */
+size_t tests_random_no(size_t n);
+
+/* Make a directory empty */
+void tests_clear_dir(const char *dir_name);
+
+/* Create an empty sub-directory or small file in the current directory */
+int64_t tests_create_entry(char *return_name);
+
+/* Remove a random file of empty sub-directory from the current directory */
+int64_t tests_remove_entry(void);
+
+/* Un-mount and re-mount test file system */
+void tests_remount(void);
+
+/* Check whether the test file system is also the root file system */
+int tests_fs_is_rootfs(void);
+
+/* Try to make a directory empty */
+void tests_try_to_clear_dir(const char *dir_name);
+
+/* Check whether the test file system is also the current file system */
+int tests_fs_is_currfs(void);
+
+/* Concatenate a pid to a string in a signal safe way */
+void tests_cat_pid(char *buf, const char *name, pid_t pid);
+
+extern char *tests_file_system_mount_dir;
+
+extern char *tests_file_system_type;
+
+/* General purpose test parameter to specify some aspect of test size.
+ May be used by different tests in different ways.
+ Set by the -z, --size options. */
+extern int64_t tests_size_parameter;
+
+/* General purpose test parameter to specify some aspect of test repetition.
+ May be used by different tests in different ways.
+ Set by the -n, --repeat options. */
+extern int64_t tests_repeat_parameter;
+
+/* General purpose test parameter to specify some aspect of test sleeping.
+ May be used by different tests in different ways.
+ Set by the -p, --sleep options. */
+extern int64_t tests_sleep_parameter;
+
+/* General purpose test parameter to specify a file should be unlinked.
+ May be used by different tests in different ways or not at all. */
+extern int tests_unlink_flag;
+
+/* General purpose test parameter to specify a file should be closed.
+ May be used by different tests in different ways or not at all. */
+extern int tests_close_flag;
+
+/* General purpose test parameter to specify a file should be deleted.
+ May be used by different tests in different ways or not at all. */
+extern int tests_delete_flag;
+
+/* General purpose test parameter to specify a file have a hole.
+ May be used by different tests in different ways or not at all. */
+extern int tests_hole_flag;
+
+/* Program name from argv[0] */
+extern char *program_name;
+
+#endif
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh b/drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh
new file mode 100644
index 00000000000..e79993a299f
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+TEST_DIR=$TEST_FILE_SYSTEM_MOUNT_DIR
+if test -z "$TEST_DIR";
+then
+ TEST_DIR="/mnt/test_file_system"
+fi
+
+rm -rf ${TEST_DIR}/*
+
+./simple/test_1 || exit 1
+
+rm -rf ${TEST_DIR}/*
+
+./simple/test_2 || exit 1
+
+rm -rf ${TEST_DIR}/*
+
+./integrity/integck || exit 1
+
+rm -rf ${TEST_DIR}/*
+
+./stress/atoms/rndrm00 -z0 || exit 1
+
+rm -rf ${TEST_DIR}/*
+
+./stress/atoms/rmdir00 -z0 || exit 1
+
+rm -rf ${TEST_DIR}/*
+
+./stress/atoms/stress_1 -z10000000 -e || exit 1
+
+rm -rf ${TEST_DIR}/*
+
+./stress/atoms/stress_2 -z10000000 || exit 1
+
+rm -rf ${TEST_DIR}/*
+
+./stress/atoms/stress_3 -z1000000000 -e || exit 1
+
+rm -rf ${TEST_DIR}/*
+
+cd stress || exit 1
+
+./stress00.sh 3600 || exit 1
+
+./stress01.sh 3600 || exit 1
+
+cd .. || exit 1
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile b/drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile
new file mode 100644
index 00000000000..8190993171d
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile
@@ -0,0 +1,28 @@
+
+ifeq ($(origin CC),default)
+CC = gcc
+endif
+
+CFLAGS := $(CFLAGS) -Wall -g -O2 -I../lib
+
+LDFLAGS := $(LDFLAGS)
+
+TARGETS = test_1 \
+ test_2 \
+ ftrunc \
+ orph
+
+all: $(TARGETS)
+
+$(TARGETS): ../lib/tests.o
+
+../lib/tests.o: ../lib/tests.h
+
+clean:
+ rm -f *.o $(TARGETS)
+
+tests: all
+ ./test_1 --sync
+ ./test_2 --sync
+ ./ftrunc
+ ./orph --sync
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c b/drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c
new file mode 100644
index 00000000000..86edf650340
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "tests.h"
+
+#define WRITE_BUFFER_SIZE 32768
+
+void ftrunc(void)
+{
+ int fd, i;
+ pid_t pid;
+ ssize_t written;
+ int64_t remains;
+ size_t block;
+ char *file_name;
+ off_t actual;
+ char buf[WRITE_BUFFER_SIZE];
+
+ file_name = "ftrunc_test_file";
+ fd = open(file_name, O_CREAT | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ CHECK(fd != -1);
+ pid = getpid();
+ srand(pid);
+ for (i = 0; i < WRITE_BUFFER_SIZE;++i)
+ buf[i] = rand();
+ remains = tests_size_parameter;
+ actual = 0;
+ while (remains > 0) {
+ if (remains > WRITE_BUFFER_SIZE)
+ block = WRITE_BUFFER_SIZE;
+ else
+ block = remains;
+ written = write(fd, buf, block);
+ if (written <= 0) {
+ CHECK(errno == ENOSPC); /* File system full */
+ errno = 0;
+ break;
+ }
+ remains -= written;
+ actual += written;
+ }
+ CHECK(ftruncate(fd, (actual ? actual - 1 : actual)) != -1);
+ CHECK(close(fd) != -1);
+ CHECK(unlink(file_name) != -1);
+}
+
+/* Title of this test */
+
+const char *ftrunc_get_title(void)
+{
+ return "Truncate a large test file";
+}
+
+/* Description of this test */
+
+const char *ftrunc_get_description(void)
+{
+ return
+ "Create a file named ftrunc_test_file. " \
+ "Truncate the file to reduce its length by 1. " \
+ "Then remove the truncated file. "
+ "The size is given by the -z or --size option, " \
+ "otherwise it defaults to 1000000.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test file size */
+ tests_size_parameter = 1000000;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, ftrunc_get_title(),
+ ftrunc_get_description(), "z");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ ftrunc();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c b/drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c
new file mode 100644
index 00000000000..f6d89564f8e
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "tests.h"
+
+#define MAX_ORPHANS 1000000
+
+void orph(void)
+{
+ pid_t pid;
+ unsigned i, j, k, n;
+ int fd, done, full;
+ int64_t repeat;
+ ssize_t sz;
+ char dir_name[256];
+ int fds[MAX_ORPHANS];
+
+ /* Create a directory to test in */
+ pid = getpid();
+ tests_cat_pid(dir_name, "orph_test_dir_", pid);
+ if (chdir(dir_name) == -1)
+ CHECK(mkdir(dir_name, 0777) != -1);
+ CHECK(chdir(dir_name) != -1);
+
+ repeat = tests_repeat_parameter;
+ for (;;) {
+ full = 0;
+ done = 0;
+ n = 0;
+ while (n + 100 < MAX_ORPHANS && !done) {
+ /* Make 100 more orphans */
+ for (i = 0; i < 100; i++) {
+ fd = tests_create_orphan(n + i);
+ if (fd < 0) {
+ done = 1;
+ if (errno == ENOSPC)
+ full = 1;
+ else if (errno != EMFILE)
+ CHECK(0);
+ errno = 0;
+ break;
+ }
+ fds[n + i] = fd;
+ }
+ if (!full) {
+ /* Write to orphans just created */
+ k = i;
+ for (i = 0; i < k; i++) {
+ if (tests_write_fragment_file(n + i,
+ fds[n+i],
+ 0, 1000)
+ != 1000) {
+ /*
+ * Out of space, so close
+ * remaining files
+ */
+ for (j = i; j < k; j++)
+ CHECK(close(fds[n + j])
+ != -1);
+ done = 1;
+ break;
+ }
+ }
+ }
+ if (!done)
+ CHECK(tests_count_files_in_dir(".") == 0);
+ n += i;
+ }
+ /* Check the data in the files */
+ for (i = 0; i < n; i++)
+ tests_check_fragment_file_fd(i, fds[i]);
+ if (!full && n) {
+ /* Ensure the file system is full */
+ n -= 1;
+ do {
+ sz = write(fds[n], fds, 4096);
+ if (sz == -1 && errno == ENOSPC) {
+ errno = 0;
+ break;
+ }
+ CHECK(sz >= 0);
+ } while (sz == 4096);
+ CHECK(close(fds[n]) != -1);
+ }
+ /* Check the data in the files */
+ for (i = 0; i < n; i++)
+ tests_check_fragment_file_fd(i, fds[i]);
+ /* Sleep */
+ if (tests_sleep_parameter > 0) {
+ unsigned us = tests_sleep_parameter * 1000;
+ unsigned rand_divisor = RAND_MAX / us;
+ unsigned s = (us / 2) + (rand() / rand_divisor);
+ usleep(s);
+ }
+ /* Close orphans */
+ for (i = 0; i < n; i++)
+ CHECK(close(fds[i]) != -1);
+ /* Break if repeat count exceeded */
+ if (tests_repeat_parameter > 0 && --repeat <= 0)
+ break;
+ }
+ CHECK(tests_count_files_in_dir(".") == 0);
+ CHECK(chdir("..") != -1);
+ CHECK(rmdir(dir_name) != -1);
+}
+
+/* Title of this test */
+
+const char *orph_get_title(void)
+{
+ return "Create many open unlinked files";
+}
+
+/* Description of this test */
+
+const char *orph_get_description(void)
+{
+ return
+ "Create a directory named orph_test_dir_pid, where " \
+ "pid is the process id. Within that directory, " \
+ "create files and keep them open and unlink them. " \
+ "Create as many files as possible until the file system is " \
+ "full or the maximum allowed open files is reached. " \
+ "If a sleep value is specified, the process sleeps. " \
+ "The sleep value is given by the -p or --sleep option, " \
+ "otherwise it defaults to 0. " \
+ "Sleep is specified in milliseconds. " \
+ "Then close the files. " \
+ "If a repeat count is specified, then the task repeats " \
+ "that number of times. " \
+ "The repeat count is given by the -n or --repeat option, " \
+ "otherwise it defaults to 1. " \
+ "A repeat count of zero repeats forever. " \
+ "Finally remove the directory.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test repetition */
+ tests_repeat_parameter = 1;
+
+ /* Set default test sleep */
+ tests_sleep_parameter = 0;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, orph_get_title(),
+ orph_get_description(), "nps");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ orph();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c b/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c
new file mode 100644
index 00000000000..69eafe4fabc
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "tests.h"
+
+void test_1(void)
+{
+ int fd;
+ pid_t pid;
+ uint64_t i;
+ uint64_t block;
+ uint64_t actual_size;
+ char name[256];
+ char old[16];
+ char buf[16];
+ off_t old_len;
+ char dir_name[256];
+
+ /* Create a directory to test in */
+ pid = getpid();
+ tests_cat_pid(dir_name, "test_1_test_dir_", pid);
+ if (chdir(dir_name) == -1)
+ CHECK(mkdir(dir_name, 0777) != -1);
+ CHECK(chdir(dir_name) != -1);
+ /* Create a file that fills half the free space on the file system */
+ tests_create_file("big_file", tests_get_big_file_size(1,2));
+ CHECK(tests_count_files_in_dir(".") == 1);
+ fd = open("big_file", O_RDWR | tests_maybe_sync_flag());
+ CHECK(fd != -1);
+ CHECK(read(fd, old, 5) == 5);
+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1);
+ CHECK(write(fd,"start", 5) == 5);
+ CHECK(lseek(fd,0,SEEK_END) != (off_t) -1);
+ CHECK(write(fd, "end", 3) == 3);
+ tests_maybe_sync(fd);
+ /* Delete the file while it is still open */
+ tests_delete_file("big_file");
+ CHECK(tests_count_files_in_dir(".") == 0);
+ /* Create files to file up the file system */
+ for (block = 1000000, i = 1; ; block /= 10) {
+ while (i != 0) {
+ sprintf(name, "fill_up_%llu", i);
+ actual_size = tests_create_file(name, block);
+ if (actual_size != 0)
+ ++i;
+ if (actual_size != block)
+ break;
+ }
+ if (block == 1)
+ break;
+ }
+ /* Check the big file */
+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1);
+ CHECK(read(fd, buf, 5) == 5);
+ CHECK(strncmp(buf, "start", 5) == 0);
+ CHECK(lseek(fd, -3, SEEK_END) != (off_t) -1);
+ CHECK(read(fd, buf, 3) == 3);
+ CHECK(strncmp(buf, "end", 3) == 0);
+ /* Check the other files and delete them */
+ i -= 1;
+ CHECK(tests_count_files_in_dir(".") == i);
+ for (; i > 0; --i) {
+ sprintf(name, "fill_up_%llu", i);
+ tests_check_filled_file(name);
+ tests_delete_file(name);
+ }
+ CHECK(tests_count_files_in_dir(".") == 0);
+ /* Check the big file again */
+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1);
+ CHECK(read(fd, buf, 5) == 5);
+ CHECK(strncmp(buf, "start", 5) == 0);
+ CHECK(lseek(fd, -3, SEEK_END) != (off_t) -1);
+ CHECK(read(fd, buf, 3) == 3);
+ CHECK(strncmp(buf, "end", 3) == 0);
+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1);
+ CHECK(write(fd,old, 5) == 5);
+ old_len = lseek(fd, -3, SEEK_END);
+ CHECK(old_len != (off_t) -1);
+ CHECK(ftruncate(fd,old_len) != -1);
+ tests_check_filled_file_fd(fd);
+ /* Close the big file*/
+ CHECK(close(fd) != -1);
+ CHECK(tests_count_files_in_dir(".") == 0);
+ CHECK(chdir("..") != -1);
+ CHECK(rmdir(dir_name) != -1);
+}
+
+/* Title of this test */
+
+const char *test_1_get_title(void)
+{
+ return "Fill file system while holding deleted big file descriptor";
+}
+
+/* Description of this test */
+
+const char *test_1_get_description(void)
+{
+ return
+ "Create a directory named test_1_test_dir_pid, where " \
+ "pid is the process id. Within that directory, " \
+ "create a big file (approx. half the file system in size), " \
+ "open it, and unlink it. " \
+ "Create many smaller files until the file system is full. " \
+ "Check the big file is ok. " \
+ "Delete all the smaller files. " \
+ "Check the big file again. " \
+ "Finally delete the big file and directory.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, test_1_get_title(),
+ test_1_get_description(), "s");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ test_1();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c b/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c
new file mode 100644
index 00000000000..20944606a92
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "tests.h"
+
+void test_2(void)
+{
+ pid_t pid;
+ int create, full;
+ unsigned i, number_of_files;
+ unsigned growth;
+ unsigned size;
+ uint64_t big_file_size;
+ int fd;
+ off_t offset;
+ char dir_name[256];
+
+ /* Create a directory to test in */
+ pid = getpid();
+ tests_cat_pid(dir_name, "test_2_test_dir_", pid);
+ if (chdir(dir_name) == -1)
+ CHECK(mkdir(dir_name, 0777) != -1);
+ CHECK(chdir(dir_name) != -1);
+ /* Create up to 1000 files appending 400 bytes at a time to each file */
+ /* until the file system is full.*/
+ create = 1;
+ full = 0;
+ number_of_files = 1000;
+ while (!full) {
+ for (i = 0; i < number_of_files; ++i) {
+ growth = tests_append_to_fragment_file(i, 400, create);
+ if (!growth) {
+ full = 1;
+ if (create)
+ number_of_files = i;
+ break;
+ }
+ }
+ create = 0;
+ }
+ /* Check the files */
+ CHECK(tests_count_files_in_dir(".") == number_of_files);
+ for (i = 0; i < number_of_files; ++i)
+ tests_check_fragment_file(i);
+ /* Delete half of them */
+ for (i = 1; i < number_of_files; i += 2)
+ tests_delete_fragment_file(i);
+ /* Check them again */
+ CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2);
+ for (i = 0; i < number_of_files; i += 2)
+ tests_check_fragment_file(i);
+ CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2);
+ /* Create a big file that fills two thirds of the free space */
+ big_file_size = tests_get_big_file_size(2,3);
+ /* Check the big file */
+ tests_create_file("big_file", big_file_size);
+ CHECK(tests_count_files_in_dir(".") == 1 + (number_of_files + 1) / 2);
+ tests_check_filled_file("big_file");
+ /* Open the big file */
+ fd = open("big_file",O_RDWR | tests_maybe_sync_flag());
+ CHECK(fd != -1);
+ /* Delete the big file while it is still open */
+ tests_delete_file("big_file");
+ /* Check the big file again */
+ CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2);
+ tests_check_filled_file_fd(fd);
+
+ /* Write parts of the files and check them */
+
+ offset = 100; /* Offset to write at, in the small files */
+ size = 200; /* Number of bytes to write at the offset */
+
+ for (i = 0; i < number_of_files; i += 2)
+ tests_overwite_fragment_file(i, offset, size);
+ /* Rewrite the big file entirely */
+ tests_write_filled_file(fd, 0, big_file_size);
+ for (i = 0; i < number_of_files; i += 2)
+ tests_check_fragment_file(i);
+ tests_check_filled_file_fd(fd);
+
+ offset = 300; /* Offset to write at, in the small files */
+ size = 400; /* Number of bytes to write at the offset */
+
+ for (i = 0; i < number_of_files; i += 2)
+ tests_overwite_fragment_file(i, offset, size);
+ /* Rewrite the big file entirely */
+ tests_write_filled_file(fd, 0, big_file_size);
+ for (i = 0; i < number_of_files; i += 2)
+ tests_check_fragment_file(i);
+ tests_check_filled_file_fd(fd);
+
+ offset = 110; /* Offset to write at, in the small files */
+ size = 10; /* Number of bytes to write at the offset */
+
+ for (i = 0; i < number_of_files; i += 2)
+ tests_overwite_fragment_file(i, offset, size);
+ /* Rewrite the big file entirely */
+ tests_write_filled_file(fd, 0, big_file_size);
+ for (i = 0; i < number_of_files; i += 2)
+ tests_check_fragment_file(i);
+ tests_check_filled_file_fd(fd);
+
+ offset = 10; /* Offset to write at, in the small files */
+ size = 1000; /* Number of bytes to write at the offset */
+
+ for (i = 0; i < number_of_files; i += 2)
+ tests_overwite_fragment_file(i, offset, size);
+ /* Rewrite the big file entirely */
+ tests_write_filled_file(fd, 0, big_file_size);
+ for (i = 0; i < number_of_files; i += 2)
+ tests_check_fragment_file(i);
+ tests_check_filled_file_fd(fd);
+
+ offset = 0; /* Offset to write at, in the small files */
+ size = 100000; /* Number of bytes to write at the offset */
+
+ for (i = 0; i < number_of_files; i += 2)
+ tests_overwite_fragment_file(i, offset, size);
+ /* Rewrite the big file entirely */
+ tests_write_filled_file(fd, 0, big_file_size);
+ for (i = 0; i < number_of_files; i += 2)
+ tests_check_fragment_file(i);
+ tests_check_filled_file_fd(fd);
+
+ /* Close the big file*/
+ CHECK(close(fd) != -1);
+ /* Check the small files */
+ CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2);
+ for (i = 0; i < number_of_files; i += 2)
+ tests_check_fragment_file(i);
+ /* Delete the small files */
+ for (i = 0; i < number_of_files; i += 2)
+ tests_delete_fragment_file(i);
+ CHECK(tests_count_files_in_dir(".") == 0);
+ CHECK(chdir("..") != -1);
+ CHECK(rmdir(dir_name) != -1);
+}
+
+/* Title of this test */
+
+const char *test_2_get_title(void)
+{
+ return "Repeated write many small files and one big deleted file";
+}
+
+/* Description of this test */
+
+const char *test_2_get_description(void)
+{
+ return
+ "Create a directory named test_2_test_dir_pid, where " \
+ "pid is the process id. Within that directory, " \
+ "create about 1000 files. Append 400 bytes to each until " \
+ "the file system is full. Then delete half of them. Then " \
+ "create a big file that uses about 2/3 of the remaining free " \
+ "space. Get a file descriptor for the big file, and delete " \
+ "the big file. Then repeatedly write to the small files " \
+ "and the big file. " \
+ "Finally delete the big file and directory.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, test_2_get_title(),
+ test_2_get_description(), "s");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ test_2();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile b/drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile
new file mode 100644
index 00000000000..c24ff3f1496
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile
@@ -0,0 +1,11 @@
+
+SUBDIRS = atoms
+
+all tests: $(SUBDIRS)
+
+clean: $(SUBDIRS)
+ rm -rf run_pdf_test_file_*
+
+.PHONY: $(SUBDIRS)
+$(SUBDIRS):
+ $(MAKE) -C $@ $(MAKECMDGOALS)
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile
new file mode 100644
index 00000000000..9fbfd39ec03
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile
@@ -0,0 +1,40 @@
+
+ifeq ($(origin CC),default)
+CC = gcc
+endif
+
+CFLAGS := $(CFLAGS) -Wall -g -O2 -I../../lib
+
+LDFLAGS := $(LDFLAGS)
+
+TARGETS = stress_1 \
+ stress_2 \
+ stress_3 \
+ pdfrun \
+ rndwrite00 \
+ fwrite00 \
+ rmdir00 \
+ rndrm00 \
+ rndrm99 \
+ gcd_hupper
+
+all: $(TARGETS)
+
+$(TARGETS): ../../lib/tests.o
+
+../lib/tests.o: ../../lib/tests.h
+
+clean:
+ rm -f *.o $(TARGETS) run_pdf_test_file
+
+tests: all
+ ./stress_1 -e
+ ./stress_2
+ ./stress_3 -e
+ ./pdfrun
+ ./rndwrite00 -e
+ ./fwrite00
+ ./rmdir00
+ ./rndrm00
+ ./rndrm99
+ ./gcd_hupper
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c
new file mode 100644
index 00000000000..2f40b3db243
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "tests.h"
+
+#define WRITE_BUFFER_SIZE 32768
+
+#define HOLE_BLOCK_SIZE 10000000
+
+void filestress00(void)
+{
+ int fd, i, deleted;
+ pid_t pid;
+ ssize_t written;
+ int64_t remains;
+ int64_t repeat;
+ size_t block;
+ char file_name[256];
+ char buf[WRITE_BUFFER_SIZE];
+
+ fd = -1;
+ deleted = 1;
+ pid = getpid();
+ tests_cat_pid(file_name, "filestress00_test_file_", pid);
+ srand(pid);
+ repeat = tests_repeat_parameter;
+ for (;;) {
+ /* Open the file */
+ if (fd == -1) {
+ fd = open(file_name, O_CREAT | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ CHECK(fd != -1);
+ deleted = 0;
+ if (tests_unlink_flag) {
+ CHECK(unlink(file_name) != -1);
+ deleted = 1;
+ }
+ }
+ /* Get a different set of random data */
+ for (i = 0; i < WRITE_BUFFER_SIZE;++i)
+ buf[i] = rand();
+ if (tests_hole_flag) {
+ /* Make a hole */
+ CHECK(lseek(fd, tests_size_parameter, SEEK_SET) != -1);
+ written = write(fd, "!", 1);
+ if (written <= 0) {
+ /* File system full */
+ CHECK(errno == ENOSPC);
+ errno = 0;
+ }
+ CHECK(lseek(fd, 0, SEEK_SET) != -1);
+ /* Write at set points into the hole */
+ remains = tests_size_parameter;
+ while (remains > HOLE_BLOCK_SIZE) {
+ CHECK(lseek(fd, HOLE_BLOCK_SIZE,
+ SEEK_CUR) != -1);
+ written = write(fd, "!", 1);
+ remains -= HOLE_BLOCK_SIZE;
+ if (written <= 0) {
+ /* File system full */
+ CHECK(errno == ENOSPC);
+ errno = 0;
+ break;
+ }
+ }
+ } else {
+ /* Write data into the file */
+ CHECK(lseek(fd, 0, SEEK_SET) != -1);
+ remains = tests_size_parameter;
+ while (remains > 0) {
+ if (remains > WRITE_BUFFER_SIZE)
+ block = WRITE_BUFFER_SIZE;
+ else
+ block = remains;
+ written = write(fd, buf, block);
+ if (written <= 0) {
+ /* File system full */
+ CHECK(errno == ENOSPC);
+ errno = 0;
+ break;
+ }
+ remains -= written;
+ }
+ }
+ /* Break if repeat count exceeded */
+ if (tests_repeat_parameter > 0 && --repeat <= 0)
+ break;
+ /* Close if tests_close_flag */
+ if (tests_close_flag) {
+ CHECK(close(fd) != -1);
+ fd = -1;
+ }
+ /* Sleep */
+ if (tests_sleep_parameter > 0) {
+ unsigned us = tests_sleep_parameter * 1000;
+ unsigned rand_divisor = RAND_MAX / us;
+ unsigned s = (us / 2) + (rand() / rand_divisor);
+ usleep(s);
+ }
+ /* Delete if tests_delete flag */
+ if (!deleted && tests_delete_flag) {
+ CHECK(unlink(file_name) != -1);
+ deleted = 1;
+ }
+ }
+ CHECK(close(fd) != -1);
+ /* Sleep */
+ if (tests_sleep_parameter > 0) {
+ unsigned us = tests_sleep_parameter * 1000;
+ unsigned rand_divisor = RAND_MAX / us;
+ unsigned s = (us / 2) + (rand() / rand_divisor);
+ usleep(s);
+ }
+ /* Tidy up */
+ if (!deleted)
+ CHECK(unlink(file_name) != -1);
+}
+
+/* Title of this test */
+
+const char *filestress00_get_title(void)
+{
+ return "File stress test 00";
+}
+
+/* Description of this test */
+
+const char *filestress00_get_description(void)
+{
+ return
+ "Create a file named filestress00_test_file_pid, where " \
+ "pid is the process id. If the unlink option " \
+ "(-u or --unlink) is specified, " \
+ "unlink the file while holding the open file descriptor. " \
+ "If the hole option (-o or --hole) is specified, " \
+ "write a single character at the end of the file, creating a " \
+ "hole. " \
+ "Write a single character in the hole every 10 million " \
+ "bytes. " \
+ "If the hole option is not specified, then the file is " \
+ "filled with random data. " \
+ "If the close option (-c or --close) is specified the file " \
+ "is closed. " \
+ "If a sleep value is specified, the process sleeps. " \
+ "If the delete option (-e or --delete) is specified, then " \
+ "the file is deleted. " \
+ "If a repeat count is specified, then the task repeats " \
+ "that number of times. " \
+ "The repeat count is given by the -n or --repeat option, " \
+ "otherwise it defaults to 1. " \
+ "A repeat count of zero repeats forever. " \
+ "The file size is given by the -z or --size option, " \
+ "otherwise it defaults to 1000000. " \
+ "The sleep value is given by the -p or --sleep option, " \
+ "otherwise it defaults to 0. " \
+ "Sleep is specified in milliseconds.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test file size */
+ tests_size_parameter = 1000000;
+
+ /* Set default test repetition */
+ tests_repeat_parameter = 1;
+
+ /* Set default test sleep */
+ tests_sleep_parameter = 0;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, filestress00_get_title(),
+ filestress00_get_description(), "znpuoce");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ filestress00();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c
new file mode 100644
index 00000000000..31c175da6e4
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <mntent.h>
+#include <signal.h>
+
+#include "tests.h"
+
+#define MAX_NAME_SIZE 1024
+
+struct gcd_pid
+{
+ struct gcd_pid *next;
+ int pid;
+ char *name;
+ int mtd_index;
+};
+
+struct gcd_pid *gcd_pid_list = NULL;
+
+int add_gcd_pid(const char *number)
+{
+ int pid;
+ FILE *f;
+ char file_name[MAX_NAME_SIZE];
+ char program_name[MAX_NAME_SIZE];
+
+ pid = atoi(number);
+ if (pid <= 0)
+ return 0;
+ snprintf(file_name, MAX_NAME_SIZE, "/proc/%s/stat", number);
+ f = fopen(file_name, "r");
+ if (f == NULL)
+ return 0;
+ if (fscanf(f, "%d %s", &pid, program_name) != 2) {
+ fclose(f);
+ return 0;
+ }
+ if (strncmp(program_name, "(jffs2_gcd_mtd", 14) != 0)
+ pid = 0;
+ if (pid) {
+ size_t sz;
+ struct gcd_pid *g;
+
+ sz = sizeof(struct gcd_pid);
+ g = (struct gcd_pid *) malloc(sz);
+ g->pid = pid;
+ g->name = (char *) malloc(strlen(program_name) + 1);
+ if (g->name)
+ strcpy(g->name, program_name);
+ else
+ exit(1);
+ g->mtd_index = atoi(program_name + 14);
+ g->next = gcd_pid_list;
+ gcd_pid_list = g;
+ }
+ fclose(f);
+ return pid;
+}
+
+int get_pid_list(void)
+{
+ DIR *dir;
+ struct dirent *entry;
+
+ dir = opendir("/proc");
+ if (dir == NULL)
+ return 1;
+ for (;;) {
+ entry = readdir(dir);
+ if (entry) {
+ if (strcmp(".",entry->d_name) != 0 &&
+ strcmp("..",entry->d_name) != 0)
+ add_gcd_pid(entry->d_name);
+ } else
+ break;
+ }
+ closedir(dir);
+ return 0;
+}
+
+int parse_index_number(const char *name)
+{
+ const char *p, *q;
+ int all_zero;
+ int index;
+
+ p = name;
+ while (*p && !isdigit(*p))
+ ++p;
+ if (!*p)
+ return -1;
+ all_zero = 1;
+ for (q = p; *q; ++q) {
+ if (!isdigit(*q))
+ return -1;
+ if (*q != '0')
+ all_zero = 0;
+ }
+ if (all_zero)
+ return 0;
+ index = atoi(p);
+ if (index <= 0)
+ return -1;
+ return index;
+}
+
+int get_mtd_index(void)
+{
+ FILE *f;
+ struct mntent *entry;
+ struct stat f_info;
+ struct stat curr_f_info;
+ int found;
+ int mtd_index = -1;
+
+ if (stat(tests_file_system_mount_dir, &f_info) == -1)
+ return -1;
+ f = fopen("/proc/mounts", "rb");
+ if (!f)
+ f = fopen("/etc/mtab", "rb");
+ if (f == NULL)
+ return -1;
+ found = 0;
+ for (;;) {
+ entry = getmntent(f);
+ if (!entry)
+ break;
+ if (stat(entry->mnt_dir, &curr_f_info) == -1)
+ continue;
+ if (f_info.st_dev == curr_f_info.st_dev) {
+ int i;
+
+ i = parse_index_number(entry->mnt_fsname);
+ if (i != -1) {
+ if (found && i != mtd_index)
+ return -1;
+ found = 1;
+ mtd_index = i;
+ }
+ }
+ }
+ fclose(f);
+ return mtd_index;
+}
+
+int get_gcd_pid()
+{
+ struct gcd_pid *g;
+ int mtd_index;
+
+ if (get_pid_list())
+ return 0;
+ mtd_index = get_mtd_index();
+ if (mtd_index == -1)
+ return 0;
+ for (g = gcd_pid_list; g; g = g->next)
+ if (g->mtd_index == mtd_index)
+ return g->pid;
+ return 0;
+}
+
+void gcd_hupper(void)
+{
+ int64_t repeat;
+ int pid;
+
+ pid = get_gcd_pid();
+ CHECK(pid != 0);
+ repeat = tests_repeat_parameter;
+ for (;;) {
+ CHECK(kill(pid, SIGHUP) != -1);
+ /* Break if repeat count exceeded */
+ if (tests_repeat_parameter > 0 && --repeat <= 0)
+ break;
+ /* Sleep */
+ if (tests_sleep_parameter > 0) {
+ unsigned us = tests_sleep_parameter * 1000;
+ unsigned rand_divisor = RAND_MAX / us;
+ unsigned s = (us / 2) + (rand() / rand_divisor);
+ usleep(s);
+ }
+ }
+}
+
+/* Title of this test */
+
+const char *gcd_hupper_get_title(void)
+{
+ return "Send HUP signals to gcd";
+}
+
+/* Description of this test */
+
+const char *gcd_hupper_get_description(void)
+{
+ return
+ "Determine the PID of the gcd process. " \
+ "Send it SIGHUP (may require root privileges). " \
+ "If a sleep value is specified, the process sleeps. " \
+ "If a repeat count is specified, then the task repeats " \
+ "that number of times. " \
+ "The repeat count is given by the -n or --repeat option, " \
+ "otherwise it defaults to 1. " \
+ "A repeat count of zero repeats forever. " \
+ "The sleep value is given by the -p or --sleep option, " \
+ "otherwise it defaults to 1. "
+ "Sleep is specified in milliseconds.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test repetition */
+ tests_repeat_parameter = 1;
+
+ /* Set default test sleep */
+ tests_sleep_parameter = 1;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, gcd_hupper_get_title(),
+ gcd_hupper_get_description(), "np");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ gcd_hupper();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c
new file mode 100644
index 00000000000..35365804afc
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "tests.h"
+
+#define WRITE_BUFFER_SIZE 32768
+
+void adjust_size(void)
+{
+ char dummy[1024];
+ unsigned long total_memory;
+ FILE *f;
+
+ total_memory = 0;
+ f = fopen("/proc/meminfo", "r");
+ fscanf(f, "%s %lu", dummy, &total_memory);
+ fclose(f);
+ if (total_memory > 0 && tests_size_parameter > total_memory / 2)
+ tests_size_parameter = total_memory / 2;
+}
+
+void run_pdf(void)
+{
+ int fd, i;
+ pid_t pid;
+ int64_t repeat;
+ ssize_t written;
+ int64_t remains;
+ size_t block;
+ char file_name[256];
+ char buf[WRITE_BUFFER_SIZE];
+
+ if (tests_fs_is_currfs())
+ return;
+ adjust_size();
+ pid = getpid();
+ tests_cat_pid(file_name, "run_pdf_test_file_", pid);
+ fd = open(file_name, O_CREAT | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ CHECK(fd != -1);
+ pid = getpid();
+ srand(pid);
+ repeat = tests_repeat_parameter;
+ for (;;) {
+ for (i = 0; i < WRITE_BUFFER_SIZE;++i)
+ buf[i] = rand();
+ remains = tests_size_parameter;
+ while (remains > 0) {
+ if (remains > WRITE_BUFFER_SIZE)
+ block = WRITE_BUFFER_SIZE;
+ else
+ block = remains;
+ written = write(fd, buf, block);
+ if (written <= 0) {
+ CHECK(errno == ENOSPC); /* File system full */
+ errno = 0;
+ break;
+ }
+ remains -= written;
+ }
+ /* Break if repeat count exceeded */
+ if (tests_repeat_parameter > 0 && --repeat <= 0)
+ break;
+ CHECK(lseek(fd, 0, SEEK_SET) == 0);
+ }
+ CHECK(close(fd) != -1);
+ CHECK(unlink(file_name) != -1);
+}
+
+/* Title of this test */
+
+const char *run_pdf_get_title(void)
+{
+ return "Create / overwrite a large file in the current directory";
+}
+
+/* Description of this test */
+
+const char *run_pdf_get_description(void)
+{
+ return
+ "Create a file named run_pdf_test_file_pid, " \
+ "where pid is the process id. The file is created " \
+ "in the current directory, " \
+ "if the current directory is NOT on the test " \
+ "file system, otherwise no action is taken. " \
+ "If a repeat count is specified, then the task repeats " \
+ "that number of times. " \
+ "The repeat count is given by the -n or --repeat option, " \
+ "otherwise it defaults to 1. " \
+ "A repeat count of zero repeats forever. " \
+ "The size is given by the -z or --size option, " \
+ "otherwise it defaults to 1000000. " \
+ "The size is adjusted so that it is not more than " \
+ "half the size of total memory.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test file size */
+ tests_size_parameter = 1000000;
+
+ /* Set default test repetition */
+ tests_repeat_parameter = 1;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, run_pdf_get_title(),
+ run_pdf_get_description(), "zn");
+ if (!run_test)
+ return 1;
+ /* Do the actual test */
+ run_pdf();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c
new file mode 100644
index 00000000000..c1d0729fd6c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "tests.h"
+
+void rmdir00(void)
+{
+ int64_t repeat;
+ int64_t size, this_size;
+ pid_t pid;
+ char dir_name[256];
+
+ /* Create a directory to test in */
+ pid = getpid();
+ tests_cat_pid(dir_name, "rmdir00_test_dir_", pid);
+ if (chdir(dir_name) == -1)
+ CHECK(mkdir(dir_name, 0777) != -1);
+ CHECK(chdir(dir_name) != -1);
+ /* Repeat loop */
+ repeat = tests_repeat_parameter;
+ size = 0;
+ for (;;) {
+ /* Remove everything in the directory */
+ tests_clear_dir(".");
+ /* Fill with sub-dirs and small files */
+ do {
+ this_size = tests_create_entry(NULL);
+ if (!this_size)
+ break;
+ size += this_size;
+ } while (this_size &&
+ (tests_size_parameter == 0 ||
+ size < tests_size_parameter));
+ /* Break if repeat count exceeded */
+ if (tests_repeat_parameter > 0 && --repeat <= 0)
+ break;
+ /* Sleep */
+ if (tests_sleep_parameter > 0) {
+ unsigned us = tests_sleep_parameter * 1000;
+ unsigned rand_divisor = RAND_MAX / us;
+ unsigned s = (us / 2) + (rand() / rand_divisor);
+ usleep(s);
+ }
+ }
+ /* Tidy up by removing everything */
+ tests_clear_dir(".");
+ CHECK(chdir("..") != -1);
+ CHECK(rmdir(dir_name) != -1);
+}
+
+/* Title of this test */
+
+const char *rmdir00_get_title(void)
+{
+ return "Create and remove directories and files";
+}
+
+/* Description of this test */
+
+const char *rmdir00_get_description(void)
+{
+ return
+ "Create a directory named rmdir00_test_dir_pid, where " \
+ "pid is the process id. Within that directory, create " \
+ "a number of sub-directories and small files. " \
+ "The total size of all sub-directories and files " \
+ "is specified by the size parameter. " \
+ "The size parameter is given by the -z or --size option, " \
+ "otherwise it defaults to 1000000. " \
+ "A size of zero fills the file system until there is no "
+ "space left. " \
+ "The task repeats, sleeping in between each iteration, " \
+ "and then removing the sub-directories and files created " \
+ "during the last iteration. " \
+ "The repeat count is set by the -n or --repeat option, " \
+ "otherwise it defaults to 1. " \
+ "A repeat count of zero repeats forever. " \
+ "The sleep value is given by the -p or --sleep option, " \
+ "otherwise it defaults to 0. "
+ "Sleep is specified in milliseconds.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test size */
+ tests_size_parameter = 1000000;
+
+ /* Set default test repetition */
+ tests_repeat_parameter = 1;
+
+ /* Set default test sleep */
+ tests_sleep_parameter = 0;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, rmdir00_get_title(),
+ rmdir00_get_description(), "znp");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ rmdir00();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c
new file mode 100644
index 00000000000..724b1c3adb7
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "tests.h"
+
+void rndrm00(void)
+{
+ int64_t repeat;
+ int64_t size, this_size;
+ pid_t pid;
+ char dir_name[256];
+
+ /* Create a directory to test in */
+ pid = getpid();
+ tests_cat_pid(dir_name, "rndrm00_test_dir_", pid);
+ if (chdir(dir_name) == -1)
+ CHECK(mkdir(dir_name, 0777) != -1);
+ CHECK(chdir(dir_name) != -1);
+ /* Repeat loop */
+ repeat = tests_repeat_parameter;
+ size = 0;
+ for (;;) {
+ /* Create and remove sub-dirs and small files, */
+ /* but tending to grow */
+ do {
+ if (tests_random_no(3)) {
+ this_size = tests_create_entry(NULL);
+ if (!this_size)
+ break;
+ size += this_size;
+ } else {
+ this_size = tests_remove_entry();
+ size -= this_size;
+ if (size < 0)
+ size = 0;
+ if (!this_size)
+ this_size = 1;
+ }
+ } while (this_size &&
+ (tests_size_parameter == 0 ||
+ size < tests_size_parameter));
+ /* Create and remove sub-dirs and small files, but */
+ /* but tending to shrink */
+ do {
+ if (!tests_random_no(3)) {
+ this_size = tests_create_entry(NULL);
+ size += this_size;
+ } else {
+ this_size = tests_remove_entry();
+ size -= this_size;
+ if (size < 0)
+ size = 0;
+ }
+ } while ((tests_size_parameter != 0 &&
+ size > tests_size_parameter / 10) ||
+ (tests_size_parameter == 0 && size > 100000));
+ /* Break if repeat count exceeded */
+ if (tests_repeat_parameter > 0 && --repeat <= 0)
+ break;
+ /* Sleep */
+ if (tests_sleep_parameter > 0) {
+ unsigned us = tests_sleep_parameter * 1000;
+ unsigned rand_divisor = RAND_MAX / us;
+ unsigned s = (us / 2) + (rand() / rand_divisor);
+ usleep(s);
+ }
+ }
+ /* Tidy up by removing everything */
+ tests_clear_dir(".");
+ CHECK(chdir("..") != -1);
+ CHECK(rmdir(dir_name) != -1);
+}
+
+/* Title of this test */
+
+const char *rndrm00_get_title(void)
+{
+ return "Randomly create and remove directories and files";
+}
+
+/* Description of this test */
+
+const char *rndrm00_get_description(void)
+{
+ return
+ "Create a directory named rndrm00_test_dir_pid, where " \
+ "pid is the process id. Within that directory, " \
+ "randomly create and remove " \
+ "a number of sub-directories and small files, " \
+ "but do more creates than removes. " \
+ "When the total size of all sub-directories and files " \
+ "is greater than the size specified by the size parameter, " \
+ "start to do more removes than creates. " \
+ "The size parameter is given by the -z or --size option, " \
+ "otherwise it defaults to 1000000. " \
+ "A size of zero fills the file system until there is no "
+ "space left. " \
+ "The task repeats, sleeping in between each iteration. " \
+ "The repeat count is set by the -n or --repeat option, " \
+ "otherwise it defaults to 1. " \
+ "A repeat count of zero repeats forever. " \
+ "The sleep value is given by the -p or --sleep option, " \
+ "otherwise it defaults to 0. "
+ "Sleep is specified in milliseconds.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test size */
+ tests_size_parameter = 1000000;
+
+ /* Set default test repetition */
+ tests_repeat_parameter = 1;
+
+ /* Set default test sleep */
+ tests_sleep_parameter = 0;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, rndrm00_get_title(),
+ rndrm00_get_description(), "znp");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ rndrm00();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c
new file mode 100644
index 00000000000..77518398fc8
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/vfs.h>
+#include <sys/statvfs.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <limits.h>
+
+#include "tests.h"
+
+uint32_t files_created = 0;
+uint32_t files_removed = 0;
+uint32_t dirs_created = 0;
+uint32_t dirs_removed = 0;
+int64_t *size_ptr = 0;
+
+void display_stats(void)
+{
+ printf( "\nrndrm99 stats:\n"
+ "\tNumber of files created = %u\n"
+ "\tNumber of files deleted = %u\n"
+ "\tNumber of directories created = %u\n"
+ "\tNumber of directories deleted = %u\n"
+ "\tCurrent net size of creates and deletes = %lld\n",
+ (unsigned) files_created,
+ (unsigned) files_removed,
+ (unsigned) dirs_created,
+ (unsigned) dirs_removed,
+ (long long) (size_ptr ? *size_ptr : 0));
+ fflush(stdout);
+}
+
+struct timeval tv_before;
+struct timeval tv_after;
+
+void before(void)
+{
+ CHECK(gettimeofday(&tv_before, NULL) != -1);
+}
+
+void after(const char *msg)
+{
+ time_t diff;
+ CHECK(gettimeofday(&tv_after, NULL) != -1);
+ diff = tv_after.tv_sec - tv_before.tv_sec;
+ if (diff >= 8) {
+ printf("\nrndrm99: the following fn took more than 8 seconds: %s (took %u secs)\n",msg,(unsigned) diff);
+ fflush(stdout);
+ display_stats();
+ }
+}
+
+#define WRITE_BUFFER_SIZE 32768
+
+static char write_buffer[WRITE_BUFFER_SIZE];
+
+static void init_write_buffer()
+{
+ static int init = 0;
+
+ if (!init) {
+ int i, d;
+ uint64_t u;
+
+ u = RAND_MAX;
+ u += 1;
+ u /= 256;
+ d = (int) u;
+ srand(1);
+ for (i = 0; i < WRITE_BUFFER_SIZE; ++i)
+ write_buffer[i] = rand() / d;
+ init = 1;
+ }
+}
+
+/* Write size random bytes into file descriptor fd at the current position,
+ returning the number of bytes actually written */
+uint64_t fill_file(int fd, uint64_t size)
+{
+ ssize_t written;
+ size_t sz;
+ unsigned start = 0, length;
+ uint64_t remains;
+ uint64_t actual_size = 0;
+
+ init_write_buffer();
+ remains = size;
+ while (remains > 0) {
+ length = WRITE_BUFFER_SIZE - start;
+ if (remains > length)
+ sz = length;
+ else
+ sz = (size_t) remains;
+ before();
+ written = write(fd, write_buffer + start, sz);
+ if (written <= 0) {
+ CHECK(errno == ENOSPC); /* File system full */
+ errno = 0;
+ after("write");
+ fprintf(stderr,"\nrndrm99: write failed with ENOSPC\n");fflush(stderr);
+ display_stats();
+ break;
+ }
+ after("write");
+ remains -= written;
+ actual_size += written;
+ if ((size_t) written == sz)
+ start = 0;
+ else
+ start += written;
+ }
+ return actual_size;
+}
+
+/* Create a file of size file_size */
+uint64_t create_file(const char *file_name, uint64_t file_size)
+{
+ int fd;
+ int flags;
+ mode_t mode;
+ uint64_t actual_size; /* Less than size if the file system is full */
+
+ flags = O_CREAT | O_TRUNC | O_WRONLY;
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+ before();
+ fd = open(file_name, flags, mode);
+ if (fd == -1 && errno == ENOSPC) {
+ errno = 0;
+ after("open");
+ fprintf(stderr,"\nrndrm99: open failed with ENOSPC\n");fflush(stderr);
+ display_stats();
+ return 0; /* File system full */
+ }
+ CHECK(fd != -1);
+ after("open");
+ actual_size = fill_file(fd, file_size);
+ before();
+ CHECK(close(fd) != -1);
+ after("close");
+ if (file_size != 0 && actual_size == 0) {
+ printf("\nrndrm99: unlinking zero size file\n");fflush(stdout);
+ before();
+ CHECK(unlink(file_name) != -1);
+ after("unlink (create_file)");
+ }
+ return actual_size;
+}
+
+/* Create an empty sub-directory or small file in the current directory */
+int64_t create_entry(char *return_name)
+{
+ int fd;
+ char name[256];
+ int64_t res;
+
+ for (;;) {
+ sprintf(name, "%u", (unsigned) tests_random_no(10000000));
+ before();
+ fd = open(name, O_RDONLY);
+ after("open (create_entry)");
+ if (fd == -1)
+ break;
+ before();
+ close(fd);
+ after("close (create_entry)");
+ }
+ if (return_name)
+ strcpy(return_name, name);
+ if (tests_random_no(2)) {
+ res = create_file(name, tests_random_no(4096));
+ if (res > 0)
+ files_created += 1;
+ return res;
+ } else {
+ before();
+ if (mkdir(name, 0777) == -1) {
+ CHECK(errno == ENOSPC);
+ after("mkdir");
+ errno = 0;
+ fprintf(stderr,"\nrndrm99: mkdir failed with ENOSPC\n");fflush(stderr);
+ display_stats();
+ return 0;
+ }
+ after("mkdir");
+ dirs_created += 1;
+ return TESTS_EMPTY_DIR_SIZE;
+ }
+}
+
+/* Remove a random file of empty sub-directory from the current directory */
+int64_t remove_entry(void)
+{
+ DIR *dir;
+ struct dirent *entry;
+ unsigned count = 0, pos;
+ int64_t result = 0;
+
+ before();
+ dir = opendir(".");
+ CHECK(dir != NULL);
+ after("opendir");
+ for (;;) {
+ errno = 0;
+ before();
+ entry = readdir(dir);
+ if (entry) {
+ after("readdir 1");
+ if (strcmp(".",entry->d_name) != 0 &&
+ strcmp("..",entry->d_name) != 0)
+ ++count;
+ } else {
+ CHECK(errno == 0);
+ after("readdir 1");
+ break;
+ }
+ }
+ pos = tests_random_no(count);
+ count = 0;
+ before();
+ rewinddir(dir);
+ after("rewinddir");
+ for (;;) {
+ errno = 0;
+ before();
+ entry = readdir(dir);
+ if (!entry) {
+ CHECK(errno == 0);
+ after("readdir 2");
+ break;
+ }
+ after("readdir 2");
+ if (strcmp(".",entry->d_name) != 0 &&
+ strcmp("..",entry->d_name) != 0) {
+ if (count == pos) {
+ if (entry->d_type == DT_DIR) {
+ before();
+ tests_clear_dir(entry->d_name);
+ after("tests_clear_dir");
+ before();
+ CHECK(rmdir(entry->d_name) != -1);
+ after("rmdir");
+ result = TESTS_EMPTY_DIR_SIZE;
+ dirs_removed += 1;
+ } else {
+ struct stat st;
+ before();
+ CHECK(stat(entry->d_name, &st) != -1);
+ after("stat");
+ result = st.st_size;
+ before();
+ CHECK(unlink(entry->d_name) != -1);
+ after("unlink");
+ files_removed += 1;
+ }
+ }
+ ++count;
+ }
+ }
+ before();
+ CHECK(closedir(dir) != -1);
+ after("closedir");
+ return result;
+}
+
+void rndrm99(void)
+{
+ int64_t repeat, loop_cnt;
+ int64_t size, this_size;
+ pid_t pid;
+ char dir_name[256];
+
+ size_ptr = &size;
+ /* Create a directory to test in */
+ pid = getpid();
+ tests_cat_pid(dir_name, "rndrm99_test_dir_", pid);
+ if (chdir(dir_name) == -1)
+ CHECK(mkdir(dir_name, 0777) != -1);
+ CHECK(chdir(dir_name) != -1);
+ /* Repeat loop */
+ repeat = tests_repeat_parameter;
+ size = 0;
+ for (;;) {
+ /* Create and remove sub-dirs and small files, */
+ /* but tending to grow */
+ printf("\nrndrm99: growing\n");fflush(stdout);
+ loop_cnt = 0;
+ do {
+ if (loop_cnt++ % 2000 == 0)
+ display_stats();
+ if (tests_random_no(3)) {
+ this_size = create_entry(NULL);
+ if (!this_size)
+ break;
+ size += this_size;
+ } else {
+ this_size = remove_entry();
+ size -= this_size;
+ if (size < 0)
+ size = 0;
+ if (!this_size)
+ this_size = 1;
+ }
+ } while (this_size &&
+ (tests_size_parameter == 0 ||
+ size < tests_size_parameter));
+ /* Create and remove sub-dirs and small files, but */
+ /* but tending to shrink */
+ printf("\nrndrm99: shrinking\n");fflush(stdout);
+ loop_cnt = 0;
+ do {
+ if (loop_cnt++ % 2000 == 0)
+ display_stats();
+ if (!tests_random_no(3)) {
+ this_size = create_entry(NULL);
+ size += this_size;
+ } else {
+ this_size = remove_entry();
+ size -= this_size;
+ if (size < 0)
+ size = 0;
+ }
+ } while ((tests_size_parameter != 0 &&
+ size > tests_size_parameter / 10) ||
+ (tests_size_parameter == 0 && size > 100000));
+ /* Break if repeat count exceeded */
+ if (tests_repeat_parameter > 0 && --repeat <= 0)
+ break;
+ /* Sleep */
+ if (tests_sleep_parameter > 0) {
+ unsigned us = tests_sleep_parameter * 1000;
+ unsigned rand_divisor = RAND_MAX / us;
+ unsigned s = (us / 2) + (rand() / rand_divisor);
+ printf("\nrndrm99: sleeping\n");fflush(stdout);
+ usleep(s);
+ }
+ }
+ printf("\nrndrm99: tidying\n");fflush(stdout);
+ display_stats();
+ /* Tidy up by removing everything */
+ tests_clear_dir(".");
+ CHECK(chdir("..") != -1);
+ CHECK(rmdir(dir_name) != -1);
+ size_ptr = 0;
+}
+
+/* Title of this test */
+
+const char *rndrm99_get_title(void)
+{
+ return "Randomly create and remove directories and files";
+}
+
+/* Description of this test */
+
+const char *rndrm99_get_description(void)
+{
+ return
+ "Create a directory named rndrm99_test_dir_pid, where " \
+ "pid is the process id. Within that directory, " \
+ "randomly create and remove " \
+ "a number of sub-directories and small files, " \
+ "but do more creates than removes. " \
+ "When the total size of all sub-directories and files " \
+ "is greater than the size specified by the size parameter, " \
+ "start to do more removes than creates. " \
+ "The size parameter is given by the -z or --size option, " \
+ "otherwise it defaults to 1000000. " \
+ "A size of zero fills the file system until there is no "
+ "space left. " \
+ "The task repeats, sleeping in between each iteration. " \
+ "The repeat count is set by the -n or --repeat option, " \
+ "otherwise it defaults to 1. " \
+ "A repeat count of zero repeats forever. " \
+ "The sleep value is given by the -p or --sleep option, " \
+ "otherwise it defaults to 0. "
+ "Sleep is specified in milliseconds.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test size */
+ tests_size_parameter = 1000000;
+
+ /* Set default test repetition */
+ tests_repeat_parameter = 1;
+
+ /* Set default test sleep */
+ tests_sleep_parameter = 0;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, rndrm99_get_title(),
+ rndrm99_get_description(), "znp");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ rndrm99();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c
new file mode 100644
index 00000000000..655d9cc23bc
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "tests.h"
+
+#define BLOCK_SIZE 32768
+#define BUFFER_SIZE 32768
+
+static void check_file(int fd, char *data, size_t length)
+{
+ size_t n, i;
+ char buf[BUFFER_SIZE];
+
+ CHECK(lseek(fd, 0, SEEK_SET) != -1);
+ n = 0;
+ for (;;) {
+ i = read(fd, buf, BUFFER_SIZE);
+ CHECK(i >= 0);
+ if (i == 0)
+ break;
+ CHECK(memcmp(buf, data + n, i) == 0);
+ n += i;
+ }
+ CHECK(n == length);
+}
+
+void rndwrite00(void)
+{
+ int fd;
+ pid_t pid;
+ ssize_t written;
+ size_t remains;
+ size_t block;
+ size_t actual_size;
+ size_t check_every;
+ char *data, *p, *q;
+ off_t offset;
+ size_t size;
+ int64_t repeat;
+ char file_name[256];
+ char buf[4096];
+
+ /* Create file */
+ pid = getpid();
+ tests_cat_pid(file_name, "rndwrite00_test_file_", pid);
+ fd = open(file_name, O_CREAT | O_RDWR | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ CHECK(fd != -1);
+ /* Allocate memory to hold file data */
+ CHECK(tests_size_parameter > 0);
+ CHECK(tests_size_parameter <= SIZE_MAX);
+ data = (char *) malloc(tests_size_parameter);
+ CHECK(data != NULL);
+ /* Fill with random data */
+ srand(pid);
+ for (p = data, q = data + tests_size_parameter; p != q; ++p)
+ *p = rand();
+ /* Write to file */
+ p = data;
+ remains = tests_size_parameter;
+ while (remains > 0) {
+ if (remains > BLOCK_SIZE)
+ block = BLOCK_SIZE;
+ else
+ block = remains;
+ written = write(fd, p, block);
+ if (written <= 0) {
+ CHECK(errno == ENOSPC); /* File system full */
+ errno = 0;
+ break;
+ }
+ remains -= written;
+ p += written;
+ }
+ actual_size = p - data;
+ /* Repeating bit */
+ repeat = tests_repeat_parameter;
+ check_every = actual_size / 8192;
+ for (;;) {
+ offset = tests_random_no(actual_size);
+ size = tests_random_no(4096);
+ /* Don't change the file size */
+ if (offset + size > actual_size)
+ size = actual_size - offset;
+ if (!size)
+ continue;
+ for (p = buf, q = p + size; p != q; ++p)
+ *p = rand();
+ CHECK(lseek(fd, offset, SEEK_SET) != -1);
+ written = write(fd, buf, size);
+ if (written <= 0) {
+ CHECK(errno == ENOSPC); /* File system full */
+ errno = 0;
+ } else
+ memcpy(data + offset, buf, written);
+ /* Break if repeat count exceeded */
+ if (tests_repeat_parameter > 0 && --repeat <= 0)
+ break;
+ if (repeat % check_every == 0)
+ check_file(fd, data, actual_size);
+ /* Sleep */
+ if (tests_sleep_parameter > 0) {
+ unsigned us = tests_sleep_parameter * 1000;
+ unsigned rand_divisor = RAND_MAX / us;
+ unsigned s = (us / 2) + (rand() / rand_divisor);
+ usleep(s);
+ }
+ }
+ /* Check and close file */
+ check_file(fd, data, actual_size);
+ CHECK(close(fd) != -1);
+ if (tests_delete_flag)
+ CHECK(unlink(file_name) != -1);
+}
+
+/* Title of this test */
+
+const char *rndwrite00_get_title(void)
+{
+ return "Randomly write a large test file";
+}
+
+/* Description of this test */
+
+const char *rndwrite00_get_description(void)
+{
+ return
+ "Create a file named rndwrite00_test_file_pid, where " \
+ "pid is the process id. " \
+ "The file is filled with random data. " \
+ "The size of the file is given by the -z or --size option, " \
+ "otherwise it defaults to 1000000. " \
+ "Then a randomly sized block of random data is written at a " \
+ "random location in the file. "\
+ "The block size is always in the range 1 to 4095. " \
+ "If a sleep value is specified, the process sleeps. " \
+ "The number of writes is given by the repeat count. " \
+ "The repeat count is set by the -n or --repeat option, " \
+ "otherwise it defaults to 10000. " \
+ "A repeat count of zero repeats forever. " \
+ "The sleep value is given by the -p or --sleep option, " \
+ "otherwise it defaults to 0. "
+ "Sleep is specified in milliseconds. " \
+ "Periodically the data in the file is checked with a copy " \
+ "held in memory. " \
+ "If the delete option is specified the file is finally " \
+ "deleted.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test file size */
+ tests_size_parameter = 1000000;
+
+ /* Set default test repetition */
+ tests_repeat_parameter = 10000;
+
+ /* Set default test sleep */
+ tests_sleep_parameter = 0;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, rndwrite00_get_title(),
+ rndwrite00_get_description(), "zne");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ rndwrite00();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c
new file mode 100644
index 00000000000..86f94c2dd93
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "tests.h"
+
+#define WRITE_BUFFER_SIZE 32768
+
+void stress_1(void)
+{
+ int fd, i;
+ pid_t pid;
+ ssize_t written;
+ int64_t remains;
+ size_t block;
+ char file_name[256];
+ char buf[WRITE_BUFFER_SIZE];
+
+ pid = getpid();
+ tests_cat_pid(file_name, "stress_1_test_file_", pid);
+ fd = open(file_name, O_CREAT | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ CHECK(fd != -1);
+ srand(pid);
+ for (i = 0; i < WRITE_BUFFER_SIZE;++i)
+ buf[i] = rand();
+ remains = tests_size_parameter;
+ while (remains > 0) {
+ if (remains > WRITE_BUFFER_SIZE)
+ block = WRITE_BUFFER_SIZE;
+ else
+ block = remains;
+ written = write(fd, buf, block);
+ if (written <= 0) {
+ CHECK(errno == ENOSPC); /* File system full */
+ errno = 0;
+ break;
+ }
+ remains -= written;
+ }
+ CHECK(close(fd) != -1);
+ if (tests_delete_flag)
+ CHECK(unlink(file_name) != -1);
+}
+
+/* Title of this test */
+
+const char *stress_1_get_title(void)
+{
+ return "Create / overwrite a large file";
+}
+
+/* Description of this test */
+
+const char *stress_1_get_description(void)
+{
+ return
+ "Create a file named stress_1_test_file_pid, " \
+ "where pid is the process id. " \
+ "The size is given by the -z or --size option, " \
+ "otherwise it defaults to 1000000. " \
+ "The file will be deleted if the delete option " \
+ "is specified. ";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test file size */
+ tests_size_parameter = 1000000;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, stress_1_get_title(),
+ stress_1_get_description(), "ze");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ stress_1();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c
new file mode 100644
index 00000000000..a9bc31a9ca4
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "tests.h"
+
+#define WRITE_BUFFER_SIZE 32768
+
+void stress_2(void)
+{
+ int fd, i;
+ pid_t pid;
+ ssize_t written;
+ int64_t remains;
+ int64_t repeat;
+ size_t block;
+ char *file_name;
+ char buf[WRITE_BUFFER_SIZE];
+
+ file_name = "stress_2_test_file";
+ fd = open(file_name, O_CREAT | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ CHECK(fd != -1);
+ CHECK(unlink(file_name) != -1);
+ pid = getpid();
+ srand(pid);
+ repeat = tests_repeat_parameter;
+ for (;;) {
+ for (i = 0; i < WRITE_BUFFER_SIZE;++i)
+ buf[i] = rand();
+ CHECK(lseek(fd, 0, SEEK_SET) != -1);
+ remains = tests_size_parameter;
+ while (remains > 0) {
+ if (remains > WRITE_BUFFER_SIZE)
+ block = WRITE_BUFFER_SIZE;
+ else
+ block = remains;
+ written = write(fd, buf, block);
+ if (written <= 0) {
+ CHECK(errno == ENOSPC); /* File system full */
+ errno = 0;
+ break;
+ }
+ remains -= written;
+ }
+ if (tests_repeat_parameter > 0 && --repeat <= 0)
+ break;
+ }
+ CHECK(close(fd) != -1);
+}
+
+/* Title of this test */
+
+const char *stress_2_get_title(void)
+{
+ return "Create / overwrite a large deleted file";
+}
+
+/* Description of this test */
+
+const char *stress_2_get_description(void)
+{
+ return
+ "Create a file named stress_2_test_file. " \
+ "Open it, delete it while holding the open file descriptor, " \
+ "then fill it with random data. " \
+ "Repeated re-write the file some number of times. " \
+ "The repeat count is given by the -n or --repeat option, " \
+ "otherwise it defaults to 10. " \
+ "The file size is given by the -z or --size option, " \
+ "otherwise it defaults to 1000000.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test file size */
+ tests_size_parameter = 1000000;
+
+ /* Set default test repetition */
+ tests_repeat_parameter = 10;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, stress_2_get_title(),
+ stress_2_get_description(), "zn");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ stress_2();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c
new file mode 100644
index 00000000000..99fb05dbf04
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "tests.h"
+
+#define WRITE_BUFFER_SIZE 32768
+
+void stress_3(void)
+{
+ int fd, i;
+ pid_t pid;
+ ssize_t written;
+ int64_t remains;
+ size_t block;
+ char file_name[256];
+ char buf[WRITE_BUFFER_SIZE];
+
+ pid = getpid();
+ tests_cat_pid(file_name, "stress_3_test_file_", pid);
+ fd = open(file_name, O_CREAT | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ CHECK(fd != -1);
+ pid = getpid();
+ srand(pid);
+ for (i = 0; i < WRITE_BUFFER_SIZE;++i)
+ buf[i] = rand();
+ CHECK(lseek(fd, tests_size_parameter, SEEK_SET) != -1);
+ CHECK(write(fd, "!", 1) == 1);
+ CHECK(lseek(fd, 0, SEEK_SET) != -1);
+ remains = tests_size_parameter;
+ while (remains > 0) {
+ if (remains > WRITE_BUFFER_SIZE)
+ block = WRITE_BUFFER_SIZE;
+ else
+ block = remains;
+ written = write(fd, buf, block);
+ if (written <= 0) {
+ CHECK(errno == ENOSPC); /* File system full */
+ errno = 0;
+ break;
+ }
+ remains -= written;
+ }
+ if (ftruncate(fd, 0) == -1) {
+ CHECK(errno == ENOSPC); /* File system full */
+ errno = 0;
+ }
+ CHECK(close(fd) != -1);
+ if (tests_delete_flag)
+ CHECK(unlink(file_name) != -1);
+}
+
+/* Title of this test */
+
+const char *stress_3_get_title(void)
+{
+ return "Create a file with a large hole and fill it";
+}
+
+/* Description of this test */
+
+const char *stress_3_get_description(void)
+{
+ return
+ "Create a file named stress_3_test_file_pid, " \
+ "where pid is the process id. " \
+ "Write a single character past the end of the file, " \
+ "based on the specified file size, " \
+ "which creates a hole in the file. "
+ "Fill the hole with random data. " \
+ "Then truncate the file length to zero. " \
+ "The size is given by the -z or --size option, " \
+ "otherwise it defaults to 1000000. " \
+ "The file will be deleted if the delete option " \
+ "is specified.";
+}
+
+int main(int argc, char *argv[])
+{
+ int run_test;
+
+ /* Set default test file size */
+ tests_size_parameter = 1000000;
+
+ /* Handle common arguments */
+ run_test = tests_get_args(argc, argv, stress_3_get_title(),
+ stress_3_get_description(), "ze");
+ if (!run_test)
+ return 1;
+ /* Change directory to the file system and check it is ok for testing */
+ tests_check_test_file_system();
+ /* Do the actual test */
+ stress_3();
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh b/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh
new file mode 100644
index 00000000000..60f8c0dbf3f
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+TEST_DIR=$TEST_FILE_SYSTEM_MOUNT_DIR
+if test -z "$TEST_DIR";
+then
+ TEST_DIR="/mnt/test_file_system"
+fi
+
+FREESPACE=`../utils/free_space "$TEST_DIR"`
+
+if test -z "$FREESPACE";
+then
+ echo "Failed to determine free space"
+ exit 1
+fi
+
+if test -n "$1";
+then
+ DURATION="-d$1";
+else
+ DURATION="";
+fi
+
+FWRITE00=atoms/fwrite00
+RNDWR=atoms/rndwrite00
+GCHUP=atoms/gcd_hupper
+PDFLUSH=atoms/pdfrun
+FSIZE=$(( $FREESPACE/15 ));
+
+../utils/fstest_monitor $DURATION \
+"$FWRITE00 -z $FSIZE -n0 -p 20" \
+"$FWRITE00 -z $FSIZE -n0 -p 10 -s" \
+"$FWRITE00 -z $FSIZE -n0 -p 20 -u" \
+"$FWRITE00 -z $FSIZE -n0 -p 70 -o" \
+"$FWRITE00 -z $FSIZE -n0 -p 15 -s -o -u" \
+"$FWRITE00 -z $FSIZE -n0 -p 10 -u -c" \
+"$FWRITE00 -z $FSIZE -n0 -p 10 -u -o -c" \
+"$FWRITE00 -z $FSIZE -n0 -p 10 -o -c" \
+"$FWRITE00 -z $FSIZE -n0 -p 100 -o -u" \
+"$FWRITE00 -z $FSIZE -n0 -p 100 -s -o -u -c" \
+"$FWRITE00 -z $FSIZE -n0 -p 100 -o -u" \
+"$FWRITE00 -z $FSIZE -n0 -p 100 -u" \
+"$FWRITE00 -z $FSIZE -n0 -p 100 -s -o" \
+"$RNDWR -z $FSIZE -n0 -p 10 -e" \
+"$RNDWR -z $FSIZE -n0 -p 100 -e" \
+"$PDFLUSH -z 1073741824 -n0"
+
+STATUS=$?
+
+rm -rf ${TEST_DIR}/*
+
+exit $STATUS
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh b/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh
new file mode 100644
index 00000000000..5913c1cc56c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+TEST_DIR=$TEST_FILE_SYSTEM_MOUNT_DIR
+if test -z "$TEST_DIR";
+then
+ TEST_DIR="/mnt/test_file_system"
+fi
+
+FREESPACE=`../utils/free_space "$TEST_DIR"`
+
+if test -z "$FREESPACE";
+then
+ echo "Failed to determine free space"
+ exit 1
+fi
+
+if test -n "$1";
+then
+ DURATION="-d$1";
+else
+ DURATION="";
+fi
+
+FWRITE00=atoms/fwrite00
+RNDWR=atoms/rndwrite00
+PDFLUSH=atoms/pdfrun
+FSIZE=$(( $FREESPACE/15 ));
+
+../utils/fstest_monitor $DURATION \
+"$FWRITE00 -z $FSIZE -n0 -p 300" \
+"$FWRITE00 -z $FSIZE -n0 -u" \
+"$FWRITE00 -z $FSIZE -n0 -u -c" \
+"$FWRITE00 -z $FSIZE -n0 -s -o" \
+"$RNDWR -z $FSIZE -n0 -e"
+
+STATUS=$?
+
+rm -rf ${TEST_DIR}/*
+
+exit $STATUS
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile b/drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile
new file mode 100644
index 00000000000..9fb60b5b1df
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile
@@ -0,0 +1,19 @@
+
+ifeq ($(origin CC),default)
+CC = gcc
+endif
+
+CFLAGS := $(CFLAGS) -Wall -g -O2 -I../lib
+
+LDFLAGS := $(LDFLAGS)
+
+TARGETS = fstest_monitor free_space
+
+all: $(TARGETS)
+
+clean:
+ rm -f *.o $(TARGETS)
+
+tests: all
+ ./fstest_monitor
+ ./free_space > /dev/null
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c b/drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c
new file mode 100644
index 00000000000..88036aac363
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/statvfs.h>
+
+int main(int argc, char *argv[])
+{
+ char *dir_name = ".";
+ uint64_t free_space;
+ struct statvfs fs_info;
+
+ if (argc > 1) {
+ if (strncmp(argv[1], "--help", 6) == 0 ||
+ strncmp(argv[1], "-h", 2) == 0) {
+ printf( "Usage is: "
+ "free_space [directory]\n"
+ "\n"
+ "Display the free space of the file system "
+ "of the directory given\n"
+ "or the current directory if no "
+ "directory is given.\nThe value output is "
+ "in bytes.\n"
+ );
+ return 1;
+ }
+ dir_name = argv[1];
+ }
+ if (statvfs(dir_name, &fs_info) == -1)
+ return 1;
+
+ free_space = (uint64_t) fs_info.f_bavail * (uint64_t) fs_info.f_frsize;
+
+ printf("%llu\n", (unsigned long long) free_space);
+
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c b/drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c
new file mode 100644
index 00000000000..298ee268314
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Author: Adrian Hunter
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+struct child_info {
+ struct child_info *next;
+ pid_t pid;
+ int terminated;
+ int killed;
+ int gone;
+};
+
+struct child_info *children = 0;
+
+void kill_children(void)
+{
+ struct child_info *child;
+
+ child = children;
+ while (child) {
+ if (!child->gone) {
+ if (!child->terminated) {
+ child->terminated = 1;
+ kill(child->pid, SIGTERM);
+ } /*else if (!child->killed) {
+ child->killed = 1;
+ kill(child->pid, SIGKILL);
+ }*/
+ }
+ child = child->next;
+ }
+}
+
+void add_child(pid_t child_pid)
+{
+ struct child_info *child;
+ size_t sz;
+
+ sz = sizeof(struct child_info);
+ child = (struct child_info *) malloc(sz);
+ memset(child, 0, sz);
+ child->pid = child_pid;
+ child->next = children;
+ children = child;
+}
+
+void mark_child_gone(pid_t child_pid)
+{
+ struct child_info *child;
+
+ child = children;
+ while (child) {
+ if (child->pid == child_pid) {
+ child->gone = 1;
+ break;
+ }
+ child = child->next;
+ }
+}
+
+int have_children(void)
+{
+ struct child_info *child;
+
+ child = children;
+ while (child) {
+ if (!child->gone)
+ return 1;
+ child = child->next;
+ }
+ return 0;
+}
+
+int parse_command_line(char *cmdline, int *pargc, char ***pargv)
+{
+ char **tmp;
+ char *p, *v, *q;
+ size_t sz;
+ int argc = 0;
+ int state = 0;
+ char *argv[1024];
+
+ if (!cmdline)
+ return 1;
+ q = v = (char *) malloc(strlen(cmdline) + 1024);
+ if (!v)
+ return 1;
+ p = cmdline;
+ for (;;) {
+ char c = *p++;
+ if (!c) {
+ *v++ = 0;
+ break;
+ }
+ switch (state) {
+ case 0: /* Between args */
+ if (isspace(c))
+ break;
+ argv[argc++] = v;
+ if (c == '"') {
+ state = 2;
+ break;
+ } else if (c == '\'') {
+ state = 3;
+ break;
+ }
+ state = 1;
+ case 1: /* Not quoted */
+ if (c == '\\') {
+ if (*p)
+ *v++ = *p;
+ } else if (isspace(c)) {
+ *v++ = 0;
+ state = 0;
+ } else
+ *v++ = c;
+ break;
+ case 2: /* Double quoted */
+ if (c == '\\' && *p == '"') {
+ *v++ = '"';
+ ++p;
+ } else if (c == '"') {
+ *v++ = 0;
+ state = 0;
+ } else
+ *v++ = c;
+ break;
+ case 3: /* Single quoted */
+ if (c == '\'') {
+ *v++ = 0;
+ state = 0;
+ } else
+ *v++ = c;
+ break;
+ }
+ }
+ argv[argc] = 0;
+ sz = sizeof(char *) * (argc + 1);
+ tmp = (char **) malloc(sz);
+ if (!tmp) {
+ free(q);
+ return 1;
+ }
+ if (argc == 0)
+ free(q);
+ memcpy(tmp, argv, sz);
+ *pargc = argc;
+ *pargv = tmp;
+ return 0;
+}
+
+void signal_handler(int signum)
+{
+ kill_children();
+}
+
+int result = 0;
+int alarm_gone_off = 0;
+
+void alarm_handler(int signum)
+{
+ if (!result)
+ alarm_gone_off = 1;
+ kill_children();
+}
+
+int main(int argc, char *argv[], char **env)
+{
+ int p;
+ pid_t child_pid;
+ int status;
+ int duration = 0;
+
+ p = 1;
+ if (argc > 1) {
+ if (strncmp(argv[p], "--help", 6) == 0 ||
+ strncmp(argv[p], "-h", 2) == 0) {
+ printf( "Usage is: "
+ "fstest_monitor options programs...\n"
+ " Options are:\n"
+ " -h, --help "
+ "This help message\n"
+ " -d, --duration arg "
+ "Stop after arg seconds\n"
+ "\n"
+ "Run programs and wait for them."
+ " If duration is specified,\n"
+ "kill all programs"
+ " after that number of seconds have elapsed.\n"
+ "Example: "
+ "fstest_monitor \"/bin/ls -l\" /bin/date\n"
+ );
+ return 1;
+ }
+ if (strncmp(argv[p], "--duration", 10) == 0 ||
+ strncmp(argv[p], "-d", 2) == 0) {
+ char *s;
+ if (p+1 < argc && !isdigit(argv[p][strlen(argv[p])-1]))
+ ++p;
+ s = argv[p];
+ while (*s && !isdigit(*s))
+ ++s;
+ duration = atoi(s);
+ ++p;
+ }
+ }
+
+ signal(SIGTERM, signal_handler);
+ signal(SIGINT, signal_handler);
+ for (; p < argc; ++p) {
+ child_pid = fork();
+ if (child_pid) {
+ /* Parent */
+ if (child_pid == (pid_t) -1) {
+ kill_children();
+ result = 1;
+ break;
+ }
+ add_child(child_pid);
+ } else {
+ /* Child */
+ int cargc;
+ char **cargv;
+
+ if (parse_command_line(argv[p], &cargc, &cargv))
+ return 1;
+ execve(cargv[0], cargv, env);
+ return 1;
+ }
+ }
+ if (!result && duration > 0) {
+ signal(SIGALRM, alarm_handler);
+ alarm(duration);
+ }
+ while (have_children()) {
+ status = 0;
+ child_pid = wait(&status);
+ if (child_pid == (pid_t) -1) {
+ if (errno == EINTR)
+ continue;
+ kill_children();
+ return 1;
+ }
+ mark_child_gone(child_pid);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ result = 1;
+ kill_children();
+ }
+ }
+
+ if (alarm_gone_off)
+ return 0;
+
+ return result;
+}
diff --git a/drivers/mtd/mtd-utils/tests/jittertest/COPYING b/drivers/mtd/mtd-utils/tests/jittertest/COPYING
new file mode 100644
index 00000000000..60549be514a
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/jittertest/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c b/drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c
new file mode 100644
index 00000000000..59c2eb76ca5
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c
@@ -0,0 +1,1044 @@
+/***********************************************************************
+ *
+ * Copyright: Daniel Measurement and Control, Inc.
+ * 9753 Pine Lake Drive
+ * Houston, TX 77055
+ *
+ * Created by: Vipin Malik and Gail Murray
+ * Released under GPL by permission of Daniel Industries.
+ *
+ * This software is licensed under the GPL version 2. Plese see the file
+ * COPYING for details on the license.
+ *
+ * NO WARRANTY: Absolutely no claims of warranty or fitness of purpose
+ * are made in this software. Please use at your own risk.
+ *
+ * Filename: JitterTest.c
+ *
+ * Description: Program to be used to measure wake jitter.
+ * See README file for more info.
+ *
+ *
+ * Revision History:
+ * $Id: JitterTest.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ * $Log: not supported by cvs2svn $
+ * Revision 1.13 2005/11/07 11:15:20 gleixner
+ * [MTD / JFFS2] Clean up trailing white spaces
+ *
+ * Revision 1.12 2001/08/10 19:23:11 vipin
+ * Ready to be released under GPL! Added proper headers etc.
+ *
+ * Revision 1.11 2001/07/09 15:35:50 vipin
+ * Couple of new features:1. The program runs by default as a "regular"
+ * (SCHED_OTHER) task by default, unless the -p n cmd line parameter is
+ * specified. It then runs as SCHED_RR at that priority.
+ * 2. Added ability to send SIGSTOP/SIGCONT to a specified PID. This
+ * would presumably be the PID of the JFFS2 GC task. SIGSTOP is sent
+ * before writing to the fs, and a SIGCONT after the write is done.
+ * 3. The "pad" data now written to the file on the "fs under test" is
+ * random, not sequential as previously.
+ *
+ * Revision 1.10 2001/06/27 19:14:24 vipin
+ * Now console file to log at can be specified from cmd line. This can enable
+ * you to run two instances of the program- one logging to the /dev/console
+ * and another to a regular file (if you want the data) or /dev/null if you don't.
+ *
+ * Revision 1.9 2001/06/25 20:21:31 vipin
+ * This is the latest version, NOT the one last checked in!
+ *
+ * Revision 1.7 2001/06/18 22:36:19 vipin
+ * Fix minor typo that excluded '\n' from msg on console.
+ *
+ * Revision 1.6 2001/06/18 21:17:50 vipin
+ * Added option to specify the amount of data written to outfile each period.
+ * The regular info is written, but is then padded to the requested size.
+ * This will enable testing of different sized writes to JFFS fs.
+ *
+ * Revision 1.5 2001/06/08 19:36:23 vipin
+ * All write() are now checked for return err code.
+ *
+ * Revision 1.4 2001/06/06 23:10:31 vipin
+ * Added README file.
+ * In JitterTest.c: Changed operation of periodic timer to one shot. The timer is now
+ * reset when the task wakes. This way every "jitter" is from the last time and
+ * jitters from previous times are not accumulated and screw aroud with our display.
+ *
+ * All jitter is now +ve. (as it should be). Also added a "read file" functionality
+ * to test for jitter in task if we have to read from JFFS fs.
+ * The program now also prints data to console- where it can be logged, interspersed with
+ * other "interesting" printk's from the kernel and drivers (flash sector erases etc.)
+ *
+ * Revision 1.3 2001/03/01 19:20:39 gmurray
+ * Add priority scheduling. Shortened name of default output file.
+ * Changed default interrupt period. Output delta time and jitter
+ * instead of time of day.
+ *
+ * Revision 1.2 2001/02/28 16:20:19 vipin
+ * Added version control Id and log fields.
+ *
+ ***********************************************************************/
+/*************************** Included Files ***************************/
+#include <stdio.h> /* fopen, printf, fprintf, fclose */
+#include <string.h> /* strcpy, strcmp */
+#include <stdlib.h> /* exit, atol, atoi */
+#include <sys/time.h> /* setitimer, settimeofday, gettimeofday */
+#include <signal.h> /* signal */
+#include <sched.h> /* sched_setscheduler, sched_get_priority_min,*/
+/* sched_get_priority_max */
+#include <unistd.h> /* gettimeofday, sleep */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+
+
+/**************************** Enumerations ****************************/
+enum timerActions
+ {
+ ONESHOT,
+ AUTORESETTING
+ };
+
+
+
+/****************************** Constants *****************************/
+/* Exit error codes */
+#define EXIT_FILE_OPEN_ERR (1) /* error opening output file*/
+#define EXIT_REG_SIGALRM_ERR (2) /* error registering SIGALRM*/
+#define EXIT_REG_SIGINT_ERR (3) /* error registering SIGINT */
+#define EXIT_INV_INT_PERIOD (4) /* error invalid int. period*/
+#define EXIT_MIN_PRIORITY_ERR (5) /* error, minimum priority */
+#define EXIT_MAX_PRIORITY_ERR (6) /* error, maximum priority */
+#define EXIT_INV_SCHED_PRIORITY (7) /* error, invalid priority */
+#define EXIT_SET_SCHEDULER_ERR (8) /* error, set scheduler */
+#define EXIT_PREV_TIME_OF_DAY_ERR (9) /* error, init. prev. */
+/* time of day */
+
+#define MAX_FILE_NAME_LEN (32) /* maximum file name length */
+
+#define STRINGS_EQUAL ((int) 0) /* strcmp value if equal */
+
+#define MIN_INT_PERIOD_MILLISEC ( 5L) /* minimum interrupt period */
+#define MAX_INT_PERIOD_MILLISEC (5000L) /* maximum interrupt period */
+#define DEF_INT_PERIOD_MILLISEC ( 10L) /* default interrupt period */
+
+#define READ_FILE_MESSAGE "This is a junk file. Must contain at least 1 byte though!\n"
+
+/* The user can specify that the program pad out the write file to
+ a given number of bytes. But a minimum number needs to be written. This
+ will contain the jitter info.
+*/
+#define MIN_WRITE_BYTES 30
+#define DEFAULT_WRITE_BYTES 30
+#define MAX_WRITE_BYTES 4096
+
+/* used for gen a printable ascii random # between spc and '~' */
+#define MIN_ASCII 32 /* <SPACE> can be char*/
+#define MAX_ASCII 126.0 /* needs to be float. See man rand() */
+
+/*----------------------------------------------------------------------
+ * It appears that the preprocessor can't handle multi-line #if
+ * statements. Thus, the check on the default is divided into two
+ * #if statements.
+ *---------------------------------------------------------------------*/
+#if (DEF_INT_PERIOD_MILLISEC < MIN_INT_PERIOD_MILLISEC)
+#error *** Invalid default interrupt period. ***
+#endif
+
+#if (DEF_INT_PERIOD_MILLISEC > MAX_INT_PERIOD_MILLISEC)
+#error *** Invalid default interrupt period. ***
+#endif
+
+
+#define TRUE 1 /* Boolean true value */
+#define FALSE 0
+
+/* Time conversion constants. */
+#define MILLISEC_PER_SEC (1000L) /* milliseconds per second */
+#define MICROSEC_PER_MILLISEC (1000L) /* microsecs per millisec */
+#define MICROSEC_PER_SEC (1000000L) /* microsecs per second */
+
+#define PRIORITY_POLICY ((int) SCHED_RR) /* If specified iwth "-p" */
+
+
+
+/************************** Module Variables **************************/
+/* version identifier (value supplied by CVS)*/
+static const char Version[] = "$Id: JitterTest.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $";
+
+static char OutFileName[MAX_FILE_NAME_LEN+1]; /* output file name */
+static char LogFile[MAX_FILE_NAME_LEN+1] = "/dev/console"; /* default */
+static char ReadFile[MAX_FILE_NAME_LEN+1]; /* This file is read. Should
+ contain at least 1 byte */
+
+static int WriteBytes = DEFAULT_WRITE_BYTES; /* pad out file to these many bytes. */
+static int Fd1; /* fd where the above buffer if o/p */
+static int Cfd; /* fd to console (or file specified) */
+static int Fd2; /* fd for the ReadFile */
+static int DoRead = FALSE; /* should we attempt to ReadFile?*/
+static long InterruptPeriodMilliSec; /* interrupt period, millisec */
+static int MinPriority; /* minimum scheduler priority */
+static int MaxPriority; /* maximum scheduler priority */
+static int RequestedPriority; /* requested priority */
+static struct itimerval ITimer; /* interrupt timer structure */
+static struct timeval PrevTimeVal; /* previous time structure */
+static struct timeval CurrTimeVal; /* current time structure */
+static long LastMaxDiff = 0; /* keeps track of worst jitter encountered */
+
+static int GrabKProfile = FALSE; /* To help determine system bottle necks
+ this parameter can be set. This causes
+ the /proc/profile file to be read and
+ stored in unique filenames in current
+ dir, and indication to be o/p on the
+ /dev/console also.
+ */
+static long ProfileTriggerMSecs = 15000l; /* Jitter time in seconds that triggers
+ a snapshot of the profile to be taken
+
+ */
+static int SignalGCTask = FALSE; /* should be signal SIGSTOP/SIGCONT to gc task?*/
+static int GCTaskPID;
+
+static int RunAsRTTask = FALSE; /* default action unless priority is
+ specified on cmd line */
+
+
+/********************* Local Function Prototypes **********************/
+void HandleCmdLineArgs(int argc, char *argv[]);
+void SetFileName(char * pFileName);
+void SetInterruptPeriod(char * pASCIIInterruptPeriodMilliSec);
+void SetSchedulerPriority(char * pASCIISchedulerPriority);
+
+void PrintVersionInfo(void);
+void PrintHelpInfo(void);
+
+int Write(int fd, void *buf, size_t bytes, int lineNo);
+
+void InitITimer(struct itimerval * pITimer, int action);
+
+/* For catching timer interrupts (SIGALRM). */
+void AlarmHandler(int sigNum);
+
+/* For catching Ctrl+C SIGINT. */
+void SignalHandler(int sigNum);
+
+
+
+/***********************************************************************
+ * main function
+ * return: exit code
+ ***********************************************************************/
+int main(
+ int argc,
+ char *argv[])
+{
+ struct sched_param schedParam;
+
+ int mypri;
+ char tmpBuf[200];
+
+
+ strcpy(OutFileName,"jitter.dat");
+ InterruptPeriodMilliSec = MIN_INT_PERIOD_MILLISEC;
+
+ /* Get the minimum and maximum priorities. */
+ MinPriority = sched_get_priority_min(PRIORITY_POLICY);
+ MaxPriority = sched_get_priority_max(PRIORITY_POLICY);
+ if (MinPriority == -1) {
+ printf("\n*** Unable to get minimum priority. ***\n");
+ exit(EXIT_MIN_PRIORITY_ERR);
+ }
+ if (MaxPriority == -1) {
+ printf("\n*** Unable to get maximum priority. ***\n");
+ exit(EXIT_MAX_PRIORITY_ERR);
+ }
+
+ /* Set requested priority to minimum value as default. */
+ RequestedPriority = MinPriority;
+
+ HandleCmdLineArgs(argc, argv);
+
+ if(mlockall(MCL_CURRENT|MCL_FUTURE) < 0){
+ printf("Could not lock task into memory. Bye\n");
+ perror("Error");
+ }
+
+ if(RunAsRTTask){
+
+ /* Set the priority. */
+ schedParam.sched_priority = RequestedPriority;
+ if (sched_setscheduler(
+ 0,
+ PRIORITY_POLICY,
+ &schedParam) != (int) 0) {
+ printf("Exiting: Unsuccessful sched_setscheduler.\n");
+ close(Fd1);
+ exit(EXIT_SET_SCHEDULER_ERR);
+ }
+
+
+ /* Double check as I have some doubts that it's really
+ running at realtime priority! */
+ if((mypri = sched_getscheduler(0)) != RequestedPriority)
+ {
+ printf("Not running with request priority %i. running with priority %i instead!\n",
+ RequestedPriority, mypri);
+ }else
+ {
+ printf("Running with %i priority. Good!\n", mypri);
+ }
+
+ }
+
+ /*------------------------- Initializations --------------------------*/
+ if((Fd1 = open(OutFileName, O_RDWR|O_CREAT|O_SYNC)) <= 0)
+ {
+ perror("Cannot open outfile for write:");
+ exit(1);
+ }
+
+ /* If a request is made to read from a specified file, then create that
+ file and fill with junk data so that there is something there to read.
+ */
+ if(DoRead)
+ {
+
+ if((Fd2 = open(ReadFile, O_RDWR|O_CREAT|O_SYNC|O_TRUNC)) <= 0)
+ {
+ perror("cannot open read file:");
+ exit(1);
+ }else
+ {
+
+ /* Don't really care how much we write here */
+ if(write(Fd2, READ_FILE_MESSAGE, strlen(READ_FILE_MESSAGE)) < 0)
+ {
+ perror("Problems writing to readfile:");
+ exit(1);
+ }
+ lseek(Fd2, 0, SEEK_SET); /* position back to byte #0 */
+ }
+ }
+
+
+
+ /* Also log output to console. This way we can capture it
+ on a serial console to a log file.
+ */
+ if((Cfd = open(LogFile, O_WRONLY|O_SYNC)) <= 0)
+ {
+ perror("cannot open o/p logfile:");
+ exit(1);
+ }
+
+
+ /* Set-up handler for periodic interrupt. */
+ if (signal(SIGALRM, &AlarmHandler) == SIG_ERR) {
+ printf("Couldn't register signal handler for SIGALRM.\n");
+ sprintf(tmpBuf,
+ "Couldn't register signal handler for SIGALRM.\n");
+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
+
+ close(Fd1);
+ exit(EXIT_REG_SIGALRM_ERR);
+ }
+
+ /* Set-up handler for Ctrl+C to exit the program. */
+ if (signal(SIGINT, &SignalHandler) == SIG_ERR) {
+ printf("Couldn't register signal handler for SIGINT.\n");
+ sprintf(tmpBuf,
+ "Couldn't register signal handler for SIGINT.\n");
+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
+
+ close(Fd1);
+ exit(EXIT_REG_SIGINT_ERR);
+ }
+
+ printf("Press Ctrl+C to exit the program.\n");
+ printf("Output File: %s\n", OutFileName);
+ printf("Scheduler priority: %d\n", RequestedPriority);
+ sprintf(tmpBuf, "\nScheduler priority: %d\n",
+ RequestedPriority);
+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
+
+ Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__);
+
+ printf("Interrupt period: %ld milliseconds\n",
+ InterruptPeriodMilliSec);
+ sprintf(tmpBuf, "Interrupt period: %ld milliseconds\n",
+ InterruptPeriodMilliSec);
+
+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
+
+ Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__);
+
+
+ fflush(0);
+
+
+
+ /* Initialize the periodic timer. */
+ InitITimer(&ITimer, ONESHOT);
+
+ /* Initialize "previous" time. */
+ if (gettimeofday(&PrevTimeVal, NULL) != (int) 0) {
+ printf("Exiting - ");
+ printf("Unable to initialize previous time of day.\n");
+ sprintf(tmpBuf, "Exiting - ");
+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
+
+ sprintf(tmpBuf,
+ "Unable to initialize previous time of day.\n");
+
+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
+
+ }
+
+ /* Start the periodic timer. */
+ setitimer(ITIMER_REAL, &ITimer, NULL);
+
+
+ while(TRUE) { /* Intentional infinite loop. */
+ /* Sleep for one second. */
+ sleep((unsigned int) 1);
+ }
+
+ /* Just in case. File should be closed in SignalHandler. */
+ close(Fd1);
+ close(Cfd);
+
+ return 0;
+}
+
+
+
+
+/***********************************************************************
+ * SignalHandler
+ * This is a handler for the SIGINT signal. It is assumed that the
+ * SIGINT is due to the user pressing Ctrl+C to halt the program.
+ * output: N/A
+ ***********************************************************************/
+void SignalHandler(
+ int sigNum)
+{
+
+ char tmpBuf[200];
+
+ /* Note sigNum not used. */
+ printf("Ctrl+C detected. Worst Jitter time was:%fms.\nJitterTest exiting.\n",
+ (float)LastMaxDiff/1000.0);
+
+ sprintf(tmpBuf,
+ "\nCtrl+C detected. Worst Jitter time was:%fms\nJitterTest exiting.\n",
+ (float)LastMaxDiff/1000.0);
+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
+
+ Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__);
+
+ close(Fd1);
+ close(Cfd);
+ exit(0);
+}
+
+
+
+
+
+/*
+ A snapshot of the /proc/profile needs to be taken.
+ This is stored as a new file every time, and the
+ stats reset by doing a (any) write to the /proc/profile
+ file.
+ */
+void doGrabKProfile(int jitterusec, char *fileName)
+{
+ int fdSnapshot;
+ int fdProfile;
+ int readBytes;
+ char readBuf[4096];
+
+ if((fdSnapshot = open(fileName, O_WRONLY | O_CREAT)) <= 0)
+ {
+ fprintf(stderr, "Could not open file %s.\n", fileName);
+ perror("Error:");
+ return;
+ }
+
+ if((fdProfile = open("/proc/profile", O_RDWR)) <= 0)
+ {
+ fprintf(stderr, "Could not open file /proc/profile. Make sure you booted with profile=2\n");
+ close(fdSnapshot);
+ return;
+ }
+
+ while((readBytes = read(fdProfile, readBuf, sizeof(readBuf))) > 0)
+ {
+ write(fdSnapshot, readBuf, readBytes);
+ }
+
+ close(fdSnapshot);
+
+ if(write(fdProfile, readBuf, 1) != 1)
+ {
+ perror("Could Not clear profile by writing to /proc/profile:");
+ }
+
+ close(fdProfile);
+
+
+
+}/* end doGrabKProfile()*/
+
+
+/*
+ Call this routine to clear the kernel profiling buffer /proc/profile
+*/
+void clearProfileBuf(void){
+
+
+ int fdProfile;
+ char readBuf[10];
+
+
+ if((fdProfile = open("/proc/profile", O_RDWR)) <= 0)
+ {
+ fprintf(stderr, "Could not open file /proc/profile. Make sure you booted with profile=2\n");
+ return;
+ }
+
+
+ if(write(fdProfile, readBuf, 1) != 1)
+ {
+ perror("Could Not clear profile by writing to /proc/profile:");
+ }
+
+ close(fdProfile);
+
+
+}/* end clearProfileBuf() */
+
+
+
+
+
+/***********************************************************************
+ * AlarmHandler
+ * This is a handler for the SIGALRM signal (due to the periodic
+ * timer interrupt). It prints the time (seconds) to
+ * the output file.
+ * output: N/A
+ ***********************************************************************/
+void AlarmHandler(
+ int sigNum) /* signal number (not used) */
+{
+
+ long timeDiffusec; /* diff time in micro seconds */
+ long intervalusec;
+
+
+ char tmpBuf[MAX_WRITE_BYTES];
+ int cntr;
+ char padChar;
+
+ static int profileFileNo = 0;
+ char profileFileName[150];
+
+ static int seedStarter = 0; /* carries over rand info to next time
+ where time() will be the same as this time
+ if invoked < 1sec apart.
+ */
+
+ if (gettimeofday(&CurrTimeVal, NULL) == (int) 0) {
+
+ /*----------------------------------------------------------------
+ * Compute the elapsed time between the current and previous
+ * time of day values and store the result.
+ *
+ * Print the elapsed time to the output file.
+ *---------------------------------------------------------------*/
+
+ timeDiffusec = (long)(((((long long)CurrTimeVal.tv_sec) * 1000000L) + CurrTimeVal.tv_usec) -
+ (((long long)PrevTimeVal.tv_sec * 1000000L) + PrevTimeVal.tv_usec));
+
+ sprintf(tmpBuf," %f ms ", (float)timeDiffusec/1000.0);
+
+ intervalusec = InterruptPeriodMilliSec * 1000L;
+
+ timeDiffusec = timeDiffusec - intervalusec;
+
+ sprintf(&tmpBuf[strlen(tmpBuf)]," %f ms", (float)timeDiffusec/1000.0);
+
+
+ /* should we send a SIGSTOP/SIGCONT to the specified PID? */
+ if(SignalGCTask){
+
+ if(kill(GCTaskPID, SIGSTOP) < 0){
+
+ perror("error:");
+ }
+ }
+
+
+ /* Store some historical #'s */
+ if(abs(timeDiffusec) > LastMaxDiff)
+ {
+ LastMaxDiff = abs(timeDiffusec);
+ sprintf(&tmpBuf[strlen(tmpBuf)],"!");
+
+ if((GrabKProfile == TRUE) && (ProfileTriggerMSecs < (abs(timeDiffusec)/1000)))
+ {
+ sprintf(profileFileName, "JitterTest.profilesnap-%i", profileFileNo);
+
+ /* go and grab the kernel performance profile. */
+ doGrabKProfile(timeDiffusec, profileFileName);
+ profileFileNo++; /* unique name next time */
+
+ /* Say so on the console so that a marker gets put in the console log */
+ sprintf(&tmpBuf[strlen(tmpBuf)],"<Profile saved in file:%s>",
+ profileFileName);
+
+ }
+
+ }
+
+
+
+
+ sprintf(&tmpBuf[strlen(tmpBuf)],"\n"); /* CR for the data going out of the console */
+
+ Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__);
+
+
+ /* The "-1" below takes out the '\n' at the end that we appended for the msg printed on
+ the console.*/
+ sprintf(&tmpBuf[strlen(tmpBuf)-1]," PadBytes:");
+
+ /* Now pad the output file if requested by user. */
+ if(WriteBytes > MIN_WRITE_BYTES)
+ {
+
+ /* start from a new place every time */
+ srand(time(NULL) + seedStarter);
+
+ /* already written MIN_WRITE_BYTES by now */
+ for(cntr = strlen(tmpBuf); cntr < WriteBytes - 1 ; cntr++) /* "-1" adj for '\n' at end */
+ {
+ /* don't accept any # < 'SPACE' */
+ padChar = (char)(MIN_ASCII+(int)((MAX_ASCII-(float)MIN_ASCII)*rand()/(RAND_MAX+1.0)));
+
+
+ /*
+ padChar = (cntr % (126-33)) + 33;
+ */
+
+ tmpBuf[cntr] = padChar;
+ }
+
+ seedStarter = tmpBuf[cntr-1]; /* save for next time */
+
+ tmpBuf[cntr] = '\n'; /* CR for the data going into the outfile. */
+ tmpBuf[cntr+1] = '\0'; /* NULL terminate the string */
+ }
+
+ /* write out the entire line to the output file. */
+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
+
+
+ /* Read a byte from the specified file */
+ if(DoRead)
+ {
+
+ read(Fd2, tmpBuf, 1);
+ lseek(Fd2, 0, SEEK_SET); /* back to start */
+ }
+
+
+ /* Start the periodic timer again. */
+ setitimer(ITIMER_REAL, &ITimer, NULL);
+
+
+ /* Update previous time with current time. */
+ PrevTimeVal.tv_sec = CurrTimeVal.tv_sec;
+ PrevTimeVal.tv_usec = CurrTimeVal.tv_usec;
+ }
+
+ else {
+ sprintf(tmpBuf, "gettimeofday error \n");
+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
+
+ printf("gettimeofday error \n");
+ }
+
+ /* now clear the profiling buffer */
+ if(GrabKProfile == TRUE){
+
+ clearProfileBuf();
+ }
+
+ /* should we send a SIGSTOP/SIGCONT to the specified PID? */
+ if(SignalGCTask){
+
+ if(kill(GCTaskPID, SIGCONT) < 0){
+
+ perror("error:");
+ }
+ }
+
+
+ return;
+}
+
+
+
+/***********************************************************************
+ * InitITimer
+ * This function initializes the 'struct itimerval' structure whose
+ * address is passed to interrupt every InterruptPeriodMilliSec.
+ * output: N/A
+ ***********************************************************************/
+void InitITimer(
+ struct itimerval * pITimer, /* pointer to interrupt timer struct*/
+ int action) /* ONESHOT or autosetting? */
+{
+ long seconds; /* seconds portion of int. period */
+ long microSeconds; /* microsec. portion of int. period */
+
+ /*--------------------------------------------------------------------
+ * Divide the desired interrupt period into its seconds and
+ * microseconds components.
+ *-------------------------------------------------------------------*/
+ if (InterruptPeriodMilliSec < MILLISEC_PER_SEC) {
+ seconds = 0L;
+ microSeconds = InterruptPeriodMilliSec * MICROSEC_PER_MILLISEC;
+ }
+ else {
+ seconds = InterruptPeriodMilliSec / MILLISEC_PER_SEC;
+ microSeconds =
+ (InterruptPeriodMilliSec - (seconds * MILLISEC_PER_SEC)) *
+ MICROSEC_PER_MILLISEC;
+ }
+
+ /* Initialize the interrupt period structure. */
+ pITimer->it_value.tv_sec = seconds;
+ pITimer->it_value.tv_usec = microSeconds;
+
+ if(action == ONESHOT)
+ {
+ /* This will (should) prevent the timer from restarting itself */
+ pITimer->it_interval.tv_sec = 0;
+ pITimer->it_interval.tv_usec = 0;
+ }else
+ {
+ pITimer->it_interval.tv_sec = seconds;
+ pITimer->it_interval.tv_usec = microSeconds;
+
+ }
+
+ return;
+}
+
+
+/***********************************************************************
+ * HandleCmdLineArgs
+ * This function handles the command line arguments.
+ * output: stack size
+ ***********************************************************************/
+void HandleCmdLineArgs(
+ int argc, /* number of command-line arguments */
+ char *argv[]) /* ptrs to command-line arguments */
+{
+ int argNum; /* argument number */
+
+ if (argc > (int) 1) {
+
+ for (argNum = (int) 1; argNum < argc; argNum++) {
+
+ /* The command line contains an argument. */
+
+ if ((strcmp(argv[argNum],"--version") == STRINGS_EQUAL) ||
+ (strcmp(argv[argNum],"-v") == STRINGS_EQUAL)) {
+ /* Print version information and exit. */
+ PrintVersionInfo();
+ exit(0);
+ }
+
+ else if ((strcmp(argv[argNum],"--help") == STRINGS_EQUAL) ||
+ (strcmp(argv[argNum],"-h") == STRINGS_EQUAL) ||
+ (strcmp(argv[argNum],"-?") == STRINGS_EQUAL)) {
+ /* Print help information and exit. */
+ PrintHelpInfo();
+ exit(0);
+ }
+
+ else if ((strcmp(argv[argNum],"--file") == STRINGS_EQUAL) ||
+ (strcmp(argv[argNum],"-f") == STRINGS_EQUAL)) {
+ /* Set the name of the output file. */
+ ++argNum;
+ if (argNum < argc) {
+ SetFileName(argv[argNum]);
+ }
+ else {
+ printf("*** Output file name not specified. ***\n");
+ printf("Default output file name will be used.\n");
+ }
+ }
+
+ else if ((strcmp(argv[argNum],"--time") == STRINGS_EQUAL) ||
+ (strcmp(argv[argNum],"-t") == STRINGS_EQUAL)) {
+ /* Set the interrupt period. */
+ ++argNum;
+ if (argNum < argc) {
+ SetInterruptPeriod(argv[argNum]);
+ }
+ else {
+ printf("*** Interrupt period not specified. ***\n");
+ printf("Default interrupt period will be used.\n");
+ }
+
+ }
+
+ else if ((strcmp(argv[argNum],"--priority") ==
+ STRINGS_EQUAL) ||
+ (strcmp(argv[argNum],"-p") == STRINGS_EQUAL)) {
+ /* Set the scheduler priority. */
+ ++argNum;
+ if (argNum < argc) {
+ SetSchedulerPriority(argv[argNum]);
+ }
+ else {
+ printf("*** Scheduler priority not specified. ***\n");
+ printf("Default scheduler priority will be used.\n");
+ }
+
+ }
+
+ else if ((strcmp(argv[argNum],"--readfile") ==
+ STRINGS_EQUAL) ||
+ (strcmp(argv[argNum],"-r") == STRINGS_EQUAL)) {
+ /* Set the file to read*/
+ ++argNum;
+
+ strncpy(ReadFile, argv[argNum], sizeof(ReadFile));
+ DoRead = TRUE;
+ }
+
+ else if ((strcmp(argv[argNum],"--write_bytes") ==
+ STRINGS_EQUAL) ||
+ (strcmp(argv[argNum],"-w") == STRINGS_EQUAL)) {
+ /* Set the file to read*/
+ ++argNum;
+
+ WriteBytes = atoi(argv[argNum]);
+
+ if(WriteBytes < MIN_WRITE_BYTES)
+ {
+ printf("Writing less than %i bytes is not allowed. Bye.\n",
+ MIN_WRITE_BYTES);
+ exit(0);
+ }
+
+
+ }
+
+ else if ((strcmp(argv[argNum],"--consolefile") ==
+ STRINGS_EQUAL) ||
+ (strcmp(argv[argNum],"-c") == STRINGS_EQUAL)) {
+ /* Set the file to log console log on. */
+ ++argNum;
+
+ strncpy(LogFile, argv[argNum], sizeof(LogFile));
+ }
+
+ else if ((strcmp(argv[argNum],"--grab_kprofile") ==
+ STRINGS_EQUAL))
+ {
+ /* We will read the /proc/profile file on configurable timeout */
+ GrabKProfile = TRUE;
+
+ ++argNum;
+
+ /* If the jittter is > this #, then the profile is grabbed. */
+ ProfileTriggerMSecs = (long) atoi(argv[argNum]);
+
+ if(ProfileTriggerMSecs <= 0){
+
+ printf("Illegal value for profile trigger threshold.\n");
+ exit(0);
+ }
+ }
+
+ else if ((strcmp(argv[argNum],"--siggc") ==
+ STRINGS_EQUAL))
+ {
+ /* We will SIGSTOP/SIGCONT the specified pid */
+ SignalGCTask = TRUE;
+
+ ++argNum;
+
+ GCTaskPID = atoi(argv[argNum]);
+
+ if(ProfileTriggerMSecs <= 0){
+
+ printf("Illegal value for JFFS(2) GC task pid.\n");
+ exit(0);
+ }
+ }
+
+
+ else {
+ /* Unknown argument. Print help information and exit. */
+ printf("Invalid option %s\n", argv[argNum]);
+ printf("Try 'JitterTest --help' for more information.\n");
+ exit(0);
+ }
+ }
+ }
+
+ return;
+}
+
+
+/***********************************************************************
+ * SetFileName
+ * This function sets the output file name.
+ * output: N/A
+ ***********************************************************************/
+void SetFileName(
+ char * pFileName) /* ptr to desired output file name */
+{
+ size_t fileNameLen; /* file name length (bytes) */
+
+ /* Check file name length. */
+ fileNameLen = strlen(pFileName);
+ if (fileNameLen > (size_t) MAX_FILE_NAME_LEN) {
+ printf("File name %s exceeds maximum length %d.\n",
+ pFileName, MAX_FILE_NAME_LEN);
+ exit(0);
+ }
+
+ /* File name length is OK so save the file name. */
+ strcpy(OutFileName, pFileName);
+
+ return;
+}
+
+
+/***********************************************************************
+ * SetInterruptPeriod
+ * This function sets the interrupt period.
+ * output: N/A
+ ***********************************************************************/
+void SetInterruptPeriod(
+ char * /* ptr to desired interrupt period */
+ pASCIIInterruptPeriodMilliSec)
+{
+ long period; /* interrupt period */
+
+ period = atol(pASCIIInterruptPeriodMilliSec);
+ if ((period < MIN_INT_PERIOD_MILLISEC) ||
+ (period > MAX_INT_PERIOD_MILLISEC)) {
+ printf("Invalid interrupt period: %ld ms.\n", period);
+ exit(EXIT_INV_INT_PERIOD);
+ }
+ else {
+ InterruptPeriodMilliSec = period;
+ }
+ return;
+}
+
+
+/***********************************************************************
+ * SetSchedulerPriority
+ * This function sets the desired scheduler priority.
+ * output: N/A
+ ***********************************************************************/
+void SetSchedulerPriority(
+ char * pASCIISchedulerPriority) /* ptr to desired scheduler priority*/
+{
+ int priority; /* desired scheduler priority value */
+
+ priority = atoi(pASCIISchedulerPriority);
+ if ((priority < MinPriority) ||
+ (priority > MaxPriority)) {
+ printf("Scheduler priority %d outside of range [%d, %d]\n",
+ priority, MinPriority, MaxPriority);
+ exit(EXIT_INV_SCHED_PRIORITY);
+ }
+ else {
+ RequestedPriority = priority;
+ RunAsRTTask = TRUE; /* We shall run as a POSIX real time task */
+ }
+ return;
+}
+
+
+/***********************************************************************
+ * PrintVersionInfo
+ * This function prints version information.
+ * output: N/A
+ ***********************************************************************/
+void PrintVersionInfo(void)
+{
+ printf("JitterTest version %s\n", Version);
+ printf("Copyright (c) 2001, Daniel Industries, Inc.\n");
+ return;
+}
+
+
+/***********************************************************************
+ * PrintHelpInfo
+ * This function prints help information.
+ * output: N/A
+ ***********************************************************************/
+void PrintHelpInfo(void)
+{
+ printf("Usage: JitterTest [options]\n");
+ printf(" *** Requires root privileges. ***\n");
+ printf("Option:\n");
+ printf(" [-h, --help, -?] Print this message and exit.\n");
+ printf(" [-v, --version] ");
+ printf( "Print the version number of JitterTest and exit.\n");
+ printf(" [-f FILE, --file FILE] Set output file name to FILE. Typically you would put this on the fs under test\n");
+ printf(" [-c FILE, --consolefile] Set device or file to write the console log to.\n\tTypically you would set this to /dev/console and save it on another computer.\n");
+ printf(" [-w BYTES, --write_bytes BYTES Write BYTES to FILE each period.\n");
+ printf(" [-r FILE, --readfile FILE] Also read 1 byte every cycle from FILE. FILE will be created and filled with data.\n");
+ printf(" [-t <n>, --time <n>] ");
+ printf( "Set interrupt period to <n> milliseconds.\n");
+ printf(" ");
+ printf( "Range: [%ld, %ld] milliseconds.\n",
+ MIN_INT_PERIOD_MILLISEC, MAX_INT_PERIOD_MILLISEC);
+ printf(" [-p <n>, --priority <n>] ");
+ printf( "Set scheduler priority to <n>.\n");
+ printf(" ");
+ printf( "Range: [%d, %d] (higher number = higher priority)\n",
+ MinPriority, MaxPriority);
+ printf(" [--grab_kprofile <THRESHOLD in ms>] Read the /proc/profile if jitter is > THRESHOLD and store in file.\n");
+ printf(" [--siggc <PID>] Before writing to fs send SIGSTOP to PID. After write send SIGCONT\n");
+ return;
+
+}
+
+
+/* A common write that checks for write errors and exits. Pass it __LINE__ for lineNo */
+int Write(int fd, void *buf, size_t bytes, int lineNo)
+{
+
+ int err;
+
+ err = write(fd, buf, bytes);
+
+ if(err < bytes)
+ {
+
+ printf("Write Error at line %i! Wanted to write %i bytes, but wrote only %i bytes.\n",
+ lineNo, bytes, err);
+ perror("Write did not complete. Error. Bye:"); /* show error from errno. */
+ exit(1);
+
+ }
+
+ return err;
+
+}/* end Write*/
diff --git a/drivers/mtd/mtd-utils/tests/jittertest/Makefile b/drivers/mtd/mtd-utils/tests/jittertest/Makefile
new file mode 100644
index 00000000000..2f113297bb3
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/jittertest/Makefile
@@ -0,0 +1,46 @@
+CC=gcc
+# uncomment following for performance
+CCFLAGS=-O3 -Wall -m486 -fomit-frame-pointer
+
+# uncomment following for debugging. Uncomment either this or the one above. Not both.
+# CCFLAGS=-Wall -g
+
+
+all: JitterTest plotJittervsFill
+
+JitterTest: JitterTest.c Makefile
+ gcc $(CCFLAGS) -lm JitterTest.c -o JitterTest
+
+plotJittervsFill: plotJittervsFill.c Makefile
+ gcc $(CCFLAGS) plotJittervsFill.c -o plotJittervsFill
+
+clean:
+ rm -rf *~
+ rm -rf core
+ rm -rf *.o
+ rm -rf JitterTest
+
+
+dep:
+ makedepend -I./ *.c
+# DO NOT DELETE
+
+JitterTest.o: /usr/include/stdio.h /usr/include/features.h
+JitterTest.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+JitterTest.o: /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stddef.h
+JitterTest.o: /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stdarg.h
+JitterTest.o: /usr/include/bits/types.h /usr/include/libio.h
+JitterTest.o: /usr/include/_G_config.h /usr/include/bits/stdio_lim.h
+JitterTest.o: /usr/include/string.h /usr/include/stdlib.h
+JitterTest.o: /usr/include/sys/types.h /usr/include/time.h
+JitterTest.o: /usr/include/endian.h /usr/include/bits/endian.h
+JitterTest.o: /usr/include/sys/select.h /usr/include/bits/select.h
+JitterTest.o: /usr/include/bits/sigset.h /usr/include/sys/sysmacros.h
+JitterTest.o: /usr/include/alloca.h /usr/include/sys/time.h
+JitterTest.o: /usr/include/bits/time.h /usr/include/signal.h
+JitterTest.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h
+JitterTest.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
+JitterTest.o: /usr/include/asm/sigcontext.h /usr/include/bits/sigstack.h
+JitterTest.o: /usr/include/sched.h /usr/include/bits/sched.h
+JitterTest.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+JitterTest.o: /usr/include/bits/confname.h /usr/include/getopt.h
diff --git a/drivers/mtd/mtd-utils/tests/jittertest/README b/drivers/mtd/mtd-utils/tests/jittertest/README
new file mode 100644
index 00000000000..7dbccded2cc
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/jittertest/README
@@ -0,0 +1,197 @@
+$Id: README,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+
+This is the README file for the JitterTest (and friends)
+program.
+
+This program is used to measure what the jitter of a
+real time task would be under "standard" Linux.
+
+More particularly, what is the effect of running
+a real time task under Linux with background
+JFFS file system activity.
+
+The jitter is measured in milli seconds (ms) from
+the expected time of arrival of a signal from a
+periodic timer (set by the task) to when the
+task actually gets the signal.
+
+This jitter is then stored in a file specified
+(or the default output file "jitter.dat").
+
+The data may also be sent out to the console by
+writing to /dev/console (See help options. This is
+highly desirable specially if you have redirected
+your console to the serial port and are storing it
+as a minicom log on another computer for later analysis
+using some tools provided here).
+
+This is particularly useful if you have a serial
+console and are outputting "interesting" info
+from inside some kernel task or driver.
+(or something as simple as a "df" program running
+periodically and redirecting o/p to the console).
+
+One "interesting" thing that I have measured
+is the effect of FLASH chip erases on the jitter
+of a real time task.
+
+One can do that by putting a printk at the
+beginning of the flash erase routine in the MTD
+flash chip driver.
+
+Now you will get jitter data interspersed with
+flash sector erase events. Other printk's can also
+be placed at suspected jitter causing locations in
+the system.
+
+
+
+EXECUTING THE PROGRAM "JitterTest"
+
+You may specify a file to be read by the
+program every time it wakes up (every cycle).
+This file is created and filled with some junk
+data. The purpose of this is to test the jitter
+of the program if it were reading from- say
+a JFFS (Journaling Flash File System) file system.
+
+By specifying the complete paths of the read and write
+(o/p) files you can test the jitter a POSIX type
+real time task will experience under Linux, under
+various conditions.
+
+These can be as follows:
+
+1. O/P file on ram file system, no i/p file.
+
+ In this case you would presumably generate other
+"typical" background activity for your system and
+examine the worst case jitter experienced by
+a task that is neither reading nor writing to
+a file system.
+
+Other cases could be:
+
+2. O/P to ram fs, I/P from JFFS (type) fs:
+
+ This is specially useful to test the proper
+operation of erase suspend type of operation
+in JFFS file systems (with an MTD layer that
+supports it).
+
+ In this test you would generate some background
+write/erase type activity that would generate
+chip erases. Since this program is reading from
+the same file system, you contrast the latencies
+with those obtained with writes going to the same
+fs.
+
+3. Both read and writes to (or just write to) JFFS
+file system:
+
+ Here you would test for latencies experienced by
+a program if it were writing (and optionally also
+reading) from a JFFS fs.
+
+
+
+
+Grabing a kernel profile:
+
+This program can also conditionally grab a kernel profile.
+Specify --grab_kprofile on the cmd line as well as
+a "threshold" parameter (see help options by -?).
+
+Any jitter greater than this "threshold" will cause the
+program to read the /proc/profile file and dump it in
+a local file with increasing file numbers. It will also
+output the filename at that time to the console file specified.
+This will allow you to corelate later in time the various profiles
+with data in your console file and what was going on at that time.
+
+These profile files may then be later examined by running them through
+ksymoops.
+
+Make sure you specify "profile=2" on the kernel command line
+when you boot the kernel if you want to use this functionality.
+
+
+
+Signalling the JFFS[2] GC task:
+
+You can also force this program to send a SIGSTOP/SIGCONT to the
+JFFS (or JFFS2) gc task by specifing --siggc <pid> on the cmd line.
+
+This will let you investigate the effect of forcing the gc task to
+wake up and do its thing when you are not writing to the fs and to
+force it to sleep when you want to write to the fs.
+
+These are just various tools to investigate the possibility of
+achieving minimal read/write latency when using JFFS[2].
+
+You need to manually do a "ps aux" and look up the PID of the gc
+thread and provide it to the program.
+
+
+
+
+EXECUTING THE PROGRAM "plotJittervsFill"
+
+This program is a post processing tool that will extract the jitter
+times as printed by the JitterTest program in its console log file
+as well as the data printed by the "df" command.
+
+This "df" data happens to be in the console log because you will
+run the shell file fillJffs2.sh on a console when you are doing
+your jitter test.
+
+This shell script copies a specified file to another specified file
+every programmable seconds. It also does a "df" and redirects output
+to /dev/console where it is mixed with the output from JitterTest.
+
+All this console data is stored on another computer, as all this data
+is being outputted to the serial port as you have redirected the console
+to the serial port (that is the only guaranteed way to not loose any
+console log or printk data).
+
+You can then run this saved console log through this program and it
+will output a very nice text file with the %fill in one col and
+corrosponding jitter values in the second. gnuplot then does a
+beautifull plot of this resulting file showing you graphically the
+jitters encountered at different fill % of your JFFS[2] fs.
+
+
+
+OTHER COMMENTS:
+
+Use the "-w BYTES" cmd line parameter to simulate your test case.
+Not everyone has the same requirements. Someone may want to measure
+the jitter of JFFS2 with 500 bytes being written every 500ms. Others
+may want to measure the system performance writing 2048 bytes every
+5 seconds.
+
+RUNNING MULTIPLE INSTANCES:
+
+Things get real interesting when you run multiple instances of this
+program *at the same time*.
+
+You could have one version running as a real time task (by specifing
+the priority with the -p cmd line parameter), not interacting with
+any fs or at the very least not reading and writing to JFFS[2].
+
+At the same time you could have another version running as a regular
+task (by not specifing any priority) but reading and writing to JFFS[2].
+
+This way you can easily measure the blocking performance of the real time
+task while another non-real time task interacts with JFFS[2] in the back ground.
+
+You get the idea.
+
+
+WATCH OUT!
+
+Be particularly careful of running this program as a real time task AND
+writing to JFFS[2]. Any blocks will cause your whole system to block till
+any garbage collect initiated by writes by this task complete. I have measured
+these blocks to be of the order of 40-50 seconds on a reasonably powerful
+32 bit embedded system.
diff --git a/drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh b/drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh
new file mode 100644
index 00000000000..10651f46033
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+# Pass following cmd line:
+# 1st - file to copy
+# 2nd - file to copy to
+# 3rd - time to sleep between copies
+
+while [ $(( 1 )) -gt $(( 0 )) ]
+do
+ cp $1 $2
+ rm $2
+ df |grep mtd > /dev/console
+ echo "sleeping $3"
+ sleep $3
+done
+
diff --git a/drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c b/drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c
new file mode 100644
index 00000000000..cc678e02a50
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c
@@ -0,0 +1,312 @@
+/*
+ ***********************************************************************
+ *
+ * Copyright: Daniel Measurement and Control, Inc.
+ * 9753 Pine Lake Drive
+ * Houston, TX 77055
+ *
+ * Created by: Vipin Malik
+ * Released under GPL by permission of Daniel Industries.
+ *
+ * This software is licensed under the GPL version 2. Plese see the file
+ * COPYING for details on the license.
+ *
+ * NO WARRANTY: Absolutely no claims of warranty or fitness of purpose
+ * are made in this software. Please use at your own risk.
+ *
+ File: plotJittervsFill.c
+ By: Vipin Malik
+
+ About: This program reads in a jitter log file as created
+ by the JitterTest.c program and extracts all the jitters
+ in the file that are greater than a threshold specified
+ as a parameter on the cmd line. It also extracts the
+ amount of disk space at (form the "df" out that should also
+ be present in the log file) after the jitter extracted.
+
+ It writes the data to the stderr (where you may redirect it).
+ It is suitable for plotting, as the data is written as
+ COL1=UsedSpace COL2=Jitter
+
+ $Id: plotJittervsFill.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ $Log: not supported by cvs2svn $
+ Revision 1.6 2005/11/07 11:15:21 gleixner
+ [MTD / JFFS2] Clean up trailing white spaces
+
+ Revision 1.5 2001/08/10 19:23:11 vipin
+ Ready to be released under GPL! Added proper headers etc.
+
+ Revision 1.4 2001/07/02 22:25:40 vipin
+ Fixed couple of minor cosmetic typos.
+
+ Revision 1.3 2001/07/02 14:46:46 vipin
+ Added a debug option where it o/p's line numbers to debug funky values.
+
+ Revision 1.2 2001/06/26 19:48:57 vipin
+ Now prints out jitter values found at end of log file, after which
+ no new "df" disk usage values were encountered. The last "df" disk usage
+ encountered is printed for these orphaned values.
+
+ Revision 1.1 2001/06/25 19:13:55 vipin
+ Added new file- plotJittervsFill.c- that mines the data log file
+ outputed from the fillFlash.sh script file and JitterTest.c file
+ and produces output suitable to be plotted.
+ This output plot may be examined to see visually the relationship
+ of the Jitter vs disk usage of the fs under test.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+static char Version_string[] = "$Id: plotJittervsFill.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $";
+static char LogFile[250] = "InputLogFile.log";
+
+static int JitterThreshold_ms = 1000;
+static int Debug = 0; /* Debug level. Each "-d" on the cmd line increases the level */
+
+#define TRUE 1
+#define FALSE 0
+
+#define MIN_JITTER_THRESHOLD 1 /* ms minimum jitter threshold */
+
+void PrintHelpInfo(void)
+{
+ printf("Usage: plotJittervsFill [options] -f [--file] <input log file name> -t [--jitter_threshold] <jitter threshold in ms>\n");
+ printf("[options]:\n-v [--version] Print version and exit\n");
+ printf("-d Debug. Prints input file line number for each data point picked up.\n");
+ printf("-h [--help] [-?] Print this help screen and exit.\n");
+}
+
+
+
+/***********************************************************************
+ * HandleCmdLineArgs
+ * This function handles the command line arguments.
+ * output: stack size
+ ***********************************************************************/
+void HandleCmdLineArgs(
+ int argc, /* number of command-line arguments */
+ char *argv[]) /* ptrs to command-line arguments */
+{
+ int argNum; /* argument number */
+
+ if (argc > (int) 1) {
+
+ for (argNum = (int) 1; argNum < argc; argNum++) {
+
+ /* The command line contains an argument. */
+
+ if ((strcmp(argv[argNum],"--version") == 0) ||
+ (strcmp(argv[argNum],"-v") == 0)) {
+ /* Print version information and exit. */
+ printf("%s\n", Version_string);
+ exit(0);
+ }
+
+ else if ((strcmp(argv[argNum],"--help") == 0) ||
+ (strcmp(argv[argNum],"-h") == 0) ||
+ (strcmp(argv[argNum],"-?") == 0)) {
+ /* Print help information and exit. */
+ PrintHelpInfo();
+ exit(0);
+ }
+
+ else if ((strcmp(argv[argNum],"--file") == 0) ||
+ (strcmp(argv[argNum],"-f") == 0)) {
+ /* Set the name of the output file. */
+ ++argNum;
+ if (argNum < argc) {
+ strncpy(LogFile, argv[argNum], sizeof(LogFile));
+ }
+ else {
+ printf("*** Input file name not specified. ***\n");
+ exit(0);
+ }
+ }
+
+ else if ((strcmp(argv[argNum],"--jitter_threshold") == 0) ||
+ (strcmp(argv[argNum],"-t") == 0)) {
+ /* Set the file to read*/
+ ++argNum;
+
+ JitterThreshold_ms = atoi(argv[argNum]);
+
+ if(JitterThreshold_ms < MIN_JITTER_THRESHOLD)
+ {
+ printf("A jitter threshold less than %i ms is not allowed. Bye.\n",
+ MIN_JITTER_THRESHOLD);
+ exit(0);
+ }
+ }
+
+ else if ((strcmp(argv[argNum],"-d") == 0))
+ {
+ /* Increment debug level */
+
+ Debug++;
+ }
+
+ else {
+ /* Unknown argument. Print help information and exit. */
+ printf("Invalid option %s\n", argv[argNum]);
+ printf("Try 'plotJittervsFill --help' for more information.\n");
+ exit(0);
+ }
+ }
+ }
+
+ return;
+}
+
+
+
+
+
+int main(
+ int argc,
+ char *argv[])
+{
+
+ char lineBuf[1024]; /* how long a single line be? */
+ int converted;
+ int lineNo = 0;
+ int cnt;
+
+ FILE *fp;
+
+ int junkInt1, junkInt2, junkInt3;
+ float junkFloat1;
+ float jitter_ms;
+
+#define MAX_SAVE_BUFFER 1000 /* How many values will be picked up while searching for
+ a % disk full line (i.e. before they can be printed out)
+ */
+ int saveJitter[MAX_SAVE_BUFFER]; /* lets us record multiple jitter values that exceed
+ our threshold till we find a "df" field- which is when
+ we can o/p all these values.
+ */
+ int dataLineNo[MAX_SAVE_BUFFER]; /* The saved line #'s for the above. Printed if debug specified. */
+
+ int saveJitterCnt = 0;
+ int lookFor_df = FALSE;
+ int dfPercent = -1; /* will be >= 0 if at least one found. The init value is a flag. */
+
+ char junkStr1[500], junkStr2[500];
+
+ HandleCmdLineArgs(argc, argv);
+
+ if((fp = fopen(LogFile, "r")) == NULL)
+ {
+ printf("Unable to open input log file %s for read.\b", LogFile);
+ perror("Error:");
+ exit(1);
+ }
+
+
+
+ while(fgets(lineBuf, sizeof(lineBuf), fp) != NULL)
+ {
+ lineNo++;
+
+
+ /* Are we looking for a "df" o/p line? (to see how full
+ the flash is?)*/
+
+ /* is there a "%" in this line? */
+ if((strstr(lineBuf, "%") != NULL) && (lookFor_df))
+ {
+ converted = sscanf(lineBuf, "%s %i %i %i %i\n",
+ junkStr1, &junkInt1, &junkInt2, &junkInt3, &dfPercent);
+ if(converted < 5)
+ {
+ printf("Line %i contains \"%%\", but expected fileds not found. Skipping.\n", lineNo);
+ }else
+ {
+ /* Now print out the saved jitter values (in col2) with this dfPercent value as the col1. */
+ for(cnt = 0; cnt < saveJitterCnt; cnt++)
+ {
+ if(Debug)
+ {
+ fprintf(stderr, "%i\t%i\t%i\n", (int)dataLineNo[cnt],
+ dfPercent, (int)saveJitter[cnt]);
+ }else
+ {
+ fprintf(stderr, "%i\t%i\n", dfPercent, (int)saveJitter[cnt]);
+ }
+
+
+ }
+
+ saveJitterCnt = 0; /* all flushed. Reset for next saves. */
+ lookFor_df = FALSE;
+ }
+
+ }
+
+
+ /* is there a "ms" in this line?*/
+ if(strstr(lineBuf, "ms") == NULL)
+ {
+ continue;
+ }
+
+ /* grab the ms jitter value */
+ converted = sscanf(lineBuf, "%f %s %f %s\n", &junkFloat1, junkStr1, &jitter_ms, junkStr2);
+ if(converted < 4)
+ {
+ printf("Line %i contains \"ms\", but expected fileds not found. Converted %i, Skipping.",
+ lineNo, converted);
+ printf("1=%i, 2=%s.\n", junkInt1, junkStr1);
+ continue; /* not our jitter line*/
+ }
+
+ /* Is the jitter value > threshold value? */
+ if(abs(jitter_ms) > JitterThreshold_ms)
+ {
+ /* Found a jitter line that matches our crietrion.
+ Now set flag to be on the look out for the next
+ "df" output so that we can see how full the flash is.
+ */
+
+ if(saveJitterCnt < MAX_SAVE_BUFFER)
+ {
+ saveJitter[saveJitterCnt] = (int)abs(jitter_ms); /* why keep the (ms) jitter in float */
+ dataLineNo[saveJitterCnt] = lineNo;
+ saveJitterCnt++;
+ lookFor_df = TRUE;
+ }
+ else
+ {
+ printf("Oops! I've run out of buffer space before I found a %% use line. Dropping itter value. Increase MAX_SAVE_BUFFER and recompile.\n");
+ }
+
+
+ }
+
+ }
+
+
+ /* Now print out any saved jitter values that were not printed out because we did not find
+ and "df" after these were picked up. Only print if a "df" disk usage was ever found.
+ */
+ if(lookFor_df && (dfPercent >= 0))
+ {
+ /* Now print out the saved jitter values (in col2) with this dfPercent value as the col1. */
+ for(cnt = 0; cnt < saveJitterCnt; cnt++)
+ {
+ fprintf(stderr, "%i\t%i\n", dfPercent, (int)saveJitter[cnt]);
+ }
+ }
+
+ return 0;
+
+
+}/* end main() */
+
+
+
+
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/Makefile b/drivers/mtd/mtd-utils/tests/ubi-tests/Makefile
new file mode 100644
index 00000000000..b02dca4024a
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/Makefile
@@ -0,0 +1,48 @@
+LIBUBI_PATH=../../ubi-utils/new-utils/
+LIBUBI_SRC_PATH=../../ubi-utils/new-utils/src/
+LIBUBI_HEADER_PATH=../../ubi-utils/new-utils/include
+UBI_HEADERS_PATH=../../include/
+UBIUTILS_PATH=../../ubi-utils/new-utils/
+
+CC := $(CROSS)gcc
+
+TESTS=io_update volrefcnt integ io_paral io_read io_basic \
+ mkvol_basic mkvol_bad mkvol_paral rsvol
+
+HELPER_NAMES=ubiupdatevol
+HELPERS=$(addprefix helpers/, $(HELPER_NAMES))
+
+# Because of implicite rules we use make treats .o files as intermediate, thus
+# it removes the. If you want to prevent the removal, uncomment the below
+#.SECONDARY: $(addsuffix .o, $(TESTS)) $(addsuffix .o, $(HELPERS))
+
+CFLAGS += -Wall -I$(LIBUBI_HEADER_PATH) -I $(UBI_HEADERS_PATH) -L. -O2
+
+all: ubi-utils libubi $(TESTS) $(HELPERS)
+
+# Compile ubilib with the udevsettle hack
+libubi: $(LIBUBI_SRC_PATH)/libubi.c $(LIBUBI_HEADER_PATH)/libubi.h $(LIBUBI_SRC_PATH)/libubi_int.h
+ $(CC) $(CFLAGS) -I $(LIBUBI_SRC_PATH) -I../../include -DUDEV_SETTLE_HACK -c $(LIBUBI_SRC_PATH)/libubi.c -o libubi.o
+ ar cr libubi.a libubi.o
+
+# The below cancels existing implicite rule to make programs from .c files,
+# in order to force make using our rule defined below
+%: %.c
+
+# The below is the rule to get an .o file from a .c file
+%.o: %.c
+ $(CC) $(CFLAGS) $< -c -o $@
+
+# And the below is the rule to get final test executable from its .o and common.o
+%: %.o common.o
+ $(CC) $(CFLAGS) $^ -lubi -o $@
+
+# *paral tests require libpthread, thus the below rule for them
+%paral: %paral.o common.o
+ $(CC) $(CFLAGS) $^ -lubi -lpthread -o $@
+
+ubi-utils:
+ make -C $(UBIUTILS_PATH)
+
+clean:
+ rm -f $(TESTS) $(addsuffix .o, $(TESTS)) libubi.* $(HELPERS) $(addsuffix .o, $(HELPERS))
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/README.udev b/drivers/mtd/mtd-utils/tests/ubi-tests/README.udev
new file mode 100644
index 00000000000..06e71d37895
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/README.udev
@@ -0,0 +1,25 @@
+There is a problem with udev: when a volume is created, there is a delay
+before corresponding /dev/ubiX_Y device node is created by udev, so some
+tests fail because of this. The symptom is error messages like
+"cannot open /dev/ubi0_0".
+
+One possible solution of this problem is to pre-create UBI device and volume
+nodes. There is even a script which may be used for this in ubi-utils/scripts/.
+But this is not enough because udev will still remove and re-create the nodes
+and tests will still fail. So you need to stop removing device nodes using
+the following udev rule:
+
+ KERNEL=="ubi*_*", ACTION=="remove", OPTIONS+="ignore_device"
+
+In our Ubuntu distribution we put that to new file:
+/etc/udev/rules.d/50-local.rules
+
+Another possibility is to call udevsettle utility in libubi after the volume
+has been created See src/libubi.c - the call is compiled in only if
+UDEV_SETTLE_HACK is defined. This is anyway an ugly hack, but works, although
+makes the tests slower. Suggestions are welcome.
+
+So, if you have udevsettel unility in your system, you do not have to do
+anyting, and the tests should work, because we compile libubi with
+UDEV_SETTLE_HACK. Otherwise, you should remove -D UDEV_SETTLE_HACK
+from the makefile and pre-create UBI device nodes.
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/common.c b/drivers/mtd/mtd-utils/tests/ubi-tests/common.c
new file mode 100644
index 00000000000..a5064fb1534
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/common.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * The stuff which is common for many tests.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "libubi.h"
+#include "common.h"
+
+/**
+ * __initial_check - check that common prerequisites which are required to run
+ * tests.
+ *
+ * @test test name
+ * @argc count of command-line arguments
+ * @argv command-line arguments
+ *
+ * This function returns %0 if all is fine and test may be run and %-1 if not.
+ */
+int __initial_check(const char *test, int argc, char * const argv[])
+{
+ libubi_t libubi;
+ struct ubi_dev_info dev_info;
+
+ /*
+ * All tests require UBI character device name as the first parameter,
+ * check this.
+ */
+ if (argc < 2) {
+ __err_msg(test, __FUNCTION__, __LINE__,
+ "UBI character device node is not specified");
+ return -1;
+ }
+
+ libubi = libubi_open();
+ if (libubi == NULL) {
+ __failed(test, __FUNCTION__, __LINE__, "libubi_open");
+ return -1;
+ }
+
+ if (ubi_get_dev_info(libubi, argv[1], &dev_info)) {
+ __failed(test, __FUNCTION__, __LINE__, "ubi_get_dev_info");
+ goto close;
+ }
+
+ if (dev_info.avail_lebs < MIN_AVAIL_EBS) {
+ __err_msg(test, __FUNCTION__, __LINE__,
+ "insufficient available eraseblocks %d on UBI "
+ "device, required %d",
+ dev_info.avail_lebs, MIN_AVAIL_EBS);
+ goto close;
+ }
+
+ if (dev_info.vol_count != 0) {
+ __err_msg(test, __FUNCTION__, __LINE__,
+ "device %s is not empty", argv[1]);
+ goto close;
+ }
+
+ libubi_close(libubi);
+ return 0;
+
+close:
+ libubi_close(libubi);
+ return -1;
+}
+
+/**
+ * __err_msg - print a message to stderr.
+ *
+ * @test test name
+ * @func function name
+ * @line line number
+ * @fmt format string
+ */
+void __err_msg(const char *test, const char *func, int line,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr, "[%s] %s():%d: ", test, func, line);
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+}
+
+/**
+ * __failed - print function fail message.
+ *
+ * @test test name
+ * @func calling function name
+ * @line line number
+ * @failed failed function name
+ */
+void __failed(const char *test, const char *func, int line,
+ const char *failed)
+{
+ fprintf(stderr, "[%s] %s():%d: function %s() failed with error %d (%s)\n",
+ test, func, line, failed, errno, strerror(errno));
+}
+
+/**
+ * __check_volume - check volume information.
+ *
+ * @libubi libubi descriptor
+ * @dev_info UBI device description
+ * @test test name
+ * @func function name
+ * @line line number
+ * @vol_id ID of existing volume to check
+ * @req volume creation request to compare with
+ *
+ * This function checks if a volume created using @req request has exactly the
+ * requested characteristics. Returns 0 in case of success and %-1 in case of
+ * error.
+ */
+int __check_volume(libubi_t libubi, struct ubi_dev_info *dev_info,
+ const char *test, const char *func, int line, int vol_id,
+ const struct ubi_mkvol_request *req)
+{
+ int ret;
+ struct ubi_vol_info vol_info;
+ int leb_size;
+ long long rsvd_bytes;
+
+ ret = ubi_get_vol_info1(libubi, dev_info->dev_num, vol_id, &vol_info);
+ if (ret) {
+ __failed(test, func, line, "ubi_get_vol_info");
+ return -1;
+ }
+
+ if (req->alignment != vol_info.alignment) {
+ __err_msg(test, func, line,
+ "bad alignment: requested %d, got %d",
+ req->alignment, vol_info.alignment);
+ return -1;
+ }
+ if (req->vol_type != vol_info.type) {
+ __err_msg(test, func, line, "bad type: requested %d, got %d",
+ req->vol_type, vol_info.type);
+ return -1;
+ }
+ if (strlen(req->name) != strlen(vol_info.name) ||
+ strcmp(req->name, vol_info.name) != 0) {
+ __err_msg(test, func, line,
+ "bad name: requested \"%s\", got \"%s\"",
+ req->name, vol_info.name);
+ return -1;
+ }
+ if (vol_info.corrupted) {
+ __err_msg(test, func, line, "corrupted new volume");
+ return -1;
+ }
+
+ leb_size = dev_info->leb_size - (dev_info->leb_size % req->alignment);
+ if (leb_size != vol_info.leb_size) {
+ __err_msg(test, func, line,
+ "bad usable LEB size %d, should be %d",
+ vol_info.leb_size, leb_size);
+ return -1;
+ }
+
+ rsvd_bytes = req->bytes;
+ if (rsvd_bytes % leb_size)
+ rsvd_bytes += leb_size - (rsvd_bytes % leb_size);
+
+ if (rsvd_bytes != vol_info.rsvd_bytes) {
+ __err_msg(test, func, line,
+ "bad reserved bytes %lld, should be %lld",
+ vol_info.rsvd_bytes, rsvd_bytes);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * __check_vol_patt - check that volume contains certain data
+ *
+ * @libubi libubi descriptor
+ * @dev_info UBI device description
+ * @test test name
+ * @func function name
+ * @line line number
+ * @node volume character device node
+ * @byte data pattern to check
+ *
+ * This function returns %0 if the volume contains only @byte bytes, and %-1 if
+ * not.
+ */
+int __check_vol_patt(libubi_t libubi, struct ubi_dev_info *dev_info,
+ const char *test, const char *func, int line,
+ const char *node, uint8_t byte)
+{
+ int ret, fd;
+ long long bytes = 0;
+ struct ubi_vol_info vol_info;
+ unsigned char buf[512];
+
+ fd = open(node, O_RDONLY);
+ if (fd == -1) {
+ __failed(test, func, line, "open");
+ __err_msg(test, func, line, "cannot open \"%s\"\n", node);
+ return -1;
+ }
+
+ ret = ubi_get_vol_info(libubi, node, &vol_info);
+ if (ret) {
+ __failed(test, func, line, "ubi_get_vol_info");
+ goto close;
+ }
+
+ while (bytes < vol_info.data_bytes) {
+ int i;
+
+ memset(buf, ~byte, 512);
+ ret = read(fd, buf, 512);
+ if (ret == -1) {
+ __failed(test, func, line, "read");
+ __err_msg(test, func, line, "bytes = %lld, ret = %d",
+ bytes, ret);
+ goto close;
+ }
+
+ if (ret == 0 && bytes + ret < vol_info.data_bytes) {
+ __err_msg(test, func, line,
+ "EOF, but read only %lld bytes of %lld",
+ bytes + ret, vol_info.data_bytes);
+ goto close;
+ }
+
+ for (i = 0; i < ret; i++)
+ if (buf[i] != byte) {
+ __err_msg(test, func, line,
+ "byte at %lld is not %#x but %#x",
+ bytes + i, byte, (int)buf[i]);
+ goto close;
+ }
+
+ bytes += ret;
+ }
+
+ close(fd);
+ return 0;
+
+close:
+ close(fd);
+ return -1;
+}
+
+/**
+ * __update_vol_patt - update volume using a certain byte pattern
+ *
+ * @libubi libubi descriptor
+ * @dev_info UBI device description
+ * @test test name
+ * @func function name
+ * @line line number
+ * @node volume character device node
+ * @byte data pattern to check
+ *
+ * This function returns %0 in case of success, and %-1 if in case of failure.
+ */
+int __update_vol_patt(libubi_t libubi, const char *test, const char *func,
+ int line, const char *node, long long bytes, uint8_t byte)
+{
+ int ret, fd;
+ long long written = 0;
+ unsigned char buf[512];
+
+ fd = open(node, O_RDWR);
+ if (fd == -1) {
+ __failed(test, func, line, "open");
+ __err_msg(test, func, line, "cannot open \"%s\"\n", node);
+ return -1;
+ }
+
+ if (ubi_update_start(libubi, fd, bytes)) {
+ __failed(test, func, line, "ubi_update_start");
+ __err_msg(test, func, line, "bytes = %lld", bytes);
+ goto close;
+ }
+
+ memset(buf, byte, 512);
+
+ while (written != bytes) {
+ ret = write(fd, buf, 512);
+ if (ret == -1) {
+ __failed(test, func, line, "write");
+ __err_msg(test, func, line, "written = %lld, ret = %d",
+ written, ret);
+ goto close;
+ }
+ written += ret;
+
+ if (written > bytes) {
+ __err_msg(test, func, line, "update length %lld bytes, "
+ "but %lld bytes are already written",
+ bytes, written);
+ goto close;
+ }
+ }
+
+ close(fd);
+ return 0;
+
+close:
+ close(fd);
+ return -1;
+}
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/common.h b/drivers/mtd/mtd-utils/tests/ubi-tests/common.h
new file mode 100644
index 00000000000..3e8ada80837
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/common.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * The stuff which is common for many tests.
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UBI_VOLUME_PATTERN "/dev/ubi%d_%d"
+#define MIN_AVAIL_EBS 5
+#define PAGE_SIZE 4096
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+#define err_msg(fmt, ...) \
+ __err_msg(TESTNAME, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)
+
+#define failed(name) \
+ __failed(TESTNAME, __FUNCTION__, __LINE__, name)
+
+#define initial_check(argc, argv) \
+ __initial_check(TESTNAME, argc, argv)
+
+#define check_volume(vol_id, req) \
+ __check_volume(libubi, &dev_info, TESTNAME, __FUNCTION__, \
+ __LINE__, vol_id, req)
+
+#define check_vol_patt(node, byte) \
+ __check_vol_patt(libubi, &dev_info, TESTNAME, __FUNCTION__, __LINE__, \
+ node, byte)
+
+#define update_vol_patt(node, bytes, byte) \
+ __update_vol_patt(libubi, TESTNAME, __FUNCTION__, __LINE__, \
+ node, bytes, byte)
+
+#define check_failed(ret, error, func, fmt, ...) ({ \
+ int __ret; \
+ \
+ if (!ret) { \
+ err_msg("%s() returned success but should have failed", func); \
+ err_msg(fmt, ##__VA_ARGS__); \
+ __ret = -1; \
+ } \
+ if (errno != (error)) { \
+ err_msg("%s failed with error %d (%s), expected %d (%s)", \
+ func, errno, strerror(errno), error, strerror(error)); \
+ err_msg(fmt, ##__VA_ARGS__); \
+ __ret = -1; \
+ } \
+ __ret = 0; \
+})
+
+/* Alignments to test, @s is eraseblock size */
+#define ALIGNMENTS(s) \
+ {3, 5, 27, 666, 512, 1024, 2048, (s)/2-3, (s)/2-2, (s)/2-1, (s)/2+1, \
+ (s)/2+2, (s)/2+3, (s)/3-3, (s)/3-2, (s)/3-1, (s)/3+1, (s)/3+2, \
+ (s)/3+3, (s)/4-3, (s)/4-2, (s)/4-1, (s)/4+1, (s)/4+2, (s)/4+3, \
+ (s)/5-3, (s)/5-2, (s)/5-1, (s)/5+1, (s)/5+2, (s)/5+3, (s)-17, (s)-9, \
+ (s)-8, (s)-6, (s)-4, (s)-1, (s)};
+
+extern void __err_msg(const char *test, const char *func, int line,
+ const char *fmt, ...);
+void __failed(const char *test, const char *func, int line,
+ const char *failed);
+int __initial_check(const char *test, int argc, char * const argv[]);
+int __check_volume(libubi_t libubi, struct ubi_dev_info *dev_info,
+ const char *test, const char *func, int line, int vol_id,
+ const struct ubi_mkvol_request *req);
+int __check_vol_patt(libubi_t libubi, struct ubi_dev_info *dev_info,
+ const char *test, const char *func, int line,
+ const char *node, uint8_t byte);
+int __update_vol_patt(libubi_t libubi, const char *test, const char *func,
+ int line, const char *node, long long bytes,
+ uint8_t byte);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__COMMON_H__ */
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c b/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c
new file mode 100644
index 00000000000..e8bffabb330
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c
@@ -0,0 +1,783 @@
+#define _LARGEFILE64_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include "libubi.h"
+
+struct erase_block_info;
+struct volume_info;
+struct ubi_device_info;
+
+struct write_info
+{
+ struct write_info *next;
+ struct erase_block_info *erase_block;
+ int offset_within_block; /* Offset within erase block */
+ off64_t offset; /* Offset within volume */
+ int size;
+ int random_seed;
+};
+
+struct erase_block_info
+{
+ struct volume_info *volume;
+ int block_number;
+ off64_t offset; /* Offset within volume */
+ off64_t top_of_data;
+ int touched; /* Have we done anything at all with this erase block */
+ int erased; /* This erased block is currently erased */
+ struct write_info *writes;
+};
+
+struct volume_fd
+{
+ struct volume_fd *next;
+ struct volume_info *volume;
+ int fd;
+};
+
+struct volume_info
+{
+ struct volume_info *next;
+ struct ubi_device_info *ubi_device;
+ struct volume_fd *fds;
+ struct erase_block_info *erase_blocks;
+ const char *device_file_name;
+ struct ubi_vol_info info;
+};
+
+struct ubi_device_info
+{
+ struct volume_info *volumes;
+ const char *device_file_name;
+ struct ubi_dev_info info;
+};
+
+struct open_volume_fd
+{
+ struct open_volume_fd *next;
+ struct volume_fd *vol_fd;
+};
+
+#define MAX_UBI_DEVICES 64
+
+static libubi_t libubi;
+
+static struct ubi_info info;
+static struct ubi_device_info ubi_array[MAX_UBI_DEVICES];
+
+static uint64_t total_written = 0;
+static uint64_t total_space = 0;
+
+static struct open_volume_fd *open_volumes;
+static size_t open_volume_count = 0;
+
+static const char *ubi_module_load_string;
+
+static unsigned char *write_buffer = NULL;
+static unsigned char *read_buffer = NULL;
+
+static long long max_ebs_per_vol = 0; /* max number of ebs per vol (zero => no max) */
+
+static unsigned long next_seed = 1;
+
+static unsigned get_next_seed()
+{
+ next_seed = next_seed * 1103515245 + 12345;
+ return ((unsigned) (next_seed / 65536) % 32768);
+}
+
+static void error_exit(const char *msg)
+{
+ int eno = errno;
+ fprintf(stderr,"UBI Integrity Test Error: %s\n",msg);
+ if (eno) {
+ fprintf(stderr, "errno = %d\n", eno);
+ fprintf(stderr, "strerror = %s\n", strerror(eno));
+ }
+ exit(1);
+}
+
+static void *allocate(size_t n)
+{
+ void *p = malloc(n);
+ if (!p)
+ error_exit("Memory allocation failure");
+ memset(p, 0, n);
+ return p;
+}
+
+static unsigned get_random_number(unsigned n)
+{
+ uint64_t r, b;
+
+ if (n < 1)
+ return 0;
+ r = rand();
+ r *= n;
+ b = RAND_MAX;
+ b += 1;
+ r /= b;
+ return r;
+}
+
+static struct volume_fd *open_volume(struct volume_info *vol)
+{
+ struct volume_fd *s;
+ struct open_volume_fd *ofd;
+ int fd;
+
+ if (vol->fds) {
+ /* If already open dup it */
+ fd = dup(vol->fds->fd);
+ if (fd == -1)
+ error_exit("Failed to dup volume device file des");
+ } else {
+ fd = open(vol->device_file_name, O_RDWR | O_LARGEFILE);
+ if (fd == -1)
+ error_exit("Failed to open volume device file");
+ }
+ s = allocate(sizeof(*s));
+ s->fd = fd;
+ s->volume = vol;
+ s->next = vol->fds;
+ vol->fds = s;
+ /* Add to open volumes list */
+ ofd = allocate(sizeof(*ofd));
+ ofd->vol_fd = s;
+ ofd->next = open_volumes;
+ open_volumes = ofd;
+ open_volume_count += 1;
+ return 0;
+}
+
+static void close_volume(struct volume_fd *vol_fd)
+{
+ struct volume_fd *vfd, *vfd_last;
+ struct open_volume_fd *ofd, *ofd_last;
+ int fd = vol_fd->fd;
+
+ /* Remove from open volumes list */
+ ofd_last = NULL;
+ ofd = open_volumes;
+ while (ofd) {
+ if (ofd->vol_fd == vol_fd) {
+ if (ofd_last)
+ ofd_last->next = ofd->next;
+ else
+ open_volumes = ofd->next;
+ free(ofd);
+ open_volume_count -= 1;
+ break;
+ }
+ ofd_last = ofd;
+ ofd = ofd->next;
+ }
+ /* Remove from volume fd list */
+ vfd_last = NULL;
+ vfd = vol_fd->volume->fds;
+ while (vfd) {
+ if (vfd == vol_fd) {
+ if (vfd_last)
+ vfd_last->next = vfd->next;
+ else
+ vol_fd->volume->fds = vfd->next;
+ free(vfd);
+ break;
+ }
+ vfd_last = vfd;
+ vfd = vfd->next;
+ }
+ /* Close volume device file */
+ if (close(fd) == -1)
+ error_exit("Failed to close volume file descriptor");
+}
+
+static void set_random_data(unsigned seed, unsigned char *buf, int size)
+{
+ int i;
+ unsigned r;
+
+ r = rand();
+ srand(seed);
+ for (i = 0; i < size; ++i)
+ buf[i] = rand();
+ srand(r);
+}
+
+#if 0
+static void print_write_info(struct write_info *w)
+{
+ printf("Offset: %lld Size:%d Seed:%u\n", w->offset, w->size, w->random_seed);
+ fflush(stdout);
+}
+#endif
+
+static void check_erase_block(struct erase_block_info *erase_block, int fd)
+{
+ struct write_info *w;
+ off64_t gap_end;
+ int leb_size = erase_block->volume->info.leb_size;
+ ssize_t bytes_read;
+
+ w = erase_block->writes;
+ gap_end = erase_block->offset + leb_size;
+ while (w) {
+ if (w->offset + w->size < gap_end) {
+ /* There is a gap. Check all 0xff */
+ off64_t gap_start = w->offset + w->size;
+ size_t size = gap_end - gap_start;
+ if (lseek64(fd, gap_start, SEEK_SET) != gap_start)
+ error_exit("lseek64 failed");
+ memset(read_buffer, 0 , size);
+ errno = 0;
+ bytes_read = read(fd, read_buffer, size);
+ if (bytes_read != size)
+ error_exit("read failed in gap");
+ while (size)
+ if (read_buffer[--size] != 0xff) {
+ fprintf(stderr, "block no. = %d\n" , erase_block->block_number);
+ fprintf(stderr, "offset = %lld\n" , (long long) gap_start);
+ fprintf(stderr, "size = %ld\n" , (long) bytes_read);
+ error_exit("verify 0xff failed");
+ }
+ }
+ if (lseek64(fd, w->offset, SEEK_SET) != w->offset)
+ error_exit("lseek64 failed");
+ memset(read_buffer, 0 , w->size);
+ errno = 0;
+ bytes_read = read(fd, read_buffer, w->size);
+ if (bytes_read != w->size) {
+ fprintf(stderr, "offset = %lld\n" , (long long) w->offset);
+ fprintf(stderr, "size = %ld\n" , (long) w->size);
+ fprintf(stderr, "bytes_read = %ld\n" , (long) bytes_read);
+ error_exit("read failed");
+ }
+ set_random_data(w->random_seed, write_buffer, w->size);
+ if (memcmp(read_buffer, write_buffer, w->size))
+ error_exit("verify failed");
+ gap_end = w->offset;
+ w = w->next;
+ }
+ if (gap_end > erase_block->offset) {
+ /* Check all 0xff */
+ off64_t gap_start = erase_block->offset;
+ size_t size = gap_end - gap_start;
+ if (lseek64(fd, gap_start, SEEK_SET) != gap_start)
+ error_exit("lseek64 failed");
+ memset(read_buffer, 0 , size);
+ errno = 0;
+ bytes_read = read(fd, read_buffer, size);
+ if (bytes_read != size)
+ error_exit("read failed in gap");
+ while (size)
+ if (read_buffer[--size] != 0xff) {
+ fprintf(stderr, "block no. = %d\n" , erase_block->block_number);
+ fprintf(stderr, "offset = %lld\n" , (long long) gap_start);
+ fprintf(stderr, "size = %ld\n" , (long) bytes_read);
+ error_exit("verify 0xff failed!");
+ }
+ }
+}
+
+static int write_to_erase_block(struct erase_block_info *erase_block, int fd)
+{
+ int page_size = erase_block->volume->ubi_device->info.min_io_size;
+ int leb_size = erase_block->volume->info.leb_size;
+ int next_offset = 0;
+ int space, size;
+ off64_t offset;
+ unsigned seed;
+ struct write_info *w;
+
+ if (erase_block->writes)
+ next_offset = erase_block->writes->offset_within_block + erase_block->writes->size;
+ space = leb_size - next_offset;
+ if (space <= 0)
+ return 0; /* No space */
+ if (!get_random_number(10)) {
+ /* 1 time in 10 leave a gap */
+ next_offset += get_random_number(space);
+ next_offset = (next_offset / page_size) * page_size;
+ space = leb_size - next_offset;
+ }
+ if (get_random_number(2))
+ size = 1 * page_size;
+ else if (get_random_number(2))
+ size = 2 * page_size;
+ else if (get_random_number(2))
+ size = 3 * page_size;
+ else if (get_random_number(2))
+ size = 4 * page_size;
+ else {
+ if (get_random_number(4))
+ size = get_random_number(space);
+ else
+ size = space;
+ size = (size / page_size) * page_size;
+ }
+ if (size == 0 || size > space)
+ size = page_size;
+ if (next_offset + size > leb_size)
+ error_exit("internal error");
+ offset = erase_block->offset + next_offset;
+ if (offset < erase_block->top_of_data)
+ error_exit("internal error!");
+ if (lseek64(fd, offset, SEEK_SET) != offset)
+ error_exit("lseek64 failed");
+ /* Do write */
+ seed = get_next_seed();
+ if (!seed)
+ seed = 1;
+ set_random_data(seed, write_buffer, size);
+ if (write(fd, write_buffer, size) != size)
+ error_exit("write failed");
+ erase_block->top_of_data = offset + size;
+ /* Make write info and add to eb */
+ w = allocate(sizeof(*w));
+ w->offset_within_block = next_offset;
+ w->offset = offset;
+ w->size = size;
+ w->random_seed = seed;
+ w->next = erase_block->writes;
+ erase_block->writes = w;
+ erase_block->touched = 1;
+ erase_block->erased = 0;
+ total_written += size;
+ return 1;
+}
+
+static void erase_erase_block(struct erase_block_info *erase_block, int fd)
+{
+ struct write_info *w;
+ uint32_t eb_no;
+ int res;
+
+ eb_no = erase_block->block_number;
+ res = ioctl(fd, UBI_IOCEBER, &eb_no);
+ if (res)
+ error_exit("Failed to erase an erase block");
+ /* Remove writes from this eb */
+ while (erase_block->writes) {
+ w = erase_block->writes;
+ erase_block->writes = erase_block->writes->next;
+ free(w);
+ }
+ erase_block->erased = 1;
+ erase_block->touched = 1;
+ erase_block->top_of_data = erase_block->offset;
+}
+
+static void operate_on_erase_block(struct erase_block_info *erase_block, int fd)
+{
+ /*
+ Possible operations:
+ read from it and verify
+ write to it
+ erase it
+ */
+ int work_done = 1;
+ static int no_work_done_count = 0;
+
+ if (!get_random_number(10) && no_work_done_count <= 5) {
+ check_erase_block(erase_block, fd);
+ work_done = 0;
+ } else if (get_random_number(100)) {
+ if (!write_to_erase_block(erase_block, fd)) {
+ /* The erase block was full */
+ if (get_random_number(2) || no_work_done_count > 5)
+ erase_erase_block(erase_block, fd);
+ else
+ work_done = 0;
+ }
+ } else
+ erase_erase_block(erase_block, fd);
+ if (work_done)
+ no_work_done_count = 0;
+ else
+ no_work_done_count += 1;
+}
+
+static void operate_on_open_volume(struct volume_fd *vol_fd)
+{
+ /*
+ Possible operations:
+ operate on an erase block
+ close volume
+ */
+ if (get_random_number(100) == 0)
+ close_volume(vol_fd);
+ else {
+ /* Pick an erase block at random */
+ int eb_no = get_random_number(vol_fd->volume->info.rsvd_lebs);
+ operate_on_erase_block(&vol_fd->volume->erase_blocks[eb_no], vol_fd->fd);
+ }
+}
+
+static void operate_on_volume(struct volume_info *vol)
+{
+ /*
+ Possible operations:
+ open it
+ resize it (must close fd's first) <- TODO
+ delete it (must close fd's first) <- TODO
+ */
+ open_volume(vol);
+}
+
+static int ubi_major(const char *device_file_name)
+{
+ struct stat buf;
+ static int maj = 0;
+
+ if (maj)
+ return maj;
+ if (stat(device_file_name, &buf) == -1)
+ error_exit("Failed to stat ubi device file");
+ maj = major(buf.st_rdev);
+ return maj;
+}
+
+static void operate_on_ubi_device(struct ubi_device_info *ubi_device)
+{
+ /*
+ TODO:
+ Possible operations:
+ create a new volume
+ operate on existing volume
+ */
+ /*
+ Simplified operation (i.e. only have 1 volume):
+ If there are no volumes create 1 volumne
+ Then operate on the volume
+ */
+ if (ubi_device->info.vol_count == 0) {
+ /* Create the one-and-only volume we will use */
+ char dev_name[1024];
+ int i, n, maj, fd;
+ struct volume_info *s;
+ struct ubi_mkvol_request req;
+
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.alignment = 1; /* TODO: What is this? */
+ req.bytes = ubi_device->info.leb_size * max_ebs_per_vol;
+ if (req.bytes == 0 || req.bytes > ubi_device->info.avail_bytes)
+ req.bytes = ubi_device->info.avail_bytes;
+ req.vol_type = UBI_DYNAMIC_VOLUME;
+ req.name = "integ-test-vol";
+ if (ubi_mkvol(libubi, ubi_device->device_file_name, &req))
+ error_exit("ubi_mkvol failed");
+ s = allocate(sizeof(*s));
+ s->ubi_device = ubi_device;
+ if (ubi_get_vol_info1(libubi, ubi_device->info.dev_num, req.vol_id, &s->info))
+ error_exit("ubi_get_vol_info failed");
+ n = s->info.rsvd_lebs;
+ s->erase_blocks = allocate(sizeof(struct erase_block_info) * n);
+ for (i = 0; i < n; ++i) {
+ s->erase_blocks[i].volume = s;
+ s->erase_blocks[i].block_number = i;
+ s->erase_blocks[i].offset = i * (off64_t) s->info.leb_size;
+ s->erase_blocks[i].top_of_data = s->erase_blocks[i].offset;
+ }
+ /* FIXME: Correctly get device file name */
+ sprintf(dev_name, "%s_%d", ubi_device->device_file_name, req.vol_id);
+ s->device_file_name = strdup(dev_name);
+ ubi_device->volumes = s;
+ ubi_device->info.vol_count += 1;
+ sleep(1);
+ fd = open(s->device_file_name, O_RDONLY);
+ if (fd == -1) {
+ /* FIXME: Correctly make node */
+ maj = ubi_major(ubi_device->device_file_name);
+ sprintf(dev_name, "mknod %s c %d %d", s->device_file_name, maj, req.vol_id + 1);
+ system(dev_name);
+ } else if (close(fd) == -1)
+ error_exit("Failed to close volume device file");
+ }
+ operate_on_volume(ubi_device->volumes);
+}
+
+static void do_an_operation(void)
+{
+ int too_few = (open_volume_count < info.dev_count * 3);
+ int too_many = (open_volume_count > info.dev_count * 5);
+
+ if (too_many || (!too_few && get_random_number(1000) > 0)) {
+ /* Operate on an open volume */
+ size_t pos;
+ struct open_volume_fd *ofd;
+ pos = get_random_number(open_volume_count);
+ for (ofd = open_volumes; pos && ofd && ofd->next; --pos)
+ ofd = ofd->next;
+ operate_on_open_volume(ofd->vol_fd);
+ } else if (info.dev_count > 0) {
+ /* Operate on a ubi device */
+ size_t ubi_pos = 0;
+ if (info.dev_count > 1)
+ ubi_pos = get_random_number(info.dev_count - 1);
+ operate_on_ubi_device(&ubi_array[ubi_pos]);
+ } else
+ error_exit("Internal error");
+}
+
+static void get_ubi_devices_info(void)
+{
+ int i, ubi_pos = 0;
+ char dev_name[1024];
+ size_t buf_size = 1024 * 128;
+
+ if (ubi_get_info(libubi, &info))
+ error_exit("ubi_get_info failed");
+ if (info.dev_count > MAX_UBI_DEVICES)
+ error_exit("Too many ubi devices");
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; ++i) {
+ struct ubi_device_info *s;
+ s = &ubi_array[ubi_pos++];
+ if (ubi_get_dev_info1(libubi, i, &s->info))
+ error_exit("ubi_get_dev_info1 failed");
+ if (s->info.vol_count)
+ error_exit("There are existing volumes");
+ /* FIXME: Correctly get device file name */
+ sprintf(dev_name, "/dev/ubi%d", i);
+ s->device_file_name = strdup(dev_name);
+ if (buf_size < s->info.leb_size)
+ buf_size = s->info.leb_size;
+ if (max_ebs_per_vol && s->info.leb_size * max_ebs_per_vol < s->info.avail_bytes)
+ total_space += s->info.leb_size * max_ebs_per_vol;
+ else
+ total_space += s->info.avail_bytes;
+ }
+ write_buffer = allocate(buf_size);
+ read_buffer = allocate(buf_size);
+}
+
+static void load_ubi(void)
+{
+ system("rmmod ubi");
+ if (system(ubi_module_load_string) != 0)
+ error_exit("Failed to load UBI module");
+ sleep(1);
+}
+
+static void do_some_operations(void)
+{
+ unsigned i = 0;
+ total_written = 0;
+ printf("Total space: %llu\n", (unsigned long long) total_space);
+ while (total_written < total_space * 3) {
+ do_an_operation();
+ if (i++ % 10000 == 0)
+ printf("Total written: %llu\n", (unsigned long long) total_written);
+ }
+ printf("Total written: %llu\n", (unsigned long long) total_written);
+}
+
+static void reload_ubi(void)
+{
+ /* Remove module */
+ if (system("rmmod ubi") != 0)
+ error_exit("Failed to remove UBI module");
+ /* Install module */
+ if (system(ubi_module_load_string) != 0)
+ error_exit("Failed to load UBI module");
+ sleep(1);
+}
+
+static void check_volume(struct volume_info *vol)
+{
+ struct erase_block_info *eb = vol->erase_blocks;
+ int pos;
+ int fd;
+
+ fd = open(vol->device_file_name, O_RDWR | O_LARGEFILE);
+ if (fd == -1)
+ error_exit("Failed to open volume device file");
+ for (pos = 0; pos < vol->info.rsvd_lebs; ++pos)
+ check_erase_block(eb++, fd);
+ if (close(fd) == -1)
+ error_exit("Failed to close volume device file");
+}
+
+static void check_ubi_device(struct ubi_device_info *ubi_device)
+{
+ struct volume_info *vol;
+
+ vol = ubi_device->volumes;
+ while (vol) {
+ check_volume(vol);
+ vol = vol->next;
+ }
+}
+
+static void check_ubi(void)
+{
+ int i;
+
+ for (i = 0; i < info.dev_count; ++i)
+ check_ubi_device(&ubi_array[i]);
+}
+
+static int is_all_digits(const char *s)
+{
+ const char *digits = "0123456789";
+ if (!s || !*s)
+ return 0;
+ for (;*s;++s)
+ if (!strchr(digits,*s))
+ return 0;
+ return 1;
+}
+
+static int get_short_arg(int *pos,const char *name,long long *result,int argc,char *argv[])
+{
+ const char *p = NULL;
+ int i = *pos;
+ size_t n = strlen(name);
+
+ if (strlen(argv[i]) > n)
+ p = argv[i] + n;
+ else if (++i < argc)
+ p = argv[i];
+ if (!is_all_digits(p))
+ return 1;
+ *result = atoll(p);
+ *pos = i;
+ return 0;
+}
+
+static int get_long_arg(int *pos,const char *name,long long *result,int argc,char *argv[])
+{
+ const char *p = NULL;
+ int i = *pos;
+ size_t n = strlen(name);
+
+ if (strlen(argv[i]) > n)
+ p = argv[i] + n;
+ else if (++i < argc)
+ p = argv[i];
+ if (p && *p == '=') {
+ p += 1;
+ if (!*p && ++i < argc)
+ p = argv[i];
+ }
+ if (!is_all_digits(p))
+ return 1;
+ *result = atoll(p);
+ *pos = i;
+ return 0;
+}
+
+static int remove_all_volumes(void)
+{
+ int i;
+
+ for (i = 0; i < info.dev_count; ++i) {
+ struct ubi_device_info *ubi_device = &ubi_array[i];
+ struct volume_info *vol;
+ vol = ubi_device->volumes;
+ while (vol) {
+ int res = ubi_rmvol(libubi,
+ ubi_device->device_file_name,
+ vol->info.vol_id);
+ if (res)
+ return res;
+ vol = vol->next;
+ }
+ }
+ return 0;
+}
+
+int main(int argc,char *argv[])
+{
+ int i;
+ long long r, repeat = 1;
+ int initial_seed = 1, args_ok = 1;
+
+ printf("UBI Integrity Test\n");
+
+ /* Get arguments */
+ ubi_module_load_string = 0;
+ for (i = 1; i < argc; ++i) {
+ if (strncmp(argv[i], "-h", 2) == 0)
+ args_ok = 0;
+ else if (strncmp(argv[i], "--help", 6) == 0)
+ args_ok = 0;
+ else if (strncmp(argv[i], "-n", 2) == 0) {
+ if (get_short_arg(&i, "-n", &repeat, argc, argv))
+ args_ok = 0;
+ } else if (strncmp(argv[i], "--repeat", 8) == 0) {
+ if (get_long_arg(&i, "--repeat", &repeat, argc, argv))
+ args_ok = 0;
+ } else if (strncmp(argv[i], "-m", 2) == 0) {
+ if (get_short_arg(&i,"-m", &max_ebs_per_vol, argc, argv))
+ args_ok = 0;
+ } else if (strncmp(argv[i], "--maxebs", 8) == 0) {
+ if (get_long_arg(&i, "--maxebs", &max_ebs_per_vol, argc, argv))
+ args_ok = 0;
+ } else if (!ubi_module_load_string)
+ ubi_module_load_string = argv[i];
+ else
+ args_ok = 0;
+ }
+ if (!args_ok || !ubi_module_load_string) {
+ fprintf(stderr, "Usage is: ubi_integ [<options>] <UBI Module load command>\n");
+ fprintf(stderr, " Options: \n");
+ fprintf(stderr, " -h, --help Help\n");
+ fprintf(stderr, " -n arg, --repeat=arg Repeat test arg times\n");
+ fprintf(stderr, " -m arg, --maxebs=arg Max no. of erase blocks\n");
+ return 1;
+ }
+
+ initial_seed = getpid();
+ printf("Initial seed = %u\n", (unsigned) initial_seed);
+ next_seed = initial_seed;
+ srand(initial_seed);
+ load_ubi();
+
+ libubi = libubi_open();
+ if (!libubi)
+ error_exit("Failed to open libubi");
+
+ get_ubi_devices_info();
+
+ r = 0;
+ while (repeat == 0 || r++ < repeat) {
+ printf("Cycle %lld\n", r);
+ do_some_operations();
+
+ /* Close all volumes */
+ while (open_volumes)
+ close_volume(open_volumes->vol_fd);
+
+ check_ubi();
+
+ libubi_close(libubi);
+
+ reload_ubi();
+
+ libubi = libubi_open();
+ if (!libubi)
+ error_exit("Failed to open libubi");
+
+ check_ubi();
+ }
+
+ if (remove_all_volumes())
+ error_exit("Failed to remove all volumes");
+
+ libubi_close(libubi);
+
+ printf("UBI Integrity Test completed ok\n");
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c b/drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c
new file mode 100644
index 00000000000..256b71b0732
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * Test basic UBI volume I/O capabilities.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "libubi.h"
+#define TESTNAME "io_basic"
+#include "common.h"
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+
+/**
+ * test_basic - check basic volume read and update capabilities.
+ *
+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_basic(int type)
+{
+ struct ubi_mkvol_request req;
+ const char *name = TESTNAME ":test_basic()";
+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.alignment = 1;
+ req.bytes = dev_info.avail_bytes;
+ req.vol_type = type;
+ req.name = name;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return -1;
+ }
+
+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id);
+
+ /* Make sure newly created volume contains only 0xFF bytes */
+ if (check_vol_patt(vol_node, 0xFF))
+ goto remove;
+
+ /* Write 0xA5 bytes to the volume */
+ if (update_vol_patt(vol_node, dev_info.avail_bytes, 0xA5))
+ goto remove;
+ if (check_vol_patt(vol_node, 0xA5))
+ goto remove;
+
+ if (ubi_rmvol(libubi, node, req.vol_id)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+
+ return 0;
+
+remove:
+ ubi_rmvol(libubi, node, req.vol_id);
+ return -1;
+}
+
+/**
+ * test_aligned - test volume alignment feature.
+ *
+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_aligned(int type)
+{
+ int i, ebsz;
+ struct ubi_mkvol_request req;
+ const char *name = TESTNAME ":test_aligned()";
+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+ int alignments[] = ALIGNMENTS(dev_info.leb_size);
+
+ req.vol_type = type;
+ req.name = name;
+
+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) {
+ req.vol_id = UBI_VOL_NUM_AUTO;
+
+ req.alignment = alignments[i];
+ req.alignment -= req.alignment % dev_info.min_io_size;
+ if (req.alignment == 0)
+ req.alignment = dev_info.min_io_size;
+
+ ebsz = dev_info.leb_size - dev_info.leb_size % req.alignment;
+ req.bytes = MIN_AVAIL_EBS * ebsz;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return -1;
+ }
+
+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id);
+
+ /* Make sure newly created volume contains only 0xFF bytes */
+ if (check_vol_patt(vol_node, 0xFF))
+ goto remove;
+
+ /* Write 0xA5 bytes to the volume */
+ if (update_vol_patt(vol_node, req.bytes, 0xA5))
+ goto remove;
+ if (check_vol_patt(vol_node, 0xA5))
+ goto remove;
+
+ if (ubi_rmvol(libubi, node, req.vol_id)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+ }
+
+ return 0;
+
+remove:
+ ubi_rmvol(libubi, node, req.vol_id);
+ return -1;
+}
+
+int main(int argc, char * const argv[])
+{
+ if (initial_check(argc, argv))
+ return 1;
+
+ node = argv[1];
+
+ libubi = libubi_open();
+ if (libubi == NULL) {
+ failed("libubi_open");
+ return 1;
+ }
+
+ if (ubi_get_dev_info(libubi, node, &dev_info)) {
+ failed("ubi_get_dev_info");
+ goto close;
+ }
+
+ if (test_basic(UBI_DYNAMIC_VOLUME))
+ goto close;
+ if (test_basic(UBI_STATIC_VOLUME))
+ goto close;
+ if (test_aligned(UBI_DYNAMIC_VOLUME))
+ goto close;
+ if (test_aligned(UBI_STATIC_VOLUME))
+ goto close;
+
+ libubi_close(libubi);
+ return 0;
+
+close:
+ libubi_close(libubi);
+ return 1;
+}
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c b/drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c
new file mode 100644
index 00000000000..7b0c3d9bb7b
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * This test does a lot of I/O to volumes in parallel.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "libubi.h"
+#define TESTNAME "io_paral"
+#include "common.h"
+
+#define THREADS_NUM 3
+#define ITERATIONS 10
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+static int iterations = ITERATIONS;
+int total_bytes;
+
+static long long memory_limit(void)
+{
+ long long result = 0;
+ FILE *f;
+
+ f = fopen("/proc/meminfo", "r");
+ if (!f)
+ return 0;
+ fscanf(f, "%*s %lld", &result);
+ fclose(f);
+ return result * 1024 / 4;
+}
+
+/**
+ * the_thread - the testing thread.
+ *
+ * @ptr thread number
+ */
+static void * the_thread(void *ptr)
+{
+ int fd, iter = iterations, vol_id = (int)ptr;
+ unsigned char *wbuf, *rbuf;
+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+
+ wbuf = malloc(total_bytes);
+ rbuf = malloc(total_bytes);
+ if (!wbuf || !rbuf) {
+ failed("malloc");
+ goto free;
+ }
+
+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, vol_id);
+
+ while (iter--) {
+ int i, ret, written = 0, rd = 0;
+ int bytes = (random() % (total_bytes - 1)) + 1;
+
+ fd = open(vol_node, O_RDWR);
+ if (fd == -1) {
+ failed("open");
+ err_msg("cannot open \"%s\"\n", node);
+ goto free;
+ }
+
+ for (i = 0; i < bytes; i++)
+ wbuf[i] = random() % 255;
+ memset(rbuf, '\0', bytes);
+
+ do {
+ ret = ubi_update_start(libubi, fd, bytes);
+ if (ret && errno != EBUSY) {
+ failed("ubi_update_start");
+ err_msg("vol_id %d", vol_id);
+ goto close;
+ }
+ } while (ret);
+
+ while (written < bytes) {
+ int to_write = random() % (bytes - written);
+
+ if (to_write == 0)
+ to_write = 1;
+
+ ret = write(fd, wbuf, to_write);
+ if (ret != to_write) {
+ failed("write");
+ err_msg("failed to write %d bytes at offset %d "
+ "of volume %d", to_write, written,
+ vol_id);
+ err_msg("update: %d bytes", bytes);
+ goto close;
+ }
+
+ written += to_write;
+ }
+
+ close(fd);
+
+ fd = open(vol_node, O_RDONLY);
+ if (fd == -1) {
+ failed("open");
+ err_msg("cannot open \"%s\"\n", node);
+ goto free;
+ }
+
+ /* read data back and check */
+ while (rd < bytes) {
+ int to_read = random() % (bytes - rd);
+
+ if (to_read == 0)
+ to_read = 1;
+
+ ret = read(fd, rbuf, to_read);
+ if (ret != to_read) {
+ failed("read");
+ err_msg("failed to read %d bytes at offset %d "
+ "of volume %d", to_read, rd, vol_id);
+ goto close;
+ }
+
+ rd += to_read;
+ }
+
+ close(fd);
+
+ }
+
+ free(wbuf);
+ free(rbuf);
+ return NULL;
+
+close:
+ close(fd);
+free:
+ free(wbuf);
+ free(rbuf);
+ return NULL;
+}
+
+int main(int argc, char * const argv[])
+{
+ int i, ret;
+ pthread_t threads[THREADS_NUM];
+ struct ubi_mkvol_request req;
+ long long mem_limit;
+
+ if (initial_check(argc, argv))
+ return 1;
+
+ node = argv[1];
+
+ libubi = libubi_open();
+ if (libubi == NULL) {
+ failed("libubi_open");
+ return 1;
+ }
+
+ if (ubi_get_dev_info(libubi, node, &dev_info)) {
+ failed("ubi_get_dev_info");
+ goto close;
+ }
+
+ req.alignment = 1;
+ mem_limit = memory_limit();
+ if (mem_limit && mem_limit < dev_info.avail_bytes)
+ total_bytes = req.bytes =
+ (mem_limit / dev_info.leb_size / THREADS_NUM)
+ * dev_info.leb_size;
+ else
+ total_bytes = req.bytes =
+ ((dev_info.avail_lebs - 3) / THREADS_NUM)
+ * dev_info.leb_size;
+ for (i = 0; i < THREADS_NUM; i++) {
+ char name[100];
+
+ req.vol_id = i;
+ sprintf(name, TESTNAME":%d", i);
+ req.name = name;
+ req.vol_type = (i & 1) ? UBI_STATIC_VOLUME : UBI_DYNAMIC_VOLUME;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ goto remove;
+ }
+ }
+
+ /* Create one volume with static data to make WL work more */
+ req.vol_id = THREADS_NUM;
+ req.name = TESTNAME ":static";
+ req.vol_type = UBI_DYNAMIC_VOLUME;
+ req.bytes = 3*dev_info.leb_size;
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ goto remove;
+ }
+
+ for (i = 0; i < THREADS_NUM; i++) {
+ ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i);
+ if (ret) {
+ failed("pthread_create");
+ goto remove;
+ }
+ }
+
+ for (i = 0; i < THREADS_NUM; i++)
+ pthread_join(threads[i], NULL);
+
+ for (i = 0; i <= THREADS_NUM; i++) {
+ if (ubi_rmvol(libubi, node, i)) {
+ failed("ubi_rmvol");
+ goto remove;
+ }
+ }
+
+ libubi_close(libubi);
+ return 0;
+
+remove:
+ for (i = 0; i <= THREADS_NUM; i++)
+ ubi_rmvol(libubi, node, i);
+
+close:
+ libubi_close(libubi);
+ return 1;
+}
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c b/drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c
new file mode 100644
index 00000000000..57a8da7dafc
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * Test UBI volume read.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "libubi.h"
+#define TESTNAME "io_basic"
+#include "common.h"
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+static int fd;
+
+/* Data lengthes to test, @io - minimal I/O unit size, @s - eraseblock size */
+#define LENGTHES(io, s) \
+ {1, (io), (io)+1, 2*(io), 3*(io)-1, 3*(io), \
+ PAGE_SIZE-1, PAGE_SIZE-(io), 2*PAGE_SIZE, 2*PAGE_SIZE-(io), \
+ (s)/2-1, (s)/2, (s)/2+1, (s)-1, (s), (s)+1, 2*(s)-(io), 2*(s), \
+ 2*(s)+(io), 3*(s), 3*(s)+(io)};
+
+/*
+ * Offsets to test, @io - minimal I/O unit size, @s - eraseblock size, @sz -
+ * volume size.
+ */
+#define OFFSETS(io, s, sz) \
+ {0, (io)-1, (io), (io)+1, 2*(io)-1, 2*(io), 3*(io)-1, 3*(io), \
+ PAGE_SIZE-1, PAGE_SIZE-(io), 2*PAGE_SIZE, 2*PAGE_SIZE-(io), \
+ (s)/2-1, (s)/2, (s)/2+1, (s)-1, (s), (s)+1, 2*(s)-(io), 2*(s), \
+ 2*(s)+(io), 3*(s), (sz)-(s)-1, (sz)-(io)-1, (sz)-PAGE_SIZE-1};
+
+/**
+ * test_static - test static volume-specific features.
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_static(void)
+{
+ struct ubi_mkvol_request req;
+ const char *name = TESTNAME ":io_basic()";
+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+ struct ubi_vol_info vol_info;
+ int fd, ret;
+ char buf[20];
+
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.alignment = 1;
+ req.bytes = dev_info.avail_bytes;
+ req.vol_type = UBI_STATIC_VOLUME;
+ req.name = name;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return -1;
+ }
+
+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id);
+
+ fd = open(vol_node, O_RDWR);
+ if (fd == -1) {
+ failed("open");
+ err_msg("cannot open \"%s\"\n", node);
+ goto remove;
+ }
+
+ if (ubi_get_vol_info(libubi, vol_node, &vol_info)) {
+ failed("ubi_get_vol_info");
+ goto close;
+ }
+
+ /* Make sure new static volume contains no data */
+ if (vol_info.data_bytes != 0) {
+ err_msg("data_bytes = %lld, not zero", vol_info.data_bytes);
+ goto close;
+ }
+
+ /* Ensure read returns EOF */
+ ret = read(fd, buf, 1);
+ if (ret < 0) {
+ failed("read");
+ goto close;
+ }
+ if (ret != 0) {
+ err_msg("read data from free static volume");
+ goto close;
+ }
+
+ if (ubi_update_start(libubi, fd, 10)) {
+ failed("ubi_update_start");
+ goto close;
+ }
+
+ ret = write(fd, buf, 10);
+ if (ret < 0) {
+ failed("write");
+ goto close;
+ }
+ if (ret != 10) {
+ err_msg("written %d bytes", ret);
+ goto close;
+ }
+
+ if (lseek(fd, 0, SEEK_SET) != 0) {
+ failed("seek");
+ goto close;
+ }
+ ret = read(fd, buf, 20);
+ if (ret < 0) {
+ failed("read");
+ goto close;
+ }
+ if (ret != 10) {
+ err_msg("read %d bytes", ret);
+ goto close;
+ }
+
+ close(fd);
+ if (ubi_rmvol(libubi, node, req.vol_id)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+
+ return 0;
+
+close:
+ close(fd);
+remove:
+ ubi_rmvol(libubi, node, req.vol_id);
+ return -1;
+}
+
+/*
+ * A helper function for test_read2().
+ */
+static int test_read3(const struct ubi_vol_info *vol_info, int len, off_t off)
+{
+ int i, len1;
+ unsigned char ck_buf[len], buf[len];
+ off_t new_off;
+
+ if (off + len > vol_info->data_bytes)
+ len1 = vol_info->data_bytes - off;
+ else
+ len1 = len;
+
+ if (lseek(fd, off, SEEK_SET) != off) {
+ failed("seek");
+ err_msg("len = %d", len);
+ return -1;
+ }
+ if (read(fd, buf, len) != len1) {
+ failed("read");
+ err_msg("len = %d", len);
+ return -1;
+ }
+
+ new_off = lseek(fd, 0, SEEK_CUR);
+ if (new_off != off + len1) {
+ if (new_off == -1)
+ failed("lseek");
+ else
+ err_msg("read %d bytes from %lld, but resulting "
+ "offset is %lld", len1, (long long) off, (long long) new_off);
+ return -1;
+ }
+
+ for (i = 0; i < len1; i++)
+ ck_buf[i] = (unsigned char)(off + i);
+
+ if (memcmp(buf, ck_buf, len1)) {
+ err_msg("incorrect data read from offset %lld",
+ (long long)off);
+ err_msg("len = %d", len);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * A helper function for test_read1().
+ */
+static int test_read2(const struct ubi_vol_info *vol_info, int len)
+{
+ int i;
+ off_t offsets[] = OFFSETS(dev_info.min_io_size, vol_info->leb_size,
+ vol_info->data_bytes);
+
+ for (i = 0; i < sizeof(offsets)/sizeof(off_t); i++) {
+ if (test_read3(vol_info, len, offsets[i])) {
+ err_msg("offset = %d", offsets[i]);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * A helper function for test_read().
+ */
+static int test_read1(struct ubi_vol_info *vol_info)
+{
+ int i, written = 0;
+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+ int lengthes[] = LENGTHES(dev_info.min_io_size, vol_info->leb_size);
+
+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num,
+ vol_info->vol_id);
+
+ fd = open(vol_node, O_RDWR);
+ if (fd == -1) {
+ failed("open");
+ err_msg("cannot open \"%s\"\n", node);
+ return -1;
+ }
+
+ /* Write some pattern to the volume */
+ if (ubi_update_start(libubi, fd, vol_info->rsvd_bytes)) {
+ failed("ubi_update_start");
+ err_msg("bytes = %lld", vol_info->rsvd_bytes);
+ goto close;
+ }
+
+ while (written < vol_info->rsvd_bytes) {
+ int i, ret;
+ unsigned char buf[512];
+
+ for (i = 0; i < 512; i++)
+ buf[i] = (unsigned char)(written + i);
+
+ ret = write(fd, buf, 512);
+ if (ret == -1) {
+ failed("write");
+ err_msg("written = %d, ret = %d", written, ret);
+ goto close;
+ }
+ written += ret;
+ }
+
+ close(fd);
+
+ if (ubi_get_vol_info(libubi, vol_node, vol_info)) {
+ failed("ubi_get_vol_info");
+ return -1;
+ }
+
+ fd = open(vol_node, O_RDONLY);
+ if (fd == -1) {
+ failed("open");
+ err_msg("cannot open \"%s\"\n", node);
+ return -1;
+ }
+
+ for (i = 0; i < sizeof(lengthes)/sizeof(int); i++) {
+ if (test_read2(vol_info, lengthes[i])) {
+ err_msg("length = %d", lengthes[i]);
+ goto close;
+ }
+ }
+
+ close(fd);
+ return 0;
+
+close:
+ close(fd);
+ return -1;
+}
+
+/**
+ * test_read - test UBI volume reading from different offsets.
+ *
+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_read(int type)
+{
+ const char *name = TESTNAME ":test_read()";
+ int alignments[] = ALIGNMENTS(dev_info.leb_size);
+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+ struct ubi_mkvol_request req;
+ int i;
+
+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) {
+ int leb_size;
+ struct ubi_vol_info vol_info;
+
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.vol_type = type;
+ req.name = name;
+
+ req.alignment = alignments[i];
+ req.alignment -= req.alignment % dev_info.min_io_size;
+ if (req.alignment == 0)
+ req.alignment = dev_info.min_io_size;
+
+ leb_size = dev_info.leb_size - dev_info.leb_size % req.alignment;
+ req.bytes = MIN_AVAIL_EBS * leb_size;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return -1;
+ }
+
+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num,
+ req.vol_id);
+
+ if (ubi_get_vol_info(libubi, vol_node, &vol_info)) {
+ failed("ubi_get_vol_info");
+ goto remove;
+ }
+
+ if (test_read1(&vol_info)) {
+ err_msg("alignment = %d", req.alignment);
+ goto remove;
+ }
+
+ if (ubi_rmvol(libubi, node, req.vol_id)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+ }
+
+ return 0;
+
+remove:
+ ubi_rmvol(libubi, node, req.vol_id);
+ return -1;
+}
+
+int main(int argc, char * const argv[])
+{
+ if (initial_check(argc, argv))
+ return 1;
+
+ node = argv[1];
+
+ libubi = libubi_open();
+ if (libubi == NULL) {
+ failed("libubi_open");
+ return 1;
+ }
+
+ if (ubi_get_dev_info(libubi, node, &dev_info)) {
+ failed("ubi_get_dev_info");
+ goto close;
+ }
+
+ if (test_static())
+ goto close;
+ if (test_read(UBI_DYNAMIC_VOLUME))
+ goto close;
+ if (test_read(UBI_STATIC_VOLUME))
+ goto close;
+
+ libubi_close(libubi);
+ return 0;
+
+close:
+ libubi_close(libubi);
+ return 1;
+}
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c b/drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c
new file mode 100644
index 00000000000..f7a122efe2f
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * Test UBI volume update and atomic LEB change
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <libubi.h>
+#include <mtd/ubi-user.h>
+#define TESTNAME "io_update"
+#include "common.h"
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+
+#define SEQUENCES(io, s) { \
+ {3*(s)-(io)-1, 1}, \
+ {512}, \
+ {666}, \
+ {2048}, \
+ {(io), (io), PAGE_SIZE}, \
+ {(io)+1, (io)+1, PAGE_SIZE}, \
+ {PAGE_SIZE}, \
+ {PAGE_SIZE-1}, \
+ {PAGE_SIZE+(io)}, \
+ {(s)}, \
+ {(s)-1}, \
+ {(s)+1}, \
+ {(io), (s)+1}, \
+ {(s)+(io), PAGE_SIZE}, \
+ {2*(s), PAGE_SIZE}, \
+ {PAGE_SIZE, 2*(s), 1}, \
+ {PAGE_SIZE, 2*(s)}, \
+ {2*(s)-1, 2*(s)-1}, \
+ {3*(s), PAGE_SIZE + 1}, \
+ {1, PAGE_SIZE}, \
+ {(io), (s)} \
+}
+
+#define SEQ_SZ 21
+
+/*
+ * test_update1 - helper function for test_update().
+ */
+static int test_update1(struct ubi_vol_info *vol_info, int leb_change)
+{
+ long long total_len = leb_change ? vol_info->leb_size
+ : vol_info->rsvd_bytes;
+ int sequences[SEQ_SZ][3] = SEQUENCES(dev_info.min_io_size,
+ leb_change ? dev_info.min_io_size * 2
+ : vol_info->leb_size);
+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+ unsigned char buf[total_len];
+ int fd, i, j;
+
+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num,
+ vol_info->vol_id);
+
+ fd = open(vol_node, O_RDWR);
+ if (fd == -1) {
+ failed("open");
+ err_msg("cannot open \"%s\"\n", node);
+ return -1;
+ }
+
+ for (i = 0; i < SEQ_SZ; i++) {
+ int ret, stop = 0, len = 0;
+ off_t off = 0;
+ long long test_len;
+ unsigned char buf1[total_len];
+
+ /*
+ * test_len is LEB size (if we test atomic LEB change) or
+ * volume size (if we test update). For better test coverage,
+ * use a little smaller LEB change/update length.
+ */
+ test_len = total_len - (rand() % (total_len / 10));
+
+ if (leb_change) {
+ if (ubi_leb_change_start(libubi, fd, 0, test_len,
+ UBI_SHORTTERM)) {
+ failed("ubi_update_start");
+ goto close;
+ }
+ } else {
+ if (ubi_update_start(libubi, fd, test_len)) {
+ failed("ubi_update_start");
+ goto close;
+ }
+ }
+
+ for (j = 0; off < test_len; j++) {
+ int n, rnd_len, l;
+
+ if (!stop) {
+ if (sequences[i][j] != 0)
+ l = len = sequences[i][j];
+ else
+ stop = 1;
+ }
+
+ /*
+ * Fill some part of the write buffer with random data,
+ * and the other part with 0xFFs to test how UBI
+ * stripes 0xFFs multiple of I/O unit size.
+ */
+ if (off + l > test_len)
+ l = test_len - off;
+ rnd_len = rand() % (l + 1);
+ for (n = 0; n < rnd_len; n++)
+ buf[off + n] = (unsigned char)rand();
+ memset(buf + off + rnd_len, 0xFF, l - rnd_len);
+
+ /*
+ * Deliberately pass len instead of l (len may be
+ * greater then l if this is the last chunk) because
+ * UBI have to read only l bytes anyway.
+ */
+ ret = write(fd, buf + off, len);
+ if (ret < 0) {
+ failed("write");
+ err_msg("failed to write %d bytes at offset "
+ "%lld", len, (long long)off);
+ goto close;
+ }
+ len = l;
+ if (ret != len) {
+ err_msg("failed to write %d bytes at offset "
+ "%lld, wrote %d", len, (long long)off, ret);
+ goto close;
+ }
+ off += len;
+ }
+
+ /* Check data */
+ if ((ret = lseek(fd, SEEK_SET, 0)) != 0) {
+ failed("lseek");
+ err_msg("cannot seek to 0");
+ goto close;
+ }
+
+ memset(buf1, 0x01, test_len);
+
+ if (vol_info->type == UBI_STATIC_VOLUME)
+ /*
+ * Static volume must not let use read more then it
+ * contains.
+ */
+ ret = read(fd, buf1, test_len + 100);
+ else
+ ret = read(fd, buf1, test_len);
+ if (ret < 0) {
+ failed("read");
+ err_msg("failed to read %d bytes", test_len);
+ goto close;
+ }
+ if (ret != test_len) {
+ err_msg("failed to read %d bytes, read %d", test_len, ret);
+ goto close;
+ }
+ if (memcmp(buf, buf1, test_len)) {
+ err_msg("data corruption");
+ goto close;
+ }
+ }
+
+ close(fd);
+ return 0;
+
+close:
+ close(fd);
+ return -1;
+}
+
+/**
+ * test_update - check volume update and atomic LEB change capabilities.
+ *
+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_update(int type)
+{
+ struct ubi_mkvol_request req;
+ const char *name = TESTNAME ":io_update()";
+ int alignments[] = ALIGNMENTS(dev_info.leb_size);
+ struct ubi_vol_info vol_info;
+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+ int i;
+
+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) {
+ int leb_size;
+
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.vol_type = type;
+ req.name = name;
+
+ req.alignment = alignments[i];
+ req.alignment -= req.alignment % dev_info.min_io_size;
+ if (req.alignment == 0)
+ req.alignment = dev_info.min_io_size;
+
+ leb_size = dev_info.leb_size - dev_info.leb_size % req.alignment;
+ req.bytes = MIN_AVAIL_EBS * leb_size;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return -1;
+ }
+
+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num,
+ req.vol_id);
+ if (ubi_get_vol_info(libubi, vol_node, &vol_info)) {
+ failed("ubi_get_vol_info");
+ goto remove;
+ }
+
+ if (test_update1(&vol_info, 0)) {
+ err_msg("alignment = %d", req.alignment);
+ goto remove;
+ }
+
+ if (vol_info.type != UBI_STATIC_VOLUME) {
+ if (test_update1(&vol_info, 1)) {
+ err_msg("alignment = %d", req.alignment);
+ goto remove;
+ }
+ }
+
+ if (ubi_rmvol(libubi, node, req.vol_id)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+ }
+
+ return 0;
+
+remove:
+ ubi_rmvol(libubi, node, req.vol_id);
+ return -1;
+}
+
+int main(int argc, char * const argv[])
+{
+ if (initial_check(argc, argv))
+ return 1;
+
+ node = argv[1];
+
+ libubi = libubi_open();
+ if (libubi == NULL) {
+ failed("libubi_open");
+ return 1;
+ }
+
+ if (ubi_get_dev_info(libubi, node, &dev_info)) {
+ failed("ubi_get_dev_info");
+ goto close;
+ }
+
+ if (test_update(UBI_DYNAMIC_VOLUME))
+ goto close;
+ if (test_update(UBI_STATIC_VOLUME))
+ goto close;
+
+ libubi_close(libubi);
+ return 0;
+
+close:
+ libubi_close(libubi);
+ return 1;
+}
+
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c b/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c
new file mode 100644
index 00000000000..2e3c450bcc9
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * Test UBI volume creation and deletion ioctl()s with bad input and in case of
+ * incorrect usage.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include "libubi.h"
+#define TESTNAME "mkvol_bad"
+#include "common.h"
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+
+/**
+ * test_mkvol - test that UBI mkvol ioctl rejects bad input parameters.
+ *
+ * This function returns %0 if the test passed and %-1 if not.
+ */
+static int test_mkvol(void)
+{
+ int ret, i;
+ struct ubi_mkvol_request req;
+ const char *name = TESTNAME ":test_mkvol()";
+
+ req.alignment = 1;
+ req.bytes = dev_info.avail_bytes;
+ req.vol_type = UBI_DYNAMIC_VOLUME;
+ req.name = name;
+
+ /* Bad volume ID */
+ req.vol_id = -2;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id))
+ return -1;
+
+ req.vol_id = dev_info.max_vol_count;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id))
+ return -1;
+
+ /* Bad alignment */
+ req.vol_id = 0;
+ req.alignment = 0;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d",
+ req.alignment))
+ return -1;
+
+ req.alignment = -1;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d",
+ req.alignment))
+ return -1;
+
+ req.alignment = dev_info.leb_size + 1;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d",
+ req.alignment))
+ return -1;
+
+ if (dev_info.min_io_size > 1) {
+ req.alignment = dev_info.min_io_size + 1;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d",
+ req.alignment))
+ return -1;
+ }
+
+ /* Bad bytes */
+ req.alignment = 1;
+ req.bytes = -1;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes))
+ return -1;
+
+ req.bytes = 0;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes))
+ return -1;
+
+ req.bytes = dev_info.avail_bytes + 1;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes))
+ return -1;
+
+ req.alignment = dev_info.leb_size - dev_info.min_io_size;
+ req.bytes = (dev_info.leb_size - dev_info.leb_size % req.alignment) *
+ dev_info.avail_lebs + 1;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes))
+ return -1;
+
+ /* Bad vol_type */
+ req.alignment = 1;
+ req.bytes = dev_info.leb_size;
+ req.vol_type = UBI_DYNAMIC_VOLUME + UBI_STATIC_VOLUME;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_type = %d",
+ req.vol_type))
+ return -1;
+
+ req.vol_type = UBI_DYNAMIC_VOLUME;
+
+ /* Too long name */
+ {
+ char name[UBI_VOL_NAME_MAX + 5];
+
+ memset(name, 'x', UBI_VOL_NAME_MAX + 1);
+ name[UBI_VOL_NAME_MAX + 1] = '\0';
+
+ req.name = name;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EINVAL, "ubi_mkvol", "name_len = %d",
+ UBI_VOL_NAME_MAX + 1))
+ return -1;
+ }
+
+ /* Try to create 2 volumes with the same ID and name */
+ req.name = name;
+ req.vol_id = 0;
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return -1;
+ }
+
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EEXIST, "ubi_mkvol",
+ "volume with ID 0 created twice"))
+ return -1;
+
+ req.vol_id = 1;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EEXIST, "ubi_mkvol",
+ "volume with name \"%s\" created twice", name))
+ return -1;
+
+ if (ubi_rmvol(libubi, node, 0)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+
+ /* Try to use too much space */
+ req.vol_id = 0;
+ req.bytes = dev_info.avail_bytes;
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return -1;
+ }
+
+ req.bytes = 1;
+ req.vol_id = 1;
+ ret = ubi_mkvol(libubi, node, &req);
+ if (check_failed(ret, EEXIST, "ubi_mkvol",
+ "created volume of maximum size %lld, but still "
+ "can create more volumes", dev_info.avail_bytes))
+ return -1;
+
+ if (ubi_rmvol(libubi, node, 0)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+
+ /* Try to create too many volumes */
+ for (i = 0; i < dev_info.max_vol_count; i++) {
+ char nm[strlen(name) + 50];
+
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.alignment = 1;
+ req.bytes = 1;
+ req.vol_type = UBI_STATIC_VOLUME;
+
+ sprintf(nm, "%s:%d", name, i);
+ req.name = nm;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ /*
+ * Note, because of gluebi we may be unable to create
+ * dev_info.max_vol_count devices (MTD restrictions).
+ */
+ if (errno == ENFILE)
+ break;
+ failed("ubi_mkvol");
+ err_msg("vol_id %d", i);
+ goto remove;
+ }
+ }
+
+ for (i = 0; i < dev_info.max_vol_count + 1; i++)
+ ubi_rmvol(libubi, node, i);
+
+ return 0;
+
+remove:
+ for (i = 0; i < dev_info.max_vol_count + 1; i++)
+ ubi_rmvol(libubi, node, i);
+ return -1;
+}
+
+/**
+ * test_rmvol - test that UBI rmvol ioctl rejects bad input parameters.
+ *
+ * This function returns %0 if the test passed and %-1 if not.
+ */
+static int test_rmvol(void)
+{
+ int ret;
+ struct ubi_mkvol_request req;
+ const char *name = TESTNAME ":test_rmvol()";
+
+ /* Bad vol_id */
+ ret = ubi_rmvol(libubi, node, -1);
+ if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = -1"))
+ return -1;
+
+ ret = ubi_rmvol(libubi, node, dev_info.max_vol_count);
+ if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = %d",
+ dev_info.max_vol_count))
+ return -1;
+
+ /* Try to remove non-existing volume */
+ ret = ubi_rmvol(libubi, node, 0);
+ if (check_failed(ret, ENODEV, "ubi_rmvol",
+ "removed non-existing volume 0"))
+ return -1;
+
+ /* Try to remove volume twice */
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.alignment = 1;
+ req.bytes = dev_info.avail_bytes;
+ req.vol_type = UBI_DYNAMIC_VOLUME;
+ req.name = name;
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return -1;
+ }
+
+ if (ubi_rmvol(libubi, node, req.vol_id)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+
+ ret = ubi_rmvol(libubi, node, req.vol_id);
+ if (check_failed(ret, ENODEV, "ubi_rmvol", "volume %d removed twice",
+ req.vol_id))
+ return -1;
+
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ if (initial_check(argc, argv))
+ return 1;
+
+ node = argv[1];
+
+ libubi = libubi_open();
+ if (libubi == NULL) {
+ failed("libubi_open");
+ return 1;
+ }
+
+ if (ubi_get_dev_info(libubi, node, &dev_info)) {
+ failed("ubi_get_dev_info");
+ goto close;
+ }
+
+ if (test_mkvol())
+ goto close;
+
+ if (test_rmvol())
+ goto close;
+
+ libubi_close(libubi);
+ return 0;
+
+close:
+ libubi_close(libubi);
+ return 1;
+}
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c b/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c
new file mode 100644
index 00000000000..880c1494297
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * Test test checks basic volume creation and deletion capabilities.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "libubi.h"
+#define TESTNAME "mkvol_basic"
+#include "common.h"
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+
+/**
+ * mkvol_alignment - create volumes with different alignments.
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int mkvol_alignment(void)
+{
+ struct ubi_mkvol_request req;
+ int i, vol_id, ebsz;
+ const char *name = TESTNAME ":mkvol_alignment()";
+ int alignments[] = ALIGNMENTS(dev_info.leb_size);
+
+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) {
+ req.vol_id = UBI_VOL_NUM_AUTO;
+
+ /* Alignment should actually be multiple of min. I/O size */
+ req.alignment = alignments[i];
+ req.alignment -= req.alignment % dev_info.min_io_size;
+ if (req.alignment == 0)
+ req.alignment = dev_info.min_io_size;
+
+ /* Bear in mind alignment reduces EB size */
+ ebsz = dev_info.leb_size - dev_info.leb_size % req.alignment;
+ req.bytes = dev_info.avail_lebs * ebsz;
+
+ req.vol_type = UBI_DYNAMIC_VOLUME;
+ req.name = name;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ err_msg("alignment %d", req.alignment);
+ return -1;
+ }
+
+ vol_id = req.vol_id;
+ if (check_volume(vol_id, &req))
+ goto remove;
+
+ if (ubi_rmvol(libubi, node, vol_id)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+ }
+
+ return 0;
+
+remove:
+ ubi_rmvol(libubi, node, vol_id);
+ return -1;
+}
+
+/**
+ * mkvol_basic - simple test that checks basic volume creation capability.
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int mkvol_basic(void)
+{
+ struct ubi_mkvol_request req;
+ struct ubi_vol_info vol_info;
+ int vol_id, ret;
+ const char *name = TESTNAME ":mkvol_basic()";
+
+ /* Create dynamic volume of maximum size */
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.alignment = 1;
+ req.bytes = dev_info.avail_bytes;
+ req.vol_type = UBI_DYNAMIC_VOLUME;
+ req.name = name;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return -1;
+ }
+
+ vol_id = req.vol_id;
+ if (check_volume(vol_id, &req))
+ goto remove;
+
+ if (ubi_rmvol(libubi, node, vol_id)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+
+ /* Create static volume of maximum size */
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.alignment = 1;
+ req.bytes = dev_info.avail_bytes;
+ req.vol_type = UBI_STATIC_VOLUME;
+ req.name = name;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return -1;
+ }
+
+ vol_id = req.vol_id;
+ if (check_volume(vol_id, &req))
+ goto remove;
+
+ if (ubi_rmvol(libubi, node, vol_id)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+
+ /* Make sure volume does not exist */
+ ret = ubi_get_vol_info1(libubi, dev_info.dev_num, vol_id, &vol_info);
+ if (ret == 0) {
+ err_msg("removed volume %d exists", vol_id);
+ goto remove;
+ }
+
+ return 0;
+
+remove:
+ ubi_rmvol(libubi, node, vol_id);
+ return -1;
+}
+
+/**
+ * mkvol_multiple - test multiple volumes creation
+ *
+ * Thus function returns %0 if the test passed and %-1 if not.
+ */
+static int mkvol_multiple(void)
+{
+ struct ubi_mkvol_request req;
+ int i, ret, max = dev_info.max_vol_count;
+ const char *name = TESTNAME ":mkvol_multiple()";
+
+ /* Create maximum number of volumes */
+ for (i = 0; i < max; i++) {
+ char nm[strlen(name) + 50];
+
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.alignment = 1;
+ req.bytes = 1;
+ req.vol_type = UBI_STATIC_VOLUME;
+
+ sprintf(nm, "%s:%d", name, i);
+ req.name = nm;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ if (errno == ENFILE) {
+ max = i;
+ break;
+ }
+ failed("ubi_mkvol");
+ err_msg("vol_id %d", i);
+ goto remove;
+ }
+
+ if (check_volume(req.vol_id, &req)) {
+ err_msg("vol_id %d", i);
+ goto remove;
+ }
+ }
+
+ for (i = 0; i < max; i++) {
+ struct ubi_vol_info vol_info;
+
+ if (ubi_rmvol(libubi, node, i)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+
+ /* Make sure volume does not exist */
+ ret = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info);
+ if (ret == 0) {
+ err_msg("removed volume %d exists", i);
+ goto remove;
+ }
+ }
+
+ return 0;
+
+remove:
+ for (i = 0; i < dev_info.max_vol_count + 1; i++)
+ ubi_rmvol(libubi, node, i);
+ return -1;
+}
+
+int main(int argc, char * const argv[])
+{
+ if (initial_check(argc, argv))
+ return 1;
+
+ node = argv[1];
+
+ libubi = libubi_open();
+ if (libubi == NULL) {
+ failed("libubi_open");
+ return 1;
+ }
+
+ if (ubi_get_dev_info(libubi, node, &dev_info)) {
+ failed("ubi_get_dev_info");
+ goto close;
+ }
+
+ if (mkvol_basic())
+ goto close;
+
+ if (mkvol_alignment())
+ goto close;
+
+ if (mkvol_multiple())
+ goto close;
+
+ libubi_close(libubi);
+ return 0;
+
+close:
+ libubi_close(libubi);
+ return 1;
+}
+
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c b/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c
new file mode 100644
index 00000000000..74be5fa0460
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * This test creates and deletes volumes in parallel.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include "libubi.h"
+#define TESTNAME "mkvol_paral"
+#include "common.h"
+
+#define THREADS_NUM 4
+#define ITERATIONS 500
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+static int iterations = ITERATIONS;
+
+/**
+ * the_thread - the testing thread.
+ *
+ * @ptr thread number
+ */
+static void * the_thread(void *ptr)
+{
+ int n = (int)ptr, iter = iterations;
+ struct ubi_mkvol_request req;
+ const char *name = TESTNAME ":the_thread()";
+ char nm[strlen(name) + 50];
+
+ req.alignment = 1;
+ req.bytes = dev_info.avail_bytes/ITERATIONS;
+ req.vol_type = UBI_DYNAMIC_VOLUME;
+ sprintf(nm, "%s:%d", name, n);
+ req.name = nm;
+
+ while (iter--) {
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return NULL;
+ }
+ if (ubi_rmvol(libubi, node, req.vol_id)) {
+ failed("ubi_rmvol");
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+int main(int argc, char * const argv[])
+{
+ int i, ret;
+ pthread_t threads[THREADS_NUM];
+
+ if (initial_check(argc, argv))
+ return 1;
+
+ node = argv[1];
+
+ libubi = libubi_open();
+ if (libubi == NULL) {
+ failed("libubi_open");
+ return 1;
+ }
+
+ if (ubi_get_dev_info(libubi, node, &dev_info)) {
+ failed("ubi_get_dev_info");
+ goto close;
+ }
+
+ for (i = 0; i < THREADS_NUM; i++) {
+ ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i);
+ if (ret) {
+ failed("pthread_create");
+ goto close;
+ }
+ }
+
+ for (i = 0; i < THREADS_NUM; i++)
+ pthread_join(threads[i], NULL);
+
+ libubi_close(libubi);
+ return 0;
+
+close:
+ libubi_close(libubi);
+ return 1;
+}
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c b/drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c
new file mode 100644
index 00000000000..8ec93bcb390
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * Tes UBI volume re-size.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "libubi.h"
+#define TESTNAME "rsvol"
+#include "common.h"
+
+static libubi_t libubi;
+static struct ubi_dev_info dev_info;
+const char *node;
+
+/**
+ * test_basic - check volume re-size capability.
+ *
+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_basic(int type)
+{
+ struct ubi_mkvol_request req;
+ const char *name = TESTNAME ":test_basic()";
+
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.alignment = 1;
+ req.bytes = MIN_AVAIL_EBS * dev_info.leb_size;
+ req.vol_type = type;
+ req.name = name;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return -1;
+ }
+
+ req.bytes = dev_info.leb_size;
+ if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) {
+ failed("ubi_rsvol");
+ goto remove;
+ }
+
+ if (check_volume(req.vol_id, &req))
+ goto remove;
+
+ req.bytes = (MIN_AVAIL_EBS + 1) * dev_info.leb_size;
+ if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) {
+ failed("ubi_rsvol");
+ goto remove;
+ }
+
+ if (check_volume(req.vol_id, &req))
+ goto remove;
+
+ req.bytes -= 1;
+ if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) {
+ failed("ubi_rsvol");
+ goto remove;
+ }
+
+ if (check_volume(req.vol_id, &req))
+ goto remove;
+
+ if (ubi_rmvol(libubi, node, req.vol_id)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+
+ return 0;
+
+remove:
+ ubi_rmvol(libubi, node, req.vol_id);
+ return -1;
+}
+
+/*
+ * Helper function for test_rsvol().
+ */
+static int test_rsvol1(struct ubi_vol_info *vol_info)
+{
+ long long bytes;
+ struct ubi_vol_info vol_info1;
+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+ unsigned char buf[vol_info->rsvd_bytes];
+ int fd, i, ret;
+
+ /* Make the volume smaller and check basic volume I/O */
+ bytes = vol_info->rsvd_bytes - vol_info->leb_size;
+ if (ubi_rsvol(libubi, node, vol_info->vol_id, bytes - 1)) {
+ failed("ubi_rsvol");
+ return -1;
+ }
+
+ if (ubi_get_vol_info1(libubi, vol_info->dev_num, vol_info->vol_id,
+ &vol_info1)) {
+ failed("ubi_get_vol_info");
+ return -1;
+ }
+
+ if (vol_info1.rsvd_bytes != bytes) {
+ err_msg("rsvd_bytes %lld, must be %lld",
+ vol_info1.rsvd_bytes, bytes);
+ return -1;
+ }
+
+ if (vol_info1.rsvd_lebs != vol_info->rsvd_lebs - 1) {
+ err_msg("rsvd_lebs %d, must be %d",
+ vol_info1.rsvd_lebs, vol_info->rsvd_lebs - 1);
+ return -1;
+ }
+
+ /* Write data to the volume */
+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num,
+ vol_info->vol_id);
+
+ fd = open(vol_node, O_RDWR);
+ if (fd == -1) {
+ failed("open");
+ err_msg("cannot open \"%s\"\n", vol_node);
+ return -1;
+ }
+
+ bytes = vol_info->rsvd_bytes - vol_info->leb_size - 1;
+ if (ubi_update_start(libubi, fd, bytes)) {
+ failed("ubi_update_start");
+ goto close;
+ }
+
+ for (i = 0; i < bytes; i++)
+ buf[i] = (unsigned char)i;
+
+ ret = write(fd, buf, bytes);
+ if (ret != bytes) {
+ failed("write");
+ goto close;
+ }
+
+ close(fd);
+
+ if (ubi_rsvol(libubi, node, vol_info->vol_id, bytes)) {
+ failed("ubi_rsvol");
+ return -1;
+ }
+
+ if (ubi_rsvol(libubi, node, vol_info->vol_id,
+ vol_info->leb_size * dev_info.avail_lebs)) {
+ failed("ubi_rsvol");
+ return -1;
+ }
+
+ fd = open(vol_node, O_RDWR);
+ if (fd == -1) {
+ failed("open");
+ err_msg("cannot open \"%s\"\n", vol_node);
+ return -1;
+ }
+
+ /* Read data back */
+ if (lseek(fd, 0, SEEK_SET) != 0) {
+ failed("seek");
+ goto close;
+ }
+ memset(buf, 0, bytes);
+ ret = read(fd, buf, bytes);
+ if (ret != bytes) {
+ failed("read");
+ goto close;
+ }
+
+ for (i = 0; i < bytes; i++) {
+ if (buf[i] != (unsigned char)i) {
+ err_msg("bad data");
+ goto close;
+ }
+ }
+
+ close(fd);
+ return 0;
+
+close:
+ close(fd);
+ return -1;
+}
+
+/**
+ * test_rsvol - test UBI volume re-size.
+ *
+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ *
+ * Thus function returns %0 in case of success and %-1 in case of failure.
+ */
+static int test_rsvol(int type)
+{
+ const char *name = TESTNAME "test_rsvol:()";
+ int alignments[] = ALIGNMENTS(dev_info.leb_size);
+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100];
+ struct ubi_mkvol_request req;
+ int i;
+
+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) {
+ int leb_size;
+ struct ubi_vol_info vol_info;
+
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.vol_type = type;
+ req.name = name;
+
+ req.alignment = alignments[i];
+ req.alignment -= req.alignment % dev_info.min_io_size;
+ if (req.alignment == 0)
+ req.alignment = dev_info.min_io_size;
+
+ leb_size = dev_info.leb_size - dev_info.leb_size % req.alignment;
+ req.bytes = MIN_AVAIL_EBS * leb_size;
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ return -1;
+ }
+
+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num,
+ req.vol_id);
+
+ if (ubi_get_vol_info(libubi, vol_node, &vol_info)) {
+ failed("ubi_get_vol_info");
+ goto remove;
+ }
+
+ if (test_rsvol1(&vol_info)) {
+ err_msg("alignment = %d", req.alignment);
+ goto remove;
+ }
+
+ if (ubi_rmvol(libubi, node, req.vol_id)) {
+ failed("ubi_rmvol");
+ return -1;
+ }
+ }
+
+ return 0;
+
+remove:
+ ubi_rmvol(libubi, node, req.vol_id);
+ return -1;
+}
+
+int main(int argc, char * const argv[])
+{
+ if (initial_check(argc, argv))
+ return 1;
+
+ node = argv[1];
+
+ libubi = libubi_open();
+ if (libubi == NULL) {
+ failed("libubi_open");
+ return 1;
+ }
+
+ if (ubi_get_dev_info(libubi, node, &dev_info)) {
+ failed("ubi_get_dev_info");
+ goto close;
+ }
+
+ if (test_basic(UBI_DYNAMIC_VOLUME))
+ goto close;
+ if (test_basic(UBI_STATIC_VOLUME))
+ goto close;
+ if (test_rsvol(UBI_DYNAMIC_VOLUME))
+ goto close;
+ if (test_rsvol(UBI_STATIC_VOLUME))
+ goto close;
+
+ libubi_close(libubi);
+ return 0;
+
+close:
+ libubi_close(libubi);
+ return 1;
+}
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh b/drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh
new file mode 100644
index 00000000000..fa10c3e2b04
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+ubidev="$1"
+tests="mkvol_basic mkvol_bad mkvol_paral rsvol io_basic io_read io_update
+io_paral volrefcnt"
+
+if test -z "$ubidev";
+then
+ echo "Usage:"
+ echo "$0 <UBI device> <ubi module load command>"
+ exit 1
+fi
+
+ubiname=`echo $ubidev | cut -d/ -f3`
+
+major=`cat /sys/class/ubi/$ubiname/dev | cut -d: -f1`
+
+for minor in `seq 0 4`; do
+ if test ! -e ${ubidev}_${minor} ;
+ then
+ mknod ${ubidev}_${minor} c $major $(($minor + 1))
+ fi
+done
+
+if ! test -c "$ubidev";
+then
+ echo "Error: $ubidev is not character device"
+ exit 1
+fi
+
+for t in `echo $tests`;
+do
+ echo "Running $t $ubidev"
+ "./$t" "$ubidev" || exit 1
+done
+
+echo SUCCESS
+
+exit 0
diff --git a/drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c b/drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c
new file mode 100644
index 00000000000..a56deae9671
--- /dev/null
+++ b/drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) Nokia Corporation, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * Test volume reference counting - create a volume, open a sysfs file
+ * belonging to the volume, delete the volume but do not close the file, make
+ * sure the file cannot be read, close the file, make sure the volume
+ * disappeard, make sure its sysfs subtree disappeared.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "libubi.h"
+#define TESTNAME "rmvol"
+#include "common.h"
+
+#define SYSFS_FILE "/sys/class/ubi/ubi%d_%d/usable_eb_size"
+
+int main(int argc, char * const argv[])
+{
+ int ret, fd;
+ char fname[sizeof(SYSFS_FILE) + 20];
+ const char *node;
+ libubi_t libubi;
+ struct ubi_dev_info dev_info;
+ struct ubi_mkvol_request req;
+ char tmp[100];
+
+ if (initial_check(argc, argv))
+ return 1;
+
+ node = argv[1];
+
+ libubi = libubi_open();
+ if (libubi == NULL) {
+ failed("libubi_open");
+ return 1;
+ }
+
+ if (ubi_get_dev_info(libubi, node, &dev_info)) {
+ failed("ubi_get_dev_info");
+ goto out_libubi;
+ }
+
+ /* Create a small dynamic volume */
+ req.vol_id = UBI_VOL_NUM_AUTO;
+ req.alignment = dev_info.min_io_size;
+ req.bytes = dev_info.leb_size;
+ req.vol_type = UBI_DYNAMIC_VOLUME;
+ req.name = "rmvol";
+
+ if (ubi_mkvol(libubi, node, &req)) {
+ failed("ubi_mkvol");
+ goto out_libubi;
+ }
+
+ /* Open volume-related sysfs file */
+ sprintf(fname, SYSFS_FILE, dev_info.dev_num, req.vol_id);
+ fd = open(fname, O_RDONLY);
+ if (fd == -1) {
+ err_msg("cannot open %s", fname);
+ failed("open");
+ goto out_rmvol;
+ }
+
+ /* Remove the volume, but do not close the file */
+ if (ubi_rmvol(libubi, node, req.vol_id)) {
+ failed("ubi_rmvol");
+ perror("ubi_rmvol");
+ goto out_close;
+ }
+
+ /* Try to read from the file, this should fail */
+ ret = read(fd, tmp, 100);
+ if (ret != -1) {
+ err_msg("read returned %d, expected -1", ret);
+ failed("read");
+ goto out_close;
+ }
+
+ /* Close the file and try to open it again, should fail */
+ close(fd);
+ fd = open(fname, O_RDONLY);
+ if (fd != -1) {
+ err_msg("opened %s again, open returned %d, expected -1",
+ fname, fd);
+ failed("open");
+ goto out_libubi;
+ }
+
+ libubi_close(libubi);
+ return 0;
+
+out_rmvol:
+ ubi_rmvol(libubi, node, req.vol_id);
+out_libubi:
+ libubi_close(libubi);
+ return 1;
+
+out_close:
+ close(fd);
+ libubi_close(libubi);
+ return 1;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/Makefile b/drivers/mtd/mtd-utils/ubi-utils/Makefile
new file mode 100644
index 00000000000..0418054d798
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/Makefile
@@ -0,0 +1,88 @@
+#
+# Makefile for ubi-utils
+#
+
+OPTFLAGS := -O2 -g -Wall
+KERNELHDR := ../include
+DESTDIR := /usr/local
+SBINDIR=/usr/sbin
+MANDIR=/usr/share/man
+INCLUDEDIR=/usr/include
+
+CROSS=mipsel-linux-
+CC := $(CROSS)gcc
+CFLAGS := -I./inc -I./src -I$(KERNELHDR) $(OPTFLAGS) -Werror \
+ -Wwrite-strings -W -std=gnu99 -DPACKAGE_VERSION=\"1.0\"
+
+PERLPROGS = mkpfi ubicrc32.pl
+
+NTARGETS = ubiattach ubicrc32 ubidetach ubimkvol ubinfo ubinize \
+ ubirmvol ubiupdatevol
+TARGETS = pfiflash pddcustomize ubimirror bin2nand nand2bin ubigen \
+ mkbootenv unubi pfi2bin $(NTARGETS)
+
+vpath %.c ./src
+
+%: %.o
+ $(CC) $(LDFLAGS) -g -o $@ $^
+
+%.o: %.c
+ $(CC) $(CFLAGS) -g -c -o $@ $< -g -Wp,-MD,.$(shell basename $<).dep
+
+all: $(TARGETS)
+ mkdir -p ubi-utils-dir
+ cp $(TARGETS) ubi-utils-dir
+ make -C new-utils
+
+IGNORE=${wildcard .*.c.dep}
+-include ${IGNORE}
+
+$(NTARGETS):
+ make -C new-utils $@
+ mv new-utils/$@ $@
+
+clean:
+ rm -rf *.o $(TARGETS) .*.c.dep
+ rm -fr ubi-utils-dir
+ make -C new-utils clean
+
+pddcustomize: pddcustomize.o error.o libubimirror.o bootenv.o hashmap.o \
+ libubi.o crc32.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+pfiflash: pfiflash.o libpfiflash.o list.o reader.o error.o libubimirror.o \
+ bootenv.o hashmap.o pfi.o libubi.o crc32.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+ubimirror: ubimirror.o error.o libubimirror.o bootenv.o hashmap.o \
+ libubi.o crc32.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+nand2bin: nand2bin.o nandecc.o nandcorr.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+bin2nand: bin2nand.o error.o nandecc.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+ubigen: ubigen.o libubigen.o crc32.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o crc32.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+unubi: unubi.o crc32.o unubi_analyze.o eb_chain.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+pfi2bin: pfi2bin.o peb.o error.o list.o crc32.o libubigen.o bootenv.o \
+ hashmap.o reader.o pfi.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+install: ${TARGETS}
+ mkdir -p ${DESTDIR}/${SBINDIR}
+ install -m0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/
+ (cd perl && install ${PERLPROGS} ${DESTDIR}/${SBINDIR}/)
+
+uninstall:
+ for file in ${TARGETS} ${PERLPROGS}; do \
+ $(RM) ${DESTDIR}/${SBINDIR}/$$file; \
+ done
diff --git a/drivers/mtd/mtd-utils/ubi-utils/README b/drivers/mtd/mtd-utils/ubi-utils/README
new file mode 100644
index 00000000000..d976a7654e2
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/README
@@ -0,0 +1,236 @@
+README
+======
+
+The programs and libraries in this directory provide a tool-chain to
+generate binary data for embedded systems which can be flashed either
+by a hardware flash programmer, e.g. JTAG debugger, or on the target
+system directly using pfiflash, or ubimkvol, ubirmvol, ubiwritevol.
+
+The latter is the case when there is already Linux running which has
+build in UBI support.
+
+Authors: Oliver Lohmann
+ Frank Haverkamp
+ Andreas Arnez
+
+mkpfi - tool for flash content generation in PFI
+ format
+pfi2bin - conversion tool to transfer a PFI file into a
+ binary image
+pfiflash - tool to update the embedded systems flash using
+ pfi files created by mkpfi
+libbootenv - library for boot-parameter processing
+libpfi - library for partial flash image (PFI) creation
+ and handling
+ubigen - tool to create binary UBI images e.g. for a
+ jtag flashing tool
+nandimg - tool to add OOB data to binary images intended
+ for NAND flash systems
+ubilib - UBI library
+
+!!! NOTICE !!!
+If you execute ./configure in the top_level directory the helper Makefile
+gets overwritten. Thats actually no problem, but be aware of that.
+
+1. Build Process
+
+1.1 Build, install and forget
+ o Build all and everything
+ $make all (takes a while, builds ppc and x86 binaries/libs)
+ o Installation:
+ $make install
+ o Uninstallation:
+ $make uninstall
+
+ o x86 only would be:
+ $make x86 && make install_x86
+
+1.2 Usage for a developer
+
+ 1.2.1 The build process in detail
+
+ o If you've checked out the sources from the CVS repository you'll find a
+ directory setup like this:
+
+ flashutils/
+ -rw-r--r-- 1 olli olli 1.3K Mar 14 11:53 Makefile
+ -rw-r--r-- 1 olli olli 1.9K Mar 14 10:50 Makefile.am
+ -rwxr-xr-x 1 olli olli 265 Mar 9 00:47 bootstrap
+ -rw-r--r-- 1 olli olli 1.1K Mar 9 16:55 configure.ac
+ drwxr-xr-x 2 olli olli 4.0K Mar 9 00:28 doc
+ drwxr-xr-x 2 olli olli 4.0K Mar 14 11:56 inc
+ drwxr-xr-x 2 olli olli 4.0K Mar 14 11:56 lib
+ drwxr-xr-x 17 olli olli 4.0K Mar 13 16:50 src
+
+ o To generate the initial build templates you have to call the bootstrap
+ script:
+ $ ./bootstrap
+ o Create a directory for the target platform
+ $ mkdir build_x86
+ o Descend into the directory and call the top-level configure script
+ with the desired options.
+ $ cd build_x86
+ $ ../configure --prefix=/usr/local [...]
+ o Now you'll find a directory structure like this:
+
+ flashutils/build_x86/
+ -rw-r--r-- 1 olli olli 47K Mar 14 13:33 Makefile
+ -rw-r--r-- 1 olli olli 33K Mar 14 13:33 config.log
+ -rwxr-xr-x 1 olli olli 38K Mar 14 13:33 config.status
+ drwxr-xr-x 2 olli olli 4.0K Mar 14 13:33 inc
+ drwxr-xr-x 3 olli olli 4.0K Mar 14 13:33 lib
+ -rwxr-xr-x 1 olli olli 202K Mar 14 13:33 libtool
+
+ o The config.guess script can be used to update the Makefiles in the
+ target directory after a change of the top-level template files
+ (i.e. the Makefile.in files).
+ $ ./config.guess
+ o To compile everything for this platform just invoke make in
+ flashutils/build_x86:
+ $ make
+ or from toplevel:
+ $ make -C ./build_x86
+ o The build process creates a new directory "bin":
+ flashutils/build_x86/
+ [...]
+ drwxr-xr-x 3 olli olli 4.0K Mar 14 13:41 bin
+ [...]
+
+ This directory contains all binary files which will be installed
+ by make install, e.g.:
+
+ flashutils/build_x86/bin/
+ -rwxr-xr-x 1 olli olli 7.2K Mar 14 13:41 bin2nand
+ -rwxr-xr-x 1 olli olli 15K Mar 14 13:41 mkbootenv
+ -rwxr-xr-x 1 olli olli 16K Mar 14 13:41 pddcustomize
+ -rwxr-xr-x 1 olli olli 36K Mar 14 13:41 pfi2bin
+ -rwxr-xr-x 1 olli olli 6.8K Mar 14 13:41 pfiflash
+ -rwxr-xr-x 1 olli olli 5.0K Mar 14 13:41 ubicrc32
+ -rwxr-xr-x 1 olli olli 13K Mar 14 13:41 ubigen
+ -rwxr-xr-x 1 olli olli 6.3K Mar 14 13:41 ubimirror
+
+
+ 1.2.2 Modifying and Adding Sources
+
+ o There is a dedicated directory which contains all source code
+ of the flashutils package, e.g.:
+
+ flashutils/src/
+ drwxr-xr-x 2 olli olli 4.0K Mar 13 11:42 libbootenv
+ drwxr-xr-x 2 olli olli 4.0K Mar 13 11:42 liberror
+ drwxr-xr-x 2 olli olli 4.0K Mar 13 16:48 mkpfi
+ drwxr-xr-x 2 olli olli 4.0K Mar 13 16:12 pddcustomize
+
+
+
+ The prefix "lib" is used to mark directories as part of a convenience
+ library. Binaries have no special prefix.
+
+ o How to add sources?
+
+ Just create a new directory at flashutils/src/, e.g.:
+
+ For a binary:
+ $ mkdir rider
+ $ cd rider
+ $ vi rider.c
+ /* do sth with that file... */
+
+ For a convenience library (as well as for "normal libs")
+ $ mkdir libworld
+ $ cd libworld
+ $ vi world.c
+ /* do sth with that file... */
+
+ o How to register sources in the build process (for binaries)?
+
+ You have to register your sources at the top-level automake Makefile:
+
+ In directory flashutils/
+ $ vi Makefile.am
+
+ Binaries have to be registered at "bin_PROGRAMS", e.g.:
+ bin_PROGRAMS = bin/pddcustomize \
+ bin/rider
+
+ Add the rule how the binary is assembled, e.g.:
+ bin_pddcustomize_SOURCES = \
+ $(top_srcdir)/src/pddcustomize/pddcustomize.c
+ bin_pddcustomize_LDADD = \
+ $(top_builddir)/lib/libbootenv.la \
+ $(top_builddir)/lib/liberror.la
+
+ bin_rider_SOURCES = \
+ $(top_srcdir)/src/rider/rider.c
+
+ This example reflects a simple build process for "rider". "rider"
+ is built without any other dependencies or convenience libraries.
+ The example for pddcustomize is a bit more complicated.
+ "_LDADD" adds some convenience libraris into the link process of
+ "pddcustomize". Imagine, that your "rider" has common code
+ with "dragon_bin" which is held in a library called "libworld".
+ The build rules would like like the following:
+
+ bin_rider_SOURCES = \
+ $(top_srcdir)/src/rider/rider.c
+ bin_rider_LDADD = \
+ $(top_builddir)/lib/libworld.la
+
+ bin_dragon_SOURCES = \
+ $(top_srcdir)/src/dragon_bin/dragon_bin.c
+ bin_dragon_LDADD = \
+ $(top_builddir)/lib/libworld.la
+
+ Don't forget to add "dragon" to "bin_PROGRAMS"!
+ Don't forget to set the build rule for the "libworld" itself!
+ This is documented in the next section.
+
+
+ o How to register sources in the build process (for libraries)?
+
+ Until now we didn't care about the build process of "libworld".
+ Libraries are handled special in this build process because
+ they are handled as "modules", i.e. they are able to be built
+ without building the binaries in the same step. Additionally,
+ it is possible to assemble complex libraries out of simple ones.
+ That especially makes sense if you want to export (install) a
+ library on a system which uses some common code and makes
+ some adoptions for usability and presents a comfortable interface to
+ the user (see libpfiflash in the sources for an example).
+
+ o Registering "libworld" as convenience library.
+
+ Instead of editing the "Makefile.am" in "flashtools/", we have to
+ edit now the "Makefile.am" in "flashtools/lib/":
+
+ noinst_LTLIBRARIES = libworld.la
+
+ libworld_la_SOURCES = $(top_srcdir)/src/libworld/world.c
+
+ o Registering "libworld" as library which gets installed.
+
+ lib_LTLIBRARIES = libworld.la
+ libworld_la_SOURCES = $(top_srcdir)/src/libworld/world.c
+ libworld_la_LDFLAGS = -no-undefined -version-info 0:0:0
+
+ o Header files
+
+ All header files are stored at "flashutils/inc", regardless
+ if convenience library or not.
+
+ If you want to export headers you have to specify this in the Makefile.am
+ located at "flashutils/inc", e.g. (this should not be done
+ for convenience libraries):
+
+ nobase_include_HEADERS = world.h
+
+
+
+Appendix
+
+A.1. FAQ
+
+ Q How to call configure to setup a cross-platform build?
+ A $ ./configure --build=i686-pc-linux-gnu --host=ppc-linux \
+ --prefix=/opt/.../ppcnf/crossroot/ \
+ --exec-prefix=/opt/..../ppcnf/crossroot/usr
diff --git a/drivers/mtd/mtd-utils/ubi-utils/UBI.TXT b/drivers/mtd/mtd-utils/ubi-utils/UBI.TXT
new file mode 100644
index 00000000000..9a1c3c78c77
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/UBI.TXT
@@ -0,0 +1,108 @@
+UBI - Unsorted Block Images
+
+UBI (Latin: "where?") manages multiple logical volumes on a single
+flash device, specifically supporting NAND flash devices. UBI provides
+a flexible partitioning concept which still allows for wear-levelling
+across the whole flash device.
+
+In a sense, UBI may be compared to the Logical Volume Manager
+(LVM). Whereas LVM maps logical sector numbers to physical HDD sector
+numbers, UBI maps logical eraseblocks to physical eraseblocks.
+
+More information may be found in the UBI design documentation:
+ubidesign.pdf. Which can be found here:
+http://www.linux-mtd.infradead.org/doc/ubi.html
+
+Partitioning/Re-partitioning
+
+ An UBI volume occupies a certain number of erase blocks. This is
+ limited by a configured maximum volume size, which could also be
+ viewed as the partition size. Each individual UBI volume's size can
+ be changed independently of the other UBI volumes, provided that the
+ sum of all volume sizes doesn't exceed a certain limit.
+
+ UBI supports dynamic volumes and static volumes. Static volumes are
+ read-only and their contents are protected by CRC check sums.
+
+Bad eraseblocks handling
+
+ UBI transparently handles bad eraseblocks. When a physical
+ eraseblock becomes bad, it is substituted by a good physical
+ eraseblock, and the user does not even notice this.
+
+Scrubbing
+
+ On a NAND flash bit flips can occur on any write operation,
+ sometimes also on read. If bit flips persist on the device, at first
+ they can still be corrected by ECC, but once they accumulate,
+ correction will become impossible. Thus it is best to actively scrub
+ the affected eraseblock, by first copying it to a free eraseblock
+ and then erasing the original. The UBI layer performs this type of
+ scrubbing under the covers, transparently to the UBI volume users.
+
+Erase Counts
+
+ UBI maintains an erase count header per eraseblock. This frees
+ higher-level layers (like file systems) from doing this and allows
+ for centralized erase count management instead. The erase counts are
+ used by the wear-levelling algorithm in the UBI layer. The algorithm
+ itself is exchangeable.
+
+Booting from NAND
+
+ For booting directly from NAND flash the hardware must at least be
+ capable of fetching and executing a small portion of the NAND
+ flash. Some NAND flash controllers have this kind of support. They
+ usually limit the window to a few kilobytes in erase block 0. This
+ "initial program loader" (IPL) must then contain sufficient logic to
+ load and execute the next boot phase.
+
+ Due to bad eraseblocks, which may be randomly scattered over the
+ flash device, it is problematic to store the "secondary program
+ loader" (SPL) statically. Also, due to bit-flips it may become
+ corrupted over time. UBI allows to solve this problem gracefully by
+ storing the SPL in a small static UBI volume.
+
+UBI volumes vs. static partitions
+
+ UBI volumes are still very similar to static MTD partitions:
+
+ * both consist of eraseblocks (logical eraseblocks in case of UBI
+ volumes, and physical eraseblocks in case of static partitions;
+ * both support three basic operations - read, write, erase.
+
+ But UBI volumes have the following advantages over traditional
+ static MTD partitions:
+
+ * there are no eraseblock wear-leveling constraints in case of UBI
+ volumes, so the user should not care about this;
+ * there are no bit-flips and bad eraseblocks in case of UBI volumes.
+
+ So, UBI volumes may be considered as flash devices with relaxed
+ restrictions.
+
+Where can it be found?
+
+ Documentation, kernel code and applications can be found in the MTD
+ gits.
+
+What are the applications for?
+
+ The applications help to create binary flash images for two
+ purposes: pfi files (partial flash images) for in-system update of
+ UBI volumes, and plain binary images, with or without OOB data in
+ case of NAND, for a manufacturing step. Furthermore some tools
+ are/and will be created that allow flash content analysis after a
+ system has crashed.
+
+Who did UBI?
+
+ The original ideas, where UBI is based on, were developed by Andreas
+ Arnez, Frank Haverkamp and Thomas Gleixner. Josh W. Boyer and
+ some others were involved too. The implementation of the kernel
+ layer was done by Artem B. Bityutskiy. The user-space applications
+ and tools were written by Oliver Lohmann with contributions from
+ Frank Haverkamp, Andreas Arnez, and Artem. Joern Engel contributed a
+ patch which modifies JFFS2 so that it can be run on a UBI
+ volume. Thomas Gleixner did modifications to the NAND layer and also
+ some to JFFS2 to make it work.
diff --git a/drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff b/drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff
new file mode 100644
index 00000000000..6cebc461fca
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff
@@ -0,0 +1,123 @@
+.TH UNUBI 1 "NOVEMBER 2006" FSP "FSP Flashutils"
+.SH NAME
+unubi \- extract volumes/eraseblocks from a raw\-UBI image
+.SH SYNOPSIS
+\fBunubi [\-aevEV] [\-d \fIout\-dir\fB] [\-r \fIvolume\-id\fB]
+[\-b \fIblock\-size\fB] \fIimage\-file
+.SH DESCRIPTION
+.PP
+\fBunubi\fR reads an image file containing blocks of UBI headers and data
+(such as produced from \fBnand2bin\fR) and rebuilds the volumes within.
+The default operation (when no flags are given) is to rebuild all valid
+volumes found in the image. \fBunubi\fR can also read straight from the
+onboard MTD device (ex. /dev/mtdblock/NAND).
+.SH OPTIONS
+.IP "\-a, \-\-analyze"
+When flagged, analysis files are generated within the output directory. These
+may include tables and or graphs detailing statistics gathered from the
+eraseblock data. Files are prefixed `analysis_'.
+
+See \fBANALYSIS\fR.
+.IP "\-b, \-\-blocksize \fIblock\-size\fR"
+Specify in bytes the \fIimage\-file\fR eraseblock size. Sizes may be
+postfixed with `KiB' or `MiB' to indicate mebibytes or kibibytes
+respectively. Default is 128KiB.
+.IP "\-d, \-\-dir \fIoutput\-dir\fR"
+Specify the output directory. If no directory is specified, the default
+is `unubi_\fIimage\-file\fR' within the curent working directory. If the
+attempt to create the output directory fails,
+.B unubi
+will try to create it in /tmp before aborting.
+.IP "\-e, \-\-eb\-split"
+When flagged, images are created for each eraseblock in \fIimage\-file\fR
+regardless of its validity. Each image is the complete eraseblock, including
+headers and any space to the end of the eraseblock after where the data may
+end.
+
+Invalid images are named `ebEEEE', where EEEE is the physical index of the
+eraseblock in the image. Valid images are named `ebEEEE_VVV_NNN_RRR' where
+VVV is the known volume ID, NNN is the logical number and RRR is the version
+of the eraseblock data. Note that the version number is in hexadecimal.
+
+Invalid images may also contain this postfix, if the data in the header
+could be valid (ie. the header contains a resonable volume ID, but the
+header and/or data CRCs are not valid). If this is the case, images are named
+`ebEEEE_VVV_NNN_RRR.reason', so as to distinguish known values from
+non\-definite ones.
+
+See \fBREASON SUFFIXES\fR.
+.IP "\-r, \-\-rebuild \fIvolume\-id\fR"
+Specify a volume to rebuild. Can be used successively to specify
+several volumes to be rebuilt.
+
+Images are named `volumeVVV' where VVV is the volume ID. For each missing
+eraseblock, an error message will be printed.
+.IP "\-v, \-\-vol\-split"
+When flagged, images are created for each valid eraseblock in
+\fIimage\-file\fR. Since a vaild eraseblock will have a defined data start and
+data length, only this range will make up the image.
+
+Images are named `volVVV_NNN_RRR_EEEE', where, for the data in the eraseblock,
+VVV is the volume ID, NNN is the logical number, RRR is the version and EEEE
+is the phyisical index of the eraseblock in the image.
+.IP "\-V, \-\-vol\-split!"
+Same as above, only all images are the complete eraseblock (including headers,
+and raw data, even past the point where the data is supposed to end).
+Overrides \-v when both \-v and \-V are flagged.
+.SH ANALYSIS
+The following files will be generated during the analysis:
+.IP "analysis_ec_hdr.data"
+A space delimited table with these two columns for each eraseblock: the
+eraseblock's index or physical position in the image, and the eraseblock's
+erase count. The third column contains the erase count data sorted.
+.IP "analysis_vid_hdr.data"
+A space delimited table with these four colums for each eraseblock: the
+volume ID, the volume logical number, the leb version, and the data size.
+In addition there are a normalized column representing the volume ID and
+volume logical number, a normalized column representing the leb version, and
+a normalized column representing the data_size. These normalized columns are
+used to better draw the the gnuplot image.
+.IP "analysis_ec_hdr.plot"
+A gnuplot script for quickly viewing a sample output from the respective .data
+file.
+.IP "analysis_vid_hdr.plot"
+A gnuplot script for quickly viewing a sample output from the respective .data
+file.
+.SH REASONS SUFFIXES
+When \-\-eb\-split produces possibly invalid, though usable, eraseblocks, the
+known reason suffixes are:
+.IP ".ec_magic"
+The erase counter header did not contain a valid magic field.
+.IP ".ec_hdr_crc"
+The erase counter header did not contain a vaild header CRC field.
+.IP ".vid_magic"
+The volume ID header did not contain a valid magic field.
+.IP ".vid_hdr_crc"
+The volume ID header did not contain a valid header CRC field.
+.IP ".data_crc"
+The volume ID header did not contain a valid data CRC field.
+.SH EXAMPLES
+To extract and rebuild all valid volumes from demo.img (note the output
+directory will be /home/user/unubi_demo.img):
+.sp 1
+.RS
+.B /home/user# unubi demo.img
+.sp 1
+.RE
+To analyze demo.img as well as extract and rebuild volume 7:
+.sp 1
+.RS
+.B /home/user# unubi \-a \-r 7 demo.img
+.sp 1
+.RE
+To split demo.img into raw images for each eraseblock into the folder
+/var/eraseblocks:
+.sp 1
+.RS
+.B /home/user# unubi \-e \-d /var/eraseblocks demo.img
+.SH AUTHORS
+Frank Haverkamp <haver@vnet.ibm.com>
+.sp 0
+Drake Dowsett <dowsett@de.ibm.com>
+.SH CONTACT
+Andreas Arnez <arnez@de.ibm.com>
diff --git a/drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h b/drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h
new file mode 100644
index 00000000000..d39c1b93ef1
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * UBI (Unsorted Block Images) library.
+ */
+
+#ifndef __LIBUBI_H__
+#define __LIBUBI_H__
+
+#include <stdint.h>
+#include <mtd/ubi-user.h>
+#include <ctype.h>
+#include <mtd/ubi-header.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* UBI version libubi is made for */
+#define LIBUBI_UBI_VERSION 1
+
+/* UBI library descriptor */
+typedef void * libubi_t;
+
+/**
+ * struct ubi_mkvol_request - volume creation request.
+ * */
+struct ubi_mkvol_request
+{
+ int vol_id;
+ int alignment;
+ long long bytes;
+ int vol_type;
+ const char *name;
+};
+
+/**
+ * struct ubi_info - general UBI information.
+ *
+ * @dev_count count of UBI devices in system
+ * @lowest_dev_num lowest UBI device number
+ * @highest_dev_num highest UBI device number
+ * @version UBI version
+ */
+struct ubi_info
+{
+ int dev_count;
+ int lowest_dev_num;
+ int highest_dev_num;
+ int version;
+};
+
+/**
+ * struct ubi_dev_info - UBI device information.
+ *
+ * @vol_count count of volumes on this UBI device
+ * @lowest_vol_num lowest volume number
+ * @highest_vol_num highest volume number
+ * @total_ebs total number of eraseblocks on this UBI device
+ * @avail_ebs how many eraseblocks are not used and available for new
+ * volumes
+ * @total_bytes @total_ebs * @eb_size
+ * @avail_bytes @avail_ebs * @eb_size
+ * @bad_count count of bad eraseblocks
+ * @eb_size size of UBI eraseblock
+ * @max_ec current highest erase counter value
+ * @bad_rsvd how many physical eraseblocks of the underlying flash
+ * device are reserved for bad eraseblocks handling
+ * @max_vol_count maximum count of volumes on this UBI device
+ * @min_io_size minimum input/output size of the UBI device
+ */
+struct ubi_dev_info
+{
+ int dev_num;
+ int vol_count;
+ int lowest_vol_num;
+ int highest_vol_num;
+ int total_ebs;
+ int avail_ebs;
+ long long total_bytes;
+ long long avail_bytes;
+ int bad_count;
+ int eb_size;
+ long long max_ec;
+ int bad_rsvd;
+ int max_vol_count;
+ int min_io_size;
+};
+
+/**
+ * struct ubi_vol_info - UBI volume information.
+ *
+ * @dev_num UBI device number the volume resides on
+ * @vol_id ID of this volume
+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @alignment alignemnt of this volume
+ * @data_bytes how many data bytes are stored on this volume (equivalent to
+ * @rsvd_bytes for dynamic volumes)
+ * @rsvd_bytes how many bytes are reserved for this volume
+ * @rsvd_ebs how many eraseblocks are reserved for this volume
+ * @eb_size logical eraseblock size of this volume (may be less then
+ * device's logical eraseblock size due to alignment)
+ * @corrupted the volume is corrupted if this flag is not zero
+ * @name volume name (null-terminated)
+ */
+struct ubi_vol_info
+{
+ int dev_num;
+ int vol_id;
+ int type;
+ int alignment;
+ long long data_bytes;
+ long long rsvd_bytes;
+ int rsvd_ebs;
+ int eb_size;
+ int corrupted;
+ char name[UBI_VOL_NAME_MAX + 1];
+};
+
+/**
+ * libubi_open - open UBI library.
+ *
+ * This function initializes and opens the UBI library and returns UBI library
+ * descriptor in case of success and %NULL in case of failure.
+ */
+libubi_t libubi_open(void);
+
+/**
+ * libubi_close - close UBI library
+ *
+ * @desc UBI library descriptor
+ */
+void libubi_close(libubi_t desc);
+
+/**
+ * ubi_get_info - get general UBI information.
+ *
+ * @info pointer to the &struct ubi_info object to fill
+ * @desc UBI library descriptor
+ *
+ * This function fills the passed @info object with general UBI information and
+ * returns %0 in case of success and %-1 in case of failure.
+ */
+int ubi_get_info(libubi_t desc, struct ubi_info *info);
+
+/**
+ * ubi_mkvol - create an UBI volume.
+ *
+ * @desc UBI library descriptor
+ * @node name of the UBI character device to create a volume at
+ * @req UBI volume creation request (defined at <mtd/ubi-user.h>)
+ *
+ * This function creates a UBI volume as described at @req and returns %0 in
+ * case of success and %-1 in case of failure. The assigned volume ID is
+ * returned in @req->vol_id.
+ */
+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req);
+
+/**
+ * ubi_rmvol - remove a UBI volume.
+ *
+ * @desc UBI library descriptor
+ * @node name of the UBI character device to remove a volume from
+ * @vol_id ID of the volume to remove
+ *
+ * This function removes volume @vol_id from UBI device @node and returns %0 in
+ * case of success and %-1 in case of failure.
+ */
+int ubi_rmvol(libubi_t desc, const char *node, int vol_id);
+
+/**
+ * ubi_rsvol - re-size UBI volume.
+ *
+ * @desc UBI library descriptor
+ * @node name of the UBI character device owning the volume which should be
+ * re-sized
+ * @vol_id volume ID to re-size
+ * @bytes new volume size in bytes
+ *
+ * This function returns %0 in case of success and %-1 in case of error.
+ */
+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes);
+
+/**
+ * ubi_get_dev_info - get UBI device information.
+ *
+ * @desc UBI library descriptor
+ * @node name of the UBI character device to fetch information about
+ * @info pointer to the &struct ubi_dev_info object to fill
+ *
+ * This function fills the passed @info object with UBI device information and
+ * returns %0 in case of success and %-1 in case of failure.
+ */
+int ubi_get_dev_info(libubi_t desc, const char *node,
+ struct ubi_dev_info *info);
+
+/**
+ * ubi_get_dev_info1 - get UBI device information.
+ *
+ * @desc UBI library descriptor
+ * @dev_num UBI device number to fetch information about
+ * @info pointer to the &struct ubi_dev_info object to fill
+ *
+ * This function is identical to 'ubi_get_dev_info()' except that it accepts UBI
+ * device number, not UBI character device.
+ */
+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info);
+
+/**
+ * ubi_get_vol_info - get UBI volume information.
+ *
+ * @desc UBI library descriptor
+ * @node name of the UBI volume character device to fetch information about
+ * @info pointer to the &struct ubi_vol_info object to fill
+ *
+ * This function fills the passed @info object with UBI volume information and
+ * returns %0 in case of success and %-1 in case of failure.
+ */
+int ubi_get_vol_info(libubi_t desc, const char *node,
+ struct ubi_vol_info *info);
+
+/**
+ * ubi_get_vol_info1 - get UBI volume information.
+ *
+ * @desc UBI library descriptor
+ * @dev_num UBI device number
+ * @vol_id ID of the UBI volume to fetch information about
+ * @info pointer to the &struct ubi_vol_info object to fill
+ *
+ * This function is identical to 'ubi_get_vol_info()' except that it accepts UBI
+ * volume number, not UBI volume character device.
+ */
+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
+ struct ubi_vol_info *info);
+
+/**
+ * ubi_update_start - start UBI volume update.
+ *
+ * @desc UBI library descriptor
+ * @fd volume character devie file descriptor
+ * @bytes how many bytes will be written to the volume
+ *
+ * This function initiates UBI volume update and returns %0 in case of success
+ * and %-1 in case of error.
+ */
+int ubi_update_start(libubi_t desc, int fd, long long bytes);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBUBI_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am b/drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am
new file mode 100644
index 00000000000..1b0dc01a663
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am
@@ -0,0 +1,58 @@
+AUTOMAKE_OPTIONS = foreign
+INCLUDES=-I$(top_srcdir)/inc -I$(top_srcdir)/../../kernel/include
+
+# -----------------------------------------------------------------------------
+# all export libs which shall be generated
+lib_LTLIBRARIES = libubi.la \
+ libpfiflash.la
+
+# -----------------------------------------------------------------------------
+# all convinence libs which shall be generated
+noinst_LTLIBRARIES = libcrc32.la \
+ libubigen.la \
+ liberror.la \
+ liblist.la \
+ libbootenv.la \
+ libpfi.la \
+ libpeb.la \
+ libreader.la \
+ libubimirror.la
+
+# -----------------------------------------------------------------------------
+# exported libs
+libpfiflash_la_SOURCES = $(top_srcdir)/src/libpfiflash/pfiflash.c
+libpfiflash_la_LDFLAGS = -no-undefined -version-info 1:0:0
+libpfiflash_la_LIBADD = libreader.la \
+ libubimirror.la \
+ libubi.la
+
+libubi_la_SOURCES = $(top_srcdir)/src/libubi/libubi.c \
+ $(top_srcdir)/src/libubi/libubi_sysfs.c
+libubi_la_LDFLAGS = -no-undefined -version-info 1:0:0
+
+# -----------------------------------------------------------------------------
+# complex convinence libs, beware for double includes.
+libreader_la_SOURCES = $(top_srcdir)/src/libreader/reader.c
+libreader_la_LIBADD = libpfi.la \
+ liblist.la \
+ libpeb.la \
+ libbootenv.la
+
+libubigen_la_SOURCES = $(top_srcdir)/src/libubigen/ubigen.c
+libubigen_la_LIBADD = libcrc32.la
+
+libbootenv_la_SOURCES = $(top_srcdir)/src/libbootenv/bootenv.c \
+ $(top_srcdir)/src/libbootenv/hashmap.c
+libbootenv_la_LIBADD = libcrc32.la
+
+libubimirror_la_SOURCES = $(top_srcdir)/src/libubimirror/ubimirror.c
+libubimirror_la_LIBADD = libubi.la
+
+
+# -----------------------------------------------------------------------------
+# simple convinence libs
+libcrc32_la_SOURCES = $(top_srcdir)/src/libcrc32/crc32.c
+liberror_la_SOURCES = $(top_srcdir)/src/liberror/error.c
+liblist_la_SOURCES = $(top_srcdir)/src/liblist/list.c
+libpeb_la_SOURCES = $(top_srcdir)/src/libpeb/peb.c
+libpfi_la_SOURCES = $(top_srcdir)/src/libpfi/pfi.c
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser b/drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser
new file mode 100644
index 00000000000..dbfa45dae4e
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser
@@ -0,0 +1,21 @@
+Copyright (c) 2000-2007 by Nicolas Devillard.
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile b/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile
new file mode 100644
index 00000000000..d21ead593f9
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile
@@ -0,0 +1,84 @@
+#
+# Makefile for ubi-utils
+#
+
+OPTFLAGS := -O2 -Wall
+KERNELHDR := ../../include
+#DESTDIR := /usr/local
+DESTDIR := /nfsroot/user/yrtan
+SBINDIR=/usr/sbin
+MANDIR=/usr/man
+INCLUDEDIR=/usr/include
+CROSS=mipsel-linux-
+CC := $(CROSS)gcc
+CFLAGS := -Iinclude -Isrc -I$(KERNELHDR) $(OPTFLAGS) -Werror -Wall
+
+LIBS = libubi libmtd libubigen libiniparser libscan
+UTILS = ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \
+ ubidetach ubiformat ubidumpvol ubicrcvol \
+ ubinize ubicrcsf ubirefimg
+vpath %.c src
+
+all: $(UTILS)
+ mkdir -p ./new-utils-dir
+ cp $(UTILS) ./new-utils-dir
+
+# The below cancels existing implicite rule to make programs from .c files,
+# in order to force make using our rule defined below
+%: %.c
+
+# The below is the rule to get an .o file from a .c file
+%.o: %.c
+ $(CC) $(CFLAGS) $< -c -o $@
+
+# And the below is the rule to get final executable from its .o and common.o
+%: libubi.a %.o common.o
+ $(CC) $(CFLAGS) $(filter %.o, $^) -L. -lubi -o $@
+
+ubicrcsf: ubicrcsf.o crc32.o
+ $(CC) $(CFLAGS) -o $@ $^
+
+ubicrcvol: ubicrcvol.o common.o crc32.o libubi.a
+ $(CC) $(CFLAGS) $(filter %.o, $^) -L. -lubi -o $@
+
+ubicrc32: ubicrc32.o crc32.o
+ $(CC) $(CFLAGS) -o $@ $^
+
+ubinize: ubinize.o common.o crc32.o libiniparser.a libubigen.a
+ $(CC) $(CFLAGS) $(filter %.o, $^) -L. -liniparser -lubigen -o $@
+
+ubiformat: ubiformat.o common.o crc32.o libmtd.a libscan.a libubi.a libubigen.a
+ $(CC) $(CFLAGS) $(filter %.o, $^) -L. -lmtd -lscan -lubi -lubigen -o $@
+
+libubi.a: libubi.o
+ $(AR) crv $@ $^
+ ranlib $@
+
+libmtd.a: libmtd.o
+ $(AR) crv $@ $^
+ ranlib $@
+
+libubigen.a: libubigen.o
+ $(AR) crv $@ $^
+ ranlib $@
+
+libiniparser.a: libiniparser.o dictionary.o
+ $(AR) crv $@ $^
+ ranlib $@
+
+libscan.a: libscan.o crc32.o
+ $(AR) crv $@ $^
+ ranlib $@
+
+clean:
+ rm -rf *.o $(addsuffix .a, $(LIBS)) $(UTILS) .*.c.dep
+ rm -rf new-utils-dir
+
+install: ${UTILS}
+ mkdir -p ${DESTDIR}/${SBINDIR}
+ install -m0755 ${UTILS} ${DESTDIR}/${SBINDIR}/
+
+uninstall:
+ for file in ${UTILS}; do \
+ $(RM) ${DESTDIR}/${SBINDIR}/$$file; \
+ done
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/README b/drivers/mtd/mtd-utils/ubi-utils/new-utils/README
new file mode 100644
index 00000000000..41c59576261
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/README
@@ -0,0 +1,55 @@
+This directory contains a new UBI toolchain which is intended to replace
+the old one. All utilities support "-h" option which prints sufficient
+usage information. See the MTD web-site for more information.
+
+Motivation for new tool-chain.
+
+I was doing very active UBI development and had to add new features like
+dynamic UBI devices and auto-resize feature. Because of the mess in the
+the old tools I basically could not figure out how to upgrade them. In
+my humble oppinion, they are unmaintainable. The original authors did not
+show enthusiasm when I mailed them and asked to clean-up the tool-chain
+[1]. Thus, I re-implemented them, but I did borrow things from the old
+tool-chain and preserved copyrights and author names.
+
+I really did try to clean-up the old tool chain, but gave up (see git
+history for confirmation). So,
+
+1. I found the source codes very difficult to navigate and read, especially
+ those related to pdd, pfi, and bootenv. Try to do this yourself - they
+ are a puzzle.
+2. I foud the concept of PFI needlesly complecated - PFI file is nothing
+ else but the initial configuration .ini file + the contents of the
+ UBI volumes packed into one file, but with some changes of the .ini file's
+ format. The PFI file format is not very nice and it is difficult to parse,
+ especially because the PFI headers do not tell you data star and end for
+ each data chunk, and you have to do additional parsing.
+
+ So basically, you have .ini file + images, then you transfer this to pfi,
+ which does not add any other information. For .ini you have libraries
+ which may parse them, for pfi - not. Then you have to parse this pfi
+ which adds unneeded and complex code. This all needs lists, hashmaps,
+ and so on - for no reason.
+3. I found the command line options of the utilities to be inconsistent.
+ This is OK when you script your single task and do not touch it anymore.
+ But when you have to use the utilities while developing and testing,
+ It is difficult to remember their inconsistent options.
+4. I found it wrong to add development options to user utilities like
+ "broken update". End users should not see them.
+5. I did not find any consistent style and convention inside which
+ irritated me.
+6. I found it weird to introduce needless "logging infrastructure" instead
+ of just re-directing stdout and stderr to another file.
+7. I found the tool to be rather IBM-setup oriented. For example, the VID
+ header position was hard-coded. Some utilities were just weird, like
+ mkbootenv, which changed some ethernet addresses mentioned in a
+ configuration file.
+8. Finally, it was very difficult to realize what is pfi and pdd, what for,
+ why I need this transiant pfi file when I just want to create an UBI
+ image. There was zero documentation.
+
+And so on.
+
+Feb 19, 2008, Artem Bityutskiy.
+
+[1]. http://lists.infradead.org/pipermail/linux-mtd/2007-December/020134.html
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h b/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h
new file mode 100644
index 00000000000..0b0ab646a95
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h
@@ -0,0 +1,280 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file iniparser.h
+ @author N. Devillard
+ @date Sep 2007
+ @version 3.0
+ @brief Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: libiniparser.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ $Revision: 1.1.1.1 $
+*/
+
+#ifndef _INIPARSER_H_
+#define _INIPARSER_H_
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * The following #include is necessary on many Unixes but not Linux.
+ * It is not needed for Windows platforms.
+ * Uncomment it if needed.
+ */
+/* #include <unistd.h> */
+
+#include "dictionary.h"
+
+/*---------------------------------------------------------------------------
+ Macros
+ ---------------------------------------------------------------------------*/
+/** For backwards compatibility only */
+#define iniparser_getstr(d, k) iniparser_getstring(d, k, NULL)
+#define iniparser_setstr iniparser_setstring
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get number of sections in a dictionary
+ @param d Dictionary to examine
+ @return int Number of sections found in dictionary
+
+ This function returns the number of sections found in a dictionary.
+ The test to recognize sections is done on the string stored in the
+ dictionary: a section name is given as "section" whereas a key is
+ stored as "section:key", thus the test looks for entries that do not
+ contain a colon.
+
+ This clearly fails in the case a section name contains a colon, but
+ this should simply be avoided.
+
+ This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+int iniparser_getnsec(dictionary * d);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get name for section n in a dictionary.
+ @param d Dictionary to examine
+ @param n Section number (from 0 to nsec-1).
+ @return Pointer to char string
+
+ This function locates the n-th section in a dictionary and returns
+ its name as a pointer to a string statically allocated inside the
+ dictionary. Do not free or modify the returned string!
+
+ This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+char * iniparser_getsecname(dictionary * d, int n);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Save a dictionary to a loadable ini file
+ @param d Dictionary to dump
+ @param f Opened file pointer to dump to
+ @return void
+
+ This function dumps a given dictionary into a loadable ini file.
+ It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_dump_ini(dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump.
+ @param f Opened file pointer to dump to.
+ @return void
+
+ This function prints out the contents of a dictionary, one element by
+ line, onto the provided file pointer. It is OK to specify @c stderr
+ or @c stdout as output files. This function is meant for debugging
+ purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param def Default value to return if key not found.
+ @return pointer to statically allocated character string
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the pointer passed as 'def' is returned.
+ The returned char pointer is pointing to a string allocated in
+ the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstring(dictionary * d, const char * key, char * def);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to an int
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ Supported values for integers include the usual C notation
+ so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+ are supported. Examples:
+
+ - "42" -> 42
+ - "042" -> 34 (octal -> decimal)
+ - "0x42" -> 66 (hexa -> decimal)
+
+ Warning: the conversion may overflow in various ways. Conversion is
+ totally outsourced to strtol(), see the associated man page for overflow
+ handling.
+
+ Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(dictionary * d, const char * key, int notfound);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a double
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return double
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+ */
+/*--------------------------------------------------------------------------*/
+double iniparser_getdouble(dictionary * d, char * key, double notfound);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a boolean
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ A true boolean is found if one of the following is matched:
+
+ - A string starting with 'y'
+ - A string starting with 'Y'
+ - A string starting with 't'
+ - A string starting with 'T'
+ - A string starting with '1'
+
+ A false boolean is found if one of the following is matched:
+
+ - A string starting with 'n'
+ - A string starting with 'N'
+ - A string starting with 'f'
+ - A string starting with 'F'
+ - A string starting with '0'
+
+ The notfound value returned if no boolean is identified, does not
+ necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(dictionary * d, const char * key, int notfound);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set an entry in a dictionary.
+ @param ini Dictionary to modify.
+ @param entry Entry to modify (entry name)
+ @param val New value to associate to the entry.
+ @return int 0 if Ok, -1 otherwise.
+
+ If the given entry can be found in the dictionary, it is modified to
+ contain the provided value. If it cannot be found, -1 is returned.
+ It is Ok to set val to NULL.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_setstring(dictionary * ini, char * entry, char * val);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete an entry in a dictionary
+ @param ini Dictionary to modify
+ @param entry Entry to delete (entry name)
+ @return void
+
+ If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, char * entry);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Finds out if a given entry exists in a dictionary
+ @param ini Dictionary to search
+ @param entry Name of the entry to look for
+ @return integer 1 if entry exists, 0 otherwise
+
+ Finds out if a given entry exists in the dictionary. Since sections
+ are stored as keys with NULL associated values, this is the only way
+ of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(dictionary * ini, char * entry) ;
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Parse an ini file and return an allocated dictionary object
+ @param ininame Name of the ini file to read.
+ @return Pointer to newly allocated dictionary
+
+ This is the parser for ini files. This function is called, providing
+ the name of the file to be read. It returns a dictionary object that
+ should not be accessed directly, but through accessor functions
+ instead.
+
+ The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Free all memory associated to an ini dictionary
+ @param d Dictionary to free
+ @return void
+
+ Free all memory associated to an ini dictionary.
+ It is mandatory to call this function before the dictionary object
+ gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d);
+
+#endif
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h b/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h
new file mode 100644
index 00000000000..d3c6a6320f3
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * MTD library.
+ */
+
+#ifndef __LIBMTD_H__
+#define __LIBMTD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * struct mtd_info - information about an MTD device.
+ * @num: MTD device number
+ * @major: major number of corresponding character device
+ * @minor: minor number of corresponding character device
+ * @type: flash type (constants like %MTD_NANDFLASH defined in mtd-abi.h)
+ * @type_str: static R/O flash type string
+ * @size: device size in bytes
+ * @eb_cnt: count of eraseblocks
+ * @eb_size: eraseblock size
+ * @min_io_size: minimum input/output unit size
+ * @subpage_size: sub-page size (not set by 'mtd_get_info()'!!!)
+ * @rdonly: non-zero if the device is read-only
+ * @allows_bb: non-zero if the MTD device may have bad eraseblocks
+ * @fd: descriptor of the opened MTD character device node
+ */
+struct mtd_info
+{
+ int num;
+ int major;
+ int minor;
+ int type;
+ const char *type_str;
+ long long size;
+ int eb_cnt;
+ int eb_size;
+ int min_io_size;
+ int subpage_size;
+ unsigned int rdonly:1;
+ unsigned int allows_bb:1;
+ int fd;
+};
+
+int mtd_get_info(const char *node, struct mtd_info *mtd);
+int mtd_erase(const struct mtd_info *mtd, int eb);
+int mtd_is_bad(const struct mtd_info *mtd, int eb);
+int mtd_read(const struct mtd_info *mtd, int eb, int offs, void *buf, int len);
+int mtd_write(const struct mtd_info *mtd, int eb, int offs, void *buf, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LIBMTD_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h b/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h
new file mode 100644
index 00000000000..5afc93e3a62
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI scanning library.
+ */
+
+#ifndef __LIBSCAN_H__
+#define __LIBSCAN_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * If an eraseblock does not contain an erase counter, this value is used
+ * instead of the erase counter.
+ */
+#define NO_EC 0xFFFFFFFF
+
+/*
+ * If an eraseblock contains a corrupted erase counter, this value is used
+ * instead of the erase counter.
+ */
+#define CORRUPT_EC 0xFFFFFFFE
+
+/*
+ * If an eraseblock does not contain an erase counter, one of these values is
+ * used.
+ *
+ * @EB_EMPTY: the eraseblock appeared to be empty
+ * @EB_CORRUPTED: the eraseblock contains corrupted erase counter header
+ * @EB_ALIEN: the eraseblock contains some non-UBI data
+ * @EC_MAX: maximum allowed erase counter value
+ */
+enum
+{
+ EB_EMPTY = 0xFFFFFFFF,
+ EB_CORRUPTED = 0xFFFFFFFE,
+ EB_ALIEN = 0xFFFFFFFD,
+ EB_BAD = 0xFFFFFFFC,
+ EC_MAX = UBI_MAX_ERASECOUNTER,
+};
+
+/**
+ * struct ubi_scan_info - UBI scanning information.
+ * @ec: erase counters or eraseblock status for all eraseblocks
+ * @mean_ec: mean erase counter
+ * @ok_cnt: count of eraseblock with correct erase counter header
+ * @empty_cnt: count of supposedly eraseblocks
+ * @corrupted_cnt: count of eraseblocks with corrupted erase counter header
+ * @alien_cnt: count of eraseblock containing non-ubi data
+ * @bad_cnt: count of bad eraseblocks
+ * @bad_cnt: count of non-bad eraseblocks
+ * @vid_hdr_offs: volume ID header offset from the found EC headers (%-1 means
+ * undefined)
+ * @data_offs: data offset from the found EC headers (%-1 means undefined)
+ */
+struct ubi_scan_info
+{
+ uint32_t *ec;
+ long long mean_ec;
+ int ok_cnt;
+ int empty_cnt;
+ int corrupted_cnt;
+ int alien_cnt;
+ int bad_cnt;
+ int good_cnt;
+ int vid_hdr_offs;
+ int data_offs;
+};
+
+struct mtd_info;
+
+/**
+ * ubi_scan - scan an MTD device.
+ * @mtd: information about the MTD device to scan
+ * @info: the result of the scanning is returned here
+ * @verbose: verbose mode: %0 - be silent, %1 - output progress information,
+ * 2 - debugging output mode
+ */
+int ubi_scan(struct mtd_info *mtd, struct ubi_scan_info **info, int verbose);
+
+/**
+ * ubi_scan_free - free scanning information.
+ * @si: scanning information to free
+ */
+void ubi_scan_free(struct ubi_scan_info *si);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LIBSCAN_H__ */
+
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h b/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h
new file mode 100644
index 00000000000..8fd857a5c5f
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI (Unsorted Block Images) library.
+ */
+
+#ifndef __LIBUBI_H__
+#define __LIBUBI_H__
+
+#include <ctype.h>
+#include <stdint.h>
+#include <mtd/ubi-user.h>
+#include <mtd/ubi-header.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* UBI version libubi is made for */
+#define LIBUBI_UBI_VERSION 1
+
+/* UBI library descriptor */
+typedef void * libubi_t;
+
+/**
+ * struct ubi_attach_request - MTD device attachement request.
+ * @dev_num: number to assigne to the newly created UBI device
+ * (%UBI_DEV_NUM_AUTO should be used to automatically assign the
+ * number)
+ * @mtd_num: MTD device number to attach
+ * @vid_hdr_offset: VID header offset (%0 means default offset and this is what
+ * most of the users want)
+ */
+struct ubi_attach_request
+{
+ int dev_num;
+ int mtd_num;
+ int vid_hdr_offset;
+};
+
+/**
+ * struct ubi_mkvol_request - volume creation request.
+ * @vol_id: ID to assign to the new volume (%UBI_VOL_NUM_AUTO should be used to
+ * automatically assign ID)
+ * @alignment: volume alignment
+ * @bytes: volume size in bytes
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @name: volume name
+ */
+struct ubi_mkvol_request
+{
+ int vol_id;
+ int alignment;
+ long long bytes;
+ int vol_type;
+ const char *name;
+};
+
+/**
+ * struct ubi_info - general UBI information.
+ * @dev_count: count of UBI devices in system
+ * @lowest_dev_num: lowest UBI device number
+ * @highest_dev_num: highest UBI device number
+ * @version: UBI version
+ * @ctrl_major: major number of the UBI control device
+ * @ctrl_minor: minor number of the UBI control device
+ */
+struct ubi_info
+{
+ int dev_count;
+ int lowest_dev_num;
+ int highest_dev_num;
+ int version;
+ int ctrl_major;
+ int ctrl_minor;
+};
+
+/**
+ * struct ubi_dev_info - UBI device information.
+ * @vol_count: count of volumes on this UBI device
+ * @lowest_vol_num: lowest volume number
+ * @highest_vol_num: highest volume number
+ * @major: major number of corresponding character device
+ * @minor: minor number of corresponding character device
+ * @total_lebs: total number of logical eraseblocks on this UBI device
+ * @avail_lebs: how many logical eraseblocks are not used and available for new
+ * volumes
+ * @total_bytes: @total_lebs * @leb_size
+ * @avail_bytes: @avail_lebs * @leb_size
+ * @bad_count: count of bad physical eraseblocks
+ * @leb_size: logical eraseblock size
+ * @max_ec: current highest erase counter value
+ * @bad_rsvd: how many physical eraseblocks of the underlying flash device are
+ * reserved for bad eraseblocks handling
+ * @max_vol_count: maximum possible number of volumes on this UBI device
+ * @min_io_size: minimum input/output unit size of the UBI device
+ */
+struct ubi_dev_info
+{
+ int dev_num;
+ int vol_count;
+ int lowest_vol_num;
+ int highest_vol_num;
+ int major;
+ int minor;
+ int total_lebs;
+ int avail_lebs;
+ long long total_bytes;
+ long long avail_bytes;
+ int bad_count;
+ int leb_size;
+ long long max_ec;
+ int bad_rsvd;
+ int max_vol_count;
+ int min_io_size;
+};
+
+/**
+ * struct ubi_vol_info - UBI volume information.
+ * @dev_num: UBI device number the volume resides on
+ * @vol_id: ID of this volume
+ * @major: major number of corresponding volume character device
+ * @minor: minor number of corresponding volume character device
+ * @dev_major: major number of corresponding UBI device character device
+ * @dev_minor: minor number of corresponding UBI device character device
+ * @type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @alignment: alignemnt of this volume
+ * @data_bytes: how many data bytes are stored on this volume (equivalent to
+ * @rsvd_bytes for dynamic volumes)
+ * @rsvd_bytes: how many bytes are reserved for this volume
+ * @rsvd_lebs: how many logical eraseblocks are reserved for this volume
+ * @leb_size: logical eraseblock size of this volume (may be less then
+ * device's logical eraseblock size due to alignment)
+ * @corrupted: non-zero if the volume is corrupted
+ * @name: volume name (null-terminated)
+ */
+struct ubi_vol_info
+{
+ int dev_num;
+ int vol_id;
+ int major;
+ int minor;
+ int dev_major;
+ int dev_minor;
+ int type;
+ int alignment;
+ long long data_bytes;
+ long long rsvd_bytes;
+ int rsvd_lebs;
+ int leb_size;
+ int corrupted;
+ char name[UBI_VOL_NAME_MAX + 1];
+};
+
+/**
+ * libubi_open - open UBI library.
+ * @required: if non-zero, libubi will print an error messages if this UBI is
+ * not present in the system
+ *
+ * This function initializes and opens the UBI library and returns UBI library
+ * descriptor in case of success and %NULL in case of failure.
+ */
+libubi_t libubi_open(int required);
+
+/**
+ * libubi_close - close UBI library.
+ * @desc UBI library descriptor
+ */
+void libubi_close(libubi_t desc);
+
+/**
+ * ubi_get_info - get general UBI information.
+ * @desc: UBI library descriptor
+ * @info: pointer to the &struct ubi_info object to fill
+ *
+ * This function fills the passed @info object with general UBI information and
+ * returns %0 in case of success and %-1 in case of failure.
+ */
+int ubi_get_info(libubi_t desc, struct ubi_info *info);
+
+/**
+ * mtd_num2ubi_dev - find UBI device by attached MTD device.
+ * @@desc: UBI library descriptor
+ * @mtd_num: MTD device number
+ * @dev_num: UBI device number is returned here
+ *
+ * This function finds UBI device to which MTD device @mtd_num is attached.
+ * Returns %0 if the UBI device was found and %-1 if not.
+ */
+int mtd_num2ubi_dev(libubi_t desc, int mtd_num, int *dev_num);
+
+/**
+ * ubi_attach_mtd - attach MTD device to UBI.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI control character device node
+ * @req: MTD attach request.
+ *
+ * This function creates a new UBI device by attaching an MTD device as
+ * described by @req. Returns %0 in case of success and %-1 in case of failure.
+ * The newly created UBI device number is returned in @req->dev_num.
+ */
+int ubi_attach_mtd(libubi_t desc, const char *node,
+ struct ubi_attach_request *req);
+
+/**
+ * ubi_detach_mtd - detach an MTD device.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI control character device node
+ * @mtd_num: MTD device number to detach
+ *
+ * This function detaches MTD device number @mtd_num from UBI, which means the
+ * corresponding UBI device is removed. Returns zero in case of success and %-1
+ * in case of failure.
+ */
+int ubi_detach_mtd(libubi_t desc, const char *node, int mtd_num);
+
+/**
+ * ubi_remove_dev - remove an UBI device.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI control character device node
+ * @ubi_dev: UBI device number to remove
+ *
+ * This function removes UBI device number @ubi_dev and returns zero in case of
+ * success and %-1 in case of failure.
+ */
+int ubi_remove_dev(libubi_t desc, const char *node, int ubi_dev);
+
+/**
+ * ubi_mkvol - create an UBI volume.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI character device to create a volume at
+ * @req: UBI volume creation request
+ *
+ * This function creates a UBI volume as described at @req and returns %0 in
+ * case of success and %-1 in case of failure. The assigned volume ID is
+ * returned in @req->vol_id.
+ */
+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req);
+
+/**
+ * ubi_rmvol - remove a UBI volume.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI character device to remove a volume from
+ * @vol_id: ID of the volume to remove
+ *
+ * This function removes volume @vol_id from UBI device @node and returns %0 in
+ * case of success and %-1 in case of failure.
+ */
+int ubi_rmvol(libubi_t desc, const char *node, int vol_id);
+
+/**
+ * ubi_rsvol - re-size UBI volume.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI character device owning the volume which should be
+ * re-sized
+ * @vol_id: volume ID to re-size
+ * @bytes: new volume size in bytes
+ *
+ * This function returns %0 in case of success and %-1 in case of error.
+ */
+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes);
+
+/**
+ * ubi_node_type - test UBI node type.
+ * @desc: UBI library descriptor
+ * @node: the node to test
+ *
+ * This function tests whether @node is a UBI device or volume node and returns
+ * %1 if this is an UBI device node, %2 if this is a volume node, and %-1 if
+ * this is not an UBI node or if an error occurred (the latter is indicated by
+ * a non-zero errno).
+ */
+int ubi_node_type(libubi_t desc, const char *node);
+
+/**
+ * ubi_get_dev_info - get UBI device information.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI character device to fetch information about
+ * @info: pointer to the &struct ubi_dev_info object to fill
+ *
+ * This function fills the passed @info object with UBI device information and
+ * returns %0 in case of success and %-1 in case of failure.
+ */
+int ubi_get_dev_info(libubi_t desc, const char *node,
+ struct ubi_dev_info *info);
+
+/**
+ * ubi_get_dev_info1 - get UBI device information.
+ * @desc: UBI library descriptor
+ * @dev_num: UBI device number to fetch information about
+ * @info: pointer to the &struct ubi_dev_info object to fill
+ *
+ * This function is identical to 'ubi_get_dev_info()' except that it accepts UBI
+ * device number, not UBI character device.
+ */
+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info);
+
+/**
+ * ubi_get_vol_info - get UBI volume information.
+ * @desc: UBI library descriptor
+ * @node: name of the UBI volume character device to fetch information about
+ * @info: pointer to the &struct ubi_vol_info object to fill
+ *
+ * This function fills the passed @info object with UBI volume information and
+ * returns %0 in case of success and %-1 in case of failure.
+ */
+int ubi_get_vol_info(libubi_t desc, const char *node,
+ struct ubi_vol_info *info);
+
+/**
+ * ubi_get_vol_info1 - get UBI volume information.
+ * @desc: UBI library descriptor
+ * @dev_num: UBI device number
+ * @vol_id: ID of the UBI volume to fetch information about
+ * @info: pointer to the &struct ubi_vol_info object to fill
+ *
+ * This function is identical to 'ubi_get_vol_info()' except that it accepts UBI
+ * volume number, not UBI volume character device.
+ */
+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
+ struct ubi_vol_info *info);
+
+/**
+ * ubi_update_start - start UBI volume update.
+ * @desc: UBI library descriptor
+ * @fd: volume character devie file descriptor
+ * @bytes: how many bytes will be written to the volume
+ *
+ * This function initiates UBI volume update and returns %0 in case of success
+ * and %-1 in case of error. The caller is assumed to write @bytes data to the
+ * volume @fd afterwards.
+ */
+int ubi_update_start(libubi_t desc, int fd, long long bytes);
+
+
+/**
+ * ubi_leb_read_start
+ * @fd: volume character devie file descriptor
+ * @leb: structure pointer for volume dump request
+ *
+ * This function call "UBI_IOCLEBREAD" ioctl.
+ * return %1 means the LEB is not mapped, no need to dump
+ * return %0 LEB read done successful
+ * return any others error
+ */
+int ubi_leb_read_start(int fd, struct ubi_leb *leb);
+
+/**
+ * ubi_leb_change_start - start atomic LEB change.
+ * @desc: UBI library descriptor
+ * @fd: volume character devie file descriptor
+ * @lnum: LEB number to change
+ * @bytes: how many bytes of new data will be written to the LEB
+ * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
+ *
+ * This function initiates atomic LEB change operation and returns %0 in case
+ * of success and %-1 in case of error. he caller is assumed to write @bytes
+ * data to the volume @fd afterwards.
+ */
+int ubi_leb_change_start(libubi_t desc, int fd, int lnum, int bytes, int dtype);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBUBI_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h b/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h
new file mode 100644
index 00000000000..c2b95b00191
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Authors: Frank Haverkamp
+ * Artem Bityutskiy
+ */
+
+#ifndef __LIBUBIGEN_H__
+#define __LIBUBIGEN_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * struct ubigen_info - libubigen information.
+ * @leb_size: logical eraseblock size
+ * @peb_size: size of the physical eraseblock
+ * @min_io_size: minimum input/output unit size
+ * @vid_hdr_offs: offset of the VID header
+ * @data_offs: data offset
+ * @ubi_ver: UBI version
+ * @vtbl_size: volume table size
+ * @max_volumes: maximum amount of volumes
+ */
+struct ubigen_info
+{
+ int leb_size;
+ int peb_size;
+ int min_io_size;
+ int vid_hdr_offs;
+ int data_offs;
+ int ubi_ver;
+ int vtbl_size;
+ int max_volumes;
+};
+
+/**
+ * struct ubigen_vol_info - information about a volume.
+ * @id: volume id
+ * @type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
+ * @alignment: volume alignment
+ * @data_pad: how many bytes are unused at the end of the each physical
+ * eraseblock to satisfy the requested alignment
+ * @usable_leb_size: LEB size accessible for volume users
+ * @name: volume name
+ * @name_len: volume name length
+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
+ * @used_ebs: total number of used logical eraseblocks in this volume (relevant
+ * for static volumes only)
+ * @bytes: size of the volume contents in bytes (relevant for static volumes
+ * only)
+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
+ */
+struct ubigen_vol_info
+{
+ int id;
+ int type;
+ int alignment;
+ int data_pad;
+ int usable_leb_size;
+ const char *name;
+ int name_len;
+ int compat;
+ int used_ebs;
+ long long bytes;
+ uint8_t flags;
+};
+
+void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
+ int subpage_size, int vid_hdr_offs, int ubi_ver);
+struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui);
+void ubigen_init_ec_hdr(const struct ubigen_info *ui,
+ struct ubi_ec_hdr *hdr, long long ec);
+int ubigen_get_vtbl_size(const struct ubigen_info *ui);
+int ubigen_add_volume(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi,
+ struct ubi_vtbl_record *vtbl);
+int ubigen_write_volume(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi, long long ec,
+ long long bytes, int in, int out);
+int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
+ long long ec1, long long ec2,
+ struct ubi_vtbl_record *vtbl, int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBUBIGEN_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c
new file mode 100644
index 00000000000..bcb775c1ca7
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2007, 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file contains various common stuff used by UBI utilities.
+ *
+ * Authors: Artem Bityutskiy
+ * Adrian Hunter
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/**
+ * get_multiplier - convert size specifier to an integer multiplier.
+ * @str: the size specifier string
+ *
+ * This function parses the @str size specifier, which may be one of
+ * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive
+ * size multiplier in case of success and %-1 in case of failure.
+ */
+static int get_multiplier(const char *str)
+{
+ if (!str)
+ return 1;
+
+ /* Remove spaces before the specifier */
+ while (*str == ' ' || *str == '\t')
+ str += 1;
+
+ if (!strcmp(str, "KiB"))
+ return 1024;
+ if (!strcmp(str, "MiB"))
+ return 1024 * 1024;
+ if (!strcmp(str, "GiB"))
+ return 1024 * 1024 * 1024;
+
+ /* Handle deprecated stuff */
+ if (!strcmp(str, "KB") || !strcmp(str, "Kib") || !strcmp(str, "kib") ||
+ !strcmp(str, "kiB")) {
+ fprintf(stderr, "Warning: use \"KiB\" instead of \"%s\" to "
+ "specify Kilobytes - support will be removed\n", str);
+ return 1024;
+ }
+ if (!strcmp(str, "MB") || !strcmp(str, "Mib") || !strcmp(str, "mb")) {
+ fprintf(stderr, "Warning: use \"MiB\" instead of \"%s\", "
+ "this support will be removed\n", str);
+ return 1024*1024;
+ }
+ if (!strcmp(str, "GB") || !strcmp(str, "Gib") || !strcmp(str, "gb")) {
+ fprintf(stderr, "Warning: use \"GiB\" instead of \"%s\", "
+ "this support will be removed\n", str);
+ return 1024*1024*1024;
+ }
+
+ return -1;
+}
+
+/**
+ * ubiutils_get_bytes - convert a string containing amount of bytes into an
+ * integer
+ * @str: string to convert
+ *
+ * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB'
+ * size specifiers. Returns positive amount of bytes in case of success and %-1
+ * in case of failure.
+ */
+long long ubiutils_get_bytes(const char *str)
+{
+ char *endp;
+ long long bytes = strtoull(str, &endp, 0);
+
+ if (endp == str || bytes < 0) {
+ fprintf(stderr, "incorrect amount of bytes: \"%s\"\n", str);
+ return -1;
+ }
+
+ if (*endp != '\0') {
+ int mult = get_multiplier(endp);
+
+ if (mult == -1) {
+ fprintf(stderr, "bad size specifier: \"%s\" - "
+ "should be 'KiB', 'MiB' or 'GiB'\n", endp);
+ return -1;
+ }
+ bytes *= mult;
+ }
+
+ return bytes;
+}
+
+/**
+ * ubiutils_print_bytes - print bytes.
+ * @bytes: variable to print
+ * @bracket: whether brackets have to be put or not
+ *
+ * This is a helper function which prints amount of bytes in a human-readable
+ * form, i.e., it prints the exact amount of bytes following by the approximate
+ * amount of Kilobytes, Megabytes, or Gigabytes, depending on how big @bytes
+ * is.
+ */
+void ubiutils_print_bytes(long long bytes, int bracket)
+{
+ const char *p;
+
+ if (bracket)
+ p = " (";
+ else
+ p = ", ";
+
+ printf("%lld bytes", bytes);
+
+ if (bytes > 1024 * 1024 * 1024)
+ printf("%s%.1f GiB", p, (double)bytes / (1024 * 1024 * 1024));
+ else if (bytes > 1024 * 1024)
+ printf("%s%.1f MiB", p, (double)bytes / (1024 * 1024));
+ else if (bytes > 1024 && bytes != 0)
+ printf("%s%.1f KiB", p, (double)bytes / 1024);
+ else
+ return;
+
+ if (bracket)
+ printf(")");
+}
+
+/**
+ * ubiutils_print_text - print text and fold it.
+ * @stream: file stream to print to
+ * @text: text to print
+ * @width: maximum allowed text width
+ *
+ * Print text and fold it so that each line would not have more then @width
+ * characters.
+ */
+void ubiutils_print_text(FILE *stream, const char *text, int width)
+{
+ int pos, bpos = 0;
+ const char *p;
+ char line[1024];
+
+ if (width > 1023) {
+ fprintf(stream, "%s\n", text);
+ return;
+ }
+ p = text;
+ pos = 0;
+ while (p[pos]) {
+ while (!isspace(p[pos])) {
+ line[pos] = p[pos];
+ if (!p[pos])
+ break;
+ ++pos;
+ if (pos == width) {
+ line[pos] = '\0';
+ fprintf(stream, "%s\n", line);
+ p += pos;
+ pos = 0;
+ }
+ }
+ while (pos < width) {
+ line[pos] = p[pos];
+ if (!p[pos]) {
+ bpos = pos;
+ break;
+ }
+ if (isspace(p[pos]))
+ bpos = pos;
+ ++pos;
+ }
+ line[bpos] = '\0';
+ fprintf(stream, "%s\n", line);
+ p += bpos;
+ pos = 0;
+ while (p[pos] && isspace(p[pos]))
+ ++p;
+ }
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h
new file mode 100644
index 00000000000..fdc69db5e3d
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) Artem Bityutskiy, 2007, 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __UBI_UTILS_COMMON_H__
+#define __UBI_UTILS_COMMON_H__
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MIN(a ,b) ((a) < (b) ? (a) : (b))
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+/* Verbose messages */
+#define verbose(verbose, fmt, ...) do { \
+ if (verbose) \
+ printf(PROGRAM_NAME ": " fmt "\n", ##__VA_ARGS__); \
+} while(0)
+
+/* Normal messages */
+#define normsg(fmt, ...) do { \
+ printf(PROGRAM_NAME ": " fmt "\n", ##__VA_ARGS__); \
+} while(0)
+#define normsg_cont(fmt, ...) do { \
+ printf(PROGRAM_NAME ": " fmt, ##__VA_ARGS__); \
+} while(0)
+#define normsg_cont(fmt, ...) do { \
+ printf(PROGRAM_NAME ": " fmt, ##__VA_ARGS__); \
+} while(0)
+
+/* Error messages */
+#define errmsg(fmt, ...) ({ \
+ fprintf(stderr, PROGRAM_NAME ": error!: " fmt "\n", ##__VA_ARGS__); \
+ -1; \
+})
+
+/* System error messages */
+#define sys_errmsg(fmt, ...) ({ \
+ int _err = errno, _i; \
+ fprintf(stderr, PROGRAM_NAME ": error!: " fmt "\n", ##__VA_ARGS__); \
+ for (_i = 0; _i < sizeof(PROGRAM_NAME) + 1; _i++) \
+ fprintf(stderr, " "); \
+ fprintf(stderr, "error %d (%s)\n", _err, strerror(_err)); \
+ -1; \
+})
+
+/* Warnings */
+#define warnmsg(fmt, ...) do { \
+ fprintf(stderr, PROGRAM_NAME ": warning!: " fmt "\n", ##__VA_ARGS__); \
+} while(0)
+
+static inline int is_power_of_2(unsigned long long n)
+{
+ return (n != 0 && ((n & (n - 1)) == 0));
+}
+
+long long ubiutils_get_bytes(const char *str);
+void ubiutils_print_bytes(long long bytes, int bracket);
+void ubiutils_print_text(FILE *stream, const char *txt, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__UBI_UTILS_COMMON_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c
new file mode 100644
index 00000000000..6b1e50c42d9
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c
@@ -0,0 +1,95 @@
+/*
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ *
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to hight-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
+ *
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
+ */
+
+#include <stdint.h>
+
+const uint32_t crc32_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h
new file mode 100644
index 00000000000..ee3145bc159
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h
@@ -0,0 +1,19 @@
+#ifndef CRC32_H
+#define CRC32_H
+
+#include <stdint.h>
+
+extern const uint32_t crc32_table[256];
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+ static inline uint32_t
+crc32(uint32_t val, const void *ss, int len)
+{
+ const unsigned char *s = ss;
+ while (--len >= 0)
+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
+ return val;
+}
+
+#endif
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c
new file mode 100644
index 00000000000..7681e2dde9c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c
@@ -0,0 +1,405 @@
+/*-------------------------------------------------------------------------*/
+/**
+ @file dictionary.c
+ @author N. Devillard
+ @date Sep 2007
+ @version $Revision: 1.1.1.1 $
+ @brief Implements a dictionary for string variables.
+
+ This module implements a simple dictionary object, i.e. a list
+ of string/string associations. This object is useful to store e.g.
+ informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: dictionary.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ $Revision: 1.1.1.1 $
+*/
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+#include "dictionary.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/** Maximum value size for integers and doubles. */
+#define MAXVALSZ 1024
+
+/** Minimal allocated number of entries in a dictionary */
+#define DICTMINSZ 128
+
+/** Invalid key token */
+#define DICT_INVALID_KEY ((char*)-1)
+
+/*---------------------------------------------------------------------------
+ Private functions
+ ---------------------------------------------------------------------------*/
+
+/* Doubles the allocated size associated to a pointer */
+/* 'size' is the current allocated size. */
+static void * mem_double(void * ptr, int size)
+{
+ void * newptr ;
+
+ newptr = calloc(2*size, 1);
+ if (newptr==NULL) {
+ return NULL ;
+ }
+ memcpy(newptr, ptr, size);
+ free(ptr);
+ return newptr ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Duplicate a string
+ @param s String to duplicate
+ @return Pointer to a newly allocated string, to be freed with free()
+
+ This is a replacement for strdup(). This implementation is provided
+ for systems that do not have it.
+ */
+/*--------------------------------------------------------------------------*/
+static char * xstrdup(char * s)
+{
+ char * t ;
+ if (!s)
+ return NULL ;
+ t = malloc(strlen(s)+1) ;
+ if (t) {
+ strcpy(t,s);
+ }
+ return t ;
+}
+
+/*---------------------------------------------------------------------------
+ Function codes
+ ---------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Compute the hash key for a string.
+ @param key Character string to use for key.
+ @return 1 unsigned int on at least 32 bits.
+
+ This hash function has been taken from an Article in Dr Dobbs Journal.
+ This is normally a collision-free function, distributing keys evenly.
+ The key is stored anyway in the struct so that collision can be avoided
+ by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(char * key)
+{
+ int len ;
+ unsigned hash ;
+ int i ;
+
+ len = strlen(key);
+ for (hash=0, i=0 ; i<len ; i++) {
+ hash += (unsigned)key[i] ;
+ hash += (hash<<10);
+ hash ^= (hash>>6) ;
+ }
+ hash += (hash <<3);
+ hash ^= (hash >>11);
+ hash += (hash <<15);
+ return hash ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Create a new dictionary object.
+ @param size Optional initial size of the dictionary.
+ @return 1 newly allocated dictionary objet.
+
+ This function allocates a new dictionary object of given size and returns
+ it. If you do not know in advance (roughly) the number of entries in the
+ dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * dictionary_new(int size)
+{
+ dictionary * d ;
+
+ /* If no size was specified, allocate space for DICTMINSZ */
+ if (size<DICTMINSZ) size=DICTMINSZ ;
+
+ if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
+ return NULL;
+ }
+ d->size = size ;
+ d->val = (char **)calloc(size, sizeof(char*));
+ d->key = (char **)calloc(size, sizeof(char*));
+ d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
+ return d ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a dictionary object
+ @param d dictionary object to deallocate.
+ @return void
+
+ Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * d)
+{
+ int i ;
+
+ if (d==NULL) return ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]!=NULL)
+ free(d->key[i]);
+ if (d->val[i]!=NULL)
+ free(d->val[i]);
+ }
+ free(d->val);
+ free(d->key);
+ free(d->hash);
+ free(d);
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value to return if key not found.
+ @return 1 pointer to internally allocated character string.
+
+ This function locates a key in a dictionary and returns a pointer to its
+ value, or the passed 'def' pointer if no such key can be found in
+ dictionary. The returned character pointer points to data internal to the
+ dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * dictionary_get(dictionary * d, char * key, char * def)
+{
+ unsigned hash ;
+ int i ;
+
+ hash = dictionary_hash(key);
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ /* Compare hash */
+ if (hash==d->hash[i]) {
+ /* Compare string, to avoid hash collisions */
+ if (!strcmp(key, d->key[i])) {
+ return d->val[i] ;
+ }
+ }
+ }
+ return def ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a value in a dictionary.
+ @param d dictionary object to modify.
+ @param key Key to modify or add.
+ @param val Value to add.
+ @return int 0 if Ok, anything else otherwise
+
+ If the given key is found in the dictionary, the associated value is
+ replaced by the provided one. If the key cannot be found in the
+ dictionary, it is added to it.
+
+ It is Ok to provide a NULL value for val, but NULL values for the dictionary
+ or the key are considered as errors: the function will return immediately
+ in such a case.
+
+ Notice that if you dictionary_set a variable to NULL, a call to
+ dictionary_get will return a NULL value: the variable will be found, and
+ its value (NULL) is returned. In other words, setting the variable
+ content to NULL is equivalent to deleting the variable from the
+ dictionary. It is not possible (in this implementation) to have a key in
+ the dictionary without value.
+
+ This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * d, char * key, char * val)
+{
+ int i ;
+ unsigned hash ;
+
+ if (d==NULL || key==NULL) return -1 ;
+
+ /* Compute hash for this key */
+ hash = dictionary_hash(key) ;
+ /* Find if value is already in dictionary */
+ if (d->n>0) {
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (hash==d->hash[i]) { /* Same hash value */
+ if (!strcmp(key, d->key[i])) { /* Same key */
+ /* Found a value: modify and return */
+ if (d->val[i]!=NULL)
+ free(d->val[i]);
+ d->val[i] = val ? xstrdup(val) : NULL ;
+ /* Value has been modified: return */
+ return 0 ;
+ }
+ }
+ }
+ }
+ /* Add a new value */
+ /* See if dictionary needs to grow */
+ if (d->n==d->size) {
+
+ /* Reached maximum size: reallocate dictionary */
+ d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ;
+ d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ;
+ d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
+ if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) {
+ /* Cannot grow dictionary */
+ return -1 ;
+ }
+ /* Double size */
+ d->size *= 2 ;
+ }
+
+ /* Insert key in the first empty slot */
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL) {
+ /* Add key here */
+ break ;
+ }
+ }
+ /* Copy key */
+ d->key[i] = xstrdup(key);
+ d->val[i] = val ? xstrdup(val) : NULL ;
+ d->hash[i] = hash;
+ d->n ++ ;
+ return 0 ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a key in a dictionary
+ @param d dictionary object to modify.
+ @param key Key to remove.
+ @return void
+
+ This function deletes a key in a dictionary. Nothing is done if the
+ key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, char * key)
+{
+ unsigned hash ;
+ int i ;
+
+ if (key == NULL) {
+ return;
+ }
+
+ hash = dictionary_hash(key);
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ /* Compare hash */
+ if (hash==d->hash[i]) {
+ /* Compare string, to avoid hash collisions */
+ if (!strcmp(key, d->key[i])) {
+ /* Found key */
+ break ;
+ }
+ }
+ }
+ if (i>=d->size)
+ /* Key not found */
+ return ;
+
+ free(d->key[i]);
+ d->key[i] = NULL ;
+ if (d->val[i]!=NULL) {
+ free(d->val[i]);
+ d->val[i] = NULL ;
+ }
+ d->hash[i] = 0 ;
+ d->n -- ;
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump
+ @param f Opened file pointer.
+ @return void
+
+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+ output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(dictionary * d, FILE * out)
+{
+ int i ;
+
+ if (d==NULL || out==NULL) return ;
+ if (d->n<1) {
+ fprintf(out, "empty dictionary\n");
+ return ;
+ }
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]) {
+ fprintf(out, "%20s\t[%s]\n",
+ d->key[i],
+ d->val[i] ? d->val[i] : "UNDEF");
+ }
+ }
+ return ;
+}
+
+
+/* Test code */
+#ifdef TESTDIC
+#define NVALS 20000
+int main(int argc, char *argv[])
+{
+ dictionary * d ;
+ char * val ;
+ int i ;
+ char cval[90] ;
+
+ /* Allocate dictionary */
+ printf("allocating...\n");
+ d = dictionary_new(0);
+
+ /* Set values in dictionary */
+ printf("setting %d values...\n", NVALS);
+ for (i=0 ; i<NVALS ; i++) {
+ sprintf(cval, "%04d", i);
+ dictionary_set(d, cval, "salut");
+ }
+ printf("getting %d values...\n", NVALS);
+ for (i=0 ; i<NVALS ; i++) {
+ sprintf(cval, "%04d", i);
+ val = dictionary_get(d, cval, DICT_INVALID_KEY);
+ if (val==DICT_INVALID_KEY) {
+ printf("cannot get value for key [%s]\n", cval);
+ }
+ }
+ printf("unsetting %d values...\n", NVALS);
+ for (i=0 ; i<NVALS ; i++) {
+ sprintf(cval, "%04d", i);
+ dictionary_unset(d, cval);
+ }
+ if (d->n != 0) {
+ printf("error deleting values\n");
+ }
+ printf("deallocating...\n");
+ dictionary_del(d);
+ return 0 ;
+}
+#endif
+/* vim: set ts=4 et sw=4 tw=75 */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h
new file mode 100644
index 00000000000..86057356898
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h
@@ -0,0 +1,174 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file dictionary.h
+ @author N. Devillard
+ @date Sep 2007
+ @version $Revision: 1.1.1.1 $
+ @brief Implements a dictionary for string variables.
+
+ This module implements a simple dictionary object, i.e. a list
+ of string/string associations. This object is useful to store e.g.
+ informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+/*
+ $Id: dictionary.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ $Author: yrtan $
+ $Date: 2008-05-13 07:15:32 $
+ $Revision: 1.1.1.1 $
+*/
+
+#ifndef _DICTIONARY_H_
+#define _DICTIONARY_H_
+
+/*---------------------------------------------------------------------------
+ Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*---------------------------------------------------------------------------
+ New types
+ ---------------------------------------------------------------------------*/
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dictionary object
+
+ This object contains a list of string/string associations. Each
+ association is identified by a unique string key. Looking up values
+ in the dictionary is speeded up by the use of a (hopefully collision-free)
+ hash function.
+ */
+/*-------------------------------------------------------------------------*/
+typedef struct _dictionary_ {
+ int n ; /** Number of entries in dictionary */
+ int size ; /** Storage size */
+ char ** val ; /** List of string values */
+ char ** key ; /** List of string keys */
+ unsigned * hash ; /** List of hash values for keys */
+} dictionary ;
+
+
+/*---------------------------------------------------------------------------
+ Function prototypes
+ ---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Compute the hash key for a string.
+ @param key Character string to use for key.
+ @return 1 unsigned int on at least 32 bits.
+
+ This hash function has been taken from an Article in Dr Dobbs Journal.
+ This is normally a collision-free function, distributing keys evenly.
+ The key is stored anyway in the struct so that collision can be avoided
+ by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(char * key);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Create a new dictionary object.
+ @param size Optional initial size of the dictionary.
+ @return 1 newly allocated dictionary objet.
+
+ This function allocates a new dictionary object of given size and returns
+ it. If you do not know in advance (roughly) the number of entries in the
+ dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * dictionary_new(int size);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a dictionary object
+ @param d dictionary object to deallocate.
+ @return void
+
+ Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * vd);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get a value from a dictionary.
+ @param d dictionary object to search.
+ @param key Key to look for in the dictionary.
+ @param def Default value to return if key not found.
+ @return 1 pointer to internally allocated character string.
+
+ This function locates a key in a dictionary and returns a pointer to its
+ value, or the passed 'def' pointer if no such key can be found in
+ dictionary. The returned character pointer points to data internal to the
+ dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * dictionary_get(dictionary * d, char * key, char * def);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set a value in a dictionary.
+ @param d dictionary object to modify.
+ @param key Key to modify or add.
+ @param val Value to add.
+ @return int 0 if Ok, anything else otherwise
+
+ If the given key is found in the dictionary, the associated value is
+ replaced by the provided one. If the key cannot be found in the
+ dictionary, it is added to it.
+
+ It is Ok to provide a NULL value for val, but NULL values for the dictionary
+ or the key are considered as errors: the function will return immediately
+ in such a case.
+
+ Notice that if you dictionary_set a variable to NULL, a call to
+ dictionary_get will return a NULL value: the variable will be found, and
+ its value (NULL) is returned. In other words, setting the variable
+ content to NULL is equivalent to deleting the variable from the
+ dictionary. It is not possible (in this implementation) to have a key in
+ the dictionary without value.
+
+ This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * vd, char * key, char * val);
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete a key in a dictionary
+ @param d dictionary object to modify.
+ @param key Key to remove.
+ @return void
+
+ This function deletes a key in a dictionary. Nothing is done if the
+ key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, char * key);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump
+ @param f Opened file pointer.
+ @return void
+
+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+ output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(dictionary * d, FILE * out);
+
+#endif
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c
new file mode 100644
index 00000000000..6f9028cfebd
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c
@@ -0,0 +1,646 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+ @file iniparser.c
+ @author N. Devillard
+ @date Sep 2007
+ @version 3.0
+ @brief Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+/*
+ $Id: libiniparser.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $
+ $Revision: 1.1.1.1 $
+ $Date: 2008-05-13 07:15:32 $
+*/
+/*---------------------------- Includes ------------------------------------*/
+#include <ctype.h>
+#include <libiniparser.h>
+
+/*---------------------------- Defines -------------------------------------*/
+#define ASCIILINESZ (1024)
+#define INI_INVALID_KEY ((char*)-1)
+
+/*---------------------------------------------------------------------------
+ Private to this module
+ ---------------------------------------------------------------------------*/
+/**
+ * This enum stores the status for each parsed line (internal use only).
+ */
+typedef enum _line_status_ {
+ LINE_UNPROCESSED,
+ LINE_ERROR,
+ LINE_EMPTY,
+ LINE_COMMENT,
+ LINE_SECTION,
+ LINE_VALUE
+} line_status ;
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Convert a string to lowercase.
+ @param s String to convert.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string
+ containing a lowercased version of the input string. Do not free
+ or modify the returned string! Since the returned string is statically
+ allocated, it will be modified at each function call (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+static char * strlwc(const char * s)
+{
+ static char l[ASCIILINESZ+1];
+ int i ;
+
+ if (s==NULL) return NULL ;
+ memset(l, 0, ASCIILINESZ+1);
+ i=0 ;
+ while (s[i] && i<ASCIILINESZ) {
+ l[i] = (char)tolower((int)s[i]);
+ i++ ;
+ }
+ l[ASCIILINESZ]=(char)0;
+ return l ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Remove blanks at the beginning and the end of a string.
+ @param s String to parse.
+ @return ptr to statically allocated string.
+
+ This function returns a pointer to a statically allocated string,
+ which is identical to the input string, except that all blank
+ characters at the end and the beg. of the string have been removed.
+ Do not free or modify the returned string! Since the returned string
+ is statically allocated, it will be modified at each function call
+ (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+static char * strstrip(char * s)
+{
+ static char l[ASCIILINESZ+1];
+ char * last ;
+
+ if (s==NULL) return NULL ;
+
+ while (isspace((int)*s) && *s) s++;
+ memset(l, 0, ASCIILINESZ+1);
+ strcpy(l, s);
+ last = l + strlen(l);
+ while (last > l) {
+ if (!isspace((int)*(last-1)))
+ break ;
+ last -- ;
+ }
+ *last = (char)0;
+ return (char*)l ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get number of sections in a dictionary
+ @param d Dictionary to examine
+ @return int Number of sections found in dictionary
+
+ This function returns the number of sections found in a dictionary.
+ The test to recognize sections is done on the string stored in the
+ dictionary: a section name is given as "section" whereas a key is
+ stored as "section:key", thus the test looks for entries that do not
+ contain a colon.
+
+ This clearly fails in the case a section name contains a colon, but
+ this should simply be avoided.
+
+ This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getnsec(dictionary * d)
+{
+ int i ;
+ int nsec ;
+
+ if (d==NULL) return -1 ;
+ nsec=0 ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (strchr(d->key[i], ':')==NULL) {
+ nsec ++ ;
+ }
+ }
+ return nsec ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get name for section n in a dictionary.
+ @param d Dictionary to examine
+ @param n Section number (from 0 to nsec-1).
+ @return Pointer to char string
+
+ This function locates the n-th section in a dictionary and returns
+ its name as a pointer to a string statically allocated inside the
+ dictionary. Do not free or modify the returned string!
+
+ This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getsecname(dictionary * d, int n)
+{
+ int i ;
+ int foundsec ;
+
+ if (d==NULL || n<0) return NULL ;
+ foundsec=0 ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (strchr(d->key[i], ':')==NULL) {
+ foundsec++ ;
+ if (foundsec>n)
+ break ;
+ }
+ }
+ if (foundsec<=n) {
+ return NULL ;
+ }
+ return d->key[i] ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Dump a dictionary to an opened file pointer.
+ @param d Dictionary to dump.
+ @param f Opened file pointer to dump to.
+ @return void
+
+ This function prints out the contents of a dictionary, one element by
+ line, onto the provided file pointer. It is OK to specify @c stderr
+ or @c stdout as output files. This function is meant for debugging
+ purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(dictionary * d, FILE * f)
+{
+ int i ;
+
+ if (d==NULL || f==NULL) return ;
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ if (d->val[i]!=NULL) {
+ fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
+ } else {
+ fprintf(f, "[%s]=UNDEF\n", d->key[i]);
+ }
+ }
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Save a dictionary to a loadable ini file
+ @param d Dictionary to dump
+ @param f Opened file pointer to dump to
+ @return void
+
+ This function dumps a given dictionary into a loadable ini file.
+ It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump_ini(dictionary * d, FILE * f)
+{
+ int i, j ;
+ char keym[ASCIILINESZ+1];
+ int nsec ;
+ char * secname ;
+ int seclen ;
+
+ if (d==NULL || f==NULL) return ;
+
+ nsec = iniparser_getnsec(d);
+ if (nsec<1) {
+ /* No section in file: dump all keys as they are */
+ for (i=0 ; i<d->size ; i++) {
+ if (d->key[i]==NULL)
+ continue ;
+ fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
+ }
+ return ;
+ }
+ for (i=0 ; i<nsec ; i++) {
+ secname = iniparser_getsecname(d, i) ;
+ seclen = (int)strlen(secname);
+ fprintf(f, "\n[%s]\n", secname);
+ sprintf(keym, "%s:", secname);
+ for (j=0 ; j<d->size ; j++) {
+ if (d->key[j]==NULL)
+ continue ;
+ if (!strncmp(d->key[j], keym, seclen+1)) {
+ fprintf(f,
+ "%-30s = %s\n",
+ d->key[j]+seclen+1,
+ d->val[j] ? d->val[j] : "");
+ }
+ }
+ }
+ fprintf(f, "\n");
+ return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param def Default value to return if key not found.
+ @return pointer to statically allocated character string
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the pointer passed as 'def' is returned.
+ The returned char pointer is pointing to a string allocated in
+ the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstring(dictionary * d, const char * key, char * def)
+{
+ char * lc_key ;
+ char * sval ;
+
+ if (d==NULL || key==NULL)
+ return def ;
+
+ lc_key = strlwc(key);
+ sval = dictionary_get(d, lc_key, def);
+ return sval ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to an int
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ Supported values for integers include the usual C notation
+ so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+ are supported. Examples:
+
+ "42" -> 42
+ "042" -> 34 (octal -> decimal)
+ "0x42" -> 66 (hexa -> decimal)
+
+ Warning: the conversion may overflow in various ways. Conversion is
+ totally outsourced to strtol(), see the associated man page for overflow
+ handling.
+
+ Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(dictionary * d, const char * key, int notfound)
+{
+ char * str ;
+
+ str = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (str==INI_INVALID_KEY) return notfound ;
+ return (int)strtol(str, NULL, 0);
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a double
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return double
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+ */
+/*--------------------------------------------------------------------------*/
+double iniparser_getdouble(dictionary * d, char * key, double notfound)
+{
+ char * str ;
+
+ str = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (str==INI_INVALID_KEY) return notfound ;
+ return atof(str);
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Get the string associated to a key, convert to a boolean
+ @param d Dictionary to search
+ @param key Key string to look for
+ @param notfound Value to return in case of error
+ @return integer
+
+ This function queries a dictionary for a key. A key as read from an
+ ini file is given as "section:key". If the key cannot be found,
+ the notfound value is returned.
+
+ A true boolean is found if one of the following is matched:
+
+ - A string starting with 'y'
+ - A string starting with 'Y'
+ - A string starting with 't'
+ - A string starting with 'T'
+ - A string starting with '1'
+
+ A false boolean is found if one of the following is matched:
+
+ - A string starting with 'n'
+ - A string starting with 'N'
+ - A string starting with 'f'
+ - A string starting with 'F'
+ - A string starting with '0'
+
+ The notfound value returned if no boolean is identified, does not
+ necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(dictionary * d, const char * key, int notfound)
+{
+ char * c ;
+ int ret ;
+
+ c = iniparser_getstring(d, key, INI_INVALID_KEY);
+ if (c==INI_INVALID_KEY) return notfound ;
+ if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
+ ret = 1 ;
+ } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
+ ret = 0 ;
+ } else {
+ ret = notfound ;
+ }
+ return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Finds out if a given entry exists in a dictionary
+ @param ini Dictionary to search
+ @param entry Name of the entry to look for
+ @return integer 1 if entry exists, 0 otherwise
+
+ Finds out if a given entry exists in the dictionary. Since sections
+ are stored as keys with NULL associated values, this is the only way
+ of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(
+ dictionary * ini,
+ char * entry
+)
+{
+ int found=0 ;
+ if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
+ found = 1 ;
+ }
+ return found ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Set an entry in a dictionary.
+ @param ini Dictionary to modify.
+ @param entry Entry to modify (entry name)
+ @param val New value to associate to the entry.
+ @return int 0 if Ok, -1 otherwise.
+
+ If the given entry can be found in the dictionary, it is modified to
+ contain the provided value. If it cannot be found, -1 is returned.
+ It is Ok to set val to NULL.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_set(dictionary * ini, char * entry, char * val)
+{
+ return dictionary_set(ini, strlwc(entry), val) ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Delete an entry in a dictionary
+ @param ini Dictionary to modify
+ @param entry Entry to delete (entry name)
+ @return void
+
+ If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, char * entry)
+{
+ dictionary_unset(ini, strlwc(entry));
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Load a single line from an INI file
+ @param input_line Input line, may be concatenated multi-line input
+ @param section Output space to store section
+ @param key Output space to store key
+ @param value Output space to store value
+ @return line_status value
+ */
+/*--------------------------------------------------------------------------*/
+static line_status iniparser_line(
+ char * input_line,
+ char * section,
+ char * key,
+ char * value)
+{
+ line_status sta ;
+ char line[ASCIILINESZ+1];
+ int len ;
+
+ strcpy(line, strstrip(input_line));
+ len = (int)strlen(line);
+
+ sta = LINE_UNPROCESSED ;
+ if (len<1) {
+ /* Empty line */
+ sta = LINE_EMPTY ;
+ } else if (line[0]=='#') {
+ /* Comment line */
+ sta = LINE_COMMENT ;
+ } else if (line[0]=='[' && line[len-1]==']') {
+ /* Section name */
+ sscanf(line, "[%[^]]", section);
+ strcpy(section, strstrip(section));
+ strcpy(section, strlwc(section));
+ sta = LINE_SECTION ;
+ } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
+ || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
+ || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
+ /* Usual key=value, with or without comments */
+ strcpy(key, strstrip(key));
+ strcpy(key, strlwc(key));
+ strcpy(value, strstrip(value));
+ /*
+ * sscanf cannot handle '' or "" as empty values
+ * this is done here
+ */
+ if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
+ value[0]=0 ;
+ }
+ sta = LINE_VALUE ;
+ } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
+ || sscanf(line, "%[^=] %[=]", key, value) == 2) {
+ /*
+ * Special cases:
+ * key=
+ * key=;
+ * key=#
+ */
+ strcpy(key, strstrip(key));
+ strcpy(key, strlwc(key));
+ value[0]=0 ;
+ sta = LINE_VALUE ;
+ } else {
+ /* Generate syntax error */
+ sta = LINE_ERROR ;
+ }
+ return sta ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Parse an ini file and return an allocated dictionary object
+ @param ininame Name of the ini file to read.
+ @return Pointer to newly allocated dictionary
+
+ This is the parser for ini files. This function is called, providing
+ the name of the file to be read. It returns a dictionary object that
+ should not be accessed directly, but through accessor functions
+ instead.
+
+ The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame)
+{
+ FILE * in ;
+
+ char line [ASCIILINESZ+1] ;
+ char section [ASCIILINESZ+1] ;
+ char key [ASCIILINESZ+1] ;
+ char tmp [ASCIILINESZ+1] ;
+ char val [ASCIILINESZ+1] ;
+
+ int last=0 ;
+ int len ;
+ int lineno=0 ;
+ int errs=0;
+
+ dictionary * dict ;
+
+ if ((in=fopen(ininame, "r"))==NULL) {
+ fprintf(stderr, "iniparser: cannot open %s\n", ininame);
+ return NULL ;
+ }
+
+ dict = dictionary_new(0) ;
+ if (!dict) {
+ fclose(in);
+ return NULL ;
+ }
+
+ memset(line, 0, ASCIILINESZ);
+ memset(section, 0, ASCIILINESZ);
+ memset(key, 0, ASCIILINESZ);
+ memset(val, 0, ASCIILINESZ);
+ last=0 ;
+
+ while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
+ lineno++ ;
+ len = (int)strlen(line)-1;
+ /* Safety check against buffer overflows */
+ if (line[len]!='\n') {
+ fprintf(stderr,
+ "iniparser: input line too long in %s (%d)\n",
+ ininame,
+ lineno);
+ dictionary_del(dict);
+ fclose(in);
+ return NULL ;
+ }
+ /* Get rid of \n and spaces at end of line */
+ while ((len>=0) &&
+ ((line[len]=='\n') || (isspace(line[len])))) {
+ line[len]=0 ;
+ len-- ;
+ }
+ /* Detect multi-line */
+ if (line[len]=='\\') {
+ /* Multi-line value */
+ last=len ;
+ continue ;
+ } else {
+ last=0 ;
+ }
+ switch (iniparser_line(line, section, key, val)) {
+ case LINE_EMPTY:
+ case LINE_COMMENT:
+ break ;
+
+ case LINE_SECTION:
+ errs = dictionary_set(dict, section, NULL);
+ break ;
+
+ case LINE_VALUE:
+ sprintf(tmp, "%s:%s", section, key);
+ errs = dictionary_set(dict, tmp, val) ;
+ break ;
+
+ case LINE_ERROR:
+ fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
+ ininame,
+ lineno);
+ fprintf(stderr, "-> %s\n", line);
+ errs++ ;
+ break;
+
+ default:
+ break ;
+ }
+ memset(line, 0, ASCIILINESZ);
+ last=0;
+ if (errs<0) {
+ fprintf(stderr, "iniparser: memory allocation failure\n");
+ break ;
+ }
+ }
+ if (errs) {
+ dictionary_del(dict);
+ dict = NULL ;
+ }
+ fclose(in);
+ return dict ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+ @brief Free all memory associated to an ini dictionary
+ @param d Dictionary to free
+ @return void
+
+ Free all memory associated to an ini dictionary.
+ It is mandatory to call this function before the dictionary object
+ gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d)
+{
+ dictionary_del(d);
+}
+
+/* vim: set ts=4 et sw=4 tw=75 */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c
new file mode 100644
index 00000000000..aab4b0ea05f
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * MTD library.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <mtd/mtd-user.h>
+#include <libmtd.h>
+#include "common.h"
+
+#define PROGRAM_NAME "libmtd"
+#define MTD_DEV_MAJOR 90
+
+/**
+ * mtd_get_info - get information about an MTD device.
+ * @node: name of the MTD device node
+ * @mtd: the MTD device information is returned here
+ *
+ * This function gets information about MTD device defined by the @node device
+ * node file and saves this information in the @mtd object. Returns %0 in case
+ * of success and %-1 in case of failure.
+ */
+int mtd_get_info(const char *node, struct mtd_info *mtd)
+{
+ struct stat st;
+ struct mtd_info_user ui;
+ int ret;
+ loff_t offs = 0;
+
+ if (stat(node, &st))
+ return sys_errmsg("cannot open \"%s\"", node);
+
+ if (!S_ISCHR(st.st_mode)) {
+ errno = EINVAL;
+ return errmsg("\"%s\" is not a character device", node);
+ }
+
+ mtd->major = major(st.st_rdev);
+ mtd->minor = minor(st.st_rdev);
+
+ if (mtd->major != MTD_DEV_MAJOR) {
+ errno = EINVAL;
+ return errmsg("\"%s\" has major number %d, MTD devices have "
+ "major %d", node, mtd->major, MTD_DEV_MAJOR);
+ }
+
+ mtd->num = mtd->minor / 2;
+ mtd->rdonly = mtd->minor & 1;
+
+ mtd->fd = open(node, O_RDWR);
+ if (mtd->fd == -1)
+ return sys_errmsg("cannot open \"%s\"", node);
+
+ if (ioctl(mtd->fd, MEMGETINFO, &ui)) {
+ sys_errmsg("MEMGETINFO ioctl request failed");
+ goto out_close;
+ }
+
+ ret = ioctl(mtd->fd, MEMGETBADBLOCK, &offs);
+ if (ret == -1) {
+ if (errno != EOPNOTSUPP) {
+ sys_errmsg("MEMGETBADBLOCK ioctl failed");
+ goto out_close;
+ }
+ errno = 0;
+ mtd->allows_bb = 0;
+ } else
+ mtd->allows_bb = 1;
+
+ mtd->type = ui.type;
+ mtd->size = ui.size;
+ mtd->eb_size = ui.erasesize;
+ mtd->min_io_size = ui.writesize;
+
+ if (mtd->min_io_size <= 0) {
+ errmsg("mtd%d (%s) has insane min. I/O unit size %d",
+ mtd->num, node, mtd->min_io_size);
+ goto out_close;
+ }
+ if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) {
+ errmsg("mtd%d (%s) has insane eraseblock size %d",
+ mtd->num, node, mtd->eb_size);
+ goto out_close;
+ }
+ if (mtd->size <= 0 || mtd->size < mtd->eb_size) {
+ errmsg("mtd%d (%s) has insane size %lld",
+ mtd->num, node, mtd->size);
+ goto out_close;
+ }
+ mtd->eb_cnt = mtd->size / mtd->eb_size;
+
+ switch(mtd->type) {
+ case MTD_ABSENT:
+ errmsg("mtd%d (%s) is removable and is not present",
+ mtd->num, node);
+ goto out_close;
+ case MTD_RAM:
+ mtd->type_str = "RAM-based";
+ break;
+ case MTD_ROM:
+ mtd->type_str = "ROM";
+ break;
+ case MTD_NORFLASH:
+ mtd->type_str = "NOR";
+ break;
+ case MTD_NANDFLASH:
+ mtd->type_str = "NAND";
+ break;
+ case MTD_DATAFLASH:
+ mtd->type_str = "DataFlash";
+ break;
+ case MTD_UBIVOLUME:
+ mtd->type_str = "UBI-emulated MTD";
+ break;
+ default:
+ mtd->type_str = "Unknown flash type";
+ break;
+ }
+
+ if (!(ui.flags & MTD_WRITEABLE))
+ mtd->rdonly = 1;
+
+ return 0;
+
+out_close:
+ close(mtd->fd);
+ return -1;
+}
+
+/**
+ * mtd_erase - erase an eraseblock.
+ * @mtd: MTD device description object
+ * @eb: eraseblock to erase
+ *
+ * This function erases the eraseblock and returns %0 in case of success and
+ * %-1 in case of failure.
+ */
+int mtd_erase(const struct mtd_info *mtd, int eb)
+{
+ struct erase_info_user ei;
+
+ ei.start = eb * mtd->eb_size;;
+ ei.length = mtd->eb_size;
+ return ioctl(mtd->fd, MEMERASE, &ei);
+}
+
+/**
+ * mtd_is_bad - check if eraseblock is bad.
+ * @mtd: MTD device description object
+ * @eb: eraseblock to check
+ *
+ * This function checks if eraseblock @eb is bad. Returns %0 if not, %1 if yes,
+ * and %-1 in case of failure.
+ */
+int mtd_is_bad(const struct mtd_info *mtd, int eb)
+{
+ int ret;
+ loff_t seek;
+
+ if (eb < 0 || eb >= mtd->eb_cnt) {
+ errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks",
+ eb, mtd->num, mtd->eb_cnt);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!mtd->allows_bb)
+ return 0;
+
+ seek = eb * mtd->eb_size;
+ ret = ioctl(mtd->fd, MEMGETBADBLOCK, &seek);
+ if (ret == -1) {
+ sys_errmsg("MEMGETBADBLOCK ioctl failed for "
+ "eraseblock %d (mtd%d)", eb, mtd->num);
+ return -1;
+ }
+
+ return ret;
+}
+
+/**
+ * mtd_read - read data from an MTD device.
+ * @mtd: MTD device description object
+ * @eb: eraseblock to read from
+ * @offs: offset withing the eraseblock to read from
+ * @buf: buffer to read data to
+ * @len: how many bytes to read
+ *
+ * This function reads @len bytes of data from eraseblock @eb and offset @offs
+ * of the MTD device defined by @mtd and stores the read data at buffer @buf.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+int mtd_read(const struct mtd_info *mtd, int eb, int offs, void *buf, int len)
+{
+ int ret, rd = 0;
+ off_t seek;
+
+ if (eb < 0 || eb >= mtd->eb_cnt) {
+ errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks",
+ eb, mtd->num, mtd->eb_cnt);
+ errno = EINVAL;
+ return -1;
+ }
+ if (offs < 0 || offs + len > mtd->eb_size) {
+ errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d",
+ offs, len, mtd->num, mtd->eb_size);
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Seek to the beginning of the eraseblock */
+ seek = eb * mtd->eb_size + offs;
+ if (lseek(mtd->fd, seek, SEEK_SET) != seek) {
+ sys_errmsg("cannot seek mtd%d to offset %llu",
+ mtd->num, (unsigned long long)seek);
+ return -1;
+ }
+
+ while (rd < len) {
+ ret = read(mtd->fd, buf, len);
+ if (ret < 0) {
+ sys_errmsg("cannot read %d bytes from mtd%d (eraseblock %d, offset %d)",
+ len, mtd->num, eb, offs);
+ return -1;
+ }
+ rd += ret;
+ }
+
+ return 0;
+}
+
+/**
+ * mtd_write - write data to an MTD device.
+ * @mtd: MTD device description object
+ * @eb: eraseblock to write to
+ * @offs: offset withing the eraseblock to write to
+ * @buf: buffer to write
+ * @len: how many bytes to write
+ *
+ * This function writes @len bytes of data to eraseblock @eb and offset @offs
+ * of the MTD device defined by @mtd. Returns %0 in case of success and %-1 in
+ * case of failure.
+ */
+int mtd_write(const struct mtd_info *mtd, int eb, int offs, void *buf, int len)
+{
+ int ret;
+ off_t seek;
+
+ if (eb < 0 || eb >= mtd->eb_cnt) {
+ errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks",
+ eb, mtd->num, mtd->eb_cnt);
+ errno = EINVAL;
+ return -1;
+ }
+ if (offs < 0 || offs + len > mtd->eb_size) {
+ errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d",
+ offs, len, mtd->num, mtd->eb_size);
+ errno = EINVAL;
+ return -1;
+ }
+#if 0
+ if (offs % mtd->subpage_size) {
+ errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
+ offs, mtd->num, mtd->subpage_size);
+ errno = EINVAL;
+ return -1;
+ }
+ if (len % mtd->subpage_size) {
+ errmsg("write length %d is not aligned to mtd%d min. I/O size %d",
+ len, mtd->num, mtd->subpage_size);
+ errno = EINVAL;
+ return -1;
+ }
+#endif
+
+ /* Seek to the beginning of the eraseblock */
+ seek = eb * mtd->eb_size + offs;
+ if (lseek(mtd->fd, seek, SEEK_SET) != seek) {
+ sys_errmsg("cannot seek mtd%d to offset %llu",
+ mtd->num, (unsigned long long)seek);
+ return -1;
+ }
+
+ ret = write(mtd->fd, buf, len);
+ if (ret != len) {
+ sys_errmsg("cannot write %d bytes to mtd%d (eraseblock %d, offset %d)",
+ len, mtd->num, eb, offs);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c
new file mode 100644
index 00000000000..34274984013
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI scanning library.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <mtd_swab.h>
+#include <mtd/ubi-header.h>
+#include <mtd/mtd-user.h>
+#include <libmtd.h>
+#include <libscan.h>
+#include "common.h"
+#include "crc32.h"
+
+#define PROGRAM_NAME "libscan"
+
+static int all_ff(const void *buf, int len)
+{
+ int i;
+ const uint8_t *p = buf;
+
+ for (i = 0; i < len; i++)
+ if (p[i] != 0xFF)
+ return 0;
+ return 1;
+}
+
+int ubi_scan(struct mtd_info *mtd, struct ubi_scan_info **info, int verbose)
+{
+ int eb, v = (verbose == 2), pr = (verbose == 1);
+ struct ubi_scan_info *si;
+ unsigned long long sum = 0;
+
+ si = calloc(1, sizeof(struct ubi_scan_info));
+ if (!si)
+ return sys_errmsg("cannot allocate %zd bytes of memory",
+ sizeof(struct ubi_scan_info));
+
+ si->ec = calloc(mtd->eb_cnt, sizeof(uint32_t));
+ if (!si->ec) {
+ sys_errmsg("cannot allocate %zd bytes of memory",
+ sizeof(struct ubi_scan_info));
+ goto out_si;
+ }
+
+ si->vid_hdr_offs = si->data_offs = -1;
+
+ verbose(v, "start scanning eraseblocks 0-%d", mtd->eb_cnt);
+ for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ int ret;
+ uint32_t crc;
+ struct ubi_ec_hdr hdr;
+ unsigned long long ec;
+
+ if (v) {
+ normsg_cont("scanning eraseblock %d", eb);
+ fflush(stdout);
+ }
+ if (pr) {
+ printf("\r" PROGRAM_NAME ": scanning eraseblock %d -- %2lld %% complete ",
+ eb, (long long)(eb + 1) * 100 / mtd->eb_cnt);
+ fflush(stdout);
+ }
+
+ ret = mtd_is_bad(mtd, eb);
+ if (ret == -1)
+ goto out_ec;
+ if (ret) {
+ si->bad_cnt += 1;
+ si->ec[eb] = EB_BAD;
+ if (v)
+ printf(": bad\n");
+ continue;
+ }
+
+ ret = mtd_read(mtd, eb, 0, &hdr, sizeof(struct ubi_ec_hdr));;
+ if (ret < 0)
+ goto out_ec;
+
+ /* Check the EC header */
+ if (be32_to_cpu(hdr.magic) != UBI_EC_HDR_MAGIC) {
+ if (all_ff(&hdr, sizeof(struct ubi_ec_hdr))) {
+ si->empty_cnt += 1;
+ si->ec[eb] = EB_EMPTY;
+ if (v)
+ printf(": empty\n");
+ } else {
+ si->alien_cnt += 1;
+ si->ec[eb] = EB_ALIEN;
+ if (v)
+ printf(": alien\n");
+ }
+ continue;
+ }
+
+ crc = crc32(UBI_CRC32_INIT, &hdr, UBI_EC_HDR_SIZE_CRC);
+ if (be32_to_cpu(hdr.hdr_crc) != crc) {
+ si->corrupted_cnt += 1;
+ si->ec[eb] = EB_CORRUPTED;
+ if (v)
+ printf(": bad CRC %#08x, should be %#08x\n",
+ crc, be32_to_cpu(hdr.hdr_crc));
+ continue;
+ }
+
+ ec = be64_to_cpu(hdr.ec);
+ if (ec > EC_MAX) {
+ if (pr)
+ printf("\n");
+ errmsg("erase counter in EB %d is %llu, while this "
+ "program expects them to be less than %u",
+ eb, ec, EC_MAX);
+ goto out_ec;
+ }
+
+ if (si->vid_hdr_offs == -1) {
+ si->vid_hdr_offs = be32_to_cpu(hdr.vid_hdr_offset);
+ si->data_offs = be32_to_cpu(hdr.data_offset);
+ if (si->data_offs % mtd->min_io_size) {
+ if (pr)
+ printf("\n");
+ if (v)
+ printf(": corrupted because of the below\n");
+ warnmsg("bad data offset %d at eraseblock %d (n"
+ "of multiple of min. I/O unit size %d)",
+ si->data_offs, eb, mtd->min_io_size);
+ warnmsg("treat eraseblock %d as corrupted", eb);
+ si->corrupted_cnt += 1;
+ si->ec[eb] = EB_CORRUPTED;
+ continue;
+
+ }
+ } else {
+ if (be32_to_cpu(hdr.vid_hdr_offset) != si->vid_hdr_offs) {
+ if (pr)
+ printf("\n");
+ if (v)
+ printf(": corrupted because of the below\n");
+ warnmsg("inconsistent VID header offset: was "
+ "%d, but is %d in eraseblock %d",
+ si->vid_hdr_offs,
+ be32_to_cpu(hdr.vid_hdr_offset), eb);
+ warnmsg("treat eraseblock %d as corrupted", eb);
+ si->corrupted_cnt += 1;
+ si->ec[eb] = EB_CORRUPTED;
+ continue;
+ }
+ if (be32_to_cpu(hdr.data_offset) != si->data_offs) {
+ if (pr)
+ printf("\n");
+ if (v)
+ printf(": corrupted because of the below\n");
+ warnmsg("inconsistent data offset: was %d, but"
+ " is %d in eraseblock %d",
+ si->data_offs,
+ be32_to_cpu(hdr.data_offset), eb);
+ warnmsg("treat eraseblock %d as corrupted", eb);
+ si->corrupted_cnt += 1;
+ si->ec[eb] = EB_CORRUPTED;
+ continue;
+ }
+ }
+
+ si->ok_cnt += 1;
+ si->ec[eb] = ec;
+ if (v)
+ printf(": OK, erase counter %u\n", si->ec[eb]);
+ }
+
+ if (si->ok_cnt != 0) {
+ /* Calculate mean erase counter */
+ for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ if (si->ec[eb] > EC_MAX)
+ continue;
+ sum += si->ec[eb];
+ }
+ si->mean_ec = sum / si->ok_cnt;
+ }
+
+ si->good_cnt = mtd->eb_cnt - si->bad_cnt;
+ verbose(v, "finished, mean EC %lld, %d OK, %d corrupted, %d empty, %d "
+ "alien, bad %d", si->mean_ec, si->ok_cnt, si->corrupted_cnt,
+ si->empty_cnt, si->alien_cnt, si->bad_cnt);
+
+ *info = si;
+ if (pr)
+ printf("\n");
+ return 0;
+
+out_ec:
+ free(si->ec);
+out_si:
+ free(si);
+ *info = NULL;
+ return -1;
+}
+
+void ubi_scan_free(struct ubi_scan_info *si)
+{
+ free(si->ec);
+ free(si);
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c
new file mode 100644
index 00000000000..9f16a47b05a
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c
@@ -0,0 +1,1154 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI (Unsorted Block Images) library.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+#include "libubi.h"
+#include "libubi_int.h"
+#include "common.h"
+
+#define PROGRAM_NAME "libubi"
+
+/**
+ * mkpath - compose full path from 2 given components.
+ * @path: the first component
+ * @name: the second component
+ *
+ * This function returns the resulting path in case of success and %NULL in
+ * case of failure.
+ */
+static char *mkpath(const char *path, const char *name)
+{
+ char *n;
+ int len1 = strlen(path);
+ int len2 = strlen(name);
+
+ n = malloc(len1 + len2 + 2);
+ if (!n) {
+ sys_errmsg("cannot allocate %d bytes", len1 + len2 + 2);
+ return NULL;
+ }
+
+ memcpy(n, path, len1);
+ if (n[len1 - 1] != '/')
+ n[len1++] = '/';
+
+ memcpy(n + len1, name, len2 + 1);
+ return n;
+}
+
+/**
+ * read_positive_ll - read a positive 'long long' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function reads file @file and interprets its contents as a positive
+ * 'long long' integer. If this is not true, it fails with %EINVAL error code.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+static int read_positive_ll(const char *file, long long *value)
+{
+ int fd, rd;
+ char buf[50];
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, buf, 50);
+ if (rd == -1) {
+ sys_errmsg("cannot read \"%s\"", file);
+ goto out_error;
+ }
+ if (rd == 50) {
+ errmsg("contents of \"%s\" is too long", file);
+ errno = EINVAL;
+ goto out_error;
+ }
+
+ if (sscanf(buf, "%lld\n", value) != 1) {
+ /* This must be a UBI bug */
+ errmsg("cannot read integer from \"%s\"\n", file);
+ errno = EINVAL;
+ goto out_error;
+ }
+
+ if (*value < 0) {
+ errmsg("negative value %lld in \"%s\"", *value, file);
+ errno = EINVAL;
+ goto out_error;
+ }
+
+ if (close(fd))
+ return sys_errmsg("close failed on \"%s\"", file);
+
+ return 0;
+
+out_error:
+ close(fd);
+ return -1;
+}
+
+/**
+ * read_positive_int - read a positive 'int' value from a file.
+ * @file: the file to read from
+ * @value: the result is stored here
+ *
+ * This function is the same as 'read_positive_ll()', but it reads an 'int'
+ * value, not 'long long'.
+ */
+static int read_positive_int(const char *file, int *value)
+{
+ long long res;
+
+ if (read_positive_ll(file, &res))
+ return -1;
+
+ /* Make sure the value is not too big */
+ if (res > INT_MAX) {
+ errmsg("value %lld read from file \"%s\" is out of range",
+ res, file);
+ errno = EINVAL;
+ return -1;
+ }
+
+ *value = res;
+ return 0;
+}
+
+/**
+ * read_data - read data from a file.
+ * @file: the file to read from
+ * @buf: the buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure. Note, if the file contains more then @buf_len bytes of
+ * date, this function fails with %EINVAL error code.
+ */
+static int read_data(const char *file, void *buf, int buf_len)
+{
+ int fd, rd, tmp, tmp1;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, buf, buf_len);
+ if (rd == -1) {
+ sys_errmsg("cannot read \"%s\"", file);
+ goto out_error;
+ }
+
+ /* Make sure all data is read */
+ tmp1 = read(fd, &tmp, 1);
+ if (tmp1 == 1) {
+ sys_errmsg("cannot read \"%s\"", file);
+ goto out_error;
+ }
+ if (tmp1) {
+ errmsg("file \"%s\" contains too much data (> %d bytes)",
+ file, buf_len);
+ errno = EINVAL;
+ goto out_error;
+ }
+
+ if (close(fd)) {
+ sys_errmsg("close failed on \"%s\"", file);
+ return -1;
+ }
+
+ return rd;
+
+out_error:
+ close(fd);
+ return -1;
+}
+
+/**
+ * read_major - read major and minor numbers from a file.
+ * @file: name of the file to read from
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns % in case of succes, and %-1 in case of failure.
+ */
+static int read_major(const char *file, int *major, int *minor)
+{
+ int ret;
+ char buf[50];
+
+ ret = read_data(file, buf, 50);
+ if (ret < 0)
+ return ret;
+
+ ret = sscanf(buf, "%d:%d\n", major, minor);
+ if (ret != 2) {
+ errno = EINVAL;
+ return errmsg("\"%s\" does not have major:minor format", file);
+ }
+
+ if (*major < 0 || *minor < 0) {
+ errno = EINVAL;
+ return errmsg("bad major:minor %d:%d in \"%s\"",
+ *major, *minor, file);
+ }
+
+ return 0;
+}
+
+/**
+ * dev_read_int - read a positive 'int' value from an UBI device sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_int(const char *patt, int dev_num, int *value)
+{
+ char file[strlen(patt) + 50];
+
+ sprintf(file, patt, dev_num);
+ return read_positive_int(file, value);
+}
+
+/**
+ * vol_read_int - read a positive 'int' value from an UBI volume sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value)
+{
+ char file[strlen(patt) + 100];
+
+ sprintf(file, patt, dev_num, vol_id);
+ return read_positive_int(file, value);
+}
+
+/**
+ * dev_read_ll - read a positive 'long long' value from an UBI device sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_ll(const char *patt, int dev_num, long long *value)
+{
+ char file[strlen(patt) + 50];
+
+ sprintf(file, patt, dev_num);
+ return read_positive_ll(file, value);
+}
+
+/**
+ * vol_read_ll - read a positive 'long long' value from an UBI volume sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @value: the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int vol_read_ll(const char *patt, int dev_num, int vol_id,
+ long long *value)
+{
+ char file[strlen(patt) + 100];
+
+ sprintf(file, patt, dev_num, vol_id);
+ return read_positive_ll(file, value);
+}
+
+/**
+ * vol_read_data - read data from an UBI volume's sysfs file.
+ * @patt: file pattern to read from
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @buf: buffer to read to
+ * @buf_len: buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure.
+ */
+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
+ int buf_len)
+{
+ char file[strlen(patt) + 100];
+
+ sprintf(file, patt, dev_num, vol_id);
+ return read_data(file, buf, buf_len);
+}
+
+/**
+ * dev_get_major - get major and minor numbers of an UBI device.
+ * @lib: libubi descriptor
+ * @dev_num: UBI device number
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns zero in case of succes and %-1 in case of failure.
+ */
+static int dev_get_major(struct libubi *lib, int dev_num, int *major, int *minor)
+{
+ char file[strlen(lib->dev_dev) + 50];
+
+ sprintf(file, lib->dev_dev, dev_num);
+ return read_major(file, major, minor);
+}
+
+/**
+ * vol_get_major - get major and minor numbers of an UBI volume.
+ * @lib: libubi descriptor
+ * @dev_num: UBI device number
+ * @vol_id: volume ID
+ * @major: major number is returned here
+ * @minor: minor number is returned here
+ *
+ * This function returns zero in case of succes and %-1 in case of failure.
+ */
+static int vol_get_major(struct libubi *lib, int dev_num, int vol_id,
+ int *major, int *minor)
+{
+ char file[strlen(lib->vol_dev) + 100];
+
+ sprintf(file, lib->vol_dev, dev_num, vol_id);
+ return read_major(file, major, minor);
+}
+
+/**
+ * vol_node2nums - find UBI device number and volume ID by volume device node
+ * file.
+ * @lib: UBI library descriptor
+ * @node: UBI character device node name
+ * @dev_num: UBI device number is returned here
+ * @vol_id: volume ID is returned hers
+ *
+ * This function returns zero in case of succes and %-1 in case of failure.
+ */
+static int vol_node2nums(struct libubi *lib, const char *node, int *dev_num,
+ int *vol_id)
+{
+ struct stat st;
+ struct ubi_info info;
+ int i, fd, major, minor;
+ char file[strlen(lib->ubi_vol) + 100];
+
+ if (lstat(node, &st))
+ return -1;
+
+ if (!S_ISCHR(st.st_mode)) {
+ errno = EINVAL;
+ return errmsg("\"%s\" is not a character device", node);
+ }
+
+ major = major(st.st_rdev);
+ minor = minor(st.st_rdev);
+
+ if (minor == 0) {
+ errno = EINVAL;
+ return errmsg("\"%s\" is not a volume character device", node);
+ }
+
+ if (ubi_get_info((libubi_t *)lib, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ int major1, minor1, ret;
+
+ ret = dev_get_major(lib, i, &major1, &minor1);
+ if (ret) {
+ if (errno == ENOENT)
+ continue;
+ return -1;
+ }
+
+ if (major1 == major)
+ break;
+ }
+
+ if (i > info.highest_dev_num) {
+ errno = ENODEV;
+ return -1;
+ }
+
+ /* Make sure this UBI volume exists */
+ sprintf(file, lib->ubi_vol, i, minor - 1);
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ errno = ENODEV;
+ return -1;
+ }
+
+ *dev_num = i;
+ *vol_id = minor - 1;
+ errno = 0;
+ return 0;
+}
+
+/**
+ * dev_node2num - find UBI device number by its character device node.
+ * @lib: UBI library descriptor
+ * @node: UBI character device node name
+ *
+ * This function returns positive UBI device number in case of success and %-1
+ * in case of failure.
+ */
+static int dev_node2num(struct libubi *lib, const char *node, int *dev_num)
+{
+ struct stat stat;
+ struct ubi_info info;
+ int i, major, minor;
+
+ if (lstat(node, &stat))
+ return -1;
+
+ if (!S_ISCHR(stat.st_mode)) {
+ errno = EINVAL;
+ return errmsg("\"%s\" is not a character device", node);
+ }
+
+ major = major(stat.st_rdev);
+ minor = minor(stat.st_rdev);
+
+ if (minor != 0) {
+ errno = EINVAL;
+ return errmsg("\"%s\" is not an UBI character device", node);
+ }
+
+ if (ubi_get_info((libubi_t *)lib, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ int major1, minor1, ret;
+
+ ret = dev_get_major(lib, i, &major1, &minor1);
+ if (ret) {
+ if (errno == ENOENT)
+ continue;
+ return -1;
+ }
+
+ if (major1 == major) {
+ if (minor1 != 0) {
+ errmsg("UBI character device minor number is "
+ "%d, but must be 0", minor1);
+ errno = EINVAL;
+ return -1;
+ }
+ errno = 0;
+ *dev_num = i;
+ return 0;
+ }
+ }
+
+ errno = ENODEV;
+ return -1;
+}
+
+int mtd_num2ubi_dev(libubi_t desc, int mtd_num, int *dev_num)
+{
+ struct ubi_info info;
+ int i, ret, mtd_num1;
+ struct libubi *lib = desc;
+
+ if (ubi_get_info(desc, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ ret = dev_read_int(lib->dev_mtd_num, i, &mtd_num1);
+ if (ret) {
+ if (errno == ENOENT)
+ continue;
+ return -1;
+ }
+
+ if (mtd_num1 == mtd_num) {
+ errno = 0;
+ *dev_num = i;
+ return 0;
+ }
+ }
+
+ errno = 0;
+ return -1;
+}
+
+libubi_t libubi_open(int required)
+{
+ int fd, version;
+ struct libubi *lib;
+
+ lib = calloc(1, sizeof(struct libubi));
+ if (!lib)
+ return NULL;
+
+ /* TODO: this must be discovered instead */
+ lib->sysfs = strdup("/sys");
+ if (!lib->sysfs)
+ goto out_error;
+
+ lib->sysfs_ctrl = mkpath(lib->sysfs, SYSFS_CTRL);
+ if (!lib->sysfs_ctrl)
+ goto out_error;
+
+ lib->ctrl_dev = mkpath(lib->sysfs_ctrl, CTRL_DEV);
+ if (!lib->ctrl_dev)
+ goto out_error;
+
+ lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI);
+ if (!lib->sysfs_ubi)
+ goto out_error;
+
+ /* Make sure UBI is present */
+ fd = open(lib->sysfs_ubi, O_RDONLY);
+ if (fd == -1) {
+ if (required)
+ errmsg("cannot open \"%s\", UBI does not seem to "
+ "exist in system", lib->sysfs_ubi);
+ goto out_error;
+ }
+
+ if (close(fd)) {
+ sys_errmsg("close failed on \"%s\"", lib->sysfs_ubi);
+ goto out_error;
+ }
+
+ lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT);
+ if (!lib->ubi_dev)
+ goto out_error;
+
+ lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER);
+ if (!lib->ubi_version)
+ goto out_error;
+
+ lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV);
+ if (!lib->dev_dev)
+ goto out_error;
+
+ lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS);
+ if (!lib->dev_avail_ebs)
+ goto out_error;
+
+ lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS);
+ if (!lib->dev_total_ebs)
+ goto out_error;
+
+ lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT);
+ if (!lib->dev_bad_count)
+ goto out_error;
+
+ lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE);
+ if (!lib->dev_eb_size)
+ goto out_error;
+
+ lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC);
+ if (!lib->dev_max_ec)
+ goto out_error;
+
+ lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD);
+ if (!lib->dev_bad_rsvd)
+ goto out_error;
+
+ lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS);
+ if (!lib->dev_max_vols)
+ goto out_error;
+
+ lib->dev_min_io_size = mkpath(lib->ubi_dev, DEV_MIN_IO_SIZE);
+ if (!lib->dev_min_io_size)
+ goto out_error;
+
+ lib->dev_mtd_num = mkpath(lib->ubi_dev, DEV_MTD_NUM);
+ if (!lib->dev_mtd_num)
+ goto out_error;
+
+ lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT);
+ if (!lib->ubi_vol)
+ goto out_error;
+
+ lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE);
+ if (!lib->vol_type)
+ goto out_error;
+
+ lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV);
+ if (!lib->vol_dev)
+ goto out_error;
+
+ lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT);
+ if (!lib->vol_alignment)
+ goto out_error;
+
+ lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES);
+ if (!lib->vol_data_bytes)
+ goto out_error;
+
+ lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS);
+ if (!lib->vol_rsvd_ebs)
+ goto out_error;
+
+ lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE);
+ if (!lib->vol_eb_size)
+ goto out_error;
+
+ lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED);
+ if (!lib->vol_corrupted)
+ goto out_error;
+
+ lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME);
+ if (!lib->vol_name)
+ goto out_error;
+
+ if (read_positive_int(lib->ubi_version, &version))
+ goto out_error;
+ if (version != LIBUBI_UBI_VERSION) {
+ errmsg("this library was made for UBI version %d, but UBI "
+ "version %d is detected\n", LIBUBI_UBI_VERSION, version);
+ goto out_error;
+ }
+
+ return lib;
+
+out_error:
+ libubi_close((libubi_t)lib);
+ return NULL;
+}
+
+void libubi_close(libubi_t desc)
+{
+ struct libubi *lib = (struct libubi *)desc;
+
+ free(lib->vol_name);
+ free(lib->vol_corrupted);
+ free(lib->vol_eb_size);
+ free(lib->vol_rsvd_ebs);
+ free(lib->vol_data_bytes);
+ free(lib->vol_alignment);
+ free(lib->vol_dev);
+ free(lib->vol_type);
+ free(lib->ubi_vol);
+ free(lib->dev_mtd_num);
+ free(lib->dev_min_io_size);
+ free(lib->dev_max_vols);
+ free(lib->dev_bad_rsvd);
+ free(lib->dev_max_ec);
+ free(lib->dev_eb_size);
+ free(lib->dev_bad_count);
+ free(lib->dev_total_ebs);
+ free(lib->dev_avail_ebs);
+ free(lib->dev_dev);
+ free(lib->ubi_version);
+ free(lib->ubi_dev);
+ free(lib->sysfs_ubi);
+ free(lib->ctrl_dev);
+ free(lib->sysfs_ctrl);
+ free(lib->sysfs);
+ free(lib);
+}
+
+int ubi_attach_mtd(libubi_t desc, const char *node,
+ struct ubi_attach_request *req)
+{
+ int fd, ret;
+ struct ubi_attach_req r;
+
+ memset(&r, sizeof(struct ubi_attach_req), '\0');
+
+ desc = desc;
+ r.ubi_num = req->dev_num;
+ r.mtd_num = req->mtd_num;
+ r.vid_hdr_offset = req->vid_hdr_offset;
+
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ ret = ioctl(fd, UBI_IOCATT, &r);
+ close(fd);
+ if (ret == -1)
+ return -1;
+
+ req->dev_num = r.ubi_num;
+
+#ifdef UDEV_SETTLE_HACK
+ if (system("udevsettle") == -1)
+ return -1;
+ if (system("udevsettle") == -1)
+ return -1;
+#endif
+
+ return ret;
+}
+
+int ubi_detach_mtd(libubi_t desc, const char *node, int mtd_num)
+{
+ int ret, ubi_dev;
+
+ ret = mtd_num2ubi_dev(desc, mtd_num, &ubi_dev);
+ if (ret == -1) {
+ errno = ENODEV;
+ return ret;
+ }
+
+ return ubi_remove_dev(desc, node, ubi_dev);
+}
+
+int ubi_remove_dev(libubi_t desc, const char *node, int ubi_dev)
+{
+ int fd, ret;
+
+ desc = desc;
+
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return -1;
+ ret = ioctl(fd, UBI_IOCDET, &ubi_dev);
+ if (ret == -1)
+ goto out_close;
+
+#ifdef UDEV_SETTLE_HACK
+ if (system("udevsettle") == -1)
+ return -1;
+#endif
+
+out_close:
+ close(fd);
+ return ret;
+}
+
+int ubi_node_type(libubi_t desc, const char *node)
+{
+ struct stat st;
+ struct ubi_info info;
+ int i, fd, major, minor;
+ struct libubi *lib = (struct libubi *)desc;
+ char file[strlen(lib->ubi_vol) + 100];
+
+ if (lstat(node, &st))
+ return -1;
+
+ if (!S_ISCHR(st.st_mode)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ major = major(st.st_rdev);
+ minor = minor(st.st_rdev);
+
+ if (ubi_get_info((libubi_t *)lib, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ int major1, minor1, ret;
+
+ ret = dev_get_major(lib, i, &major1, &minor1);
+ if (ret) {
+ if (errno == ENOENT)
+ continue;
+ return -1;
+ }
+
+ if (major1 == major)
+ break;
+ }
+
+ if (i > info.highest_dev_num) {
+ /*
+ * The character device node does not correspond to any
+ * existing UBI device or volume, but we do not want to return
+ * any error number in this case, to indicate the fact that it
+ * could be a UBI device/volume, but it doesn't.
+ */
+ errno = 0;
+ return -1;
+ }
+
+ if (minor == 0)
+ return 1;
+
+ /* This is supposdely an UBI volume device node */
+ sprintf(file, lib->ubi_vol, i, minor - 1);
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ errno = 0;
+ return -1;
+ }
+
+ return 2;
+}
+
+int ubi_get_info(libubi_t desc, struct ubi_info *info)
+{
+ DIR *sysfs_ubi;
+ struct dirent *dirent;
+ struct libubi *lib = (struct libubi *)desc;
+
+ memset(info, '\0', sizeof(struct ubi_info));
+
+ if (read_major(lib->ctrl_dev, &info->ctrl_major, &info->ctrl_minor)) {
+ /*
+ * Older UBI versions did not have control device, so we do not
+ * panic here for compatibility reasons. May be few years later
+ * we could return -1 here, but for now just set major:minor to
+ * -1.
+ */
+ info->ctrl_major = info->ctrl_minor = -1;
+ }
+
+ /*
+ * We have to scan the UBI sysfs directory to identify how many UBI
+ * devices are present.
+ */
+ sysfs_ubi = opendir(lib->sysfs_ubi);
+ if (!sysfs_ubi)
+ return sys_errmsg("cannot open %s", lib->sysfs_ubi);
+
+ info->lowest_dev_num = INT_MAX;
+ while (1) {
+ int dev_num, ret;
+ char tmp_buf[256];
+
+ errno = 0;
+ dirent = readdir(sysfs_ubi);
+ if (!dirent)
+ break;
+
+ if (strlen(dirent->d_name) > 256) {
+ errmsg("invalid entry in %s: \"%s\"",
+ lib->sysfs_ubi, dirent->d_name);
+ goto out_close;
+ }
+
+ ret = sscanf(dirent->d_name, UBI_DEV_NAME_PATT"%s",
+ &dev_num, tmp_buf);
+ if (ret == 1) {
+ info->dev_count += 1;
+ if (dev_num > info->highest_dev_num)
+ info->highest_dev_num = dev_num;
+ if (dev_num < info->lowest_dev_num)
+ info->lowest_dev_num = dev_num;
+ }
+ }
+
+ if (!dirent && errno) {
+ sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
+ goto out_close;
+ }
+
+ if (closedir(sysfs_ubi))
+ return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
+
+ if (info->lowest_dev_num == INT_MAX)
+ info->lowest_dev_num = 0;
+
+ if (read_positive_int(lib->ubi_version, &info->version))
+ return -1;
+
+ return 0;
+
+out_close:
+ closedir(sysfs_ubi);
+ return -1;
+}
+
+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
+{
+ int fd, ret;
+ struct ubi_mkvol_req r;
+ size_t n;
+
+ memset(&r, sizeof(struct ubi_mkvol_req), '\0');
+
+ desc = desc;
+ r.vol_id = req->vol_id;
+ r.alignment = req->alignment;
+ r.bytes = req->bytes;
+ r.vol_type = req->vol_type;
+
+ n = strlen(req->name);
+ if (n > UBI_MAX_VOLUME_NAME)
+ return -1;
+
+ strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME + 1);
+ r.name_len = n;
+
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ ret = ioctl(fd, UBI_IOCMKVOL, &r);
+ if (ret == -1)
+ goto out_close;
+
+ req->vol_id = r.vol_id;
+
+#ifdef UDEV_SETTLE_HACK
+ if (system("udevsettle") == -1)
+ return -1;
+#endif
+
+out_close:
+ close(fd);
+ return ret;
+}
+
+int ubi_rmvol(libubi_t desc, const char *node, int vol_id)
+{
+ int fd, ret;
+
+ desc = desc;
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ ret = ioctl(fd, UBI_IOCRMVOL, &vol_id);
+ if (ret == -1)
+ goto out_close;
+
+#ifdef UDEV_SETTLE_HACK
+ if (system("udevsettle") == -1)
+ return -1;
+#endif
+
+out_close:
+ close(fd);
+ return ret;
+}
+
+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes)
+{
+ int fd, ret;
+ struct ubi_rsvol_req req;
+
+ desc = desc;
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ req.bytes = bytes;
+ req.vol_id = vol_id;
+
+ ret = ioctl(fd, UBI_IOCRSVOL, &req);
+ close(fd);
+ return ret;
+}
+
+int ubi_update_start(libubi_t desc, int fd, long long bytes)
+{
+ desc = desc;
+ if (ioctl(fd, UBI_IOCVOLUP, &bytes))
+ return -1;
+ return 0;
+}
+
+int ubi_leb_read_start(int fd, struct ubi_leb *leb)
+{
+ return ioctl(fd, UBI_IOCLEBREAD, leb);
+}
+
+int ubi_leb_change_start(libubi_t desc, int fd, int lnum, int bytes, int dtype)
+{
+ struct ubi_leb_change_req req;
+
+ desc = desc;
+ memset(&req, 0, sizeof(struct ubi_leb_change_req));
+ req.lnum = lnum;
+ req.bytes = bytes;
+ req.dtype = dtype;
+
+ if (ioctl(fd, UBI_IOCEBCH, &req))
+ return -1;
+ return 0;
+}
+
+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
+{
+ DIR *sysfs_ubi;
+ struct dirent *dirent;
+ struct libubi *lib = (struct libubi *)desc;
+
+ memset(info, '\0', sizeof(struct ubi_dev_info));
+ info->dev_num = dev_num;
+
+ sysfs_ubi = opendir(lib->sysfs_ubi);
+ if (!sysfs_ubi)
+ return -1;
+
+ info->lowest_vol_num = INT_MAX;
+
+ while (1) {
+ int vol_id, ret, devno;
+ char tmp_buf[256];
+
+ errno = 0;
+ dirent = readdir(sysfs_ubi);
+ if (!dirent)
+ break;
+
+ if (strlen(dirent->d_name) > 256) {
+ errmsg("invalid entry in %s: \"%s\"",
+ lib->sysfs_ubi, dirent->d_name);
+ goto out_close;
+ }
+
+ ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT"%s", &devno, &vol_id, tmp_buf);
+ if (ret == 2 && devno == dev_num) {
+ info->vol_count += 1;
+ if (vol_id > info->highest_vol_num)
+ info->highest_vol_num = vol_id;
+ if (vol_id < info->lowest_vol_num)
+ info->lowest_vol_num = vol_id;
+ }
+ }
+
+ if (!dirent && errno) {
+ sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi);
+ goto out_close;
+ }
+
+ if (closedir(sysfs_ubi))
+ return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi);
+
+ if (info->lowest_vol_num == INT_MAX)
+ info->lowest_vol_num = 0;
+
+ if (dev_get_major(lib, dev_num, &info->major, &info->minor))
+ return -1;
+
+ if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_lebs))
+ return -1;
+ if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_lebs))
+ return -1;
+ if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count))
+ return -1;
+ if (dev_read_int(lib->dev_eb_size, dev_num, &info->leb_size))
+ return -1;
+ if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd))
+ return -1;
+ if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec))
+ return -1;
+ if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count))
+ return -1;
+ if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size))
+ return -1;
+
+ info->avail_bytes = info->avail_lebs * info->leb_size;
+ info->total_bytes = info->total_lebs * info->leb_size;
+
+ return 0;
+
+out_close:
+ closedir(sysfs_ubi);
+ return -1;
+}
+
+int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info)
+{
+ int dev_num;
+ struct libubi *lib = (struct libubi *)desc;
+
+ if (dev_node2num(lib, node, &dev_num))
+ return -1;
+
+ return ubi_get_dev_info1(desc, dev_num, info);
+}
+
+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
+ struct ubi_vol_info *info)
+{
+ int ret;
+ struct libubi *lib = (struct libubi *)desc;
+ char buf[50];
+
+ memset(info, '\0', sizeof(struct ubi_vol_info));
+ info->dev_num = dev_num;
+ info->vol_id = vol_id;
+
+ if (dev_get_major(lib, dev_num, &info->dev_major, &info->dev_minor))
+ return -1;
+ if (vol_get_major(lib, dev_num, vol_id, &info->major, &info->minor))
+ return -1;
+
+ ret = vol_read_data(lib->vol_type, dev_num, vol_id, buf, 50);
+ if (ret < 0)
+ return -1;
+
+ if (strncmp(buf, "static\n", ret) == 0)
+ info->type = UBI_STATIC_VOLUME;
+ else if (strncmp(buf, "dynamic\n", ret) == 0)
+ info->type = UBI_DYNAMIC_VOLUME;
+ else {
+ errmsg("bad value at \"%s\"", buf);
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = vol_read_int(lib->vol_alignment, dev_num, vol_id,
+ &info->alignment);
+ if (ret)
+ return -1;
+ ret = vol_read_ll(lib->vol_data_bytes, dev_num, vol_id,
+ &info->data_bytes);
+ if (ret)
+ return -1;
+ ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_lebs);
+ if (ret)
+ return -1;
+ ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->leb_size);
+ if (ret)
+ return -1;
+ ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id,
+ &info->corrupted);
+ if (ret)
+ return -1;
+ info->rsvd_bytes = info->leb_size * info->rsvd_lebs;
+
+ ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name,
+ UBI_VOL_NAME_MAX + 2);
+ if (ret < 0)
+ return -1;
+
+ info->name[ret - 1] = '\0';
+ return 0;
+}
+
+int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info)
+{
+ int vol_id, dev_num;
+ struct libubi *lib = (struct libubi *)desc;
+
+ if (vol_node2nums(lib, node, &dev_num, &vol_id))
+ return -1;
+
+ return ubi_get_vol_info1(desc, dev_num, vol_id, info);
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h
new file mode 100644
index 00000000000..2e664b87506
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem Bityutskiy
+ *
+ * UBI (Unsorted Block Images) library.
+ */
+
+#ifndef __LIBUBI_INT_H__
+#define __LIBUBI_INT_H__
+
+#include <string.h>
+#include <errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The below are pre-define UBI file and directory names.
+ *
+ * Note, older kernels put 'ubiX_Y' directories straight to '/sys/class/ubi/'.
+ * New kernels puts 'ubiX_Y' directories to '/sys/class/ubi/ubiX/', which is
+ * saner. And for compatibility reasons it also puts symlinks to 'ubiX_Y'
+ * directories to '/sys/class/ubi/'. For now libubi assumes old layout.
+ */
+
+#define SYSFS_UBI "class/ubi"
+#define SYSFS_CTRL "class/misc/ubi_ctrl/"
+
+#define CTRL_DEV "dev"
+
+#define UBI_VER "version"
+#define UBI_DEV_NAME_PATT "ubi%d"
+
+#define DEV_DEV "dev"
+#define DEV_AVAIL_EBS "avail_eraseblocks"
+#define DEV_TOTAL_EBS "total_eraseblocks"
+#define DEV_BAD_COUNT "bad_peb_count"
+#define DEV_EB_SIZE "eraseblock_size"
+#define DEV_MAX_EC "max_ec"
+#define DEV_MAX_RSVD "reserved_for_bad"
+#define DEV_MAX_VOLS "max_vol_count"
+#define DEV_MIN_IO_SIZE "min_io_size"
+#define DEV_MTD_NUM "mtd_num"
+
+#define UBI_VOL_NAME_PATT "ubi%d_%d"
+#define VOL_TYPE "type"
+#define VOL_DEV "dev"
+#define VOL_ALIGNMENT "alignment"
+#define VOL_DATA_BYTES "data_bytes"
+#define VOL_RSVD_EBS "reserved_ebs"
+#define VOL_EB_SIZE "usable_eb_size"
+#define VOL_CORRUPTED "corrupted"
+#define VOL_NAME "name"
+
+/**
+ * libubi - UBI library description data structure.
+ * @sysfs: sysfs file system path
+ * @sysfs_ctrl: UBI control device directory in sysfs
+ * @ctrl_dev: UBI control device major/minor numbers sysfs file
+ * @sysfs_ubi: UBI directory in sysfs
+ * @ubi_dev: UBI device sysfs directory pattern
+ * @ubi_version: UBI version file sysfs path
+ * @dev_dev: UBI device major/minor numbers file pattern
+ * @dev_avail_ebs: count of available eraseblocks sysfs path pattern
+ * @dev_total_ebs: total eraseblocks count sysfs path pattern
+ * @dev_bad_count: count of bad eraseblocks sysfs path pattern
+ * @dev_eb_size: size of UBI device's eraseblocks sysfs path pattern
+ * @dev_max_ec: maximum erase counter sysfs path pattern
+ * @dev_bad_rsvd: count of physical eraseblock reserved for bad eraseblocks
+ * handling
+ * @dev_max_vols: maximum volumes number count sysfs path pattern
+ * @dev_min_io_size: minimum I/O unit size sysfs path pattern
+ * @ubi_vol: UBI volume sysfs directory pattern
+ * @vol_type: volume type sysfs path pattern
+ * @vol_dev: volume major/minor numbers file pattern
+ * @vol_alignment: volume alignment sysfs path pattern
+ * @vol_data_bytes: volume data size sysfs path pattern
+ * @vol_rsvd_ebs: volume reserved size sysfs path pattern
+ * @vol_eb_size: volume eraseblock size sysfs path pattern
+ * @vol_corrupted: volume corruption flag sysfs path pattern
+ * @vol_name: volume name sysfs path pattern
+ */
+struct libubi
+{
+ char *sysfs;
+ char *sysfs_ctrl;
+ char *ctrl_dev;
+ char *sysfs_ubi;
+ char *ubi_dev;
+ char *ubi_version;
+ char *dev_dev;
+ char *dev_avail_ebs;
+ char *dev_total_ebs;
+ char *dev_bad_count;
+ char *dev_eb_size;
+ char *dev_max_ec;
+ char *dev_bad_rsvd;
+ char *dev_max_vols;
+ char *dev_min_io_size;
+ char *dev_mtd_num;
+ char *ubi_vol;
+ char *vol_type;
+ char *vol_dev;
+ char *vol_alignment;
+ char *vol_data_bytes;
+ char *vol_rsvd_ebs;
+ char *vol_eb_size;
+ char *vol_corrupted;
+ char *vol_name;
+ char *vol_max_count;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBUBI_INT_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c
new file mode 100644
index 00000000000..f3e77690287
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Generating UBI images.
+ *
+ * Authors: Oliver Lohmann
+ * Artem Bityutskiy
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <mtd/ubi-header.h>
+#include <mtd_swab.h>
+#include <libubigen.h>
+#include "crc32.h"
+#include "common.h"
+
+#define PROGRAM_NAME "libubigen"
+
+/**
+ * ubigen_info_init - initialize libubigen.
+ * @ui: libubigen information
+ * @peb_size: flash physical eraseblock size
+ * @min_io_size: flash minimum input/output unit size
+ * @subpage_size: flash sub-page, if present (has to be equivalent to
+ * @min_io_size if does not exist)
+ * @vid_hdr_offs: offset of the VID header
+ * @ubi_ver: UBI version
+ */
+void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
+ int subpage_size, int vid_hdr_offs, int ubi_ver)
+{
+ if (!vid_hdr_offs) {
+ vid_hdr_offs = UBI_EC_HDR_SIZE + subpage_size - 1;
+ vid_hdr_offs /= subpage_size;
+ vid_hdr_offs *= subpage_size;
+ }
+
+ ui->peb_size = peb_size;
+ ui->min_io_size = min_io_size;
+ ui->vid_hdr_offs = vid_hdr_offs;
+ ui->data_offs = vid_hdr_offs + UBI_VID_HDR_SIZE + min_io_size - 1;
+ ui->data_offs /= min_io_size;
+ ui->data_offs *= min_io_size;
+ ui->leb_size = peb_size - ui->data_offs;
+ ui->ubi_ver = ubi_ver;
+
+ ui->max_volumes = ui->leb_size / UBI_VTBL_RECORD_SIZE;
+ if (ui->max_volumes > UBI_MAX_VOLUMES)
+ ui->max_volumes = UBI_MAX_VOLUMES;
+ ui->vtbl_size = ui->max_volumes * UBI_VTBL_RECORD_SIZE;
+}
+
+/**
+ * ubigen_create_empty_vtbl - creates empty volume table.
+ *
+ * This function creates an empty volume table and returns a pointer to it in
+ * case of success and %NULL in case of failure. The returned object has to be
+ * freed with 'free()' call.
+ */
+struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui)
+{
+ struct ubi_vtbl_record *vtbl;
+ int i;
+
+ vtbl = calloc(1, ui->vtbl_size);
+ if (!vtbl) {
+ sys_errmsg("cannot allocate %d bytes of memory", ui->vtbl_size);
+ return NULL;
+ }
+
+ for (i = 0; i < ui->max_volumes; i++) {
+ uint32_t crc = crc32(UBI_CRC32_INIT, &vtbl[i],
+ UBI_VTBL_RECORD_SIZE_CRC);
+ vtbl[i].crc = cpu_to_be32(crc);
+ }
+
+ return vtbl;
+}
+
+/**
+ * ubigen_add_volume - add a volume to the volume table.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @vtbl: volume table to add to
+ *
+ * This function adds volume described by input parameters to the volume table
+ * @vtbl.
+ */
+int ubigen_add_volume(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi,
+ struct ubi_vtbl_record *vtbl)
+{
+ struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id];
+ uint32_t tmp;
+
+ if (vi->id >= ui->max_volumes)
+ return errmsg("too high volume id %d, max. volumes is %d",
+ vi->id, ui->max_volumes);
+
+ if (vi->alignment >= ui->leb_size)
+ return errmsg("too large alignment %d, max is %d (LEB size)",
+ vi->alignment, ui->leb_size);
+
+ memset(vtbl_rec, '\0', sizeof(struct ubi_vtbl_record));
+ tmp = (vi->bytes + ui->leb_size - 1) / ui->leb_size;
+ vtbl_rec->reserved_pebs = cpu_to_be32(tmp);
+ vtbl_rec->alignment = cpu_to_be32(vi->alignment);
+ vtbl_rec->vol_type = vi->type;
+ tmp = ui->leb_size % vi->alignment;
+ vtbl_rec->data_pad = cpu_to_be32(tmp);
+ vtbl_rec->flags = vi->flags;
+
+ memcpy(vtbl_rec->name, vi->name, vi->name_len);
+ vtbl_rec->name[vi->name_len] = '\0';
+ vtbl_rec->name_len = cpu_to_be16(vi->name_len);
+
+ tmp = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
+ vtbl_rec->crc = cpu_to_be32(tmp);
+ return 0;
+}
+
+/**
+ * ubigen_init_ec_hdr - initialize EC header.
+ * @ui: libubigen information
+ * @hdr: the EC header to initialize
+ * @ec: erase counter value
+ */
+void ubigen_init_ec_hdr(const struct ubigen_info *ui,
+ struct ubi_ec_hdr *hdr, long long ec)
+{
+ uint32_t crc;
+
+ memset(hdr, '\0', sizeof(struct ubi_ec_hdr));
+
+ hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
+ hdr->version = ui->ubi_ver;
+ hdr->ec = cpu_to_be64(ec);
+ hdr->vid_hdr_offset = cpu_to_be32(ui->vid_hdr_offs);
+
+ hdr->data_offset = cpu_to_be32(ui->data_offs);
+
+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+ hdr->hdr_crc = cpu_to_be32(crc);
+}
+
+/**
+ * init_vid_hdr - initialize VID header.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @hdr: the VID header to initialize
+ * @lnum: logical eraseblock number
+ * @data: the contents of the LEB (static volumes only)
+ * @data_size: amount of data in this LEB (static volumes only)
+ *
+ * Note, @used_ebs, @data and @data_size are ignored in case of dynamic
+ * volumes.
+ */
+static void init_vid_hdr(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi,
+ struct ubi_vid_hdr *hdr, int lnum,
+ const void *data, int data_size)
+{
+ uint32_t crc;
+
+ memset(hdr, '\0', sizeof(struct ubi_vid_hdr));
+
+ hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
+ hdr->version = ui->ubi_ver;
+ hdr->vol_type = vi->type;
+ hdr->vol_id = cpu_to_be32(vi->id);
+ hdr->lnum = cpu_to_be32(lnum);
+ hdr->data_pad = cpu_to_be32(vi->data_pad);
+ hdr->compat = vi->compat;
+
+ if (vi->type == UBI_VID_STATIC) {
+ hdr->data_size = cpu_to_be32(data_size);
+ hdr->used_ebs = cpu_to_be32(vi->used_ebs);
+ crc = crc32(UBI_CRC32_INIT, data, data_size);
+ hdr->data_crc = cpu_to_be32(crc);
+ }
+
+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_VID_HDR_SIZE_CRC);
+ hdr->hdr_crc = cpu_to_be32(crc);
+}
+
+/**
+ * ubigen_write_volume - write UBI volume.
+ * @ui: libubigen information
+ * @vi: volume information
+ * @ec: erase coutner value to put to EC headers
+ * @bytes: volume size in bytes
+ * @in: input file descriptor (has to be properly seeked)
+ * @out: output file descriptor
+ *
+ * This function reads the contents of the volume from the input file @in and
+ * writes the UBI volume to the output file @out. Returns zero on success and
+ * %-1 on failure.
+ */
+int ubigen_write_volume(const struct ubigen_info *ui,
+ const struct ubigen_vol_info *vi, long long ec,
+ long long bytes, int in, int out)
+{
+ int len = vi->usable_leb_size, rd, lnum = 0;
+ char inbuf[ui->leb_size+sizeof(unsigned int)], outbuf[ui->peb_size];
+
+ if (vi->id >= ui->max_volumes)
+ return errmsg("too high volume id %d, max. volumes is %d",
+ vi->id, ui->max_volumes);
+
+ if (vi->alignment >= ui->leb_size)
+ return errmsg("too large alignment %d, max is %d (LEB size)",
+ vi->alignment, ui->leb_size);
+
+ memset(outbuf, 0xFF, ui->data_offs);
+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec);
+
+ while (bytes) {
+ int l;
+ struct ubi_vid_hdr *vid_hdr;
+
+ if (bytes < len)
+ len = bytes;
+ bytes -= len;
+
+ l = len;
+ do {
+ rd = read(in, inbuf + len - l, sizeof(unsigned int));
+ if (rd != sizeof(unsigned int))
+ return sys_errmsg("cannot read leb lnum from the input file");
+
+ rd = read(in, inbuf + len - l + sizeof(unsigned int), l);
+ if (rd != l)
+ return sys_errmsg("cannot read %d bytes from the input file", l);
+
+ l -= rd;
+ } while (l);
+
+ vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
+ lnum = ((unsigned int *)inbuf)[0];
+ init_vid_hdr(ui, vi, vid_hdr, lnum, inbuf+sizeof(unsigned int), len);
+
+ memcpy(outbuf + ui->data_offs, inbuf+sizeof(unsigned int), len);
+ memset(outbuf + ui->data_offs + len, 0xFF,
+ ui->peb_size - ui->data_offs - len);
+
+ if (write(out, outbuf, ui->peb_size) != ui->peb_size)
+ return sys_errmsg("cannot write %d bytes to the output file", ui->peb_size);
+
+// lnum += 1;
+ }
+
+ return 0;
+}
+
+/**
+ * ubigen_write_layout_vol - write UBI layout volume
+ * @ui: libubigen information
+ * @peb1: physical eraseblock number to write the first volume table copy
+ * @peb2: physical eraseblock number to write the second volume table copy
+ * @ec1: erase counter value for @peb1
+ * @ec2: erase counter value for @peb1
+ * @vtbl: volume table
+ * @fd: output file descriptor seeked to the proper position
+ *
+ * This function creates the UBI layout volume which contains 2 copies of the
+ * volume table. Returns zero in case of success and %-1 in case of failure.
+ */
+int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
+ long long ec1, long long ec2,
+ struct ubi_vtbl_record *vtbl, int fd)
+{
+ int ret;
+ struct ubigen_vol_info vi;
+ char outbuf[ui->peb_size];
+ struct ubi_vid_hdr *vid_hdr;
+ off_t seek;
+
+ vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS;
+ vi.id = UBI_LAYOUT_VOLUME_ID;
+ vi.alignment = UBI_LAYOUT_VOLUME_ALIGN;
+ vi.data_pad = ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN;
+ vi.usable_leb_size = ui->leb_size - vi.data_pad;
+ vi.data_pad = ui->leb_size - vi.usable_leb_size;
+ vi.type = UBI_LAYOUT_VOLUME_TYPE;
+ vi.name = UBI_LAYOUT_VOLUME_NAME;
+ vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME);
+ vi.compat = UBI_LAYOUT_VOLUME_COMPAT;
+
+ memset(outbuf, 0xFF, ui->data_offs);
+ vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
+ memcpy(outbuf + ui->data_offs, vtbl, ui->vtbl_size);
+ memset(outbuf + ui->data_offs + ui->vtbl_size, 0xFF,
+ ui->peb_size - ui->data_offs - ui->vtbl_size);
+
+ seek = peb1 * ui->peb_size;
+ if (lseek(fd, seek, SEEK_SET) != seek)
+ return sys_errmsg("cannot seek output file");
+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec1);
+ init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0);
+ ret = write(fd, outbuf, ui->peb_size);
+ if (ret != ui->peb_size)
+ return sys_errmsg("cannot write %d bytes", ui->peb_size);
+
+ seek = peb2 * ui->peb_size;
+ if (lseek(fd, seek, SEEK_SET) != seek)
+ return sys_errmsg("cannot seek output file");
+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec2);
+ init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0);
+ ret = write(fd, outbuf, ui->peb_size);
+ if (ret != ui->peb_size)
+ return sys_errmsg("cannot write %d bytes", ui->peb_size);
+
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c
new file mode 100644
index 00000000000..3e19ecaf39d
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * An utility to attach MTD devices to UBI.
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubiattach"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int devn;
+ int mtdn;
+ int vidoffs;
+ const char *node;
+};
+
+static struct args args = {
+ .devn = UBI_DEV_NUM_AUTO,
+ .mtdn = -1,
+ .vidoffs = 0,
+ .node = NULL,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to attach MTD device to UBI.";
+
+static const char *optionsstr =
+"-d, --devn=<UBI device number> the number to assign to the newly created UBI device\n"
+" (the number is assigned automatically if this is not\n"
+" specified\n"
+"-m, --mtdn=<MTD device number> MTD device number to attach\n"
+"-O, --vid-hdr-offset VID header offset (do not specify this unless you\n"
+" really know what you do and the optimal defaults will\n"
+" be used)\n"
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME "<UBI control device node file name> [-m <MTD device number>] [-d <UBI device number>]\n"
+"\t\t[--mtdn=<MTD device number>] [--devn <UBI device number>]\n"
+"Example 1: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 - attach MTD device 0 (mtd0) to UBI\n"
+"Example 2: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 -d 3 - attach MTD device 0 (mtd0) to UBI and\n"
+" and create UBI device number 3 (ubi3)";
+
+static const struct option long_options[] = {
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' },
+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "m:d:O:hV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'd':
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: \"%s\"", optarg);
+
+ break;
+
+ case 'm':
+ args.mtdn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.mtdn < 0)
+ return errmsg("bad MTD device number: \"%s\"", optarg);
+
+ break;
+
+ case 'O':
+ args.vidoffs = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.vidoffs <= 0)
+ return errmsg("bad VID header offset: \"%s\"", optarg);
+
+ break;
+
+ case 'h':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (optind == argc)
+ return errmsg("UBI control device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("more then one UBI control device specified (use -h for help)");
+
+ if (args.mtdn == -1)
+ return errmsg("MTD device number was not specified (use -h for help)");
+
+ args.node = argv[optind];
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+ struct ubi_info ubi_info;
+ struct ubi_dev_info dev_info;
+ struct ubi_attach_request req;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ libubi = libubi_open(1);
+ if (libubi == NULL)
+ return sys_errmsg("cannot open libubi");
+
+ /*
+ * Make sure the kernel is fresh enough and this feature is supported.
+ */
+ err = ubi_get_info(libubi, &ubi_info);
+ if (err) {
+ sys_errmsg("cannot get UBI information");
+ goto out_libubi;
+ }
+
+ if (ubi_info.ctrl_major == -1) {
+ errmsg("MTD attach/detach feature is not supported by your kernel");
+ goto out_libubi;
+ }
+
+ req.dev_num = args.devn;
+ req.mtd_num = args.mtdn;
+ req.vid_hdr_offset = args.vidoffs;
+
+ err = ubi_attach_mtd(libubi, args.node, &req);
+ if (err) {
+ sys_errmsg("cannot attach mtd%d", args.mtdn);
+ goto out_libubi;
+ }
+
+ /* Print some information about the new UBI device */
+ err = ubi_get_dev_info1(libubi, req.dev_num, &dev_info);
+ if (err) {
+ sys_errmsg("cannot get information about newly created UBI device");
+ goto out_libubi;
+ }
+
+ printf("UBI device number %d, total %d LEBs (", dev_info.dev_num, dev_info.total_lebs);
+ ubiutils_print_bytes(dev_info.total_bytes, 0);
+ printf("), available %d LEBs (", dev_info.avail_lebs);
+ ubiutils_print_bytes(dev_info.avail_bytes, 0);
+ printf("), LEB size ");
+ ubiutils_print_bytes(dev_info.leb_size, 1);
+ printf("\n");
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c
new file mode 100644
index 00000000000..4f5b32e8f68
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Calculate CRC32 with UBI start value (0xFFFFFFFF) for a given binary image.
+ *
+ * Author: Oliver Lohmann
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <mtd/ubi-header.h>
+
+#include "crc32.h"
+#include "common.h"
+
+#define BUFSIZE 4096
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubicrc32"
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to calculate CRC32 with UBI start value (0xFFFFFFFF)";
+
+static const char *optionsstr =
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <file to calculate CRC32 for> [-h] [--help]";
+
+static const struct option long_options[] = {
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "hV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'h':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err = 0;
+ uint32_t crc = UBI_CRC32_INIT;
+ char buf[BUFSIZE];
+ FILE *fp;
+
+ if (argc > 1) {
+ fp = fopen(argv[1], "r");
+ if (!fp)
+ return sys_errmsg("cannot open \"%s\"", argv[1]);
+ } else
+ fp = stdin;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return err;
+
+ while (!feof(fp)) {
+ size_t read;
+
+ read = fread(buf, 1, BUFSIZE, fp);
+ if (ferror(fp)) {
+ sys_errmsg("cannot read input file");
+ err = -1;
+ goto out_close;
+ }
+ crc = crc32(crc, buf, read);
+ }
+
+ printf("0x%08x\n", crc);
+
+out_close:
+ if (fp != stdin)
+ fclose(fp);
+ return err;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c
new file mode 100644
index 00000000000..6a06fb2cf2e
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * An utility to generate input file CRC
+ *
+ * Authors: Yurong Tan (Nancy)
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <libubi.h>
+#include "common.h"
+#include "crc32.h"
+
+#define PROGRAM_VERSION "1.1"
+#define PROGRAM_NAME "ubicrcsf"
+#define UBI_LEB_SIZE 258048
+#define BUF_SIZE (UBI_LEB_SIZE + sizeof(unsigned int))
+
+/*
+ * usage: $ubicrcsf ubifs.img
+ */
+int main(int argc, char * const argv[])
+{
+ int err, ifd, tmp, i;
+ int crc_sum = 0;
+ struct stat st;
+ char *buf=NULL;
+
+ buf = malloc(BUF_SIZE);
+ if(buf==NULL){
+ printf("no mem\n");
+ goto out_free;
+ }
+
+ err = stat(argv[1], &st);
+ if (err < 0) {
+ printf("stat failed on \"%s\"", argv[1]);
+ goto out_free;
+ }
+
+ ifd = open(argv[1], O_RDONLY);
+ if (ifd == -1) {
+ printf("cannot open \"%s\"", argv[1]);
+ goto out_close;
+ }
+
+ tmp = st.st_size/BUF_SIZE;
+
+ for( i=0; i< tmp; i++ ){
+ err = read(ifd, buf, BUF_SIZE);
+ if (err != BUF_SIZE) {
+ printf("read error\n");
+ goto out_close;
+ }
+ crc_sum = crc32(crc_sum, &buf[sizeof(unsigned int)], UBI_LEB_SIZE);
+ }
+
+ printf("CRC sum: %d\n",crc_sum);
+ free(buf);
+ close(ifd);
+ return 0;
+out_close:
+ close(ifd);
+out_free:
+ free(buf);
+ return -1;
+}
+
+
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c
new file mode 100644
index 00000000000..8658cd884b3
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * An utility to update UBI volumes.
+ *
+ * Authors: Frank Haverkamp
+ * Joshua W. Boyer
+ * Artem Bityutskiy
+ * Yurong Tan (Nancy)
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <libubi.h>
+#include "common.h"
+#include "crc32.h"
+
+#define PROGRAM_VERSION "1.1"
+#define PROGRAM_NAME "ubicrcfatvol"
+
+struct args {
+ const char *node;
+ long long size;
+ int devn;
+ char dev_name[256];
+};
+
+static struct args args = {
+ .devn = -1,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to read UBI volumes data and generate CRC.";
+
+static const char *optionsstr =
+"-h, --help print help message\n"
+"-V, --version print program version\n\n"
+"-s, --read size\n"
+;
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <UBI volume node file name> [-s] [-h] [-V] [--help]\n"
+"\t\t\t[--version] \n\n"
+ "Example 1: " PROGRAM_NAME " /dev/ubi0_1 \n";
+
+struct option long_options[] = {
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ /* Deprecated -d and -B options */
+ { .name = "size", .has_arg = 1, .flag = NULL, .val = 's' },
+ { NULL, 0, NULL, 0}
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "n:sh?Vd:", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+
+ case 'h':
+ case '?':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 's':
+ args.size = ubiutils_get_bytes(optarg);
+ if (args.size <= 0)
+ return errmsg("bad read size: \"%s\"", optarg);
+ break;
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ /* Handle deprecated -d option */
+ if (args.devn != -1) {
+ sprintf(args.dev_name, "/dev/ubi%d", args.devn);
+ args.node = args.dev_name;
+ } else {
+ if (optind == argc)
+ return errmsg("UBI device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("specify UBI device name and image file name as first 2 "
+ "parameters (use -h for help)");
+ }
+
+ args.node = argv[optind];
+
+ return 0;
+}
+
+static int crc_volume(libubi_t libubi, struct ubi_vol_info *vol_info)
+{
+ int fd;
+ struct ubi_leb leb;
+ int i, tmp;
+ int crc_sum = 0;
+
+ leb.buf = malloc(vol_info->leb_size);
+ if (!leb.buf)
+ return errmsg("cannot allocate %d bytes of memory", vol_info->leb_size);
+
+ fd = open(args.node, O_RDONLY);
+ if (fd == -1) {
+ sys_errmsg("cannot open UBI volume \"%s\"", args.node);
+ goto out_free;
+ }
+
+ for(i=0; i < vol_info->rsvd_lebs ; i++){
+ leb.lnum = i;
+ tmp = ubi_leb_read_start(fd, &leb);
+ if(tmp == 1)
+ continue;
+ else if(tmp == 0){
+ crc_sum = crc32(crc_sum, leb.buf, vol_info->leb_size);
+ }else{
+ printf("LEB %d read error\n", i);
+ goto out_close;
+ }
+ }
+
+ close(fd);
+ free(leb.buf);
+ printf("CRC sum: %d\n",crc_sum);
+ return 0;
+ goto out_close;
+out_close:
+ close(fd);
+out_free:
+ free(leb.buf);
+ return -1;
+}
+
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+ struct ubi_vol_info vol_info;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ libubi = libubi_open(1);
+ if (libubi == NULL) {
+ sys_errmsg("cannot open libubi");
+ goto out_libubi;
+ }
+
+ err = ubi_node_type(libubi, args.node);
+ if (err == 1) {
+ errmsg("\"%s\" is an UBI device node, not an UBI volume node",
+ args.node);
+ goto out_libubi;
+ } else if (err < 0) {
+ errmsg("\"%s\" is not an UBI volume node", args.node);
+ goto out_libubi;
+ }
+
+ err = ubi_get_vol_info(libubi, args.node, &vol_info);
+ if (err) {
+ sys_errmsg("cannot get information about UBI volume \"%s\"",
+ args.node);
+ goto out_libubi;
+ }
+
+ err = crc_volume(libubi, &vol_info);
+ if (err)
+ goto out_libubi;
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+
+}
+
+
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c
new file mode 100644
index 00000000000..50670d05b82
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * An utility to delete UBI devices (detach MTD devices from UBI).
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubidetach"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int devn;
+ int mtdn;
+ const char *node;
+};
+
+static struct args args = {
+ .devn = UBI_DEV_NUM_AUTO,
+ .mtdn = -1,
+ .node = NULL,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+" - a tool to remove UBI devices (detach MTD devices from UBI)";
+
+static const char *optionsstr =
+"-d, --devn=<UBI device number> UBI device number to delete\n"
+"-m, --mtdn=<MTD device number> or altrnatively, MTD device number to detach -\n"
+" this will delete corresponding UBI device\n"
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME "<UBI control device node file name> [-d <UBI device number>] [-m <MTD device number>]\n"
+"\t\t[--devn <UBI device number>] [--mtdn=<MTD device number>]\n"
+"Example 1: " PROGRAM_NAME " /dev/ubi_ctrl -d 2 - delete UBI device 2 (ubi2)\n"
+"Example 2: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 - detach MTD device 0 (mtd0)";
+
+static const struct option long_options[] = {
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "m:d:hV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'd':
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: \"%s\"", optarg);
+
+ break;
+
+ case 'm':
+ args.mtdn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.mtdn < 0)
+ return errmsg("bad MTD device number: \"%s\"", optarg);
+
+ break;
+
+ case 'h':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (optind == argc)
+ return errmsg("UBI control device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("more then one UBI control device specified (use -h for help)");
+
+ if (args.mtdn == -1 && args.devn == -1)
+ return errmsg("neither MTD nor UBI devices were specified (use -h for help)");
+
+ if (args.mtdn != -1 && args.devn != -1)
+ return errmsg("specify either MTD or UBI device (use -h for help)");
+
+ args.node = argv[optind];
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+ struct ubi_info ubi_info;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ libubi = libubi_open(1);
+ if (libubi == NULL)
+ return sys_errmsg("cannot open libubi");
+
+ /*
+ * Make sure the kernel is fresh enough and this feature is supported.
+ */
+ err = ubi_get_info(libubi, &ubi_info);
+ if (err) {
+ sys_errmsg("cannot get UBI information");
+ goto out_libubi;
+ }
+
+ if (ubi_info.ctrl_major == -1) {
+ errmsg("MTD detach/detach feature is not supported by your kernel");
+ goto out_libubi;
+ }
+
+ if (args.devn != -1) {
+ err = ubi_remove_dev(libubi, args.node, args.devn);
+ if (err) {
+ sys_errmsg("cannot remove ubi%d", args.devn);
+ goto out_libubi;
+ }
+ } else {
+ err = ubi_detach_mtd(libubi, args.node, args.mtdn);
+ if (err) {
+ sys_errmsg("cannot detach mtd%d", args.mtdn);
+ goto out_libubi;
+ }
+ }
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
+
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c
new file mode 100644
index 00000000000..802ef3d64d2
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * An utility to update UBI volumes.
+ *
+ * Authors: Frank Haverkamp
+ * Joshua W. Boyer
+ * Artem Bityutskiy
+ * Yurong Tan (Nancy)
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.1"
+#define PROGRAM_NAME "ubidumpvol"
+
+struct args {
+ int truncate;
+ const char *node;
+ const char *img;
+ /* For deprecated -d and -B options handling */
+ int devn;
+ char dev_name[256];
+ int broken_update;
+};
+
+static struct args args = {
+ .devn = -1,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to write data to UBI volumes.";
+
+static const char *optionsstr =
+"-n, --vol_id=<volume id> ID of UBI volume to update\n"
+"-t, --truncate truncate volume (wipe it out)\n"
+"-h, --help print help message\n"
+"-V, --version print program version\n\n"
+"The following are compatibility options which are deprecated, do not use them\n"
+"-d, --devn=<devn> UBI device number - may be used instead of the UBI\n"
+" device node name in which case the utility assumes\n"
+" that the device node is \"/dev/ubi<devn>\"\n"
+"-B, --broken-update broken update, this is for testing";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <UBI volume node file name> [-t] [-h] [-V] [--truncate] [--help]\n"
+"\t\t\t[--version] <image file>\n\n"
+ "Example 1: " PROGRAM_NAME " /dev/ubi0_1 fs.img - dump UBI volume /dev/ubi0_1 to file \"fs.img\" \n";
+
+struct option long_options[] = {
+ { .name = "truncate", .has_arg = 0, .flag = NULL, .val = 't' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ /* Deprecated -d and -B options */
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "broken-update", .has_arg = 1, .flag = NULL, .val = 'B' },
+ { NULL, 0, NULL, 0}
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "n:th?Vd:", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 't':
+ args.truncate = 1;
+ break;
+
+ case 'h':
+ case '?':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'd':
+ {
+ char *endp;
+
+ /* Handle deprecated -d option */
+ warnmsg("-d is depricated and will be removed, do not use it");
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: " "\"%s\"", optarg);
+ break;
+ }
+
+ case 'B':
+ /* Handle deprecated -B option */
+ warnmsg("-B is depricated and will be removed, do not use it");
+ args.broken_update = 1;
+ break;
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ /* Handle deprecated -d option */
+ if (args.devn != -1) {
+ sprintf(args.dev_name, "/dev/ubi%d", args.devn);
+ args.node = args.dev_name;
+ } else {
+ if (optind == argc)
+ return errmsg("UBI device name was not specified (use -h for help)");
+ else if (optind != argc - 2)
+ return errmsg("specify UBI device name and image file name as first 2 "
+ "parameters (use -h for help)");
+ }
+
+ args.node = argv[optind];
+ args.img = argv[optind + 1];
+
+ return 0;
+}
+
+static int dump_volume(libubi_t libubi, struct ubi_vol_info *vol_info)
+{
+ int err, fd, ifd;
+ struct ubi_leb leb;
+ int i, tmp;
+
+ leb.buf = malloc(vol_info->leb_size);
+ if (!leb.buf)
+ return errmsg("cannot allocate %d bytes of memory", vol_info->leb_size);
+
+ fd = open(args.node, O_RDONLY);
+ if (fd == -1) {
+ sys_errmsg("cannot open UBI volume \"%s\"", args.node);
+ goto out_free;
+ }
+
+ ifd = open(args.img, O_WRONLY | O_TRUNC | O_CREAT, 0644);
+ if (ifd == -1) {
+ sys_errmsg("cannot open \"%s\"", args.img);
+ goto out_close1;
+ }
+
+ for(i=0; i < vol_info->rsvd_lebs; i++){
+ leb.lnum = i;
+ tmp = ubi_leb_read_start(fd, &leb);
+ if(tmp == 1)
+ continue;
+ else if(tmp == 0){
+ // write lnum
+ err = write(ifd, (char *)&leb.lnum, sizeof(leb.lnum));
+ if (err != sizeof(leb.lnum)){
+ perror("Image file write error\n");
+ goto out_close;
+ }
+ // write LEB data
+ err = write(ifd, leb.buf, vol_info->leb_size);
+ if (err != vol_info->leb_size){
+ perror("Image file write error\n");
+ goto out_close;
+ }
+ }else{
+ printf("LEB %d read error\n", i);
+ goto out_close;
+ }
+ }
+
+ close(ifd);
+ close(fd);
+ free(leb.buf);
+ printf("Dump Volume succeed\n");
+ return 0;
+ goto out_close;
+out_close:
+ close(ifd);
+out_close1:
+ close(fd);
+out_free:
+ free(leb.buf);
+ return -1;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+ struct ubi_vol_info vol_info;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ if (!args.img && !args.truncate)
+ return errmsg("incorrect arguments, use -h for help");
+
+ libubi = libubi_open(1);
+ if (libubi == NULL) {
+ sys_errmsg("cannot open libubi");
+ goto out_libubi;
+ }
+
+ err = ubi_node_type(libubi, args.node);
+ if (err == 1) {
+ errmsg("\"%s\" is an UBI device node, not an UBI volume node",
+ args.node);
+ goto out_libubi;
+ } else if (err < 0) {
+ errmsg("\"%s\" is not an UBI volume node", args.node);
+ goto out_libubi;
+ }
+
+ err = ubi_get_vol_info(libubi, args.node, &vol_info);
+ if (err) {
+ sys_errmsg("cannot get information about UBI volume \"%s\"",
+ args.node);
+ goto out_libubi;
+ }
+
+ err = dump_volume(libubi, &vol_info);
+ if (err)
+ goto out_libubi;
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c
new file mode 100644
index 00000000000..d82461c5fb3
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c
@@ -0,0 +1,712 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * An utility to format MTD devices into UBI and flash UBI images.
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <fcntl.h>
+
+#include <libubi.h>
+#include <libmtd.h>
+#include <libscan.h>
+#include <libubigen.h>
+#include <mtd_swab.h>
+#include "crc32.h"
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubiformat"
+
+/* The variables below are set by command line arguments */
+struct args {
+ unsigned int yes:1;
+ unsigned int quiet:1;
+ unsigned int verbose:1;
+ unsigned int override_ec:1;
+ unsigned int novtbl:1;
+ int subpage_size;
+ int vid_hdr_offs;
+ int ubi_ver;
+ long long ec;
+ const char *image;
+ const char *node;
+};
+
+static struct args args =
+{
+ .ubi_ver = 1,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to format MTD devices and flash UBI images";
+
+static const char *optionsstr =
+"-s, --sub-page-size=<bytes> minimum input/output unit used for UBI\n"
+" headers, e.g. sub-page size in case of NAND\n"
+" flash (equivalent to the minimum input/output\n"
+" unit size by default)\n"
+"-O, --vid-hdr-offset=<offs> offset if the VID header from start of the\n"
+" physical eraseblock (default is the next\n"
+" minimum I/O unit or sub-page after the EC\n"
+" header)\n"
+"-n, --no-volume-table only erase all eraseblock and preserve erase\n"
+" counters, do not write empty volume table\n"
+"-f, --flash-image=<file> flash image file\n"
+"-e, --erase-counter=<value> use <value> as the erase counter value for all\n"
+" eraseblocks\n"
+"-y, --yes assume the answer is \"yes\" for all question\n"
+" this program would otherwise ask\n"
+"-q, --quiet suppress progress percentage information\n"
+"-v, --verbose be verbose\n"
+"-x, --ubi-ver=<num> UBI version number to put to EC headers\n"
+" (default is 1)\n"
+"-h, -?, --help print help message\n"
+"-V, --version print program version\n";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <MTD device node file name> [-h] [-V] [-y] [-q] [-v]\n"
+"\t\t\t[-x <num>] [-E <value>] [-s <bytes>] [-O <offs>] [-n]\n"
+"\t\t\t[--help] [--version] [--yes] [--verbose] [--quiet]\n"
+"\t\t\t[--ec=<value>] [--vid-hdr-offset=<offs>]\n"
+"\t\t\t[--ubi-ver=<num>] [--no-volume-table]\n\n"
+
+"Example 1: " PROGRAM_NAME " /dev/mtd0 -y - format MTD device number 0 and do\n"
+" not ask questions.\n"
+"Example 2: " PROGRAM_NAME " /dev/mtd0 -q -e 0 - format MTD device number 0,\n"
+" be quiet and force erase counter value 0.";
+
+static const struct option long_options[] = {
+ { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' },
+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' },
+ { .name = "no-volume-table", .has_arg = 0, .flag = NULL, .val = 'n' },
+ { .name = "flash-image", .has_arg = 0, .flag = NULL, .val = 'f' },
+ { .name = "yes", .has_arg = 0, .flag = NULL, .val = 'y' },
+ { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' },
+ { .name = "quiet", .has_arg = 0, .flag = NULL, .val = 'q' },
+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
+ { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "nh?Vyqve:x:s:O:f:", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 's':
+ args.subpage_size = ubiutils_get_bytes(optarg);
+ if (args.subpage_size <= 0)
+ return errmsg("bad sub-page size: \"%s\"", optarg);
+ if (!is_power_of_2(args.subpage_size))
+ return errmsg("sub-page size should be power of 2");
+ break;
+
+ case 'O':
+ args.vid_hdr_offs = strtoul(optarg, &endp, 0);
+ if (args.vid_hdr_offs <= 0 || *endp != '\0' || endp == optarg)
+ return errmsg("bad VID header offset: \"%s\"", optarg);
+ break;
+
+ case 'e':
+ args.ec = strtoull(optarg, &endp, 0);
+ if (args.ec <= 0 || *endp != '\0' || endp == optarg)
+ return errmsg("bad erase counter value: \"%s\"", optarg);
+ if (args.ec >= EC_MAX)
+ return errmsg("too high erase %llu, counter, max is %u", args.ec, EC_MAX);
+ args.override_ec = 1;
+ break;
+
+ case 'f':
+ args.image = optarg;
+ break;
+
+ case 'n':
+ args.novtbl = 1;
+ break;
+
+ case 'y':
+ args.yes = 1;
+ break;
+
+ case 'q':
+ args.quiet = 1;
+ break;
+
+ case 'x':
+ args.ubi_ver = strtoul(optarg, &endp, 0);
+ if (args.ubi_ver < 0 || *endp != '\0' || endp == optarg)
+ return errmsg("bad UBI version: \"%s\"", optarg);
+ break;
+
+ case 'v':
+ args.verbose = 1;
+ break;
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case 'h':
+ case '?':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (args.quiet && args.verbose)
+ return errmsg("using \"-q\" and \"-v\" at the same time does not make sense");
+
+ if (optind == argc)
+ return errmsg("MTD device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("more then one MTD device specified (use -h for help)");
+
+ if (args.image && args.novtbl)
+ return errmsg("-n cannot be used together with -f");
+
+ args.node = argv[optind];
+ return 0;
+}
+
+static int want_exit(void)
+{
+ char buf[4];
+
+ while (1) {
+ normsg_cont("continue? (yes/no) ");
+ scanf("%3s", buf);
+ if (!strncmp(buf, "yes", 3) || !strncmp(buf, "y", 1))
+ return 0;
+ if (!strncmp(buf, "no", 2) || !strncmp(buf, "n", 1))
+ return 1;
+ }
+}
+
+static int answer_is_yes(void)
+{
+ char buf[4];
+
+ while (1) {
+ scanf("%3s", buf);
+ if (!strncmp(buf, "yes", 3) || !strncmp(buf, "y", 1))
+ return 1;
+ if (!strncmp(buf, "no", 2) || !strncmp(buf, "n", 1))
+ return 0;
+ }
+}
+
+static void print_bad_eraseblocks(const struct mtd_info *mtd,
+ const struct ubi_scan_info *si)
+{
+ int first = 1, eb;
+
+ if (si->bad_cnt == 0)
+ return;
+
+ normsg_cont("bad eraseblocks: ");
+ for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ if (si->ec[eb] != EB_BAD)
+ continue;
+ if (first) {
+ printf("%d", eb);
+ first = 0;
+ } else
+ printf(", %d", eb);
+ }
+ printf("\n");
+}
+
+static int change_ec(struct ubi_ec_hdr *hdr, long long ec)
+{
+ uint32_t crc;
+
+ /* Check the EC header */
+ if (be32_to_cpu(hdr->magic) != UBI_EC_HDR_MAGIC)
+ return errmsg("mad UBI magic %#08x, should be %#08x",
+ be32_to_cpu(hdr->magic), UBI_EC_HDR_MAGIC);
+
+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+ if (be32_to_cpu(hdr->hdr_crc) != crc)
+ return errmsg("bad CRC %#08x, should be %#08x\n",
+ crc, be32_to_cpu(hdr->hdr_crc));
+
+ hdr->ec = cpu_to_be64(ec);
+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
+ hdr->hdr_crc = cpu_to_be32(crc);
+
+ return 0;
+}
+
+static int drop_ffs(const struct mtd_info *mtd, const void *buf, int len)
+{
+ int i;
+
+ for (i = len - 1; i >= 0; i--)
+ if (((const uint8_t *)buf)[i] != 0xFF)
+ break;
+
+ /* The resulting length must be aligned to the minimum flash I/O size */
+ len = i + 1;
+ len = (len + mtd->min_io_size - 1) / mtd->min_io_size;
+ len *= mtd->min_io_size;
+ return len;
+}
+
+static int flash_image(const struct mtd_info *mtd, const struct ubigen_info *ui,
+ struct ubi_scan_info *si)
+{
+ int fd, img_ebs, eb, written_ebs = 0, divisor;
+ struct stat st;
+
+ if (stat(args.image, &st))
+ return sys_errmsg("cannot open \"%s\"", args.image);
+
+ img_ebs = st.st_size / mtd->eb_size;
+ if (img_ebs > si->good_cnt)
+ return sys_errmsg("file \"%s\" is too large (%lld bytes)",
+ args.image, (long long)st.st_size);
+
+ if (st.st_size % mtd->eb_size)
+ return sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of eraseblock size (%d bytes)",
+ args.image, (long long)st.st_size, mtd->eb_size);
+
+ fd = open(args.image, O_RDONLY);
+ if (fd == -1)
+ return sys_errmsg("cannot open \"%s\"", args.image);
+
+ verbose(args.verbose, "will write %d eraseblocks", img_ebs);
+ divisor = img_ebs;
+ for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ int err, new_len;
+ char buf[mtd->eb_size];
+ long long ec;
+
+ if (!args.quiet && !args.verbose) {
+ printf("\r" PROGRAM_NAME ": flashing eraseblock %d -- %2lld %% complete ",
+ eb, (long long)(eb + 1) * 100 / divisor);
+ fflush(stdout);
+ }
+
+ if (si->ec[eb] == EB_BAD) {
+ divisor += 1;
+ continue;
+ }
+
+ if (args.verbose) {
+ normsg_cont("eraseblock %d: erase", eb);
+ fflush(stdout);
+ }
+
+ err = mtd_erase(mtd, eb);
+ if (err) {
+ sys_errmsg("failed to erase eraseblock %d", eb);
+ goto out_close;
+ }
+
+ if (read(fd, buf, mtd->eb_size) != mtd->eb_size) {
+ sys_errmsg("failed to read eraseblock %d from \"%s\"",
+ written_ebs, args.image);
+ goto out_close;
+ }
+
+
+ if (si->ec[eb] <= EC_MAX)
+ ec = si->ec[eb] + 1;
+ else if (!args.override_ec)
+ ec = si->mean_ec;
+ else
+ ec = args.ec;
+
+ if (args.verbose) {
+ printf(", change EC to %lld", ec);
+ fflush(stdout);
+ }
+
+ err = change_ec((struct ubi_ec_hdr *)buf, ec);
+ if (err) {
+ errmsg("bad EC header at eraseblock %d of \"%s\"",
+ written_ebs, args.image);
+ goto out_close;
+ }
+
+ if (args.verbose) {
+ printf(", write data\n");
+ fflush(stdout);
+ }
+
+ new_len = drop_ffs(mtd, buf, mtd->eb_size);
+
+ err = mtd_write(mtd, eb, 0, buf, new_len);
+ if (err) {
+ sys_errmsg("cannot write eraseblock %d", eb);
+ goto out_close;
+ }
+ if (++written_ebs >= img_ebs)
+ break;
+ }
+
+ if (!args.quiet && !args.verbose)
+ printf("\n");
+ close(fd);
+ return eb + 1;
+
+out_close:
+ close(fd);
+ return -1;
+}
+
+static int format(const struct mtd_info *mtd, const struct ubigen_info *ui,
+ const struct ubi_scan_info *si, int start_eb, int novtbl)
+{
+ int eb, err, write_size;
+ struct ubi_ec_hdr *hdr;
+ struct ubi_vtbl_record *vtbl;
+ int eb1 = -1, eb2 = -1;
+ long long ec1 = -1, ec2 = -1;
+
+ write_size = UBI_EC_HDR_SIZE + mtd->subpage_size - 1;
+ write_size /= mtd->subpage_size;
+ write_size *= mtd->subpage_size;
+ hdr = malloc(write_size);
+ if (!hdr)
+ return sys_errmsg("cannot allocate %d bytes of memory", write_size);
+
+ memset(hdr, 0xFF, write_size);
+
+ for (eb = start_eb; eb < mtd->eb_cnt; eb++) {
+ long long ec;
+
+ if (!args.quiet && !args.verbose) {
+ printf("\r" PROGRAM_NAME ": formatting eraseblock %d -- %2lld %% complete ",
+ eb, (long long)(eb + 1 - start_eb) * 100 / (mtd->eb_cnt - start_eb));
+ fflush(stdout);
+ }
+
+ if (si->ec[eb] == EB_BAD)
+ continue;
+
+ if (si->ec[eb] <= EC_MAX)
+ ec = si->ec[eb] + 1;
+ else if (!args.override_ec)
+ ec = si->mean_ec;
+ else
+ ec = args.ec;
+ ubigen_init_ec_hdr(ui, hdr, ec);
+
+ if (args.verbose) {
+ normsg_cont("eraseblock %d: erase", eb);
+ fflush(stdout);
+ }
+
+ err = mtd_erase(mtd, eb);
+ if (err) {
+ sys_errmsg("failed to erase eraseblock %d", eb);
+ goto out_free;
+ }
+
+ if ((eb1 == -1 || eb2 == -1) && !novtbl) {
+ if (eb1 == -1) {
+ eb1 = eb;
+ ec1 = ec;
+ } else if (eb2 == -1) {
+ eb2 = eb;
+ ec2 = ec;
+ }
+ if (args.verbose)
+ printf(", do not write EC, leave for vtbl\n");
+ continue;
+ }
+
+ if (args.verbose) {
+ printf(", write EC %lld\n", ec);
+ fflush(stdout);
+ }
+
+ err = mtd_write(mtd, eb, 0, hdr, write_size);
+ if (err) {
+ sys_errmsg("cannot write EC header (%d bytes buffer) to eraseblock %d",
+ write_size, eb);
+ if (args.subpage_size != mtd->min_io_size)
+ normsg("may be %d is incorrect?", args.subpage_size);
+ goto out_free;
+ }
+ }
+
+ if (!args.quiet && !args.verbose)
+ printf("\n");
+
+ if (!novtbl) {
+ if (eb1 == -1 || eb2 == -1) {
+ errmsg("no eraseblocks for volume table");
+ goto out_free;
+ }
+
+ verbose(args.verbose, "write volume table to eraseblocks %d and %d", eb1, eb2);
+ vtbl = ubigen_create_empty_vtbl(ui);
+ if (!vtbl)
+ goto out_free;
+
+ err = ubigen_write_layout_vol(ui, eb1, eb2, ec1, ec2, vtbl, mtd->fd);
+ free(vtbl);
+ if (err) {
+ errmsg("cannot write layout volume");
+ goto out_free;
+ }
+ }
+
+ free(hdr);
+ return 0;
+
+out_free:
+ free(hdr);
+ return -1;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err, verbose;
+ struct mtd_info mtd;
+ libubi_t libubi;
+ struct ubigen_info ui;
+ struct ubi_scan_info *si;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ err = mtd_get_info(args.node, &mtd);
+ if (err)
+ return errmsg("cannot get information about \"%s\"", args.node);
+
+ if (args.subpage_size == 0)
+ args.subpage_size = mtd.min_io_size;
+ else {
+ if (args.subpage_size > mtd.min_io_size) {
+ errmsg("sub-page cannot be larger than min. I/O unit");
+ goto out_close;
+ }
+
+ if (mtd.min_io_size % args.subpage_size) {
+ errmsg("min. I/O unit size should be multiple of sub-page size");
+ goto out_close;
+ }
+ }
+
+ /* Validate VID header offset if it was specified */
+ if (args.vid_hdr_offs != 0) {
+ if (args.vid_hdr_offs % 8) {
+ errmsg("VID header offset has to be multiple of min. I/O unit size");
+ goto out_close;
+ }
+ if (args.vid_hdr_offs + UBI_VID_HDR_SIZE > mtd.eb_size) {
+ errmsg("bad VID header offset");
+ goto out_close;
+ }
+ }
+
+ /*
+ * Because of MTD interface limitations 'mtd_get_info()' cannot get
+ * sub-page so we force the user to pass it via the command line. Let's
+ * hope the user passed us something sane.
+ */
+ mtd.subpage_size = args.subpage_size;
+
+ if (mtd.rdonly) {
+ errmsg("mtd%d (%s) is a read-only device", mtd.num, args.node);
+ goto out_close;
+ }
+
+ /* Make sure this MTD device is not attached to UBI */
+ libubi = libubi_open(0);
+ if (libubi) {
+ int ubi_dev_num;
+
+ err = mtd_num2ubi_dev(libubi, mtd.num, &ubi_dev_num);
+ libubi_close(libubi);
+ if (!err) {
+ errmsg("please, first detach mtd%d (%s) from ubi%d",
+ mtd.num, args.node, ubi_dev_num);
+ goto out_close;
+ }
+ }
+
+ if (!args.quiet) {
+ normsg_cont("mtd%d (%s), size ", mtd.num, mtd.type_str);
+ ubiutils_print_bytes(mtd.size, 1);
+ printf(", %d eraseblocks of ", mtd.eb_size);
+ ubiutils_print_bytes(mtd.eb_size, 1);
+ printf(", min. I/O size %d bytes\n", mtd.min_io_size);
+ }
+
+ if (args.quiet)
+ verbose = 0;
+ else if (args.verbose)
+ verbose = 2;
+ else
+ verbose = 1;
+ err = ubi_scan(&mtd, &si, verbose);
+ if (err) {
+ errmsg("failed to scan mtd%d (%s)", mtd.num, args.node);
+ goto out_close;
+ }
+
+ if (si->good_cnt == 0) {
+ errmsg("all %d eraseblocks are bad", si->bad_cnt);
+ goto out_free;
+ }
+
+ if (si->good_cnt < 2 && (!args.novtbl || args.image)) {
+ errmsg("too few non-bad eraseblocks (%d) on mtd%d", si->good_cnt, mtd.num);
+ goto out_free;
+ }
+
+ if (!args.quiet) {
+ if (si->ok_cnt)
+ normsg("%d eraseblocks have valid erase counter, mean value is %lld",
+ si->ok_cnt, si->mean_ec);
+ if (si->empty_cnt)
+ normsg("%d eraseblocks are supposedly empty", si->empty_cnt);
+ if (si->corrupted_cnt)
+ normsg("%d corrupted erase counters", si->corrupted_cnt);
+ print_bad_eraseblocks(&mtd, si);
+ }
+
+ if (si->alien_cnt) {
+ if (!args.yes || !args.quiet)
+ warnmsg("%d of %d eraseblocks contain non-ubifs data",
+ si->alien_cnt, si->good_cnt);
+ if (!args.yes && want_exit()) {
+ if (args.yes && !args.quiet)
+ printf("yes\n");
+ goto out_free;
+ }
+ }
+
+ if (!args.override_ec && si->empty_cnt < si->good_cnt) {
+ int percent = ((double)si->ok_cnt)/si->good_cnt * 100;
+
+ /*
+ * Make sure the majority of eraseblocks have valid
+ * erase counters.
+ */
+ if (percent < 50) {
+ if (!args.yes || !args.quiet)
+ warnmsg("only %d of %d eraseblocks have valid erase counter",
+ si->ok_cnt, si->good_cnt);
+ normsg("erase counter 0 will be used for all eraseblocks");
+ normsg("note, arbitrary erase counter value may be specified using -e option");
+ if (!args.yes && want_exit()) {
+ if (args.yes && !args.quiet)
+ printf("yes\n");
+ goto out_free;
+ }
+ args.ec = 0;
+ args.override_ec = 1;
+ } else if (percent < 95) {
+ if (!args.yes || !args.quiet)
+ warnmsg("only %d of %d eraseblocks have valid erase counter",
+ si->ok_cnt, si->good_cnt);
+ normsg("mean erase counter %lld will be used for the rest of eraseblock",
+ si->mean_ec);
+ if (!args.yes && want_exit()) {
+ if (args.yes && !args.quiet)
+ printf("yes\n");
+ goto out_free;
+ }
+ args.ec = si->mean_ec;
+ args.override_ec = 1;
+ }
+ }
+
+ if (!args.quiet && args.override_ec)
+ normsg("use erase counter %lld for all eraseblocks", args.ec);
+
+ ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, args.subpage_size,
+ args.vid_hdr_offs, args.ubi_ver);
+
+ if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) {
+ /*
+ * Hmm, what we read from flash and what we calculated using
+ * min. I/O unit size and sub-page size differs.
+ */
+ if (!args.yes || !args.quiet) {
+ warnmsg("VID header and data offsets on flash are %d and %d, "
+ "which is different to calculated offsets %d and %d",
+ si->vid_hdr_offs, si->data_offs, ui.vid_hdr_offs,
+ ui.data_offs);
+ normsg_cont("use old offsets %d and %d? (yes/no) ",
+ si->vid_hdr_offs, si->data_offs);
+ }
+ if (args.yes || answer_is_yes()) {
+ if (args.yes && !args.quiet)
+ printf("yes\n");
+ ui.vid_hdr_offs = si->vid_hdr_offs;
+ ui.data_offs = si->data_offs;
+ }
+ }
+
+ if (args.image) {
+ err = flash_image(&mtd, &ui, si);
+ if (err < 0)
+ goto out_free;
+
+ err = format(&mtd, &ui, si, err, 1);
+ if (err)
+ goto out_free;
+ } else {
+ err = format(&mtd, &ui, si, 0, args.novtbl);
+ if (err)
+ goto out_free;
+ }
+
+ ubi_scan_free(si);
+ close(mtd.fd);
+ return 0;
+
+out_free:
+ ubi_scan_free(si);
+out_close:
+ close(mtd.fd);
+ return -1;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c
new file mode 100644
index 00000000000..fd8c56852bc
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * An utility to create UBI volumes.
+ *
+ * Authors: Artem Bityutskiy <dedekind@infradead.org>
+ * Frank Haverkamp <haver@vnet.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubimkvol"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int vol_id;
+ int vol_type;
+ long long bytes;
+ int lebs;
+ int alignment;
+ const char *name;
+ int nlen;
+ const char *node;
+ int maxavs;
+ /* For deprecated -d option handling */
+ int devn;
+ char dev_name[256];
+};
+
+static struct args args = {
+ .vol_type = UBI_DYNAMIC_VOLUME,
+ .bytes = -1,
+ .lebs = -1,
+ .alignment = 1,
+ .vol_id = UBI_VOL_NUM_AUTO,
+ .devn = -1,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to create UBI volumes.";
+
+static const char *optionsstr =
+"-a, --alignment=<alignment> volume alignment (default is 1)\n"
+"-n, --vol_id=<volume ID> UBI volume ID, if not specified, the volume ID\n"
+" will be assigned automatically\n"
+"-N, --name=<name> volume name\n"
+"-s, --size=<bytes> volume size volume size in bytes, kilobytes (KiB)\n"
+" or megabytes (MiB)\n"
+"-S, --lebs=<LEBs count> alternative way to give volume size in logical\n"
+" eraseblocks\n"
+"-m, --maxavsize set volume size to maximum available size\n"
+"-t, --type=<static|dynamic> volume type (dynamic, static), default is dynamic\n"
+"-h, -?, --help print help message\n"
+"-V, --version print program version\n\n"
+"The following is a compatibility option which is deprecated, do not use it\n"
+"-d, --devn=<devn> UBI device number - may be used instead of the UBI\n"
+" device node name in which case the utility assumes\n"
+" that the device node is \"/dev/ubi<devn>\"";
+
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <UBI device node file name> [-h] [-a <alignment>] [-n <volume ID>] [-N <name>]\n"
+"\t\t\t[-s <bytes>] [-S <LEBs>] [-t <static|dynamic>] [-V] [-m]\n"
+"\t\t\t[--alignment=<alignment>][--vol_id=<volume ID>] [--name=<name>]\n"
+"\t\t\t[--size=<bytes>] [--lebs=<LEBs>] [--type=<static|dynamic>] [--help]\n"
+"\t\t\t[--version] [--maxavsize]\n\n"
+"Example: " PROGRAM_NAME "/dev/ubi0 -s 20MiB -N config_data - create a 20 Megabytes volume\n"
+" named \"config_data\" on UBI device /dev/ubi0.";
+
+static const struct option long_options[] = {
+ { .name = "alignment", .has_arg = 1, .flag = NULL, .val = 'a' },
+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' },
+ { .name = "name", .has_arg = 1, .flag = NULL, .val = 'N' },
+ { .name = "size", .has_arg = 1, .flag = NULL, .val = 's' },
+ { .name = "lebs", .has_arg = 1, .flag = NULL, .val = 'S' },
+ { .name = "type", .has_arg = 1, .flag = NULL, .val = 't' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { .name = "maxavsize", .has_arg = 0, .flag = NULL, .val = 'm' },
+ /* Deprecated -d option */
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { NULL, 0, NULL, 0},
+};
+
+static int param_sanity_check(void)
+{
+ int len;
+
+ if (args.bytes == -1 && !args.maxavs && args.lebs == -1)
+ return errmsg("volume size was not specified (use -h for help)");
+
+ if ((args.bytes != -1 && (args.maxavs || args.lebs != -1)) ||
+ (args.lebs != -1 && (args.maxavs || args.bytes != -1)) ||
+ (args.maxavs && (args.bytes != -1 || args.lebs != -1)))
+ return errmsg("size specified with more then one option");
+
+ if (args.name == NULL)
+ return errmsg("volume name was not specified (use -h for help)");
+
+ len = strlen(args.name);
+ if (len > UBI_MAX_VOLUME_NAME)
+ return errmsg("too long name (%d symbols), max is %d", len, UBI_MAX_VOLUME_NAME);
+
+ return 0;
+}
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "a:n:N:s:S:t:h?Vmd:", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 't':
+ if (!strcmp(optarg, "dynamic"))
+ args.vol_type = UBI_DYNAMIC_VOLUME;
+ else if (!strcmp(optarg, "static"))
+ args.vol_type = UBI_STATIC_VOLUME;
+ else
+ return errmsg("bad volume type: \"%s\"", optarg);
+ break;
+
+ case 's':
+ args.bytes = ubiutils_get_bytes(optarg);
+ if (args.bytes <= 0)
+ return errmsg("bad volume size: \"%s\"", optarg);
+ break;
+
+ case 'S':
+ args.lebs = strtoull(optarg, &endp, 0);
+ if (endp == optarg || args.lebs <= 0 || *endp != '\0')
+ return errmsg("bad LEB count: \"%s\"", optarg);
+ break;
+
+ case 'a':
+ args.alignment = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.alignment <= 0)
+ return errmsg("bad volume alignment: \"%s\"", optarg);
+ break;
+
+ case 'n':
+ args.vol_id = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.vol_id < 0)
+ return errmsg("bad volume ID: " "\"%s\"", optarg);
+ break;
+
+ case 'd':
+ /* Handle deprecated -d option */
+ warnmsg("-d is depricated and will be removed, do not use it");
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: " "\"%s\"", optarg);
+ break;
+
+ case 'N':
+ args.name = optarg;
+ args.nlen = strlen(args.name);
+ break;
+
+ case 'h':
+ case '?':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case 'm':
+ args.maxavs = 1;
+ break;
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ /* Handle deprecated -d option */
+ if (args.devn != -1) {
+ sprintf(args.dev_name, "/dev/ubi%d", args.devn);
+ args.node = args.dev_name;
+ } else {
+ if (optind == argc)
+ return errmsg("UBI device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("more then one UBI device specified (use -h for help)");
+
+ args.node = argv[optind];
+ }
+
+ if (param_sanity_check())
+ return -1;
+
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+ struct ubi_dev_info dev_info;
+ struct ubi_vol_info vol_info;
+ struct ubi_mkvol_request req;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return err;
+
+ libubi = libubi_open(1);
+ if (!libubi)
+ return sys_errmsg("cannot open libubi");
+
+ err = ubi_node_type(libubi, args.node);
+ if (err == 2) {
+ errmsg("\"%s\" is an UBI volume node, not an UBI device node",
+ args.node);
+ goto out_libubi;
+ } else if (err < 0) {
+ errmsg("\"%s\" is not an UBI device node", args.node);
+ goto out_libubi;
+ }
+
+ err = ubi_get_dev_info(libubi, args.node, &dev_info);
+ if (err) {
+ sys_errmsg("cannot get information about UBI device \"%s\"",
+ args.node);
+ goto out_libubi;
+ }
+
+ if (args.maxavs) {
+ args.bytes = dev_info.avail_bytes;
+ printf("Set volume size to %lld\n", args.bytes);
+ }
+
+ if (args.lebs != -1) {
+ args.bytes = dev_info.leb_size;
+ args.bytes -= dev_info.leb_size % args.alignment;
+ args.bytes *= args.lebs;
+ }
+
+ req.vol_id = args.vol_id;
+ req.alignment = args.alignment;
+ req.bytes = args.bytes;
+ req.vol_type = args.vol_type;
+ req.name = args.name;
+
+ err = ubi_mkvol(libubi, args.node, &req);
+ if (err < 0) {
+ sys_errmsg("cannot UBI create volume");
+ goto out_libubi;
+ }
+
+ args.vol_id = req.vol_id;
+
+ /* Print information about the created device */
+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, args.vol_id, &vol_info);
+ if (err) {
+ sys_errmsg("cannot get information about newly created UBI volume");
+ goto out_libubi;
+ }
+
+ printf("Volume ID %d, size %d LEBs (", vol_info.vol_id, vol_info.rsvd_lebs);
+ ubiutils_print_bytes(vol_info.rsvd_bytes, 0);
+ printf("), LEB size ");
+ ubiutils_print_bytes(vol_info.leb_size, 1);
+ printf(", %s, name \"%s\", alignment %d\n",
+ req.vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static",
+ vol_info.name, vol_info.alignment);
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c
new file mode 100644
index 00000000000..fdf169a6613
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2007, 2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * An utility to get UBI information.
+ *
+ * Author: Artem Bityutskiy
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubinfo"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int devn;
+ int vol_id;
+ int all;
+ const char *node;
+};
+
+static struct args args = {
+ .vol_id = -1,
+ .devn = -1,
+ .all = 0,
+ .node = NULL,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to print UBI information.";
+
+static const char *optionsstr =
+"-d, --devn=<UBI device number> UBI device number to get information about\n"
+"-n, --vol_id=<volume ID> ID of UBI volume to print information about\n"
+"-a, --all print information about all devices and volumes,\n"
+" or about all volumes if the UBI device was\n"
+" specified\n"
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage 1: " PROGRAM_NAME " [-d <UBI device number>] [-n <volume ID>] [-a] [-h] [-V] [--vol_id=<volume ID>]\n"
+"\t\t[--devn <UBI device number>] [--all] [--help] [--version]\n"
+"Usage 2: " PROGRAM_NAME " <UBI device node file name> [-a] [-h] [-V] [--all] [--help] [--version]\n"
+"Usage 3: " PROGRAM_NAME " <UBI volume node file name> [-h] [-V] [--help] [--version]\n\n"
+"Example 1: " PROGRAM_NAME " - (no arguments) print general UBI information\n"
+"Example 2: " PROGRAM_NAME " -d 1 - print information about UBI device number 1\n"
+"Example 3: " PROGRAM_NAME " /dev/ubi0 -a - print information about all volumes of UBI\n"
+" device /dev/ubi0\n"
+"Example 4: " PROGRAM_NAME " /dev/ubi1_0 - print information about UBI volume /dev/ubi1_0\n"
+"Example 5: " PROGRAM_NAME " -a - print all information\n";
+
+static const struct option long_options[] = {
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' },
+ { .name = "all", .has_arg = 0, .flag = NULL, .val = 'a' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "an:d:hV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'a':
+ args.all = 1;
+ break;
+
+ case 'n':
+ args.vol_id = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.vol_id < 0)
+ return errmsg("bad volume ID: " "\"%s\"", optarg);
+ break;
+
+ case 'd':
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: \"%s\"", optarg);
+
+ break;
+
+ case 'h':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (optind == argc - 1)
+ args.node = argv[optind];
+ else if (optind < argc)
+ return errmsg("more then one UBI devices specified (use -h for help)");
+
+ return 0;
+}
+
+static int translate_dev(libubi_t libubi, const char *node)
+{
+ int err;
+
+ err = ubi_node_type(libubi, node);
+ if (err == -1) {
+ if (errno)
+ return errmsg("unrecognized device node \"%s\"", node);
+ return errmsg("\"%s\" does not correspond to any UBI device or volume", node);
+ }
+
+ if (err == 1) {
+ struct ubi_dev_info dev_info;
+
+ err = ubi_get_dev_info(libubi, node, &dev_info);
+ if (err)
+ return sys_errmsg("cannot get information about UBI device \"%s\"", node);
+
+ args.devn = dev_info.dev_num;
+ } else {
+ struct ubi_vol_info vol_info;
+
+ err = ubi_get_vol_info(libubi, node, &vol_info);
+ if (err)
+ return sys_errmsg("cannot get information about UBI volume \"%s\"", node);
+
+ if (args.vol_id != -1)
+ return errmsg("both volume character device node (\"%s\") and "
+ "volume ID (%d) are specify, use only one of them"
+ "(use -h for help)", node, args.vol_id);
+
+ args.devn = vol_info.dev_num;
+ args.vol_id = vol_info.vol_id;
+ }
+
+ return 0;
+}
+
+static int print_vol_info(libubi_t libubi, int dev_num, int vol_id)
+{
+ int err;
+ struct ubi_vol_info vol_info;
+
+ err = ubi_get_vol_info1(libubi, dev_num, vol_id, &vol_info);
+ if (err)
+ return sys_errmsg("cannot get information about UBI volume %d on ubi%d",
+ vol_id, dev_num);
+
+ printf("Volume ID: %d (on ubi%d)\n", vol_info.vol_id, vol_info.dev_num);
+ printf("Type: %s\n",
+ vol_info.type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static");
+ printf("Alignment: %d\n", vol_info.alignment);
+
+ printf("Size: %d LEBs (", vol_info.rsvd_lebs);
+ ubiutils_print_bytes(vol_info.rsvd_bytes, 0);
+ printf(")\n");
+
+ if (vol_info.type == UBI_STATIC_VOLUME) {
+ printf("Data bytes: ");
+ ubiutils_print_bytes(vol_info.data_bytes, 1);
+ }
+ printf("State: %s\n", vol_info.corrupted ? "corrupted" : "OK");
+ printf("Name: %s\n", vol_info.name);
+ printf("Character device major/minor: %d:%d\n",
+ vol_info.major, vol_info.minor);
+
+ return 0;
+}
+
+static int print_dev_info(libubi_t libubi, int dev_num, int all)
+{
+ int i, err, first = 1;
+ struct ubi_dev_info dev_info;
+ struct ubi_vol_info vol_info;
+
+ err = ubi_get_dev_info1(libubi, dev_num, &dev_info);
+ if (err)
+ return sys_errmsg("cannot get information about UBI device %d", dev_num);
+
+ printf("ubi%d:\n", dev_info.dev_num);
+ printf("Volumes count: %d\n", dev_info.vol_count);
+ printf("Logical eraseblock size: %d\n", dev_info.leb_size);
+
+ printf("Total amount of logical eraseblocks: %d (", dev_info.total_lebs);
+ ubiutils_print_bytes(dev_info.total_bytes, 0);
+ printf(")\n");
+
+ printf("Amount of available logical eraseblocks: %d (", dev_info.avail_lebs);
+ ubiutils_print_bytes(dev_info.avail_bytes, 0);
+ printf(")\n");
+
+ printf("Maximum count of volumes %d\n", dev_info.max_vol_count);
+ printf("Count of bad physical eraseblocks: %d\n", dev_info.bad_count);
+ printf("Count of reserved physical eraseblocks: %d\n", dev_info.bad_rsvd);
+ printf("Current maximum erase counter value: %lld\n", dev_info.max_ec);
+ printf("Minimum input/output unit size: %d bytes\n", dev_info.min_io_size);
+ printf("Character device major/minor: %d:%d\n",
+ dev_info.major, dev_info.minor);
+
+ if (dev_info.vol_count == 0)
+ return 0;
+
+ printf("Present volumes: ");
+ for (i = dev_info.lowest_vol_num;
+ i <= dev_info.highest_vol_num; i++) {
+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+
+ return sys_errmsg("libubi failed to probe volume %d on ubi%d",
+ i, dev_info.dev_num);
+ }
+
+ if (!first)
+ printf(", %d", i);
+ else {
+ printf("%d", i);
+ first = 0;
+ }
+ }
+ printf("\n");
+
+ if (!all)
+ return 0;
+
+ first = 1;
+ printf("\n");
+
+ for (i = dev_info.lowest_vol_num;
+ i <= dev_info.highest_vol_num; i++) {
+ if(!first)
+ printf("-----------------------------------\n");
+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+
+ return sys_errmsg("libubi failed to probe volume %d on ubi%d",
+ i, dev_info.dev_num);
+ }
+ first = 0;
+
+ err = print_vol_info(libubi, dev_info.dev_num, i);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int print_general_info(libubi_t libubi, int all)
+{
+ int i, err, first = 1;
+ struct ubi_info ubi_info;
+ struct ubi_dev_info dev_info;
+
+ err = ubi_get_info(libubi, &ubi_info);
+ if (err)
+ return sys_errmsg("cannot get UBI information");
+
+ printf("UBI version: %d\n", ubi_info.version);
+ printf("Count of UBI devices: %d\n", ubi_info.dev_count);
+ if (ubi_info.ctrl_major != -1)
+ printf("UBI control device major/minor: %d:%d\n",
+ ubi_info.ctrl_major, ubi_info.ctrl_minor);
+ else
+ printf("UBI control device is not supported by this kernel\n");
+
+ if (ubi_info.dev_count == 0)
+ return 0;
+
+ printf("Present UBI devices: ");
+ for (i = ubi_info.lowest_dev_num;
+ i <= ubi_info.highest_dev_num; i++) {
+ err = ubi_get_dev_info1(libubi, i, &dev_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+
+ return sys_errmsg("libubi failed to probe UBI device %d", i);
+ }
+
+ if (!first)
+ printf(", ubi%d", i);
+ else {
+ printf("ubi%d", i);
+ first = 0;
+ }
+ }
+ printf("\n");
+
+ if (!all)
+ return 0;
+
+ first = 1;
+ printf("\n");
+
+ for (i = ubi_info.lowest_dev_num;
+ i <= ubi_info.highest_dev_num; i++) {
+ if(!first)
+ printf("\n===================================\n\n");
+ err = ubi_get_dev_info1(libubi, i, &dev_info);
+ if (err == -1) {
+ if (errno == ENOENT)
+ continue;
+
+ return sys_errmsg("libubi failed to probe UBI device %d", i);
+ }
+ first = 0;
+
+ err = print_dev_info(libubi, i, all);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ if (!args.node && args.devn != -1)
+ return errmsg("specify either device number or node file (use -h for help)");
+
+ libubi = libubi_open(1);
+ if (libubi == NULL)
+ return sys_errmsg("cannot open libubi");
+
+ if (args.node) {
+ /*
+ * A character device was specified, translate this into UBI
+ * device number and volume ID.
+ */
+ err = translate_dev(libubi, args.node);
+ if (err)
+ goto out_libubi;
+ }
+
+ if (args.vol_id != -1 && args.devn == -1) {
+ errmsg("volume ID is specified, but UBI device number is not "
+ "(use -h for help)\n");
+ goto out_libubi;
+ }
+
+ if (args.devn != -1 && args.vol_id != -1) {
+ print_vol_info(libubi, args.devn, args.vol_id);
+ goto out;
+ }
+
+ if (args.devn == -1 && args.vol_id == -1)
+ err = print_general_info(libubi, args.all);
+ else if (args.devn != -1 && args.vol_id == -1)
+ err = print_dev_info(libubi, args.devn, args.all);
+
+ if (err)
+ goto out_libubi;
+
+out:
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c
new file mode 100644
index 00000000000..b786f70a1ff
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Generate UBI images.
+ *
+ * Authors: Artem Bityutskiy
+ * Oliver Lohmann
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <mtd/ubi-header.h>
+#include <libubigen.h>
+#include <libiniparser.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubinize"
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+" - a tool to generate UBI images. An UBI image may contain one or more UBI "
+"volumes which have to be defined in the input configuration ini-file. The "
+"ini file defines all the UBI volumes - their characteristics and the and the "
+"contents, but it does not define the characteristics of the flash the UBI "
+"image is generated for. Instead, the flash characteristics are defined via "
+"the command-line options. Note, if not sure about some of the command-line "
+"parameters, do not specify them and let the utility to use default values.";
+
+static const char *optionsstr =
+"-o, --output=<file name> output file name\n"
+"-p, --peb-size=<bytes> size of the physical eraseblock of the flash\n"
+" this UBI image is created for in bytes,\n"
+" kilobytes (KiB), or megabytes (MiB)\n"
+" (mandatory parameter)\n"
+"-m, --min-io-size=<bytes> minimum input/output unit size of the flash\n"
+" in bytes\n"
+"-s, --sub-page-size=<bytes> minimum input/output unit used for UBI\n"
+" headers, e.g. sub-page size in case of NAND\n"
+" flash (equivalent to the minimum input/output\n"
+" unit size by default)\n"
+"-O, --vid-hdr-offset=<num> offset if the VID header from start of the\n"
+" physical eraseblock (default is the next\n"
+" minimum I/O unit or sub-page after the EC\n"
+" header)\n"
+"-e, --erase-counter=<num> the erase counter value to put to EC headers\n"
+" (default is 0)\n"
+"-x, --ubi-ver=<num> UBI version number to put to EC headers\n"
+" (default is 1)\n"
+"-v, --verbose be verbose\n"
+"-h, --help print help message\n"
+"-V, --version print program version";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " [-o filename] [-h] [-V] [--output=<filename>] [--help]\n"
+"\t\t[--version] ini-file\n"
+"Example: " PROGRAM_NAME " -o ubi.img cfg.ini - create UBI image 'ubi.img' as\n"
+" described by configuration file 'cfg.ini'";
+
+static const char *ini_doc = "INI-file format.\n"
+"The input configuration ini-file describes all the volumes which have to\n"
+"be included to the output UBI image. Each volume is described in its own\n"
+"section which may be named arbitrarily. The section consists on\n"
+"\"key=value\" pairs, for example:\n\n"
+"[jffs2-volume]\n"
+"mode=ubi\n"
+"image=../jffs2.img\n"
+"vol_id=1\n"
+"vol_size=30MiB\n"
+"vol_type=dynamic\n"
+"vol_name=jffs2_volume\n"
+"vol_flags=autoresize\n"
+"vol_alignment=1\n\n"
+"This example configuration file tells the utility to create an UBI image\n"
+"with one volume with ID 1, volume size 30MiB, the volume is dynamic, has\n"
+"name \"jffs2_volume\", \"autoresize\" volume flag, and alignment 1. The\n"
+"\"image=../jffs2.img\" line tells the utility to take the contents of the\n"
+"volume from the \"../jffs2.img\" file. The size of the image file has to be\n"
+"less or equivalent to the volume size (30MiB). The \"mode=ubi\" line is\n"
+"mandatory and just tells that the section describes an UBI volume - other\n"
+"section modes may be added in the future.\n"
+"Notes:\n"
+" * size in vol_size might be specified kilobytes (KiB), megabytes (MiB),\n"
+" gigabytes (GiB) or bytes (no modifier);\n"
+" * if \"vol_size\" key is absent, the volume size is assumed to be\n"
+" equivalent to the size of the image file (defined by \"image\" key);\n"
+" * if the \"image\" is absent, the volume is assumed to be empty;\n"
+" * volume alignment must not be greater than the logical eraseblock size;\n"
+" * one ini file may contain arbitrary number of sections, the utility will\n"
+" put all the volumes which are described by these section to the output\n"
+" UBI image file.";
+
+struct option long_options[] = {
+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
+ { .name = "peb-size", .has_arg = 1, .flag = NULL, .val = 'p' },
+ { .name = "min-io-size", .has_arg = 1, .flag = NULL, .val = 'm' },
+ { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' },
+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' },
+ { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' },
+ { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' },
+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0}
+};
+
+struct args {
+ const char *f_in;
+ const char *f_out;
+ int out_fd;
+ int peb_size;
+ int min_io_size;
+ int subpage_size;
+ int vid_hdr_offs;
+ int ec;
+ int ubi_ver;
+ int verbose;
+ dictionary *dict;
+};
+
+static struct args args = {
+ .peb_size = -1,
+ .min_io_size = -1,
+ .subpage_size = -1,
+ .ubi_ver = 1,
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "o:p:m:s:O:e:x:vhV", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'o':
+ args.out_fd = open(optarg, O_CREAT | O_TRUNC | O_WRONLY,
+ S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ if (args.out_fd == -1)
+ return sys_errmsg("cannot open file \"%s\"", optarg);
+ args.f_out = optarg;
+ break;
+
+ case 'p':
+ args.peb_size = ubiutils_get_bytes(optarg);
+ if (args.peb_size <= 0)
+ return errmsg("bad physical eraseblock size: \"%s\"", optarg);
+ break;
+
+ case 'm':
+ args.min_io_size = ubiutils_get_bytes(optarg);
+ if (args.min_io_size <= 0)
+ return errmsg("bad min. I/O unit size: \"%s\"", optarg);
+ if (!is_power_of_2(args.min_io_size))
+ return errmsg("min. I/O unit size should be power of 2");
+ break;
+
+ case 's':
+ args.subpage_size = ubiutils_get_bytes(optarg);
+ if (args.subpage_size <= 0)
+ return errmsg("bad sub-page size: \"%s\"", optarg);
+ if (!is_power_of_2(args.subpage_size))
+ return errmsg("sub-page size should be power of 2");
+ break;
+
+ case 'O':
+ args.vid_hdr_offs = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.vid_hdr_offs < 0)
+ return errmsg("bad VID header offset: \"%s\"", optarg);
+ break;
+
+ case 'e':
+ args.ec = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.ec < 0)
+ return errmsg("bad erase counter value: \"%s\"", optarg);
+ break;
+
+ case 'x':
+ args.ubi_ver = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.ubi_ver < 0)
+ return errmsg("bad UBI version: \"%s\"", optarg);
+ break;
+
+ case 'v':
+ args.verbose = 1;
+ break;
+
+ case 'h':
+ ubiutils_print_text(stderr, doc, 80);
+ fprintf(stderr, "\n%s\n\n", ini_doc);
+ fprintf(stderr, "%s\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (optind == argc)
+ return errmsg("input configuration file was not specified (use -h for help)");
+
+ if (optind != argc - 1)
+ return errmsg("more then one configuration file was specified (use -h for help)");
+
+ args.f_in = argv[optind];
+
+ if (args.peb_size < 0)
+ return errmsg("physical eraseblock size was not specified (use -h for help)");
+
+ if (args.peb_size > 1024*1024)
+ return errmsg("too high physical eraseblock size %d", args.peb_size);
+
+ if (args.min_io_size < 0)
+ return errmsg("min. I/O unit size was not specified (use -h for help)");
+
+ if (args.subpage_size < 0)
+ args.subpage_size = args.min_io_size;
+
+ if (args.subpage_size > args.min_io_size)
+ return errmsg("sub-page cannot be larger then min. I/O unit");
+
+ if (args.peb_size % args.min_io_size)
+ return errmsg("physical eraseblock should be multiple of min. I/O units");
+
+ if (args.min_io_size % args.subpage_size)
+ return errmsg("min. I/O unit size should be multiple of sub-page size");
+
+ if (!args.f_out)
+ return errmsg("output file was not specified (use -h for help)");
+
+ if (args.vid_hdr_offs) {
+ if (args.vid_hdr_offs + UBI_VID_HDR_SIZE >= args.peb_size)
+ return errmsg("bad VID header position");
+ if (args.vid_hdr_offs % 8)
+ return errmsg("VID header offset has to be multiple of min. I/O unit size");
+ }
+
+ return 0;
+}
+
+static int read_section(const char *sname, struct ubigen_vol_info *vi,
+ const char **img)
+{
+ char buf[256];
+ const char *p;
+
+ *img = NULL;
+
+ if (strlen(sname) > 128)
+ return errmsg("too long section name \"%s\"", sname);
+
+ /* Make sure mode is UBI, otherwise ignore this section */
+ sprintf(buf, "%s:mode", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (!p) {
+ errmsg("\"mode\" key not found in section \"%s\"", sname);
+ errmsg("the \"mode\" key is mandatory and has to be "
+ "\"mode=ubi\" if the section describes an UBI volume");
+ return -1;
+ }
+
+ /* If mode is not UBI, skip this section */
+ if (strcmp(p, "ubi")) {
+ verbose(args.verbose, "skip non-ubi section \"%s\"", sname);
+ return 1;
+ }
+
+ verbose(args.verbose, "mode=ubi, keep parsing");
+
+ /* Fetch the name of the volume image file */
+ sprintf(buf, "%s:image", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (p)
+ *img = p;
+
+ /* Fetch volume id */
+ sprintf(buf, "%s:vol_id", sname);
+ vi->id = iniparser_getint(args.dict, buf, -1);
+ if (vi->id == -1)
+ return errmsg("\"vol_id\" key not found in section \"%s\"", sname);
+
+ if (vi->id < 0)
+ return errmsg("negative volume ID %d", vi->id);
+
+ if (vi->id >= UBI_MAX_VOLUMES)
+ return errmsg("too high volume ID %d, max. is %d", vi->id, UBI_MAX_VOLUMES);
+
+ verbose(args.verbose, "volume ID: %d", vi->id);
+
+ /* Fetch volume size */
+ sprintf(buf, "%s:vol_size", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (p) {
+ vi->bytes = ubiutils_get_bytes(p);
+ if (vi->bytes <= 0)
+ return errmsg("bad \"vol_size\" key: \"%s\"", p);
+
+ verbose(args.verbose, "volume size: %lld bytes", vi->bytes);
+ } else {
+ struct stat st;
+
+ if (!*img)
+ return errmsg("neither image file (\"image=\") nor volume size (\"vol_size=\") specified");
+
+ if (stat(*img, &st))
+ return sys_errmsg("cannot stat \"%s\"", *img);
+
+ vi->bytes = st.st_size;
+
+ if (vi->bytes == 0)
+ return errmsg("file \"%s\" referred from section \"%s\" is empty", *img, sname);
+
+ normsg_cont("volume size was not specified in section \"%s\", assume ", sname);
+ ubiutils_print_bytes(vi->bytes, 1);
+ printf("\n");
+ }
+
+ /* Fetch volume type */
+ sprintf(buf, "%s:vol_type", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (!p) {
+ normsg("volume type was not specified in "
+ "section \"%s\", assume \"dynamic\"\n", sname);
+ vi->type = UBI_VID_DYNAMIC;
+ } else {
+ if (!strcmp(p, "static"))
+ vi->type = UBI_VID_STATIC;
+ else if (!strcmp(p, "dynamic"))
+ vi->type = UBI_VID_DYNAMIC;
+ else
+ return errmsg("invalid volume type \"%s\"", p);
+ }
+
+ verbose(args.verbose, "volume type: %s",
+ vi->type == UBI_VID_DYNAMIC ? "dynamic" : "static");
+
+ /* Fetch volume name */
+ sprintf(buf, "%s:vol_name", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (!p)
+ return errmsg("\"vol_name\" key not found in section \"%s\"", sname);
+
+ vi->name = p;
+ vi->name_len = strlen(p);
+ if (vi->name_len > UBI_VOL_NAME_MAX)
+ return errmsg("too long volume name in section \"%s\", max. is %d characters",
+ vi->name, UBI_VOL_NAME_MAX);
+
+ verbose(args.verbose, "volume name: %s", p);
+
+ /* Fetch volume alignment */
+ sprintf(buf, "%s:vol_alignment", sname);
+ vi->alignment = iniparser_getint(args.dict, buf, -1);
+ if (vi->alignment == -1) {
+ normsg("volume alignment was not specified in section "
+ "\"%s\", assume 1", sname);
+ vi->alignment = 1;
+ } else if (vi->id < 0)
+ return errmsg("negative volume alignement %d", vi->alignment);
+
+ verbose(args.verbose, "volume alignment: %d", vi->alignment);
+
+ /* Fetch volume flags */
+ sprintf(buf, "%s:vol_flags", sname);
+ p = iniparser_getstring(args.dict, buf, NULL);
+ if (p) {
+ if (!strcmp(p, "autoresize")) {
+ verbose(args.verbose, "autoresize flags found");
+ vi->flags |= UBI_VTBL_AUTORESIZE_FLG;
+ } else {
+ return errmsg("unknown flags \"%s\" in section \"%s\"", p, sname);
+ }
+ }
+
+ return 0;
+}
+
+static void init_vol_info(const struct ubigen_info *ui,
+ struct ubigen_vol_info *vi)
+{
+ vi->data_pad = ui->leb_size % vi->alignment;
+ vi->usable_leb_size = ui->leb_size - vi->data_pad;
+ vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size;
+ vi->compat = 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err = -1, sects, i, volumes, autoresize_was_already = 0;
+ struct ubigen_info ui;
+ struct ubi_vtbl_record *vtbl;
+ off_t seek;
+ int tmp;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ ubigen_info_init(&ui, args.peb_size, args.min_io_size,
+ args.subpage_size, args.vid_hdr_offs,
+ args.ubi_ver);
+
+ verbose(args.verbose, "LEB size: %d", ui.leb_size);
+ verbose(args.verbose, "PEB size: %d", ui.peb_size);
+ verbose(args.verbose, "min. I/O size: %d", ui.min_io_size);
+ verbose(args.verbose, "sub-page size: %d", ui.min_io_size);
+ verbose(args.verbose, "VID offset: %d", ui.vid_hdr_offs);
+ verbose(args.verbose, "data offset: %d", ui.data_offs);
+
+ vtbl = ubigen_create_empty_vtbl(&ui);
+ if (!vtbl)
+ goto out;
+
+ args.dict = iniparser_load(args.f_in);
+ if (!args.dict) {
+ errmsg("cannot load the input ini file \"%s\"", args.f_in);
+ goto out_vtbl;
+ }
+
+ verbose(args.verbose, "loaded the ini-file \"%s\"", args.f_in);
+
+ /* Each section describes one volume */
+ sects = iniparser_getnsec(args.dict);
+ if (sects == -1) {
+ errmsg("ini-file parsing error (iniparser_getnsec)");
+ goto out_dict;
+ }
+
+ verbose(args.verbose, "count of sections: %d", sects);
+ if (sects == 0) {
+ errmsg("no sections found the ini-file \"%s\"", args.f_in);
+ goto out_dict;
+ }
+
+ /*
+ * Skip 2 PEBs at the beginning of the file for the volume table which
+ * will be written later.
+ */
+ seek = ui.peb_size * 2;
+ if (lseek(args.out_fd, seek, SEEK_SET) != seek) {
+ sys_errmsg("cannot seek file \"%s\"", args.f_out);
+ goto out_dict;
+ }
+
+ for (i = 0; i < sects; i++) {
+ const char *sname = iniparser_getsecname(args.dict, i);
+ struct ubigen_vol_info vi;
+ const char *img = NULL;
+ struct stat st;
+ int fd;
+
+ if (!sname) {
+ errmsg("ini-file parsing error (iniparser_getsecname)");
+ goto out_dict;
+ }
+
+ if (args.verbose)
+ printf("\n");
+ verbose(args.verbose, "parsing section \"%s\"", sname);
+
+ err = read_section(sname, &vi, &img);
+ if (err == -1)
+ goto out_dict;
+ if (!err)
+ volumes += 1;
+ init_vol_info(&ui, &vi);
+
+ if (vi.id >= ui.max_volumes)
+ return errmsg("too high volume ID %d, max. is %d",
+ vi.id, ui.max_volumes);
+
+ verbose(args.verbose, "adding volume %d", vi.id);
+
+ /* Make sure only one volume has auto-resize flag */
+ if (vi.flags & UBI_VTBL_AUTORESIZE_FLG) {
+ if (autoresize_was_already)
+ return errmsg("only one volume is allowed "
+ "to have auto-resize flag");
+ autoresize_was_already = 1;
+ }
+
+ err = ubigen_add_volume(&ui, &vi, vtbl);
+ if (err) {
+ errmsg("cannot add volume for section \"%s\"", sname);
+ goto out_dict;
+ }
+
+ if (!img)
+ continue;
+
+ if (stat(img, &st)) {
+ sys_errmsg("cannot stat \"%s\"", img);
+ goto out_dict;
+ }
+
+ /*
+ * Make sure the image size is not larger then the volume size.
+ */
+ tmp = (st.st_size / (ui.leb_size + sizeof(unsigned int))) * sizeof(unsigned int);
+ if (st.st_size - tmp> vi.bytes) {
+ errmsg("error in section \"%s\": size of the image file \"%s\" "
+ "is %lld, which is larger then the volume size %lld",
+ sname, img, (long long)st.st_size, vi.bytes);
+ goto out_dict;
+ }
+
+ fd = open(img, O_RDONLY);
+ if (fd == -1) {
+ sys_errmsg("cannot open \"%s\"", img);
+ goto out_dict;
+ }
+
+ verbose(args.verbose, "writing volume %d", vi.id);
+ verbose(args.verbose, "image file: %s", img);
+
+ err = ubigen_write_volume(&ui, &vi, args.ec, st.st_size-tmp, fd, args.out_fd);
+ close(fd);
+ if (err) {
+ errmsg("cannot write volume for section \"%s\"", sname);
+ goto out_dict;
+ }
+
+ if (args.verbose)
+ printf("\n");
+ }
+
+ verbose(args.verbose, "writing layout volume");
+
+ err = ubigen_write_layout_vol(&ui, 0, 1, args.ec, args.ec, vtbl, args.out_fd);
+ if (err) {
+ errmsg("cannot write layout volume");
+ goto out_dict;
+ }
+
+ verbose(args.verbose, "done");
+
+ iniparser_freedict(args.dict);
+ free(vtbl);
+ close(args.out_fd);
+ return 0;
+
+out_dict:
+ iniparser_freedict(args.dict);
+out_vtbl:
+ free(vtbl);
+out:
+ close(args.out_fd);
+ remove(args.f_out);
+ return err;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c
new file mode 100644
index 00000000000..f5187d5468a
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c
@@ -0,0 +1,99 @@
+/*
+ * An utility to reformat the image file generated by mkfs.ubifs
+ *
+ * Authors: Yurong Tan (Nancy)
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+#define PROGRAM_VERSION "1.1"
+#define PROGRAM_NAME "ubirefimg"
+#define UBI_LEB_SIZE 258048
+
+/*
+ * sourcefile usually generated by mkfs.ubifs.
+ * usage: #ubirefimg sourcefile outputfile
+ */
+int main(int argc, char * const argv[])
+{
+ int err, ifd, ofd, i, j, tmp;
+ struct stat st;
+ unsigned char *buf=NULL;
+
+ buf = malloc(UBI_LEB_SIZE);
+ if(buf==NULL){
+ printf("no mem\n");
+ goto out_free;
+ }
+
+ err = stat(argv[1], &st);
+ if (err < 0) {
+ printf("stat failed on \"%s\"", argv[1]);
+ goto out_free;
+ }
+
+ ifd = open(argv[1], O_RDONLY);
+ if (ifd == -1) {
+ printf("cannot open \"%s\"", argv[1]);
+ goto out_close;
+ }
+
+ ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644);
+ if (ofd == -1) {
+ printf("cannot create \"%s\"", argv[2]);
+ goto out_close;
+ }
+
+ tmp = st.st_size/UBI_LEB_SIZE;
+
+ for( i=0; i< tmp; i++ ){
+ err = read(ifd, buf, UBI_LEB_SIZE);
+ if (err != UBI_LEB_SIZE) {
+ printf("read error\n");
+ goto out_close1;
+ }
+ for(j=0; j<UBI_LEB_SIZE; j++)
+ if( buf[j] != 0xff )
+ break;
+ /* if that was an umapped LEB, skip */
+ if(j == UBI_LEB_SIZE )
+ continue;
+ /* write LEB's lnum */
+ err = write(ofd, &i, sizeof(unsigned int));
+ if (err != sizeof(unsigned int)) {
+ printf("write error\n");
+ goto out_close1;
+ }
+ /* write LEB's data */
+ err = write(ofd, buf, UBI_LEB_SIZE);
+ if (err != UBI_LEB_SIZE) {
+ printf("write error\n");
+ goto out_close1;
+ }
+
+ }
+
+ free(buf);
+ close(ifd);
+ close(ofd);
+ return 0;
+
+out_close1:
+ close(ofd);
+out_close:
+ close(ifd);
+out_free:
+ free(buf);
+ return -1;
+}
+
+
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirmvol.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirmvol.c
new file mode 100644
index 00000000000..10be9758f6f
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirmvol.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * An utility to remove UBI volumes.
+ *
+ * Authors: Artem Bityutskiy <dedekind@infradead.org>
+ * Frank Haverkamp <haver@vnet.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.0"
+#define PROGRAM_NAME "ubirmvol"
+
+/* The variables below are set by command line arguments */
+struct args {
+ int vol_id;
+ const char *node;
+ /* For deprecated -d option handling */
+ int devn;
+ char dev_name[256];
+};
+
+static struct args args = {
+ .vol_id = -1,
+ .devn = -1,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to remove UBI volumes.";
+
+static const char *optionsstr =
+"-n, --vol_id=<volume id> volume ID to remove\n"
+"-h, -?, --help print help message\n"
+"-V, --version print program version\n\n"
+"The following is a compatibility option which is deprecated, do not use it\n"
+"-d, --devn=<devn> UBI device number - may be used instead of the UBI\n"
+" device node name in which case the utility assumes\n"
+" that the device node is \"/dev/ubi<devn>\"";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <UBI device node file name> [-n <volume id>] [--vol_id=<volume id>] [-h] [--help]\n\n"
+"Example: " PROGRAM_NAME "/dev/ubi0 -n 1 - remove UBI volume 1 from UBI device corresponding\n"
+" to the node file /dev/ubi0.";
+
+static const struct option long_options[] = {
+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ /* Deprecated -d option */
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { NULL, 0, NULL, 0},
+};
+
+static int param_sanity_check(void)
+{
+ if (args.vol_id == -1) {
+ errmsg("volume ID is was not specified");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+ char *endp;
+
+ key = getopt_long(argc, argv, "n:h?Vd:", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+
+ case 'n':
+ args.vol_id = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.vol_id < 0) {
+ errmsg("bad volume ID: " "\"%s\"", optarg);
+ return -1;
+ }
+ break;
+
+ case 'h':
+ case '?':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'd':
+ /* Handle deprecated -d option */
+ warnmsg("-d is depricated and will be removed, do not use it");
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: " "\"%s\"", optarg);
+ break;
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ errmsg("parameter is missing");
+ return -1;
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ /* Handle deprecated -d option */
+ if (args.devn != -1) {
+ sprintf(args.dev_name, "/dev/ubi%d", args.devn);
+ args.node = args.dev_name;
+ } else {
+ if (optind == argc) {
+ errmsg("UBI device name was not specified (use -h for help)");
+ return -1;
+ } else if (optind != argc - 1) {
+ errmsg("more then one UBI device specified (use -h for help)");
+ return -1;
+ }
+
+ args.node = argv[optind];
+ }
+
+
+ if (param_sanity_check())
+ return -1;
+
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ libubi = libubi_open(1);
+ if (libubi == NULL)
+ return sys_errmsg("cannot open libubi");
+
+ err = ubi_node_type(libubi, args.node);
+ if (err == 2) {
+ errmsg("\"%s\" is an UBI volume node, not an UBI device node",
+ args.node);
+ goto out_libubi;
+ } else if (err < 0) {
+ errmsg("\"%s\" is not an UBI device node", args.node);
+ goto out_libubi;
+ }
+
+ err = ubi_rmvol(libubi, args.node, args.vol_id);
+ if (err) {
+ sys_errmsg("cannot UBI remove volume");
+ goto out_libubi;
+ }
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c
new file mode 100644
index 00000000000..69de89569bc
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * An utility to update UBI volumes.
+ *
+ * Authors: Frank Haverkamp
+ * Joshua W. Boyer
+ * Artem Bityutskiy
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <libubi.h>
+#include "common.h"
+
+#define PROGRAM_VERSION "1.1"
+#define PROGRAM_NAME "ubiupdatevol"
+
+struct args {
+ int truncate;
+ const char *node;
+ const char *img;
+ /* For deprecated -d and -B options handling */
+ int devn;
+ char dev_name[256];
+ int broken_update;
+};
+
+static struct args args = {
+ .devn = -1,
+};
+
+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION
+ " - a tool to write data to UBI volumes.";
+
+static const char *optionsstr =
+"-n, --vol_id=<volume id> ID of UBI volume to update\n"
+"-t, --truncate truncate volume (wipe it out)\n"
+"-h, --help print help message\n"
+"-V, --version print program version\n\n"
+"The following are compatibility options which are deprecated, do not use them\n"
+"-d, --devn=<devn> UBI device number - may be used instead of the UBI\n"
+" device node name in which case the utility assumes\n"
+" that the device node is \"/dev/ubi<devn>\"\n"
+"-B, --broken-update broken update, this is for testing";
+
+static const char *usage =
+"Usage: " PROGRAM_NAME " <UBI volume node file name> [-t] [-h] [-V] [--truncate] [--help]\n"
+"\t\t\t[--version] <image file>\n\n"
+"Example 1: " PROGRAM_NAME " /dev/ubi0_1 fs.img - write file \"fs.img\" to UBI volume /dev/ubi0_1\n"
+"Example 2: " PROGRAM_NAME " /dev/ubi0_1 -t - wipe out UBI volume /dev/ubi0_1";
+
+struct option long_options[] = {
+ { .name = "truncate", .has_arg = 0, .flag = NULL, .val = 't' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ /* Deprecated -d and -B options */
+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "broken-update", .has_arg = 1, .flag = NULL, .val = 'B' },
+ { NULL, 0, NULL, 0}
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "n:th?Vd:", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 't':
+ args.truncate = 1;
+ break;
+
+ case 'h':
+ case '?':
+ fprintf(stderr, "%s\n\n", doc);
+ fprintf(stderr, "%s\n\n", usage);
+ fprintf(stderr, "%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+
+ case 'd':
+ {
+ char *endp;
+
+ /* Handle deprecated -d option */
+ warnmsg("-d is depricated and will be removed, do not use it");
+ args.devn = strtoul(optarg, &endp, 0);
+ if (*endp != '\0' || endp == optarg || args.devn < 0)
+ return errmsg("bad UBI device number: " "\"%s\"", optarg);
+ break;
+ }
+
+ case 'B':
+ /* Handle deprecated -B option */
+ warnmsg("-B is depricated and will be removed, do not use it");
+ args.broken_update = 1;
+ break;
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(EXIT_SUCCESS);
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ /* Handle deprecated -d option */
+ if (args.devn != -1) {
+ sprintf(args.dev_name, "/dev/ubi%d", args.devn);
+ args.node = args.dev_name;
+ } else {
+ if (optind == argc)
+ return errmsg("UBI device name was not specified (use -h for help)");
+ else if (optind != argc - 2 && !args.truncate)
+ return errmsg("specify UBI device name and image file name as first 2 "
+ "parameters (use -h for help)");
+ }
+
+ args.node = argv[optind];
+ args.img = argv[optind + 1];
+
+ return 0;
+}
+
+static int truncate_volume(libubi_t libubi)
+{
+ int err, fd;
+
+ fd = open(args.node, O_RDWR);
+ if (fd == -1)
+ return sys_errmsg("cannot open \"%s\"", args.node);
+
+ err = ubi_update_start(libubi, fd, 0);
+ if (err) {
+ sys_errmsg("cannot truncate volume \"%s\"", args.node);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+static int ubi_write(int fd, const void *buf, int len)
+{
+ int ret;
+
+ while (len) {
+ ret = write(fd, buf, len);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ warnmsg("do not interrupt me!");
+ continue;
+ }
+ return sys_errmsg("cannot write %d bytes to volume \"%s\"",
+ len, args.node);
+ }
+
+ if (ret == 0)
+ return errmsg("cannot write %d bytes to volume \"%s\"", len, args.node);
+
+ len -= ret;
+ buf += ret;
+ }
+
+ return 0;
+}
+
+static int update_volume(libubi_t libubi, struct ubi_vol_info *vol_info)
+{
+ int err, fd, ifd;
+ long long bytes, tmp;
+ struct stat st;
+ char *buf;
+
+ buf = malloc(vol_info->leb_size+sizeof(unsigned int));
+ if (!buf)
+ return errmsg("cannot allocate %d bytes of memory", vol_info->leb_size);
+
+ err = stat(args.img, &st);
+ if (err < 0) {
+ errmsg("stat failed on \"%s\"", args.img);
+ goto out_free;
+ }
+
+ bytes = st.st_size;
+ tmp = bytes / (vol_info->leb_size + sizeof(unsigned int)) * sizeof(unsigned int);
+ bytes -= tmp;
+ if (bytes > vol_info->rsvd_bytes ) {
+ errmsg("\"%s\" (size %lld) will not fit volume \"%s\" (size %lld)",
+ args.img, bytes, args.node, vol_info->rsvd_bytes);
+ goto out_free;
+ }
+
+ /* A hack to handle deprecated -B option */
+ if (args.broken_update)
+ bytes = 1;
+
+ fd = open(args.node, O_RDWR);
+ if (fd == -1) {
+ sys_errmsg("cannot open UBI volume \"%s\"", args.node);
+ goto out_free;
+ }
+
+ ifd = open(args.img, O_RDONLY);
+ if (ifd == -1) {
+ sys_errmsg("cannot open \"%s\"", args.img);
+ goto out_close1;
+ }
+
+ err = ubi_update_start(libubi, fd, bytes);
+ if (err) {
+ sys_errmsg("cannot start volume \"%s\" update", args.node);
+ goto out_close;
+ }
+
+ bytes += tmp;
+ while (bytes) {
+ int tocopy = vol_info->leb_size + sizeof(unsigned int) ;
+
+ if (tocopy > bytes)
+ tocopy = bytes;
+
+ err = read(ifd, buf, tocopy);
+ if (err != tocopy) {
+ if (errno == EINTR) {
+ warnmsg("do not interrupt me!");
+ continue;
+ } else {
+ sys_errmsg("cannot read %d bytes from \"%s\"",
+ tocopy, args.img);
+ goto out_close;
+ }
+ }
+
+ err = ubi_write(fd, buf, tocopy-sizeof(unsigned int));
+ if (err)
+ goto out_close;
+
+ bytes -= tocopy;
+ }
+
+ close(ifd);
+ close(fd);
+ free(buf);
+ return 0;
+
+out_close:
+ close(ifd);
+out_close1:
+ close(fd);
+out_free:
+ free(buf);
+ return -1;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libubi_t libubi;
+ struct ubi_vol_info vol_info;
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ libubi = libubi_open(1);
+ if (libubi == NULL) {
+ sys_errmsg("cannot open libubi");
+ goto out_libubi;
+ }
+
+ err = ubi_node_type(libubi, args.node);
+ if (err == 1) {
+ errmsg("\"%s\" is an UBI device node, not an UBI volume node",
+ args.node);
+ goto out_libubi;
+ } else if (err < 0) {
+ errmsg("\"%s\" is not an UBI volume node", args.node);
+ goto out_libubi;
+ }
+
+ err = ubi_get_vol_info(libubi, args.node, &vol_info);
+ if (err) {
+ sys_errmsg("cannot get information about UBI volume \"%s\"",
+ args.node);
+ goto out_libubi;
+ }
+
+ if (args.truncate)
+ err = truncate_volume(libubi);
+ else
+ err = update_volume(libubi, &vol_info);
+ if (err)
+ goto out_libubi;
+
+ libubi_close(libubi);
+ return 0;
+
+out_libubi:
+ libubi_close(libubi);
+ return -1;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg b/drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg
new file mode 100644
index 00000000000..e468d9d03c3
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg
@@ -0,0 +1,38 @@
+[targets]
+complete=ipl,spl,bootenv,kernel,rootfs
+bootcode=spl,bootenv
+
+# Build sections
+[ipl]
+image=ipl.bin
+raw_starts=0x00000000
+raw_total_size=128kiB
+
+[spl]
+image=u-boot.bin
+ubi_ids=2,3
+ubi_size=2MiB
+ubi_type=static
+ubi_names=spl_0,spl_1
+
+[bootenv]
+bootenv_file=bootenv_complete.txt
+ubi_ids=4,5
+ubi_size=128kiB
+ubi_type=static
+ubi_names=bootenv_0,bootenv_1
+
+[kernel]
+image=vmlinux.bin
+ubi_ids=6,7
+ubi_size=6MiB
+ubi_type=static
+ubi_names=kernel_0,kernel_1
+
+[rootfs]
+image=rootfs.bin
+ubi_ids=8,9
+ubi_alignment=2kiB
+ubi_size=16MiB
+ubi_type=dynamic
+ubi_names=rootfs_0,rootfs_1
diff --git a/drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg b/drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg
new file mode 100644
index 00000000000..fd44e2773c0
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg
@@ -0,0 +1,39 @@
+[targets]
+complete=ipl,spl,bootenv,kernel,rootfs
+bootcode=spl,bootenv
+rootfs=rootfs
+
+# Build sections
+[ipl]
+image=ipl.bin
+raw_starts=0x02FE0000, 0x03FE0000
+raw_total_size=128kiB
+
+[spl]
+image=u-boot.bin
+ubi_ids=2,3
+ubi_size=2MiB
+ubi_type=static
+ubi_names=spl_0,spl_1
+
+[bootenv]
+bootenv_file=bootenv_complete.txt
+ubi_ids=4,5
+ubi_size=128kiB
+ubi_type=static
+ubi_names=bootenv_0,bootenv_1
+
+[kernel]
+image=vmlinux.bin
+ubi_ids=6,7
+ubi_size=6MiB
+ubi_type=static
+ubi_names=kernel_0,kernel_1
+
+[rootfs]
+image=rootfs.bin
+ubi_ids=8,9
+ubi_alignment=2kiB
+ubi_size=16128kiB
+ubi_type=dynamic
+ubi_names=rootfs_0,rootfs_1
diff --git a/drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi b/drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi
new file mode 100644
index 00000000000..2cce587ba2b
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi
@@ -0,0 +1,723 @@
+#!/usr/bin/perl
+#
+# Copyright (c) International Business Machines Corp., 2006
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+# the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+#
+# mkpfi
+#
+# This perl program is assembles PFI files from a config file.
+#
+# Author: Oliver Lohmann (oliloh@de.ibm.com)
+#
+use warnings;
+use strict;
+use lib "/usr/lib/perl5"; # Please change this path as you need it, or
+ # make a proposal how this could be done
+ # nicer.
+use Getopt::Long;
+use Pod::Usage;
+use Config::IniFiles;
+use File::Temp;
+
+# ----------------------------------------------------------------------------
+# Versions
+our $version : unique = "0.1";
+our $pfi_version : unique = "0x1";
+
+# ----------------------------------------------------------------------------
+# Globals
+my $verbose = 0;
+my $cfg;
+
+my %opts = ();
+my %files = (config => "");
+my @tmp_files;
+
+my %tools = (ubicrc32 => "ubicrc32");
+
+# ----------------------------------------------------------------------------
+# Processing the input sections
+#
+# The idea is to combine each section entry with a function
+# in order to allow some kind of preprocessing for the values
+# before they are written into the PFI file.
+# This is especially useful to be more verbose and
+# user-friendly in the layout file.
+#
+# All key-function hashes are applied after the general
+# validation of the configuration file.
+# If any mandatory key is missing in a section the user
+# will be informed and the PFI creation process is aborted.
+#
+# Default keys will be checked for their presence inside the config
+# file. If they are missing, they will be generated with appr. values.
+
+# Mandatory keys for UBI volumes.
+my %ubi_keys = ("ubi_ids" => \&check_id_list,
+ "ubi_size" => \&replace_num,
+ "ubi_type" => \&replace_type,
+ "ubi_names" => \&remove_spaces,
+ "ubi_alignment" => \&replace_num);
+
+# Mandatory keys for RAW sections.
+my %raw_keys = ("raw_starts" => \&expand_starts,
+ "raw_total_size" => \&replace_num);
+
+# Common default keys for documentation and control purposes.
+my %common_keys = ("flags" => \&replace_num,
+ "label" => \&do_nothing);
+
+# Define any defaults here. Values which maintained in this default
+# region need not to be specified by the user explicitly.
+my %def_ubi_keys = ("ubi_alignment" => [\&set_default, "0x1"]);
+my %def_raw_keys = ();
+my %def_common_keys = ("flags" => [\&set_default, "0x0"],
+ "label" => [\&generate_label, ""]);
+
+# ----------------------------------------------------------------------------
+# Input keys, actually the path to the input data.
+
+my %input_keys = ("image" => \&do_nothing);
+
+# Placeholder keys allow the replacement via a special
+# purpose function. E.g. the bootenv_file key will be used
+# to generate bootenv binary data from an text file and
+# replace the bootenv_file key with an image key to handle it
+# in the same way in the further creation process.
+my %input_placeholder_keys = ("bootenv_file" => \&create_bootenv_image);
+
+# ----------------------------------------------------------------------------
+# Helper
+
+# @brief Get current time string.
+sub get_date {
+ my $tmp = scalar localtime;
+ $tmp =~ s/ /_/g;
+ return $tmp;
+}
+
+# @brief Print an info message to stdout.
+sub INFO($) {
+ my $str = shift;
+
+ if (!$verbose) {
+ return;
+ }
+
+ print STDOUT $str;
+}
+
+# @brief Print an error message to stderr.
+sub ERR($) {
+ my $str = shift;
+ print STDERR $str;
+}
+
+# @brief Print a warning message to stderr.
+sub WARN($) {
+ my $str = shift;
+ print STDERR $str;
+}
+
+sub parse_command_line($) {
+ my $opt = shift;
+ my $result = GetOptions( "help" => \$$opt{'help'},
+ "man" => \$$opt{'man'},
+ "config=s" => \$$opt{'config'},
+ "verbose" => \$$opt{'verbose'},
+ ) or pod2usage(2);
+ pod2usage(1) if defined ($$opt{help});
+ pod2usage(-verbose => 2) if defined ($$opt{man});
+
+ $verbose = $$opt{verbose} if defined $$opt{verbose};
+
+ if (!defined $$opt{config}) {
+ ERR("[ ERROR: No config file specified. Aborting...\n");
+ exit 1;
+ }
+
+}
+
+# @brief Check if all needed tools are in PATH.
+sub check_tools {
+ my $err = 0;
+ my $key;
+
+ foreach $key (keys %tools) {
+ if (`which $tools{$key}` eq "") {
+ ERR("\n") if ($err == 0);
+ ERR("! Please add the tool \'$tools{$key}\' " .
+ "to your path!\n");
+ $err = 1;
+ }
+ }
+ die "[ ERROR: Did not find all needed tools!\n" if $err;
+}
+
+sub open_cfg_file($) {
+ my $fname = shift;
+ my $res = new Config::IniFiles( -file => $fname );
+
+ die "[ ERROR: Cannot load your config file!\n" if (!defined $res);
+ return $res;
+}
+
+sub set_default($$$$) {
+ my ($cfg, $section, $parameter, $def_value) = @_;
+ $cfg->newval($section, $parameter, $def_value);
+ return;
+}
+
+sub generate_label($$$$) {
+ my ($cfg, $section, $parameter, $def_value) = @_;
+ my $new_label = $def_value . $section;
+ $new_label .= "_" . get_date;
+ $cfg->newval($section, $parameter, $new_label);
+ return;
+}
+
+# @brief Converts any num to a unified hex string, i.e the resulting value
+# always starts with "0x" and is aligned to 8 hexdigits.
+# @return Returns 0 on success, otherwise an error occured.
+#
+sub any_num_to_hex($$) {
+ my $val = shift;
+ my $res = shift;
+
+ # M(iB)
+ if ($val =~ m/([0-9]+)[Mm][i]?[Bb]?/g) {
+ $$res = sprintf("0x%08x", $1 * 1024 * 1024);
+ }
+ # k(iB)
+ elsif ($val =~ m/([0-9]+)[kK][i]?[Bb]?/g) {
+ $$res = sprintf("0x%08x", $1 * 1024);
+ }
+ # hex
+ elsif ($val =~ m/0x?([0-9a-fA-F]+)/g) {
+ $$res = sprintf("0x%08x", hex $1);
+ }
+ # decimal
+ elsif ($val =~ m/^([0-9]+)$/g) {
+ $$res = sprintf("0x%08x", $1);
+ }
+ else {
+ $$res = "";
+ return -1;
+ }
+
+ return 0;
+}
+
+sub remove_spaces($$$) {
+ my ($cfg, $section, $parameter) = @_;
+ my ($start, @starts, @new_starts);
+ my $val = $cfg->val($section, $parameter);
+ my $res;
+
+ $val =~ s/ //g; # spaces
+ $cfg->newval($section, $parameter, $val);
+}
+
+sub expand_starts($$$) {
+ my ($cfg, $section, $parameter) = @_;
+ my ($start, @starts, @new_starts);
+ my $val = $cfg->val($section, $parameter);
+ my $res;
+
+ $val =~ s/ //g; # spaces
+ @starts = split(/,/, $val);
+
+ foreach $start (@starts) {
+ if (any_num_to_hex($start, \$res) != 0) {
+ ERR("[ ERROR: [$section]\n");
+ ERR("[ Expecting a list of numeric " .
+ "values for parameter: $parameter\n");
+ exit 1;
+ }
+ push (@new_starts, $res);
+ }
+ $res = join(',', @starts);
+
+ $cfg->newval($section, $parameter, $res);
+}
+
+sub check_id_list($$$) {
+ my ($cfg, $section, $parameter) = @_;
+ my $val = $cfg->val($section, $parameter);
+ my $res;
+
+ if (!($val =~ m/^[0-9]+[,0-9]*/)) {
+ ERR("[ ERROR: Syntax error in 'ubi_ids' in " .
+ "section '$section': $val\n");
+ ERR("[ Aborting... ");
+ exit 1;
+ }
+}
+
+sub replace_type($$$) {
+ my ($cfg, $section, $parameter) = @_;
+ my $val = $cfg->val($section, $parameter);
+ my $res;
+
+ $res = lc($val);
+ grep {$res eq $_} ('static', 'dynamic')
+ or die "[ ERROR: Unknown UBI Volume Type in " .
+ "section '$section': $val\n";
+
+ $cfg->newval($section, $parameter, $res);
+}
+
+
+sub replace_num($$$) {
+ my ($cfg, $section, $parameter) = @_;
+ my $val = $cfg->val($section, $parameter);
+ my $res = "";
+
+ if (any_num_to_hex($val, \$res) != 0) {
+ ERR("[ ERROR: [$section]\n");
+ ERR("[ Expecting a numeric value " .
+ "for parameter: $parameter\n");
+ exit 1;
+ }
+ $cfg->newval($section, $parameter, $res);
+}
+
+sub do_nothing($$$) {
+ my ($cfg, $section, $parameter) = @_;
+ return;
+}
+
+sub bootenv_sanity_check($) {
+ my $env = shift; # hash array containing bootenv
+ my %pdd = ();
+
+ defined($$env{'pdd'}) or return "'pdd' not defined";
+ foreach (split /,/, $$env{'pdd'}) {
+ defined($$env{$_}) or return "undefined '$_' in pdd";
+ $pdd{$_} = 1;
+ }
+
+ defined $$env{'pdd_preserve'} or
+ return "";
+ foreach (split /,/, $$env{'pdd_preserve'}) {
+ defined($pdd{$_})
+ or return "pdd_preserve field '$_' not in pdd";
+ }
+ return "";
+}
+
+sub create_bootenv_image($$$) {
+ my ($cfg, $section, $parameter) = @_;
+ my $txt_fn = $cfg->val($section, "bootenv_file");
+ my $in;
+
+ my %value = ();
+ my @key = ();
+
+ open $in, "<", $txt_fn
+ or die "[ ERROR: can't open bootenv file '$txt_fn'.\n";
+ while (<$in>) {
+ next if (/^\s*(\#.*)?$/); # Skip comments/whitespace.
+
+ if (/^(\S+?)\+\=(.*)$/) {
+ defined($value{$1}) or
+ die "$txt_fn:$.: error: appending to" .
+ " non-existent '$1'\n";
+ $value{$1} .= $2;
+ } elsif (/^(\S+?)\=(.*)$/) {
+ not defined($value{$1}) or
+ die "$txt_fn:$.: error: trying to" .
+ " redefine '$1'\n";
+ push @key, $1;
+ $value{$1} = $2;
+ } else {
+ die "$txt_fn:$.: error: unrecognized syntax\n";
+ }
+ }
+ close $in;
+
+ $_ = &bootenv_sanity_check(\%value)
+ and die "$txt_fn: error: $_\n";
+
+ my $tmp_file = new File::Temp();
+ push (@tmp_files, $tmp_file);
+
+ foreach (@key) {
+ print $tmp_file "$_=", $value{$_}, "\0";
+ }
+ close $tmp_file;
+
+ $cfg->newval($section, "image", $tmp_file-> filename);
+}
+
+sub process_keys($$$) {
+ my ($cfg, $section, $keys) = @_;
+ my @parameters = $cfg->Parameters($section);
+ my $i;
+
+ for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) {
+ if (defined($$keys{$parameters[$i]})) {
+ $$keys{$parameters[$i]}->($cfg, $section,
+ $parameters[$i]);
+ }
+ }
+
+}
+
+sub is_in_keylist($$) {
+ my ($key, $keys) = @_;
+ my $i;
+
+ for ($i = 0; $i < scalar(@$keys); $i++) {
+ if ($$keys[$i] eq $key) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+sub check_default_keys($$$) {
+ my ($cfg, $section, $keys) = @_;
+ my @parameters = $cfg->Parameters($section);
+ my $key;
+
+ foreach $key (keys %$keys) {
+ if (!is_in_keylist($key, \@parameters)) {
+ $$keys{$key}[0]->
+ ($cfg, $section, $key, $$keys{$key}[1]);
+ }
+ }
+
+}
+
+
+
+sub check_keys($$$) {
+ my ($cfg, $section, $keys) = @_;
+ my @parameters = $cfg->Parameters($section);
+ my ($i, $key, $err);
+
+ $err = 0;
+ for ($i = 0 ; $i < scalar(@$keys) ; $i++ ) {
+ if (!is_in_keylist($$keys[$i], \@parameters)) {
+ ERR("[ ERROR: [$section]\n") if $err == 0;
+ $err = 1;
+ ERR("[ Missing key '$$keys[$i]'\n");
+ }
+ }
+
+ if ($err) {
+ ERR("[ Aborting...\n");
+ exit 1;
+ }
+}
+
+sub push_pfi_data($$$$$) {
+ my ($cfg, $section, $pfi_infos, $keys, $mode) = @_;
+ my ($tmp, $i, $hdr);
+
+ my %pfi_info = ();
+ $pfi_info{'mode'} = $mode;
+ $pfi_info{'image'} = $cfg->val($section, "image");
+
+ # Build the PFI header
+ $hdr = sprintf("PFI!\n");
+ $hdr .= sprintf("version=0x%08x\n", hex $pfi_version);
+ $hdr .= sprintf("mode=$mode\n");
+
+ # calculate the size of the binary data part
+ $tmp = -s $cfg->val($section, "image");
+ if (!defined $tmp) {
+ ERR("[ ERROR: [$section]\n");
+ ERR("[ Missing input image: "
+ . $cfg->val($section, "image") . "\n");
+ exit 1;
+ }
+ # Check for the image to fit into the given space
+ my $quota;
+ if ($mode eq 'raw') {
+ $quota = oct $cfg->val($section, "raw_total_size");
+ } elsif ($mode eq 'ubi') {
+ $quota = oct $cfg->val($section, "ubi_size");
+ }
+ $tmp <= $quota
+ or die "[ERROR: image file too big: " .
+ $cfg->val($section, "image") . "\n";
+ $pfi_info{'size'} = $tmp;
+
+ $hdr .= sprintf("size=0x%08x\n", $tmp);
+
+ my $img_file = $cfg->val($section, "image");
+ my $crc32 = `$tools{'ubicrc32'} $img_file 2>&1`;
+ if (any_num_to_hex($crc32, \$tmp) != 0) {
+ die "[ ERROR: $tools{'ubicrc32'} returned with errors";
+ }
+ $hdr .= sprintf("crc=$tmp\n");
+
+
+ # Process all remaining keys
+ for ($i = 0; $i < scalar (@$keys); $i++) {
+ if ($$keys[$i] eq "image") { # special case image input file
+ if (! -e ($tmp = $cfg->val($section, "image"))) {
+ ERR("[ ERROR: [$section]\n");
+ ERR("[ Cannot find input file $tmp\n");
+ exit 1;
+ }
+ next;
+ }
+ $hdr .= sprintf("%s=%s\n", $$keys[$i],
+ $cfg->val($section, $$keys[$i]));
+ }
+
+ $hdr .= sprintf("\n"); # end marker for PFI-header
+
+ $pfi_info{'header'} = $hdr;
+
+ # store in the header list
+ push @$pfi_infos, \%pfi_info;
+}
+
+sub process_section($$$$$$) {
+ my ($cfg, $section, $pfi_infos, $custom_keys,
+ $def_custom_keys, $mode) = @_;
+ my @keys = (keys %common_keys, keys %$custom_keys);
+ my @complete_keys = (@keys, keys %input_keys);
+
+ # set defaults if necessary
+ check_default_keys($cfg, $section, $def_custom_keys);
+ check_default_keys($cfg, $section, \%def_common_keys);
+
+ # check for placeholders...
+ process_keys($cfg, $section, \%input_placeholder_keys);
+
+ # VALIDATE layout.cfg entries
+ check_keys($cfg, $section, \@complete_keys);
+
+ # execute linked functions (if any)
+ process_keys($cfg, $section, \%common_keys);
+ process_keys($cfg, $section, $custom_keys);
+
+ push_pfi_data($cfg, $section, $pfi_infos, \@keys, $mode);
+}
+
+sub get_section_info($$) {
+ my ($cfg, $section) = @_;
+ my @parameters = $cfg->Parameters($section);
+ my ($ubi, $raw, $i, @res);
+
+ $ubi = $raw = 0;
+ for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) {
+ if ($parameters[$i] =~ m/ubi_/gi) {
+ $ubi = 1;
+ @res = (\%ubi_keys, \%def_ubi_keys, "ubi");
+ }
+ if ($parameters[$i] =~ m/raw_/gi) {
+ $raw = 1;
+ @res = (\%raw_keys, \%def_raw_keys, "raw");
+ }
+ }
+
+ if (($ubi + $raw) != 1) { # double definition in section
+ ERR("[ ERROR: Layout error in section '$section'\n");
+ exit 1;
+ }
+
+ return @res;
+}
+
+sub mk_target_list($$) {
+ my $val = shift;
+ my $tmp = shift;
+ my $complete = 0;
+
+ if ($val =~ m/\((.*)\)/g) {
+ $val = $1;
+ $complete = 1;
+ }
+ $val =~ s/ //g; # spaces
+
+ @$tmp = split(/,/, $val);
+
+ return $complete;
+}
+
+sub copy_bytes($$$) {
+ my ($in, $out, $to_copy) = @_;
+
+ while ($to_copy) {
+ my $buf;
+ my $bufsize = 1024*1024;
+
+ $bufsize < $to_copy or $bufsize = $to_copy;
+ read($in, $buf, $bufsize) == $bufsize
+ or die "[ ERROR: Image file shrunk during operation\n";
+ print $out $buf;
+ $to_copy -= $bufsize;
+ }
+}
+
+sub write_target($$) {
+ my ($pfi_infos, $target) = @_;
+ my ($pfi_info);
+
+ INFO("[ Writting target pfi file: '$target.pfi'...\n");
+ if (-e "$target.pfi") {
+ WARN("! Replaced old pfi...\n");
+ `rm -f $target.pfi`;
+ }
+ open(FILE, ">", "$target.pfi")
+ or die "[ ERROR: Cannot create output file: $target.pfi\n";
+ binmode(FILE);
+
+ # @FIXME sort by mode (first raw, then ubi)
+ # Currently this ordering is based on a string comparism. :-)
+ @$pfi_infos = sort {(lc $$a{'mode'}) cmp (lc $$b{'mode'})} @$pfi_infos;
+
+ # Print all headers first
+ foreach $pfi_info (@$pfi_infos) {
+ print FILE $$pfi_info{'header'};
+
+ }
+ # Print the linked data sections
+ print FILE "DATA\n";
+ foreach $pfi_info (@$pfi_infos) {
+ open(IMAGE, "<", $$pfi_info{'image'})
+ or die "[ ERROR: Cannot open input image: " .
+ "$$pfi_info{'image'}" . "\n";
+ binmode(IMAGE);
+ &copy_bytes(\*IMAGE, \*FILE, $$pfi_info{'size'});
+ close(IMAGE) or die "[ ERROR: Cannot close input image: " .
+ "$$pfi_info{'image'}" . "\n";
+ }
+ close(FILE) or die "[ ERROR: Cannot close output file: $target.pfi\n";
+}
+
+sub process_config($) {
+ my $cfg = shift;
+ my @sections = $cfg->Sections;
+ my ($i, $j, $keylist, $def_keylist, $mode, $tmp,
+ @tlist, $complete,@pfi_infos);
+
+ my @parameters = $cfg->Parameters("targets") or
+ die "[ ERROR: Config file has no 'targets' section!\n";
+
+ for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) {
+ INFO("[ Processing target '$parameters[$i]'...\n");
+ @pfi_infos = ();
+
+ # get a list of subtargets
+ $complete = mk_target_list($cfg->val("targets",
+ $parameters[$i]), \@tlist);
+ # build all subtargets
+ for ($j = 0 ; $j < scalar(@tlist) ; $j++ ) {
+ ($keylist, $def_keylist, $mode)
+ = get_section_info($cfg, $tlist[$j]);
+ process_section($cfg, $tlist[$j],
+ \@pfi_infos,
+ $keylist, $def_keylist, $mode);
+ }
+
+ write_target(\@pfi_infos, $parameters[$i]);
+ }
+
+ INFO("[ Success.\n");
+
+
+}
+
+sub clear_files() {
+ # @FIXME:
+ # Works implicitly and Fedora seems to have removed
+ # the cleanup call. Thus for now, inactive.
+ # File::Temp::cleanup();
+}
+
+require 5.008_000; # Tested with version 5.8.0.
+select STDOUT; $| = 1; # make STDOUT output unbuffered
+select STDERR; $| = 1; # make STDERR output unbuffered
+
+parse_command_line(\%opts);
+check_tools;
+$cfg = open_cfg_file($opts{config});
+process_config($cfg);
+clear_files;
+
+__END__
+
+
+=head1 NAME
+
+mkpfi - Using GetOpt::Long, Pod::Usage, Config::IniFiles
+
+
+=head1 SYNOPSIS
+
+mkpfi [OPTIONS ...]
+
+
+ OPTION
+
+ [--config] [--help] [--man]
+
+
+=head1 ABSTRACT
+
+Perl script for generating pdd pfi files from given config files.
+
+=head1 OPTIONS
+
+=over
+
+=item B<--help>
+
+Print out brief help message.
+
+=item B<--usage>
+
+Print usage.
+
+=item B<--config>
+
+Config input file.
+
+=item B<--man>
+
+Print manual page, same as 'perldoc mkpfi'.
+
+=item B<--verbose>
+
+Be verbose!
+
+=back
+
+=head1 BUGS
+
+Report via MTD mailing list
+
+
+=head1 SEE ALSO
+
+http://www.linux-mtd.infradead.org/
+
+
+=head1 AUTHOR
+
+Oliver Lohmann (oliloh@de.ibm.com)
+
+=cut
diff --git a/drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl b/drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl
new file mode 100644
index 00000000000..add5f9d9d50
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl
@@ -0,0 +1,74 @@
+#!/usr/bin/perl -w
+
+# Subroutine crc32(): Calculates the CRC on a given string.
+
+{
+ my @table = ();
+
+ # @brief Calculate CRC32 for a given string.
+ sub crc32
+ {
+ unless (@table) {
+ # Initialize the CRC table
+ my $poly = 0xEDB88320;
+ @table = ();
+
+ for my $i (0..255) {
+ my $c = $i;
+
+ for my $j (0..7) {
+ $c = ($c & 1) ? (($c >> 1) ^ $poly) : ($c >> 1);
+ }
+ $table[$i] = $c;
+ }
+ }
+ my $s = shift; # string to calculate the CRC for
+ my $crc = shift; # CRC start value
+
+ defined($crc)
+ or $crc = 0xffffffff; # Default CRC start value
+
+ for (my $i = 0; $i < length($s); $i++) {
+ $crc = $table[($crc ^ ord(substr($s, $i, 1))) & 0xff]
+ ^ ($crc >> 8);
+ }
+ return $crc;
+ }
+}
+
+sub crc32_on_file
+{
+ my $file = shift;
+
+ my $crc32 = crc32('');
+ my $buf = '';
+ my $ret = 0;
+
+ while ($ret = read($file, $buf, 8192)) {
+ $crc32 = crc32($buf, $crc32);
+ }
+ defined($ret)
+ or return undef;
+ printf("0x%x\n", $crc32);
+}
+
+
+# Main routine: Calculate the CRCs on the given files and print the
+# results.
+
+{
+ if (@ARGV) {
+ while (my $path = shift) {
+ my $file;
+ open $file, "<", $path
+ or die "Error opening '$path'.\n";
+
+ &crc32_on_file($file)
+ or die "Error reading from '$path'.\n";
+ close $file;
+ }
+ } else {
+ &crc32_on_file(\*STDIN)
+ or die "Error reading from stdin.\n";
+ }
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile b/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile
new file mode 100644
index 00000000000..ebd9bc6c083
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile
@@ -0,0 +1,75 @@
+#
+# Makefile
+#
+# Testcase for UBI pfi update.
+#
+# Author: Frank Haverkamp <haverkam@de.ibm.com>
+#
+
+card = test
+mkpfi_cfg = test.cfg
+
+#
+# Some default values you might want to overwrite. Try it if you need
+# it and add more if needed. Note that no real sanity checking is done
+# on those values. If you do it wrong your card has no valid PDD data.
+#
+
+PATH := $(PATH):/opt/ppc/usr/bin:../perl:..
+
+dd = dd
+sed = sed
+bin2nand = bin2nand
+ubigen = ubigen
+mkpfi = mkpfi -v
+pfi2bin = pfi2bin -v
+
+vmlinux_bin ?= test_vmlinux.bin
+rootfs_bin ?= test_rootfs.bin
+spl_bin ?= test_u-boot.bin
+pdd_txt ?= pdd.txt
+
+flashtype ?= nand
+pagesize ?= 2048
+
+compl ?= $(card)_complete
+compl_pfi ?= $(compl).pfi
+compl_img ?= $(compl).img
+
+compl_nand2048_mif=$(compl).$(flashtype)$(pagesize).mif
+compl_nand2048_img=$(compl).$(flashtype)$(pagesize).img
+
+all: $(compl_pfi) $(compl_nand2048_mif)
+
+$(compl_pfi): $(vmlinux_bin) $(rootfs_bin) $(spl_bin)
+ $(mkpfi) -c $(mkpfi_cfg)
+
+# Binary data and out of band data (OOB)
+#
+$(compl_nand2048_mif): $(compl_img)
+ $(bin2nand) -p $(pagesize) -o $(compl_nand2048_mif) $<
+
+# Binary data only
+#
+$(compl_img): $(compl_pfi)
+ $(pfi2bin) -j $(pdd_txt) -o $@ $<
+
+#
+# Default data
+#
+# If the binary data is not available in the current working directory
+# we try to create symlinks to our test data.
+#
+$(vmlinux_bin) $(rootfs_bin) $(spl_bin):
+ @echo
+ @echo "No $@ found, will use defaults !"
+ @echo
+ @echo "OR press CTRL-C to provide your own $@" && \
+ sleep 1 && \
+ $(dd) if=/dev/urandom of=$@ bs=1M count=1
+
+clean:
+ $(RM) *.pfi *~
+
+distclean: clean
+ $(RM) *.bin *.mif *.oob *.img
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/README b/drivers/mtd/mtd-utils/ubi-utils/scripts/README
new file mode 100644
index 00000000000..899b4a18f6c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/README
@@ -0,0 +1,11 @@
+README
+======
+
+This procedure creates a test pfi which should be flashed to our
+system with pfiflash. The testcase should read the data back and
+compare with the original.
+
+We should try not forget to run these tests before we release
+a new version of UBI.
+
+Frank
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/TODO b/drivers/mtd/mtd-utils/ubi-utils/scripts/TODO
new file mode 100644
index 00000000000..f093e77549b
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/TODO
@@ -0,0 +1,5 @@
+TODO
+====
+
+ * Range checking is broken, reserving 2M and offering 3M binary data
+ ... works!? No!
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh b/drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh
new file mode 100644
index 00000000000..a17c91bf013
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh
@@ -0,0 +1,184 @@
+#!/bin/sh
+#
+# Testcase for nand2bin and bin2nand. Generate testdata and inject
+# biterrors. Convert data back and compare with original data.
+#
+# Conversion:
+# bin -> bin2nand -> mif -> nand2bin -> img
+#
+
+inject_biterror=./scripts/inject_biterror.pl
+
+pagesize=2048
+oobsize=64
+
+# Create test data
+dd if=/dev/urandom of=testblock.bin bs=131072 count=1
+
+echo "Test conversion without bitflips ..."
+
+echo -n "Convert bin to mif ... "
+bin2nand --pagesize=${pagesize} -o testblock.mif testblock.bin
+if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+else
+ echo "ok"
+fi
+
+echo -n "Convert mif to bin ... "
+nand2bin --pagesize=${pagesize} -o testblock.img testblock.mif
+if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+else
+ echo "ok"
+fi
+
+echo -n "Comparing data ... "
+diff testblock.bin testblock.img
+if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+else
+ echo "ok"
+fi
+
+echo "Test conversion with uncorrectable ECC erors ..."
+echo -n "Inject biterror at offset $ioffs ... "
+${inject_biterror} --offset=0 --bitmask=0x81 \
+ --input=testblock.mif \
+ --output=testblock_bitflip.mif
+if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+else
+ echo "ok"
+fi
+
+echo "Convert mif to bin ... "
+rm testblock.img
+nand2bin --correct-ecc --pagesize=${pagesize} -o testblock.img \
+ testblock_bitflip.mif
+if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+else
+ echo "ok"
+fi
+
+echo -n "Comparing data, must fail due to uncorrectable ECC ... "
+diff testblock.bin testblock.img
+if [ $? -ne "0" ]; then
+ echo "ok" # Must fail!
+else
+ echo "failed!"
+ exit 1
+fi
+
+echo "Test bitflips in data ... "
+for offs in `seq 0 255` ; do
+
+ cp testblock.mif testblock_bitflip.mif
+
+ for xoffs in 0 256 512 768 ; do
+ let ioffs=$offs+$xoffs
+
+ cp testblock_bitflip.mif testblock_bitflip_tmp.mif
+ echo -n "Inject biterror at offset $ioffs ... "
+ ${inject_biterror} --offset=${ioffs} --bitmask=0x01 \
+ --input=testblock_bitflip_tmp.mif \
+ --output=testblock_bitflip.mif
+ if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+ else
+ echo "ok"
+ fi
+ done
+
+ echo "Convert mif to bin ... "
+ rm testblock.img
+ nand2bin --correct-ecc --pagesize=${pagesize} -o testblock.img \
+ testblock_bitflip.mif
+ if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+ else
+ echo "ok"
+ fi
+
+ echo -n "Comparing data ... "
+ diff testblock.bin testblock.img
+ if [ $? -ne "0" ]; then
+ hexdump testblock.bin > testblock.bin.txt
+ hexdump testblock.img > testblock.img.txt
+ echo "Use tkdiff testblock.bin.txt testblock.img.txt to compare"
+ echo "failed!"
+ exit 1
+ else
+ echo "ok"
+ fi
+
+ # Without correction
+ echo "Convert mif to bin ... "
+ rm testblock.img
+ nand2bin --pagesize=${pagesize} -o testblock.img \
+ testblock_bitflip.mif
+ if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+ else
+ echo "ok"
+ fi
+
+ echo -n "Comparing data must differ, correction is disabled ... "
+ diff testblock.bin testblock.img
+ if [ $? -ne "0" ]; then
+ echo "ok" # must fail
+ else
+ echo "failed!"
+ exit 1
+ fi
+done
+
+echo "Test bitflips in OOB data ... "
+for offs in `seq 0 $oobsize` ; do
+
+ let ioffs=$pagesize+$offs
+
+ echo -n "Inject biterror at offset $ioffs ... "
+ ${inject_biterror} --offset=${ioffs} --bitmask=0x01 \
+ --input=testblock.mif \
+ --output=testblock_bitflip.mif
+ if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+ else
+ echo "ok"
+ fi
+
+ echo "Convert mif to bin ... "
+ rm testblock.img
+ nand2bin --correct-ecc --pagesize=${pagesize} -o testblock.img \
+ testblock_bitflip.mif
+ if [ $? -ne "0" ]; then
+ echo "failed!"
+ exit 1
+ else
+ echo "ok"
+ fi
+
+ echo -n "Comparing data ... "
+ diff testblock.bin testblock.img
+ if [ $? -ne "0" ]; then
+ hexdump testblock.bin > testblock.bin.txt
+ hexdump testblock.img > testblock.img.txt
+ echo "Use tkdiff testblock.bin.txt testblock.img.txt to compare"
+ echo "failed!"
+ exit 1
+ else
+ echo "ok"
+ fi
+done
+
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl b/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl
new file mode 100644
index 00000000000..b4a862a13d2
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl
@@ -0,0 +1,94 @@
+#!/usr/bin/perl -w
+#
+# 2007 Frank Haverkamp <haver@vnet.ibm.com>
+#
+# Program for bit-error injection. I am sure that perl experts do it
+# in 1 line. Please let me know how it is done right ;-).
+#
+
+use strict;
+use warnings;
+use Getopt::Long;
+use Pod::Usage;
+
+my $i;
+my $help;
+my $result;
+my $offset = 0;
+my $bitmask = 0x01;
+my $in = "input.mif";
+my $out = "output.mif";
+
+$result = GetOptions ("offset=i" => \$offset, # numeric
+ "bitmask=o" => \$bitmask, # numeric
+ "input=s" => \$in, # string
+ "output=s" => \$out, # string
+ "help|?" => \$help) or pod2usage(2);
+
+pod2usage(1) if $help;
+
+my $buf;
+
+open(my $in_fh, "<", $in)
+ or die "Cannot open file $in: $!";
+binmode $in_fh;
+
+open(my $out_fh, ">", $out) or
+ die "Cannot open file $out: $!";
+binmode $out_fh;
+
+$i = 0;
+while (sysread($in_fh, $buf, 1)) {
+
+ $buf = pack('C', unpack('C', $buf) ^ $bitmask) if ($i == $offset);
+ syswrite($out_fh, $buf, 1) or
+ die "Cannot write to offset $offset: $!";
+ $i++;
+}
+
+close $in_fh;
+close $out_fh;
+
+__END__
+
+=head1 NAME
+
+inject_biterrors.pl
+
+=head1 SYNOPSIS
+
+inject_biterror.pl [options]
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<--help>
+
+Print a brief help message and exits.
+
+=item B<--offset>=I<offset>
+
+Byte-offset where bit-error should be injected.
+
+=item B<--bitmask>=I<bitmask>
+
+Bit-mask where to inject errors in the byte.
+
+=item B<--input>=I<input-file>
+
+Input file.
+
+=item B<--output>=I<output-file>
+
+Output file.
+
+=back
+
+=head1 DESCRIPTION
+
+B<inject_biterrors.pl> will read the given input file and inject
+biterrors at the I<offset> specified. The location of the biterrors
+are defined by the I<bitmask> parameter.
+
+=cut
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh b/drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh
new file mode 100644
index 00000000000..0cc9f0c3a77
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+#
+# Testcase for JFFS2 verification. We do not want to see any
+# kernel errors occuring when this is executed.
+#
+#
+# To have a standardized output I define the following function to be
+# used when a test was ok or when it failed.
+#
+failed ()
+{
+ echo "FAILED"
+}
+
+passed ()
+{
+ echo "PASSED"
+}
+
+#
+# Print sucess message. Consider to exit with zero as return code.
+#
+exit_success ()
+{
+ echo "SUCCESS"
+ exit 0
+}
+
+#
+# Print failure message. Consider to exit with non zero return code.
+#
+exit_failure ()
+{
+ echo "FAILED"
+ exit 1
+}
+
+echo "***********************************************************************"
+echo "* jffs2 testing ... *"
+echo "***********************************************************************"
+
+ulimit -c unlimited
+
+for i in `seq 5000`; do
+ echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... "
+ dd if=/dev/urandom of=test.bin bs=$i count=1;
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo "Copy to different file ... "
+ dd if=test.bin of=new.bin bs=$i count=1;
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo "Comparing files ... "
+ cmp test.bin new.bin
+ dd if=test.bin of=new.bin bs=$i count=1;
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+done
+
+for i in `seq 5000`; do
+ echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... "
+ dd if=/dev/urandom of=foo bs=$i count=1;
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+done
+
+for i in `seq 5000`; do
+ echo "Testing $i byte (dd if=/dev/zero of=foo bs=$i count=1) ... "
+ dd if=/dev/zero of=foo bs=$i count=1;
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+done
+
+echo "***********************************************************************"
+echo "* Congratulations, no errors found! *"
+echo "* Have fun with your cool JFFS2 using system! *"
+echo "***********************************************************************"
+
+exit_success
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl b/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl
new file mode 100644
index 00000000000..f0fd4647750
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl
@@ -0,0 +1,32 @@
+#!/usr/bin/perl -w
+
+#
+# Author: Artem B. Bityutskiy <dedekind@oktetlabs.ru>
+#
+# A small scrip which creates UBI device nodes in /dev. UBI allocates
+# major number dynamically, so the script looks at /proc/devices to find
+# out UBI's major number.
+#
+
+
+my $proc = '/proc/devices';
+my $regexp = '(\d+) (ubi\d+)$';
+
+
+open FILE, "<", $proc or die "Cannot open $proc file: $!\n";
+my @file = <FILE>;
+close FILE;
+
+foreach (@file) {
+ next if not m/$regexp/g;
+ print "found $2\n";
+
+ system("rm -rf /dev/$2");
+ system("mknod /dev/$2 c $1 0");
+
+ for (my $i = 0; $i < 128; $i += 1) {
+ system("rm -rf /dev/$2_$i");
+ my $j = $i + 1;
+ system("mknod /dev/$2_$i c $1 $j");
+ }
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt b/drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt
new file mode 100644
index 00000000000..a3ad915225b
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt
@@ -0,0 +1,16 @@
+pdd=flash_type,flash_size,flash_eraseblock_size,flash_page_size,card_serialnumber,card_type,ethaddr,eth1addr,eth0,eth1,total,card_hardwarelevel
+pdd_preserve=ethaddr,eth1addr,card_serialnumber
+# To be personalized
+ethaddr=00:04:34:56:78:9A
+eth1addr=00:04:34:56:78:9B
+card_serialnumber=SN0
+# Static for this card type
+total=102M
+card_type=nand_driven_testcard
+card_hardwarelevel=0
+eth0=bcm5222,eth0,0
+eth1=bcm5222,eth0,1
+flash_type=NAND
+flash_size=0x08000000
+flash_eraseblock_size=0x00020000
+flash_page_size=0x00000800
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh b/drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh
new file mode 100644
index 00000000000..040bcbdec2f
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh
@@ -0,0 +1,101 @@
+#!/bin/sh
+
+exit_success ()
+{
+ echo "UBI Utils Test Scripts - SUCCESS!"
+ exit 0
+}
+
+exit_failure ()
+{
+ echo $1
+ echo "UBI Utils Test Scripts - FAILED!"
+ exit 1
+}
+
+echo UBI Utils Test Scripts
+
+devno=$1
+logfile=temp-test-log.txt
+
+if test -z "$devno";
+then
+ echo "Usage is $0 <mtd device number>"
+ exit 1
+fi
+
+cwd=`pwd` || exit_failure "pwd failed"
+
+log="${cwd}/${logfile}"
+
+PATH=$PATH:$cwd:..
+
+cat /dev/null > $log || exit_failure "Failed to create $log"
+
+echo "Setting up for jffs2_test.sh" | tee -a $log
+
+avail=`cat /sys/class/ubi/ubi${devno}/avail_eraseblocks`
+size=`cat /sys/class/ubi/ubi${devno}/eraseblock_size`
+
+bytes=`expr $avail \* $size`
+
+ubimkvol -d$devno -s$bytes -n0 -Njtstvol || exit_failure "ubimkvol failed"
+
+mkdir -p /mnt/test_file_system || exit_failure "mkdir failed"
+
+mtd=`cat /proc/mtd | grep jtstvol | cut -d: -f1`
+
+if test -z "$mtd";
+then
+ exit_failure "mtd device not found"
+fi
+
+mount -t jffs2 $mtd /mnt/test_file_system || exit_failure "mount failed"
+
+cd /mnt/test_file_system || exit_failure "cd failed"
+
+echo Running jffs2_test.sh | tee -a $log
+
+jffs2_test.sh >> $log 2>&1 || exit_failure "jffs2_test.sh failed"
+
+rm -f *
+
+cd $cwd || exit_failure "cd failed"
+
+umount /mnt/test_file_system || exit_failure "umount failed"
+
+ubirmvol -d$devno -n0 || exit_failure "ubirmvol failed"
+
+major=`cat /sys/class/ubi/ubi${devno}/dev | cut -d: -f1`
+
+for minor in `seq 0 32`; do
+ if test ! -e /dev/ubi${devno}_$minor ;
+ then
+ mknod /dev/ubi${devno}_$minor c $major $(($minor + 1))
+ fi
+done
+
+rm -f testdata.bin readdata.bin
+
+echo Running ubi_jffs2_test.sh | tee -a $log
+
+ubi_jffs2_test.sh >> $log 2>&1 || exit_failure "ubi_jffs2_test.sh failed"
+
+echo Running ubi_test.sh | tee -a $log
+
+ubi_test.sh >> $log 2>&1 || exit_failure "ubi_test.sh failed"
+
+for minor in `seq 0 32`; do
+ if test -e /sys/class/ubi/ubi${devno}/$minor;
+ then
+ ubirmvol -d$devno -n$minor || exit_failure "ubirmvol failed"
+ fi
+done
+
+echo Running ubi_tools_test.sh | tee -a $log
+
+ubi_tools_test.sh >> $log 2>&1 || exit_failure "ubi_tools_test failed"
+
+rm -f $log
+
+exit_success
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg b/drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg
new file mode 100644
index 00000000000..0b5ec48dcad
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg
@@ -0,0 +1,23 @@
+[targets]
+test_complete=spl,kernel,rootfs
+
+[spl]
+image=test_u-boot.bin
+ubi_ids=10,11
+ubi_size=1MiB
+ubi_type=static
+ubi_names=test_spl_0,test_spl_1
+
+[kernel]
+image=test_vmlinux.bin
+ubi_ids=12,13
+ubi_size=2MiB
+ubi_type=static
+ubi_names=test_kernel_0,test_kernel_1
+
+[rootfs]
+image=test_rootfs.bin
+ubi_ids=14,15
+ubi_size=2MiB
+ubi_type=dynamic
+ubi_names=test_rootfs_0,test_rootfs_1
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh b/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh
new file mode 100644
index 00000000000..883903dbee3
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh
@@ -0,0 +1,411 @@
+#!/bin/sh
+#
+# UBI Volume creation/deletion/write/read and JFFS2 on top of UBI
+# testcases.
+#
+# Written in shell language to reduce dependencies to more sophisticated
+# interpreters, which may not be available on some stupid platforms.
+#
+# Author: Frank Haverkamp <haver@vnet.ibm.com>
+#
+# 1.0 Initial version
+# 1.1 Added fixup for delayed device node creation by udev
+# This points to a problem in the tools, mabe in the desing
+# Tue Oct 31 14:14:54 CET 2006
+#
+
+VERSION="1.1"
+
+export PATH=$PATH:/bin:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashutils/bin/
+
+ITERATIONS=250
+ALIGNMENT=2048
+
+UBIMKVOL="ubimkvol -a $ALIGNMENT"
+UBIRMVOL=ubirmvol
+UBIUPDATEVOL=ubiupdatevol
+
+SIZE_512K=524288
+SIZE_1M=1310720
+
+MINVOL=10
+MAXVOL=12
+
+TLOG=/dev/null
+
+#
+# To have a standardized output I define the following function to be
+# used when a test was ok or when it failed.
+#
+failed ()
+{
+ echo "FAILED"
+}
+
+passed ()
+{
+ echo "PASSED"
+}
+
+#
+# Print sucess message. Consider to exit with zero as return code.
+#
+exit_success ()
+{
+ echo "SUCCESS"
+ exit 0
+}
+
+#
+# Print failure message. Consider to exit with non zero return code.
+#
+exit_failure ()
+{
+ echo "FAILED"
+ exit 1
+}
+
+###############################################################################
+#
+# START
+#
+###############################################################################
+
+fix_sysfs_issue ()
+{
+ echo "*** Fixing the sysfs issue with the /dev nodes ... "
+
+ minor=0
+ major=`grep ubi0 /proc/devices | sed -e 's/\(.*\) ubi0/\1/'`
+
+ rm -rf /dev/ubi0
+ mknod /dev/ubi0 c $major 0
+
+ for minor in `seq $MINVOL $MAXVOL`; do
+ echo " -> mknod /dev/ubi0_$minor c $major $(($minor + 1))"
+ rm -rf /dev/ubi0_$minor
+ mknod /dev/ubi0_$minor c $major $(($minor + 1))
+ done
+ passed
+}
+
+#
+# FIXME Udev needs some time until the device nodes are created.
+# This will cause trouble if after ubimkvol an update attempt
+# is started immediately, since the device node is not yet
+# available. We should either fix the tools with inotify or
+# other ideas or figure out a different way to solve the problem
+# e.g. to use ubi0 and make the volume device nodes obsolete...
+#
+udev_wait ()
+{
+ echo -n "FIXME Waiting for udev to create/delete device node "
+ grep 2\.6\.5 /proc/version > /dev/null
+ if [ $? -eq "0" ]; then
+ for i in `seq 0 5`; do
+ sleep 1; echo -n ".";
+ done
+ echo " ok"
+ fi
+}
+
+# delete_volume - Delete a volume. If it does not exist, do not try
+# to delete it.
+# @id: volume id
+#
+delete_volume ()
+{
+ volume=$1
+
+ ### FIXME broken sysfs!!!!
+ if [ -e /sys/class/ubi/$volume -o \
+ -e /sys/class/ubi/ubi0/$volume -o \
+ -e /sys/class/ubi/ubi0_$volume ]; then
+
+ echo "*** Truncate volume if it exists ... "
+ echo " $UBIUPDATEVOL -d0 -n$volume -t"
+ $UBIUPDATEVOL -d0 -n$volume -t
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo -n "*** Delete volume if it exists ... "
+ $UBIRMVOL -d0 -n$volume
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+ # udev_wait
+ fi
+}
+
+# writevol_test - Tests volume creation and writing data to it.
+#
+# @volume: Volume number
+# @size: Size of random data to write
+# @type: Volume type static or dynamic
+#
+writevol_test ()
+{
+ volume=$1
+ size=$2
+ type=$3
+
+ echo "*** Write volume test with size $size"
+
+### Make sure that volume exist, delete existing volume, create new
+
+ delete_volume $volume
+
+ echo "*** Try to create volume"
+ echo " $UBIMKVOL -d0 -n$volume -t$type -NNEW$volume -s $size ... "
+ $UBIMKVOL -d0 -n$volume -t$type -N"NEW$volume" -s $size
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+ udev_wait
+
+### Try to create same volume again
+ echo -n "*** Try to create some volume again, this must fail ... "
+ $UBIMKVOL -d0 -n$volume -t$type -N"NEW$volume" -s $size
+ if [ $? -eq "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+### Now create test data, write it, read it, compare it
+ echo -n "*** Create test data ... "
+ dd if=/dev/urandom of=testdata.bin bs=$size count=1
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo "*** Now writing data to volume ... "
+ echo " $UBIUPDATEVOL -d0 -n$volume testdata.bin"
+ ls -l testdata.bin
+ $UBIUPDATEVOL -d0 -n$volume testdata.bin
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo "*** Download data with dd bs=1 ... "
+ dd if=/dev/ubi0_$volume of=readdata.bin bs=$size count=1
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo -n "*** Comparing data ... "
+ cmp readdata.bin testdata.bin
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo -n "*** Now truncate volume ... "
+ $UBIUPDATEVOL -d0 -n$volume -t
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+}
+
+jffs2_torture ()
+{
+ cat /dev/null > TLOG
+
+ echo "*** Torture test ... "
+
+ for i in `seq $iterations`; do
+ dd if=/dev/urandom of=test.bin bs=$i count=1 2>> $TLOG
+ if [ $? -ne "0" ] ; then
+ echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... "
+ exit_failure
+ fi
+ #passed
+
+ dd if=test.bin of=new.bin bs=$i count=1 2>> $TLOG
+ if [ $? -ne "0" ] ; then
+ echo "dd if=test.bin of=new.bin bs=$i count=1 2>> $TLOG"
+ exit_failure
+ fi
+ #passed
+
+ #echo "Comparing files ... "
+ cmp test.bin new.bin
+ dd if=test.bin of=new.bin bs=$i count=1 2>> $TLOG
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ #passed
+ #echo -n "."
+ done
+
+ echo -n "step0:ok "
+
+ for i in `seq $iterations`; do
+ dd if=/dev/urandom of=foo bs=$i count=1 2>> $TLOG
+ if [ $? -ne "0" ] ; then
+ echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... "
+ exit_failure
+ fi
+ #passed
+ done
+
+ echo -n "step1:ok "
+
+ for i in `seq $iterations`; do
+ dd if=/dev/zero of=foo bs=1 count=$i 2>> $TLOG
+ if [ $? -ne "0" ] ; then
+ echo "Testing $i byte (dd if=/dev/zero of=foo bs=1 count=$i) ... "
+ exit_failure
+ fi
+ #passed
+ done
+
+ echo -n "step2:ok "
+
+ for i in `seq $iterations`; do
+ dd if=/dev/zero of=foo bs=$i count=16 2>> $TLOG
+ if [ $? -ne "0" ] ; then
+ echo "Testing $i byte (dd if=/dev/zero of=foo bs=$i count=1024) ... "
+ exit_failure
+ fi
+ #passed
+ done
+
+ echo -n "step3:ok "
+
+ passed
+}
+
+# writevol_test - Tests volume creation and writing data to it.
+#
+# @volume: Volume number
+# @size: Size of random data to write
+# @type: Volume type static or dynamic
+#
+jffs2_test ()
+{
+ name=$1
+ iterations=$2
+ directory=`pwd`
+
+ ### Setup
+ ulimit -c unlimited
+
+ echo -n "*** Create directory /mnt/$name ... "
+ mkdir -p /mnt/$name
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo -n "*** mount -t jffs2 mtd:$name /mnt/$name ... "
+ mount -t jffs2 mtd:$name /mnt/$name
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo -n "*** change directory ... "
+ cd /mnt/$name
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ ls
+ echo "*** list directory ... "
+ ls -la
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ ### Torture
+ echo -n "*** touch I_WAS_HERE ... "
+ touch I_WAS_HERE
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ jffs2_torture
+
+ echo "*** list directory ... "
+ ls -la
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ ### Cleanup
+ echo -n "*** go back ... "
+ cd $directory
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ ### Still mounted, ubiupdatevol must fail!
+
+ echo -n "*** $UBIUPDATEVOL -d0 -n$volume -t must fail! ..."
+ $UBIUPDATEVOL -d0 -n$volume -t
+ if [ $? -eq "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo -n "*** umount /mnt/$name ... "
+ umount /mnt/$name
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ return
+}
+
+echo "***********************************************************************"
+echo "* UBI JFFS2 Testing starts now ... *"
+echo "* Good luck! *"
+echo "***********************************************************************"
+echo "VERSION: $VERSION"
+
+# Set to zero if not running on example hardware
+grep ubi /proc/devices > /dev/null
+if [ $? -ne "0" ]; then
+ echo "No UBI found in /proc/devices! I am broken!"
+ exit_failure
+fi
+
+# Set to zero if not running on example hardware
+grep 1142 /proc/cpuinfo > /dev/null
+if [ $? -eq "0" ]; then
+ echo "Running on example hardware"
+ mount -o remount,rw / /
+ sleep 1
+ fix_sysfs_issue
+else
+ echo "Running on Artems hardware"
+fi
+
+for volume in `seq $MINVOL $MAXVOL`; do
+ echo -n "************ VOLUME $volume NEW$volume "
+ echo "******************************************"
+ writevol_test $volume $SIZE_1M dynamic
+ jffs2_test NEW$volume $ITERATIONS
+ delete_volume $volume
+done
+
+echo "***********************************************************************"
+echo "* Congratulations, no errors found! *"
+echo "* Have fun with your cool UBI system! *"
+echo "***********************************************************************"
+
+exit_success
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh b/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh
new file mode 100644
index 00000000000..73e4b195f67
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh
@@ -0,0 +1,328 @@
+#!/bin/sh
+#
+# UBI Volume creation/deletion/write/read test script
+#
+# Written in shell language to reduce dependencies to more sophisticated
+# interpreters, which may not be available on some stupid platforms.
+#
+# Author: Frank Haverkamp <haver@vnet.ibm.com>
+#
+# 1.0 Initial version
+# 1.1 Use ubiupdatevol instead of ubiwritevol
+#
+
+VERSION="1.1"
+
+export PATH=$PATH:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashutils/bin/
+
+UBIMKVOL=ubimkvol
+UBIRMVOL=ubirmvol
+UBIUPDATEVOL=ubiupdatevol
+
+# 128 KiB 131072
+# 256 KiB 262144
+# 512 KiB 524288
+
+SIZE_512K=524288
+SIZE_1M=1310720
+
+SELF=$0
+MINVOL=10
+MAXVOL=12
+
+#
+# To have a standardized output I define the following function to be
+# used when a test was ok or when it failed.
+#
+failed ()
+{
+ echo "FAILED"
+}
+
+passed ()
+{
+ echo "PASSED"
+}
+
+#
+# Print sucess message. Consider to exit with zero as return code.
+#
+exit_success ()
+{
+ echo "SUCCESS"
+ exit 0
+}
+
+#
+# Print failure message. Consider to exit with non zero return code.
+#
+exit_failure ()
+{
+ echo "FAILED"
+ exit 1
+}
+
+###############################################################################
+#
+# START
+#
+###############################################################################
+
+fix_sysfs_issue ()
+{
+ echo -n "*** Fixing the sysfs issue with the /dev nodes ... "
+
+ minor=0
+ major=`grep ubi0 /proc/devices | sed -e 's/\(.*\) ubi0/\1/'`
+
+ rm -rf /dev/ubi0
+ mknod /dev/ubi0 c $major 0
+
+ for minor in `seq 0 $MAXVOL`; do
+ ### echo " mknod /dev/ubi0_$minor c $major $(($minor + 1))"
+ rm -rf /dev/ubi0_$minor
+ mknod /dev/ubi0_$minor c $major $(($minor + 1))
+ done
+ passed
+}
+
+# delete_volume - Delete a volume. If it does not exist, do not try
+# to delete it.
+# @id: volume id
+#
+delete_volume ()
+{
+ volume=$1
+
+ ### FIXME broken sysfs!!!!
+ if [ -e /sys/class/ubi/$volume -o -e /sys/class/ubi/ubi0/$volume -o -e /sys/class/ubi/ubi0_$volume ]; then
+
+ echo -n "*** Truncate volume if it exists ... "
+ $UBIUPDATEVOL -d0 -n$volume -t
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo -n "*** Delete volume if it exists ... "
+ $UBIRMVOL -d0 -n$volume
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+ fi
+}
+
+mkvol_rmvol_test ()
+{
+ type=$1
+
+### Test if volume delete on non-existing volumes fails nicely
+
+ for i in `seq $MINVOL $MAXVOL`; do
+ echo "*** Delete if exist or not $i ... "
+
+ delete_volume $i
+ passed
+ done
+
+### Now deleting volumes must fail
+
+ for i in `seq $MINVOL $MAXVOL`; do
+ echo "*** Trying to delete non existing UBI Volume $i ... "
+
+ $UBIRMVOL -d0 -n$i
+ if [ $? -eq "0" ] ; then
+ exit_failure
+ fi
+ passed
+ done
+
+### Test if volume creation works ok
+
+ for i in `seq $MINVOL $MAXVOL`; do
+ echo "*** Creating UBI Volume $i ... "
+ echo " $UBIMKVOL -d0 -n$i -t$type -NNEW$i -s $SIZE_512K"
+
+ $UBIMKVOL -d0 -n$i -t$type -N"NEW$i" -s $SIZE_512K
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+ done
+
+### Now deleting volumes must be ok
+
+ for i in `seq $MINVOL $MAXVOL`; do
+ echo "*** Trying to delete UBI Volume $i ... "
+
+ $UBIRMVOL -d0 -n$i
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+ done
+
+### Now allocate too large volume
+
+ echo -n "*** Try to create too large volume"
+ $UBIMKVOL -d0 -n$MINVOL -t$type -N"NEW$MINVOL" -s 800000000
+ if [ $? -eq "0" ] ; then
+ exit_failure
+ fi
+ passed
+}
+
+# writevol_test - Tests volume creation and writing data to it.
+#
+# @size: Size of random data to write
+# @type: Volume type static or dynamic
+#
+writevol_test ()
+{
+ size=$1
+ type=$2
+
+ echo "*** Write volume test with size $size"
+
+### Make sure that volume exist, delete existing volume, create new
+
+ delete_volume $MINVOL
+
+ echo -n "*** Try to create volume ... "
+ $UBIMKVOL -d0 -n$MINVOL -t$type -N"NEW$MINVOL" -s $SIZE_1M
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+### Try to create same volume again
+ echo -n "*** Try to create some volume again, this must fail ... "
+ $UBIMKVOL -d0 -n$MINVOL -t$type -N"NEW$MINVOL" -s $SIZE_1M
+ if [ $? -eq "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+### Now create test data, write it, read it, compare it
+ echo -n "*** Create test data ... "
+ dd if=/dev/urandom of=testdata.bin bs=$size count=1
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo "*** Now writing data to volume ... "
+ # sleep 5
+ ls -l testdata.bin
+ echo " $UBIUPDATEVOL -d0 -n$MINVOL testdata.bin"
+ $UBIUPDATEVOL -d0 -n$MINVOL testdata.bin
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ if [ $type = "static" ] ; then
+ echo "*** Download data with cat ... "
+ cat /dev/ubi0_$MINVOL > readdata.bin
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+ else
+ echo "*** Download data with dd bs=1 ... "
+ dd if=/dev/ubi0_$MINVOL of=readdata.bin bs=$size count=1
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ # Size 1 does not work with this test ...
+ #
+ #echo "*** Download data with dd bs=$size ... "
+ #dd if=/dev/ubi0_$MINVOL of=readdata2.bin bs=$size count=1
+ #if [ $? -ne "0" ] ; then
+ # exit_failure
+ #fi
+ #passed
+
+ #echo -n "*** Comparing data (1) ... "
+ #cmp readdata.bin readdata2.bin
+ #if [ $? -ne "0" ] ; then
+ # exit_failure
+ #fi
+ #passed
+ fi
+
+ echo -n "*** Comparing data ... "
+ cmp readdata.bin testdata.bin
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+}
+
+echo "***********************************************************************"
+echo "* UBI Testing starts now ... *"
+echo "* Good luck! *"
+echo "***********************************************************************"
+
+# Set to zero if not running on example hardware
+grep ubi /proc/devices > /dev/null
+if [ $? -ne "0" ]; then
+ echo "No UBI found in /proc/devices! I am broken!"
+ exit_failure
+fi
+
+# Set to zero if not running on example hardware
+grep 1142 /proc/cpuinfo > /dev/null
+if [ $? -eq "0" ]; then
+ echo "Running on example hardware"
+ mount -o remount,rw / /
+ sleep 1
+ fix_sysfs_issue
+else
+ echo "Running on Artems hardware"
+fi
+
+echo "***********************************************************************"
+echo "* mkvol/rmvol testing for static volumes ... *"
+echo "***********************************************************************"
+
+mkvol_rmvol_test static
+
+echo "***********************************************************************"
+echo "* mkvol/rmvol testing for dynamic volumes ... *"
+echo "***********************************************************************"
+
+mkvol_rmvol_test dynamic
+
+echo "***********************************************************************"
+echo "* write to static volumes ... *"
+echo "***********************************************************************"
+
+# 10 Erase blocks = (128 KiB - 64 * 2) * 10
+# = 1309440 bytes
+# 128 KiB 131072
+# 256 KiB 262144
+# 512 KiB 524288
+
+for size in 262144 131073 131072 2048 1 4096 12800 31313 ; do
+ writevol_test $size static
+done
+
+echo "***********************************************************************"
+echo "* write to dynamic volumes ... *"
+echo "***********************************************************************"
+echo "VERSION: $VERSION"
+
+for size in 131073 131072 2048 1 4096 12800 31313 262144 ; do
+ writevol_test $size dynamic
+done
+
+echo "***********************************************************************"
+echo "* Congratulations, no errors found! *"
+echo "* Have fun with your cool UBI system! *"
+echo "***********************************************************************"
+
+exit_success
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh b/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh
new file mode 100644
index 00000000000..7f121f134db
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh
@@ -0,0 +1,252 @@
+#!/bin/sh
+#
+# UBI Volume creation/deletion/write/read test script.
+# Uses our flash update tools and the associated toolchain for flash
+# image creation.
+#
+# Written in shell language to reduce dependencies to more sophisticated
+# interpreters, which may not be available on some stupid platforms.
+#
+# Author: Frank Haverkamp <haver@vnet.ibm.com>
+#
+# 1.0 Initial version
+#
+
+VERSION="1.0"
+
+export PATH=$PATH:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashutils/bin/
+
+UBIMKVOL=ubimkvol
+UBIRMVOL=ubirmvol
+UBIWRITEVOL=ubiupdatevol
+PFIFLASH=pfiflash
+CMP=cmp
+
+MAXVOL=32
+
+test_pfi=test_complete.pfi
+real_pfi=example_complete.pfi
+
+# 128 KiB 131072
+# 256 KiB 262144
+# 512 KiB 524288
+
+#
+# To have a standardized output I define the following function to be
+# used when a test was ok or when it failed.
+#
+failed ()
+{
+ echo "FAILED"
+}
+
+passed ()
+{
+ echo "PASSED"
+}
+
+#
+# Print sucess message. Consider to exit with zero as return code.
+#
+exit_success ()
+{
+ echo "SUCCESS"
+ exit 0
+}
+
+#
+# Print failure message. Consider to exit with non zero return code.
+#
+exit_failure ()
+{
+ echo "FAILED"
+ exit 1
+}
+
+###############################################################################
+#
+# START
+#
+###############################################################################
+
+fix_sysfs_issue ()
+{
+ echo -n "*** Fixing the sysfs issue with the /dev nodes ... "
+
+ minor=0
+ major=`grep ubi0 /proc/devices | sed -e 's/\(.*\) ubi0/\1/'`
+
+ rm -rf /dev/ubi0
+ mknod /dev/ubi0 c $major 0
+
+ for minor in `seq 0 $MAXVOL`; do
+ ### echo " mknod /dev/ubi0_$minor c $major $(($minor + 1))"
+ rm -rf /dev/ubi0_$minor
+ mknod /dev/ubi0_$minor c $major $(($minor + 1))
+ done
+ passed
+}
+
+# delete_volume - Delete a volume. If it does not exist, do not try
+# to delete it.
+# @id: volume id
+#
+delete_volume ()
+{
+ volume=$1
+
+ ### FIXME broken sysfs!!!!
+ if [ -e /sys/class/ubi/$volume -o -e /sys/class/ubi/ubi0/$volume -o -e /sys/class/ubi/ubi0_$volume ]; then
+
+ echo -n "*** Truncate volume if it exists ... "
+ $UBIWRITEVOL -d0 -n$volume -t
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+
+ echo -n "*** Delete volume if it exists ... "
+ $UBIRMVOL -d0 -n$volume
+ if [ $? -ne "0" ] ; then
+ exit_failure
+ fi
+ passed
+ fi
+}
+
+echo "***********************************************************************"
+echo "* UBI Tools Testing starts now ... *"
+echo "* Good luck! *"
+echo "***********************************************************************"
+
+# Set to zero if not running on example hardware
+grep ubi /proc/devices > /dev/null
+if [ $? -ne "0" ]; then
+ echo "No UBI found in /proc/devices! I am broken!"
+ exit_failure
+fi
+
+# Set to zero if not running on example hardware
+grep 1142 /proc/cpuinfo > /dev/null
+if [ $? -eq "0" ]; then
+ echo "Running on example hardware"
+ mount -o remount,rw / /
+ sleep 1
+ fix_sysfs_issue
+else
+ echo "Running on other hardware"
+fi
+
+### Test basic stuff
+pfiflash_basic ()
+{
+ echo "Calling pfiflash with test-data ... "
+ echo " $PFIFLASH $test_pfi"
+ $PFIFLASH $test_pfi
+ if [ $? -ne "0" ]; then
+ echo "Uhhh something went wrong!"
+ exit_failure
+ fi
+ passed
+
+ echo "Testing if data is correct 10 and 11 ... "
+ $CMP /dev/ubi0_10 /dev/ubi0_11
+ if [ $? -ne "0" ]; then
+ echo "Mirrored volumes not equal!"
+ exit_failure
+ fi
+ passed
+
+ echo "Comparing against original data ... "
+ $CMP /dev/ubi0_10 test_u-boot.bin
+ if [ $? -ne "0" ]; then
+ echo "Compared volume not equal!"
+ exit_failure
+ fi
+ passed
+
+ echo "Testing if data is correct 12 and 13 ... "
+ $CMP /dev/ubi0_12 /dev/ubi0_13
+ if [ $? -ne "0" ]; then
+ echo "Mirrored volumes not equal!"
+ exit_failure
+ fi
+ passed
+
+ echo "Comparing against original data ... "
+ $CMP /dev/ubi0_12 test_vmlinux.bin
+ if [ $? -ne "0" ]; then
+ echo "Compared volume not equal!"
+ exit_failure
+ fi
+ passed
+
+ echo "Testing if data is correct 14 and 15 ... "
+ $CMP /dev/ubi0_14 /dev/ubi0_15
+ if [ $? -ne "0" ]; then
+ echo "Mirrored volumes not equal!"
+ exit_failure
+ fi
+ passed
+}
+
+### Test each and everything
+pfiflash_advanced ()
+{
+ if [ -e example_complete.pfi ]; then
+ echo "Calling pfiflash with real data ... "
+ $PFIFLASH -p overwrite --complete example_complete.pfi
+ if [ $? -ne "0" ]; then
+ echo "Uhhh something went wrong!"
+ exit_failure
+ fi
+ passed
+
+ echo "Testing if data is correct 2 and 3 ... "
+ $CMP /dev/ubi0_2 /dev/ubi0_3
+ if [ $? -ne "0" ]; then
+ echo "Mirrored volumes not equal!"
+ exit_failure
+ fi
+ passed
+
+ echo "Comparing against original data ... "
+ $CMP /dev/ubi0_2 u-boot.bin
+ if [ $? -ne "0" ]; then
+ echo "Compared volume not equal!"
+ exit_failure
+ fi
+ passed
+
+ echo "Testing if data is correct 6 and 7 ... "
+ $CMP /dev/ubi0_6 /dev/ubi0_7
+ if [ $? -ne "0" ]; then
+ echo "Mirrored volumes not equal!"
+ exit_failure
+ fi
+ passed
+
+ echo "Comparing against original data ... "
+ $CMP /dev/ubi0_6 vmlinux.bin
+ if [ $? -ne "0" ]; then
+ echo "Compared volume not equal!"
+ exit_failure
+ fi
+ passed
+ fi
+}
+
+echo "***********************************************************************"
+echo "* Testing pfiflash ... *"
+echo "***********************************************************************"
+echo "VERSION: $VERSION"
+
+pfiflash_basic
+pfiflash_advanced
+
+echo "***********************************************************************"
+echo "* Congratulations, no errors found! *"
+echo "* Have fun with your cool UBI system! *"
+echo "***********************************************************************"
+
+exit_success
diff --git a/drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh b/drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh
new file mode 100644
index 00000000000..40dc2e24b21
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh
@@ -0,0 +1,105 @@
+#!/bin/sh
+#
+# Use raw NAND data, extract UBI image and apply tool to it.
+# Test basic functionality.
+#
+# 2007 Frank Haverkamp <haver@vnet.ibm.com>
+#
+
+version=1.1
+
+image=data.mif
+oob=oob.bin
+data=data.bin
+pagesize=2048
+volmax=31
+datadir=unubi_data
+
+# general arguments e.g. debug enablement
+# unubi_args="-D"
+
+echo "------------------------------------------------------------------------"
+echo "Testcase: ${0} Version: ${version}"
+echo "------------------------------------------------------------------------"
+echo "Testing nand2bin ..."
+echo " Input: ${image}"
+echo " Data: ${data}"
+echo " OOB: ${oob}"
+echo " Pagesize: ${pagesize}"
+nand2bin --pagesize ${pagesize} -o ${data} -O ${oob} ${image}
+echo
+
+echo "------------------------------------------------------------------------"
+echo "Testing unubi ..."
+echo "------------------------------------------------------------------------"
+unubi --version
+echo
+
+echo "------------------------------------------------------------------------"
+echo "Trying to extract first ${volmax} volumes ..."
+echo "------------------------------------------------------------------------"
+mkdir -p ${datadir}/volumes
+for v in `seq 0 ${volmax}` ; do
+ unubi ${unubi_args} -r${v} -d${datadir}/volumes ${data}
+ echo -n "."
+done
+echo "ok"
+ls -l ${datadir}/volumes
+echo
+
+echo "------------------------------------------------------------------------"
+echo "Extracting graphics ..."
+echo "------------------------------------------------------------------------"
+unubi -a -d${datadir} ${data}
+echo "Use gnuplot to display:"
+ls ${datadir}/*.plot
+ls ${datadir}/*.data
+echo
+
+echo "------------------------------------------------------------------------"
+echo "eb-split"
+echo "------------------------------------------------------------------------"
+unubi -e -d${datadir}/eb-split ${data}
+ls -l ${datadir}/eb-split
+echo
+
+echo "------------------------------------------------------------------------"
+echo "vol-split"
+echo "------------------------------------------------------------------------"
+unubi -v -d${datadir}/vol-split ${data}
+ls -l ${datadir}/vol-split
+echo
+echo "The generated images contain only the data (126KiB in our "
+echo "case) not including the UBI erase count and volume info "
+echo "header. For dynamic volumes the data should be the full "
+echo "126KiB. Unubi cannot know how much of the data is valid. "
+echo
+
+echo "------------------------------------------------------------------------"
+echo "!vol-split"
+echo "------------------------------------------------------------------------"
+unubi -V -d${datadir}/vol-split! ${data}
+ls -l ${datadir}/vol-split\!
+echo
+echo "The generated images contain the full block data of 128KiB "
+echo "including the UBI erase count and volume information header."
+echo
+
+echo "------------------------------------------------------------------------"
+echo "Extracting volume info table ..."
+echo "------------------------------------------------------------------------"
+unubi -i -d${datadir} ${data}
+echo "I strongly hope that empty ubi blocks are filled with 0xff! "
+echo
+
+echo "------------------------------------------------------------------------"
+echo "Table 0"
+echo "------------------------------------------------------------------------"
+cat ${datadir}/vol_info_table0
+echo
+
+echo "------------------------------------------------------------------------"
+echo "Table 1"
+echo "------------------------------------------------------------------------"
+cat ${datadir}/vol_info_table1
+echo
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c b/drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c
new file mode 100644
index 00000000000..c7c7ccc8bbe
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ */
+
+/*
+ * Create a flashable NAND image from a binary image
+ *
+ * History:
+ * 1.0 Initial release (tglx)
+ * 1.1 Understands hex and dec input parameters (tglx)
+ * 1.2 Generates separated OOB data, if needed. (oloh)
+ * 1.3 Padds data/oob to a given size. (oloh)
+ * 1.4 Removed argp because we want to use uClibc.
+ * 1.5 Minor cleanup
+ * 1.6 written variable not initialized (-j did not work) (haver)
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "error.h"
+#include "config.h"
+#include "nandecc.h"
+
+#define PROGRAM_VERSION "1.6"
+
+#define CHECK_ENDP(option, endp) do { \
+ if (*endp) { \
+ fprintf(stderr, \
+ "Parse error option \'%s\'. " \
+ "No correct numeric value.\n" \
+ , option); \
+ exit(EXIT_FAILURE); \
+ } \
+} while(0)
+
+typedef enum action_t {
+ ACT_NORMAL = 0x00000001,
+} action_t;
+
+#define PAGESIZE 2048
+#define PADDING 0 /* 0 means, do not adjust anything */
+#define BUFSIZE 4096
+
+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
+ "bin2nand - a tool for adding OOB information to a "
+ "binary input file.\n";
+
+static const char *optionsstr =
+" -c, --copyright Print copyright informatoin.\n"
+" -j, --padding=<num> Padding in Byte/Mi/ki. Default = no padding\n"
+" -p, --pagesize=<num> Pagesize in Byte/Mi/ki. Default = 2048\n"
+" -o, --output=<fname> Output filename. Interleaved Data/OOB if\n"
+" output-oob not specified.\n"
+" -q, --output-oob=<fname> Write OOB data in separate file.\n"
+" -?, --help Give this help list\n"
+" --usage Give a short usage message\n"
+" -V, --version Print program version\n";
+
+static const char *usage =
+"Usage: bin2nand [-c?V] [-j <num>] [-p <num>] [-o <fname>] [-q <fname>]\n"
+" [--copyright] [--padding=<num>] [--pagesize=<num>]\n"
+" [--output=<fname>] [--output-oob=<fname>] [--help] [--usage]\n"
+" [--version]\n";
+
+struct option long_options[] = {
+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
+ { .name = "padding", .has_arg = 1, .flag = NULL, .val = 'j' },
+ { .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' },
+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
+ { .name = "output-oob", .has_arg = 1, .flag = NULL, .val = 'q' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0}
+};
+
+static const char copyright [] __attribute__((unused)) =
+ "Copyright IBM Corp. 2006";
+
+typedef struct myargs {
+ action_t action;
+
+ size_t pagesize;
+ size_t padding;
+
+ FILE* fp_in;
+ char *file_out_data; /* Either: Data and OOB interleaved
+ or plain data */
+ char *file_out_oob; /* OOB Data only. */
+
+ /* special stuff needed to get additional arguments */
+ char *arg1;
+ char **options; /* [STRING...] */
+} myargs;
+
+
+static int ustrtoull(const char *cp, char **endp, unsigned int base)
+{
+ unsigned long long res = strtoull(cp, endp, base);
+
+ switch (**endp) {
+ case 'G':
+ res *= 1024;
+ case 'M':
+ res *= 1024;
+ case 'k':
+ case 'K':
+ res *= 1024;
+ /* "Ki", "ki", "Mi" or "Gi" are to be used. */
+ if ((*endp)[1] == 'i')
+ (*endp) += 2;
+ }
+ return res;
+}
+
+static int
+parse_opt(int argc, char **argv, myargs *args)
+{
+ char* endp;
+
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "cj:p:o:q:?V", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'p': /* pagesize */
+ args->pagesize = (size_t)
+ ustrtoull(optarg, &endp, 0);
+ CHECK_ENDP("p", endp);
+ break;
+ case 'j': /* padding */
+ args->padding = (size_t)
+ ustrtoull(optarg, &endp, 0);
+ CHECK_ENDP("j", endp);
+ break;
+ case 'o': /* output */
+ args->file_out_data = optarg;
+ break;
+ case 'q': /* output oob */
+ args->file_out_oob = optarg;
+ break;
+ case '?': /* help */
+ printf("%s", doc);
+ printf("%s", optionsstr);
+ exit(0);
+ break;
+ case 'V':
+ printf("%s\n", PROGRAM_VERSION);
+ exit(0);
+ break;
+ case 'c':
+ printf("%s\n", copyright);
+ exit(0);
+ default:
+ printf("%s", usage);
+ exit(-1);
+ }
+ }
+
+ if (optind < argc) {
+ args->fp_in = fopen(argv[optind++], "rb");
+ if ((args->fp_in) == NULL) {
+ err_quit("Cannot open file %s for input\n",
+ argv[optind++]);
+ }
+ }
+
+ return 0;
+}
+
+static int
+process_page(uint8_t* buf, size_t pagesize,
+ FILE *fp_data, FILE* fp_oob, size_t* written)
+{
+ int eccpoi, oobsize;
+ size_t i;
+ uint8_t oobbuf[64];
+
+ memset(oobbuf, 0xff, sizeof(oobbuf));
+
+ switch(pagesize) {
+ case 2048: oobsize = 64; eccpoi = 64 / 2; break;
+ case 512: oobsize = 16; eccpoi = 16 / 2; break;
+ default:
+ err_msg("Unsupported page size: %d\n", pagesize);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < pagesize; i += 256, eccpoi += 3) {
+ oobbuf[eccpoi++] = 0x0;
+ /* Calculate ECC */
+ nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]);
+ }
+
+ /* write data */
+ *written += fwrite(buf, 1, pagesize, fp_data);
+
+ /* either separate oob or interleave with data */
+ if (fp_oob) {
+ i = fwrite(oobbuf, 1, oobsize, fp_oob);
+ if (ferror(fp_oob)) {
+ err_msg("IO error\n");
+ return -EIO;
+ }
+ }
+ else {
+ i = fwrite(oobbuf, 1, oobsize, fp_data);
+ if (ferror(fp_data)) {
+ err_msg("IO error\n");
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+int main (int argc, char** argv)
+{
+ int rc = -1;
+ int res = 0;
+ size_t written = 0, read;
+ myargs args = {
+ .action = ACT_NORMAL,
+ .pagesize = PAGESIZE,
+ .padding = PADDING,
+ .fp_in = NULL,
+ .file_out_data = NULL,
+ .file_out_oob = NULL,
+ };
+
+ FILE* fp_out_data = stdout;
+ FILE* fp_out_oob = NULL;
+
+ parse_opt(argc, argv, &args);
+
+ uint8_t* buf = calloc(1, BUFSIZE);
+ if (!buf) {
+ err_quit("Cannot allocate page buffer.\n");
+ }
+
+ if (!args.fp_in) {
+ err_msg("No input image specified!\n");
+ goto err;
+ }
+
+ if (args.file_out_data) {
+ fp_out_data = fopen(args.file_out_data, "wb");
+ if (fp_out_data == NULL) {
+ err_sys("Cannot open file %s for output\n",
+ args.file_out_data);
+ goto err;
+ }
+ }
+
+ if (args.file_out_oob) {
+ fp_out_oob = fopen(args.file_out_oob, "wb");
+ if (fp_out_oob == NULL) {
+ err_sys("Cannot open file %s for output\n",
+ args.file_out_oob);
+ goto err;
+ }
+ }
+
+
+ while(1) {
+ read = fread(buf, 1, args.pagesize, args.fp_in);
+ if (feof(args.fp_in) && read == 0)
+ break;
+
+ if (read < args.pagesize) {
+ err_msg("Image not page aligned\n");
+ goto err;
+ }
+
+ if (ferror(args.fp_in)) {
+ err_msg("Read error\n");
+ goto err;
+ }
+
+ res = process_page(buf, args.pagesize, fp_out_data,
+ fp_out_oob, &written);
+ if (res != 0)
+ goto err;
+ }
+
+ while (written < args.padding) {
+ memset(buf, 0xff, args.pagesize);
+ res = process_page(buf, args.pagesize, fp_out_data,
+ fp_out_oob, &written);
+ if (res != 0)
+ goto err;
+ }
+
+ rc = 0;
+err:
+ free(buf);
+
+ if (args.fp_in)
+ fclose(args.fp_in);
+
+ if (fp_out_oob)
+ fclose(fp_out_oob);
+
+ if (fp_out_data && fp_out_data != stdout)
+ fclose(fp_out_data);
+
+ if (rc != 0) {
+ err_msg("Error during conversion. rc: %d\n", rc);
+ if (args.file_out_data)
+ remove(args.file_out_data);
+ if (args.file_out_oob)
+ remove(args.file_out_oob);
+ }
+ return rc;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c b/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c
new file mode 100644
index 00000000000..fd02bd19978
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c
@@ -0,0 +1,1032 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <sys/stat.h>
+#include <bootenv.h>
+
+#include "hashmap.h"
+#include "error.h"
+
+#include <mtd/ubi-header.h>
+#include "crc32.h"
+
+#define ubi_unused __attribute__((unused))
+
+#define BOOTENV_MAXLINE 512 /* max line size of a bootenv.txt file */
+
+/* Structures */
+struct bootenv {
+ hashmap_t map; ///< Pointer to hashmap which holds data structure.
+};
+
+struct bootenv_list {
+ hashmap_t head; ///< Pointer to list which holds the data structure.
+};
+
+/**
+ * @brief Remove the '\n' from a given line.
+ * @param line Input/Output line.
+ * @param size Size of the line.
+ * @param fp File Pointer.
+ * @return 0
+ * @return or error
+ */
+static int
+remove_lf(char *line, size_t size, FILE* fp)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ if (line[i] == '\n') {
+ line[i] = '\0';
+ return 0;
+ }
+ }
+
+ if (!feof(fp)) {
+ return BOOTENV_EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Determine if a line contains only WS.
+ * @param line The line to process.
+ * @param size Size of input line.
+ * @return 1 Yes, only WS.
+ * @return 0 No, contains data.
+ */
+static int
+is_ws(const char *line, size_t size)
+{
+ size_t i = 0;
+
+ while (i < size) {
+ switch (line[i]) {
+ case '\n':
+ return 1;
+ case '#':
+ return 1;
+ case ' ':
+ i++;
+ continue;
+ case '\t':
+ i++;
+ continue;
+ default: /* any other char -> no cmnt */
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @brief Build a list from a comma seperated value string.
+ * @param list Pointer to hashmap structure which shall store
+ * the list.
+ * @param value Comma seperated value string.
+ * @return 0
+ * @return or error.
+ */
+static int
+build_list_definition(hashmap_t list, const char *value)
+{
+ int rc = 0;
+ char *str = NULL;
+ char *ptr = NULL;
+ size_t len, i, j;
+
+ /* str: val1,val2 , val4,...,valN */
+ len = strlen(value);
+ str = (char*) malloc((len+1) * sizeof(char));
+
+ /* 1. reformat string: remove spaces */
+ for (i = 0, j = 0; i < len; i++) {
+ if (value[i] == ' ')
+ continue;
+
+ str[j] = value[i];
+ j++;
+ }
+ str[j] = '\0';
+
+ /* str: val1,val2,val4,...,valN\0*/
+ /* 2. replace ',' seperator with '\0' */
+ len = strlen(str);
+ for (i = 0; i < len; i++) {
+ if (str[i] == ',') {
+ str[i] = '\0';
+ }
+ }
+
+ /* str: val1\0val2\0val4\0...\0valN\0*/
+ /* 3. insert definitions into a hash map, using it like a list */
+ i = j = 0;
+ ptr = str;
+ while (((i = strlen(ptr)) > 0) && (j < len)) {
+ rc = hashmap_add(list, ptr, "");
+ if (rc != 0) {
+ free(str);
+ return rc;
+ }
+ j += i+1;
+ if (j < len)
+ ptr += i+1;
+ }
+
+ free(str);
+ return rc;
+}
+
+/**
+ * @brief Extract a key value pair and add it to a hashmap
+ * @param str Input string which contains a key value pair.
+ * @param env The updated handle which contains the new pair.
+ * @return 0
+ * @return or error
+ * @note The input string format is: "key=value"
+ */
+static int
+extract_pair(const char *str, bootenv_t env)
+{
+ int rc = 0;
+ char *key = NULL;
+ char *val = NULL;
+
+ key = strdup(str);
+ if (key == NULL)
+ return -ENOMEM;
+
+ val = strstr(key, "=");
+ if (val == NULL) {
+ rc = BOOTENV_EBADENTRY;
+ goto err;
+ }
+
+ *val = '\0'; /* split strings */
+ val++;
+
+ rc = bootenv_set(env, key, val);
+
+ err:
+ free(key);
+ return rc;
+}
+
+int
+bootenv_destroy(bootenv_t* env)
+{
+ int rc = 0;
+
+ if (env == NULL || *env == NULL)
+ return -EINVAL;
+
+ bootenv_t tmp = *env;
+
+ rc = hashmap_free(tmp->map);
+ if (rc != 0)
+ return rc;
+
+ free(tmp);
+ return rc;
+}
+
+int
+bootenv_create(bootenv_t* env)
+{
+ bootenv_t res;
+ res = (bootenv_t) calloc(1, sizeof(struct bootenv));
+
+ if (res == NULL)
+ return -ENOMEM;
+
+ res->map = hashmap_new();
+
+ if (res->map == NULL) {
+ free(res);
+ return -ENOMEM;
+ }
+
+ *env = res;
+
+ return 0;
+}
+
+
+/**
+ * @brief Read a formatted buffer and scan it for valid bootenv
+ * key/value pairs. Add those pairs into a hashmap.
+ * @param env Hashmap which shall be used to hold the data.
+ * @param buf Formatted buffer.
+ * @param size Size of the buffer.
+ * @return 0
+ * @return or error
+ */
+static int
+rd_buffer(bootenv_t env, const char *buf, size_t size)
+{
+ const char *curr = buf; /* ptr to current key/value pair */
+ uint32_t i, j; /* current length, chars processed */
+
+ if (buf[size - 1] != '\0') /* must end in '\0' */
+ return BOOTENV_EFMT;
+
+ for (j = 0; j < size; j += i, curr += i) {
+ /* strlen returns the size of the string upto
+ but not including the null terminator;
+ adding 1 to account for '\0' */
+ i = strlen(curr) + 1;
+
+ if (i == 1)
+ return 0; /* no string found */
+
+ if (extract_pair(curr, env) != 0)
+ return BOOTENV_EINVAL;
+ }
+
+ return 0;
+}
+
+
+int
+bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t* ret_crc)
+{
+ int rc;
+ char *buf = NULL;
+ size_t i = 0;
+ uint32_t crc32_table[256];
+
+ if ((fp == NULL) || (env == NULL))
+ return -EINVAL;
+
+ /* allocate temp buffer */
+ buf = (char*) calloc(1, size * sizeof(char));
+ if (buf == NULL)
+ return -ENOMEM;
+
+ /* FIXME Andreas, please review this I removed size-1 and
+ * replaced it by just size, I saw the kernel image starting
+ * with a 0x0060.... and not with the 0x60.... what it should
+ * be. Is this a tools problem or is it a problem here where
+ * fp is moved not to the right place due to the former size-1
+ * here.
+ */
+ while((i < size) && (!feof(fp))) {
+ int c = fgetc(fp);
+ if (c == EOF) {
+ /* FIXME isn't this dangerous, to update
+ the boot envs with incomplete data? */
+ buf[i++] = '\0';
+ break; /* we have enough */
+ }
+ if (ferror(fp)) {
+ rc = -EIO;
+ goto err;
+ }
+
+ buf[i++] = (char)c;
+ }
+
+ /* calculate crc to return */
+ if (ret_crc != NULL) {
+ init_crc32_table(crc32_table);
+ *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size);
+ }
+
+ /* transfer to hashmap */
+ rc = rd_buffer(env, buf, size);
+
+err:
+ free(buf);
+ return rc;
+}
+
+
+/**
+ * If we have a single file containing the boot-parameter size should
+ * be specified either as the size of the file or as BOOTENV_MAXSIZE.
+ * If the bootparameter are in the middle of a file we need the exact
+ * length of the data.
+ */
+int
+bootenv_read(FILE* fp, bootenv_t env, size_t size)
+{
+ return bootenv_read_crc(fp, env, size, NULL);
+}
+
+
+int
+bootenv_read_txt(FILE* fp, bootenv_t env)
+{
+ int rc = 0;
+ char *buf = NULL;
+ char *line = NULL;
+ char *lstart = NULL;
+ char *curr = NULL;
+ size_t len;
+ size_t size;
+
+ if ((fp == NULL) || (env == NULL))
+ return -EINVAL;
+
+ size = BOOTENV_MAXSIZE;
+
+ /* allocate temp buffers */
+ buf = (char*) calloc(1, size * sizeof(char));
+ lstart = line = (char*) calloc(1, size * sizeof(char));
+ if ((buf == NULL) || (line == NULL)) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ curr = buf;
+ while ((line = fgets(line, size, fp)) != NULL) {
+ if (is_ws(line, size)) {
+ continue;
+ }
+ rc = remove_lf(line, BOOTENV_MAXSIZE, fp);
+ if (rc != 0) {
+ goto err;
+ }
+
+ /* copy new line to binary buffer */
+ len = strlen(line);
+ if (len > size) {
+ rc = -EFBIG;
+ goto err;
+ }
+ size -= len; /* track remaining space */
+
+ memcpy(curr, line, len);
+ curr += len + 1; /* for \0 seperator */
+ }
+
+ rc = rd_buffer(env, buf, BOOTENV_MAXSIZE);
+err:
+ if (buf != NULL)
+ free(buf);
+ if (lstart != NULL)
+ free(lstart);
+ return rc;
+}
+
+static int
+fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max ubi_unused,
+ size_t *written)
+{
+ int rc = 0;
+ size_t keys_size, i;
+ size_t wr = 0;
+ const char **keys = NULL;
+ const char *val = NULL;
+
+ rc = bootenv_get_key_vector(env, &keys_size, 1, &keys);
+ if (rc != 0)
+ goto err;
+
+ for (i = 0; i < keys_size; i++) {
+ if (wr > BOOTENV_MAXSIZE) {
+ rc = -ENOSPC;
+ goto err;
+ }
+
+ rc = bootenv_get(env, keys[i], &val);
+ if (rc != 0)
+ goto err;
+
+ wr += snprintf(buf + wr, BOOTENV_MAXSIZE - wr,
+ "%s=%s", keys[i], val);
+ wr++; /* for \0 */
+ }
+
+ *written = wr;
+
+err:
+ if (keys != NULL)
+ free(keys);
+
+ return rc;
+}
+
+int
+bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc)
+{
+ int rc = 0;
+ size_t size = 0;
+ char *buf = NULL;
+ uint32_t crc32_table[256];
+
+ if ((fp == NULL) || (env == NULL))
+ return -EINVAL;
+
+ buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char));
+ if (buf == NULL)
+ return -ENOMEM;
+
+
+ rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, &size);
+ if (rc != 0)
+ goto err;
+
+ /* calculate crc to return */
+ if (ret_crc != NULL) {
+ init_crc32_table(crc32_table);
+ *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size);
+ }
+
+ if (fwrite(buf, size, 1, fp) != 1) {
+ rc = -EIO;
+ goto err;
+ }
+
+err:
+ if (buf != NULL)
+ free(buf);
+ return rc;
+}
+
+int
+bootenv_write(FILE* fp, bootenv_t env)
+{
+ return bootenv_write_crc(fp, env, NULL);
+}
+
+int
+bootenv_compare(bootenv_t first, bootenv_t second)
+{
+ int rc;
+ size_t written_first, written_second;
+ char *buf_first, *buf_second;
+
+ if (first == NULL || second == NULL)
+ return -EINVAL;
+
+ buf_first = malloc(BOOTENV_MAXSIZE);
+ if (!buf_first)
+ return -ENOMEM;
+ buf_second = malloc(BOOTENV_MAXSIZE);
+ if (!buf_second) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ rc = fill_output_buffer(first, buf_first, BOOTENV_MAXSIZE,
+ &written_first);
+ if (rc < 0)
+ goto err;
+ rc = fill_output_buffer(second, buf_second, BOOTENV_MAXSIZE,
+ &written_second);
+ if (rc < 0)
+ goto err;
+
+ if (written_first != written_second) {
+ rc = 1;
+ goto err;
+ }
+
+ rc = memcmp(buf_first, buf_second, written_first);
+ if (rc != 0) {
+ rc = 2;
+ goto err;
+ }
+
+err:
+ if (buf_first)
+ free(buf_first);
+ if (buf_second)
+ free(buf_second);
+
+ return rc;
+}
+
+int
+bootenv_size(bootenv_t env, size_t *size)
+{
+ int rc = 0;
+ char *buf = NULL;
+
+ if (env == NULL)
+ return -EINVAL;
+
+ buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char));
+ if (buf == NULL)
+ return -ENOMEM;
+
+ rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, size);
+ if (rc != 0)
+ goto err;
+
+err:
+ if (buf != NULL)
+ free(buf);
+ return rc;
+}
+
+int
+bootenv_write_txt(FILE* fp, bootenv_t env)
+{
+ int rc = 0;
+ size_t size, wr, i;
+ const char **keys = NULL;
+ const char *key = NULL;
+ const char *val = NULL;
+
+ if ((fp == NULL) || (env == NULL))
+ return -EINVAL;
+
+ rc = bootenv_get_key_vector(env, &size, 1, &keys);
+ if (rc != 0)
+ goto err;
+
+ for (i = 0; i < size; i++) {
+ key = keys[i];
+ rc = bootenv_get(env, key, &val);
+ if (rc != 0)
+ goto err;
+
+ wr = fprintf(fp, "%s=%s\n", key, val);
+ if (wr != strlen(key) + strlen(val) + 2) {
+ rc = -EIO;
+ goto err;
+ }
+ }
+
+err:
+ if (keys != NULL)
+ free(keys);
+ return rc;
+}
+
+int
+bootenv_valid(bootenv_t env ubi_unused)
+{
+ /* @FIXME No sanity check implemented. */
+ return 0;
+}
+
+int
+bootenv_copy_bootenv(bootenv_t in, bootenv_t *out)
+{
+ int rc = 0;
+ const char *tmp = NULL;
+ const char **keys = NULL;
+ size_t vec_size, i;
+
+ if ((in == NULL) || (out == NULL))
+ return -EINVAL;
+
+ /* purge output var for sure... */
+ rc = bootenv_destroy(out);
+ if (rc != 0)
+ return rc;
+
+ /* create the new map */
+ rc = bootenv_create(out);
+ if (rc != 0)
+ goto err;
+
+ /* get the key list from the input map */
+ rc = bootenv_get_key_vector(in, &vec_size, 0, &keys);
+ if (rc != 0)
+ goto err;
+
+ if (vec_size != hashmap_size(in->map)) {
+ rc = BOOTENV_ECOPY;
+ goto err;
+ }
+
+ /* make a deep copy of the hashmap */
+ for (i = 0; i < vec_size; i++) {
+ rc = bootenv_get(in, keys[i], &tmp);
+ if (rc != 0)
+ goto err;
+
+ rc = bootenv_set(*out, keys[i], tmp);
+ if (rc != 0)
+ goto err;
+ }
+
+err:
+ if (keys != NULL)
+ free(keys);
+
+ return rc;
+}
+
+/* ------------------------------------------------------------------------- */
+
+
+int
+bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res,
+ int *warnings, char *err_buf ubi_unused,
+ size_t err_buf_size ubi_unused)
+{
+ bootenv_list_t l_old = NULL;
+ bootenv_list_t l_new = NULL;
+ const char *pdd_old = NULL;
+ const char *pdd_new = NULL;
+ const char *tmp = NULL;
+ const char **vec_old = NULL;
+ const char **vec_new = NULL;
+ const char **pdd_up_vec = NULL;
+ size_t vec_old_size, vec_new_size, pdd_up_vec_size, i;
+ int rc = 0;
+
+ if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL))
+ return -EINVAL;
+
+ /* get the pdd strings, e.g.:
+ * pdd_old=a,b,c
+ * pdd_new=a,c,d,e */
+ rc = bootenv_get(env_old, "pdd", &pdd_old);
+ if (rc != 0)
+ goto err;
+ rc = bootenv_get(env_new, "pdd", &pdd_new);
+ if (rc != 0)
+ goto err;
+
+ /* put it into a list and then convert it to an vector */
+ rc = bootenv_list_create(&l_old);
+ if (rc != 0)
+ goto err;
+ rc = bootenv_list_create(&l_new);
+ if (rc != 0)
+ goto err;
+
+ rc = bootenv_list_import(l_old, pdd_old);
+ if (rc != 0)
+ goto err;
+
+ rc = bootenv_list_import(l_new, pdd_new);
+ if (rc != 0)
+ goto err;
+
+ rc = bootenv_list_to_vector(l_old, &vec_old_size, &vec_old);
+ if (rc != 0)
+ goto err;
+
+ rc = bootenv_list_to_vector(l_new, &vec_new_size, &vec_new);
+ if (rc != 0)
+ goto err;
+
+ rc = bootenv_copy_bootenv(env_new, env_res);
+ if (rc != 0)
+ goto err;
+
+ /* calculate the update vector between the old and new pdd */
+ pdd_up_vec = hashmap_get_update_key_vector(vec_old, vec_old_size,
+ vec_new, vec_new_size, &pdd_up_vec_size);
+
+ if (pdd_up_vec == NULL) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ if (pdd_up_vec_size != 0) {
+ /* need to warn the user about the unset of
+ * some pdd/bootenv values */
+ *warnings = BOOTENV_WPDD_STRING_DIFFERS;
+
+ /* remove all entries in the new bootenv load */
+ for (i = 0; i < pdd_up_vec_size; i++) {
+ bootenv_unset(*env_res, pdd_up_vec[i]);
+ }
+ }
+
+ /* generate the keep array and copy old pdd values to new bootenv */
+ for (i = 0; i < vec_old_size; i++) {
+ rc = bootenv_get(env_old, vec_old[i], &tmp);
+ if (rc != 0) {
+ rc = BOOTENV_EPDDINVAL;
+ goto err;
+ }
+ rc = bootenv_set(*env_res, vec_old[i], tmp);
+ if (rc != 0) {
+ goto err;
+ }
+ }
+ /* put the old pdd string into the result map */
+ rc = bootenv_set(*env_res, "pdd", pdd_old);
+ if (rc != 0) {
+ goto err;
+ }
+
+
+err:
+ if (vec_old != NULL)
+ free(vec_old);
+ if (vec_new != NULL)
+ free(vec_new);
+ if (pdd_up_vec != NULL)
+ free(pdd_up_vec);
+
+ bootenv_list_destroy(&l_old);
+ bootenv_list_destroy(&l_new);
+ return rc;
+}
+
+
+int
+bootenv_pdd_overwrite(bootenv_t env_old, bootenv_t env_new,
+ bootenv_t *env_res, int *warnings ubi_unused,
+ char *err_buf ubi_unused, size_t err_buf_size ubi_unused)
+{
+ if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL))
+ return -EINVAL;
+
+ return bootenv_copy_bootenv(env_new, env_res);
+}
+
+int
+bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res,
+ int *warnings ubi_unused, char *err_buf, size_t err_buf_size)
+{
+ if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL))
+ return -EINVAL;
+
+ snprintf(err_buf, err_buf_size, "The PDD merge operation is not "
+ "implemented. Contact: <oliloh@de.ibm.com>");
+
+ return BOOTENV_ENOTIMPL;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int
+bootenv_get(bootenv_t env, const char *key, const char **value)
+{
+ if (env == NULL)
+ return -EINVAL;
+
+ *value = hashmap_lookup(env->map, key);
+ if (*value == NULL)
+ return BOOTENV_ENOTFOUND;
+
+ return 0;
+}
+
+int
+bootenv_get_num(bootenv_t env, const char *key, uint32_t *value)
+{
+ char *endptr = NULL;
+ const char *str;
+
+ if (env == NULL)
+ return 0;
+
+ str = hashmap_lookup(env->map, key);
+ if (!str)
+ return -EINVAL;
+
+ *value = strtoul(str, &endptr, 0);
+
+ if (*endptr == '\0') {
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int
+bootenv_set(bootenv_t env, const char *key, const char *value)
+{
+ if (env == NULL)
+ return -EINVAL;
+
+ return hashmap_add(env->map, key, value);
+}
+
+int
+bootenv_unset(bootenv_t env, const char *key)
+{
+ if (env == NULL)
+ return -EINVAL;
+
+ return hashmap_remove(env->map, key);
+}
+
+int
+bootenv_get_key_vector(bootenv_t env, size_t* size, int sort,
+ const char ***vector)
+{
+ if ((env == NULL) || (size == NULL))
+ return -EINVAL;
+
+ *vector = hashmap_get_key_vector(env->map, size, sort);
+
+ if (*vector == NULL)
+ return -EINVAL;
+
+ return 0;
+}
+
+int
+bootenv_dump(bootenv_t env)
+{
+ if (env == NULL)
+ return -EINVAL;
+
+ return hashmap_dump(env->map);
+}
+
+int
+bootenv_list_create(bootenv_list_t *list)
+{
+ bootenv_list_t res;
+ res = (bootenv_list_t) calloc(1, sizeof(struct bootenv_list));
+
+ if (res == NULL)
+ return -ENOMEM;
+
+ res->head = hashmap_new();
+
+ if (res->head == NULL) {
+ free(res);
+ return -ENOMEM;
+ }
+
+ *list = res;
+ return 0;
+}
+
+int
+bootenv_list_destroy(bootenv_list_t *list)
+{
+ int rc = 0;
+
+ if (list == NULL)
+ return -EINVAL;
+
+ bootenv_list_t tmp = *list;
+ if (tmp == 0)
+ return 0;
+
+ rc = hashmap_free(tmp->head);
+ if (rc != 0)
+ return rc;
+
+ free(tmp);
+ *list = NULL;
+ return 0;
+}
+
+int
+bootenv_list_import(bootenv_list_t list, const char *str)
+{
+ if (list == NULL)
+ return -EINVAL;
+
+ return build_list_definition(list->head, str);
+}
+
+int
+bootenv_list_export(bootenv_list_t list, char **string)
+{
+ size_t size, i, j, bufsize, tmp, rc = 0;
+ const char **items;
+
+ if (list == NULL)
+ return -EINVAL;
+
+ bufsize = BOOTENV_MAXLINE;
+ char *res = (char*) malloc(bufsize * sizeof(char));
+ if (res == NULL)
+ return -ENOMEM;
+
+ rc = bootenv_list_to_vector(list, &size, &items);
+ if (rc != 0) {
+ goto err;
+ }
+
+ j = 0;
+ for (i = 0; i < size; i++) {
+ tmp = strlen(items[i]);
+ if (j >= bufsize) {
+ bufsize += BOOTENV_MAXLINE;
+ res = (char*) realloc(res, bufsize * sizeof(char));
+ if (res == NULL) {
+ rc = -ENOMEM;
+ goto err;
+ }
+ }
+ memcpy(res + j, items[i], tmp);
+ j += tmp;
+ if (i < (size - 1)) {
+ res[j] = ',';
+ j++;
+ }
+ }
+ j++;
+ res[j] = '\0';
+ free(items);
+ *string = res;
+ return 0;
+err:
+ free(items);
+ return rc;
+}
+
+int
+bootenv_list_add(bootenv_list_t list, const char *item)
+{
+ if ((list == NULL) || (item == NULL))
+ return -EINVAL;
+
+ return hashmap_add(list->head, item, "");
+}
+
+int
+bootenv_list_remove(bootenv_list_t list, const char *item)
+{
+ if ((list == NULL) || (item == NULL))
+ return -EINVAL;
+
+ return hashmap_remove(list->head, item);
+}
+
+int
+bootenv_list_is_in(bootenv_list_t list, const char *item)
+{
+ if ((list == NULL) || (item == NULL))
+ return -EINVAL;
+
+ return hashmap_lookup(list->head, item) != NULL ? 1 : 0;
+}
+
+int
+bootenv_list_to_vector(bootenv_list_t list, size_t *size, const char ***vector)
+{
+ if ((list == NULL) || (size == NULL))
+ return -EINVAL;
+
+ *vector = hashmap_get_key_vector(list->head, size, 1);
+ if (*vector == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+int
+bootenv_list_to_num_vector(bootenv_list_t list, size_t *size,
+ uint32_t **vector)
+{
+ int rc = 0;
+ size_t i;
+ uint32_t* res = NULL;
+ char *endptr = NULL;
+ const char **a = NULL;
+
+ rc = bootenv_list_to_vector(list, size, &a);
+ if (rc != 0)
+ goto err;
+
+ res = (uint32_t*) malloc (*size * sizeof(uint32_t));
+ if (!res)
+ goto err;
+
+ for (i = 0; i < *size; i++) {
+ res[i] = strtoul(a[i], &endptr, 0);
+ if (*endptr != '\0')
+ goto err;
+ }
+
+ if (a)
+ free(a);
+ *vector = res;
+ return 0;
+
+err:
+ if (a)
+ free(a);
+ if (res)
+ free(res);
+ return rc;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h b/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h
new file mode 100644
index 00000000000..8fecdbf4179
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h
@@ -0,0 +1,434 @@
+#ifndef __BOOTENV_H__
+#define __BOOTENV_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h> /* FILE */
+#include <stdint.h>
+#include <pfiflash.h>
+
+/* DOXYGEN DOCUMENTATION */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file bootenv.h
+ * @author oliloh@de.ibm.com
+ * @version 1.3
+ *
+ * 1.3 Some renaming
+ */
+
+/**
+ * @mainpage Usage
+ *
+ * @section intro Introduction
+ * This library provides all functionality to handle with the so-called
+ * platform description data (PDD) and the bootparameters defined in
+ * U-Boot. It is able to apply the defined PDD operations in PDD update
+ * scenarios. For more information about the PDD and bootparameter
+ * environment "bootenv" confer the PDD documentation.
+ *
+ * @section ret Return codes
+ * This library defines some return codes which will be delivered classified
+ * as warnings or errors. See the "Defines" section for details and numeric
+ * values.
+ *
+ * @section benv Bootenv format description
+ * There are two different input formats:
+ * - text files
+ * - binary files
+ *
+ * @subsection txt Text Files
+ * Text files have to be specified like:
+ * @verbatim key1=value1,value2,value7\n key2=value55,value1\n key4=value1\n@endverbatim
+ *
+ * @subsection bin Binary files
+ * Binary files have to be specified like:
+ * @verbatim<CRC32-bit>key1=value1,value2,value7\0key2=value55,value1\0... @endverbatim
+ * You can confer the U-Boot documentation for more details.
+ *
+ * @section benvlists Bootenv lists format description.
+ * Values referenced in the preceeding subsection can be
+ * defined like lists:
+ * @verbatim value1,value2,value3 @endverbatim
+ * There are some situation where a conversion of a comma
+ * seperated list can be useful, e.g. to get a list
+ * of defined PDD entries.
+ */
+
+#define BOOTENV_MAXSIZE (1024 * 100) /* max 100kiB space for bootenv */
+
+/**
+ * @def BOOTENV_ECRC
+ * @brief Given binary file is to large.
+ * @def BOOTENV_EFMT
+ * @brief Given bootenv section has an invalid format
+ * @def BOOTENV_EBADENTRY
+ * @brief Bad entry in the bootenv section.
+ * @def BOOTENV_EINVAL
+ * @brief Invalid bootenv defintion.
+ * @def BOOTENV_ENOPDD
+ * @brief Given bootenv sectoin has no PDD defintion string (pdd=...).
+ * @def BOOTENV_EPDDINVAL
+ * @brief Given bootenv section has an invalid PDD defintion.
+ * @def BOOTENV_ENOTIMPL
+ * @brief Functionality not implemented.
+ * @def BOOTENV_ECOPY
+ * @brief Bootenv memory copy error
+ * @def BOOTENV_ENOTFOUND
+ * @brief Given key has has no value.
+ * @def BOOTENV_EMAX
+ * @brief Highest error value.
+ */
+#define BOOTENV_ETOOBIG 1
+#define BOOTENV_EFMT 2
+#define BOOTENV_EBADENTRY 3
+#define BOOTENV_EINVAL 4
+#define BOOTENV_ENOPDD 5
+#define BOOTENV_EPDDINVAL 6
+#define BOOTENV_ENOTIMPL 7
+#define BOOTENV_ECOPY 8
+#define BOOTENV_ENOTFOUND 9
+#define BOOTENV_EMAX 10
+
+/**
+ * @def BOOTENV_W
+ * @brief A warning which is handled internally as an error
+ * but can be recovered by manual effort.
+ * @def BOOTENV_WPDD_STRING_DIFFERS
+ * @brief The PDD strings of old and new PDD differ and
+ * can cause update problems, because new PDD values
+ * are removed from the bootenv section completely.
+ */
+#define BOOTENV_W 20
+#define BOOTENV_WPDD_STRING_DIFFERS 21
+#define BOOTENV_WMAX 22 /* highest warning value */
+
+
+typedef struct bootenv *bootenv_t;
+ /**< A bootenv library handle. */
+
+typedef struct bootenv_list *bootenv_list_t;
+ /**< A handle for a value list. */
+
+typedef int(*pdd_func_t)(bootenv_t, bootenv_t, bootenv_t*,
+ int*, char*, size_t);
+
+
+/**
+ * @brief Get a new handle.
+ * @return 0
+ * @return or error
+ * */
+int bootenv_create(bootenv_t *env);
+
+/**
+ * @brief Cleanup structure.
+ * @param env Bootenv structure which shall be destroyed.
+ * @return 0
+ * @return or error
+ */
+int bootenv_destroy(bootenv_t *env);
+
+/**
+ * @brief Copy a bootenv handle.
+ * @param in The input bootenv.
+ * @param out The copied output bootenv. Discards old data.
+ * @return 0
+ * @return or error
+ */
+int bootenv_copy_bootenv(bootenv_t in, bootenv_t *out);
+
+/**
+ * @brief Looks for a value inside the bootenv data.
+ * @param env Handle to a bootenv structure.
+ * @param key The key.
+ * @return NULL key not found
+ * @return !NULL ptr to value
+ */
+int bootenv_get(bootenv_t env, const char *key, const char **value);
+
+
+/**
+ * @brief Looks for a value inside the bootenv data and converts it to num.
+ * @param env Handle to a bootenv structure.
+ * @param key The key.
+ * @param value A pointer to the resulting numerical value
+ * @return NULL key not found
+ * @return !NULL ptr to value
+ */
+int bootenv_get_num(bootenv_t env, const char *key, uint32_t *value);
+
+/**
+ * @brief Set a bootenv value by key.
+ * @param env Handle to a bootenv structure.
+ * @param key Key.
+ * @param value Value to set.
+ * @return 0
+ * @return or error
+ */
+int bootenv_set(bootenv_t env, const char *key, const char *value);
+
+/**
+ * @brief Remove the given key (and its value) from a bootenv structure.
+ * @param env Handle to a bootenv structure.
+ * @param key Key.
+ * @return 0
+ * @return or error
+ */
+int bootenv_unset(bootenv_t env, const char *key);
+
+
+/**
+ * @brief Get a vector of all keys which are currently set
+ * within a bootenv handle.
+ * @param env Handle to a bootenv structure.
+ * @param size The size of the allocated array structure.
+ * @param sort Flag, if set the vector is sorted ascending.
+ * @return NULL on error.
+ * @return !NULL a pointer to the first element the allocated vector.
+ * @warning Free the allocate memory yourself!
+ */
+int bootenv_get_key_vector(bootenv_t env, size_t *size, int sort,
+ const char ***vector);
+
+/**
+ * @brief Calculate the size in bytes which are necessary to write the
+ * current bootenv section in a *binary file.
+ * @param env bootenv handle.
+ * @param size The size in bytes of the bootenv handle.
+ * @return 0
+ * @return or ERROR.
+ */
+int bootenv_size(bootenv_t env, size_t *size);
+
+/**
+ * @brief Read a binary bootenv file.
+ * @param fp File pointer to input stream.
+ * @param env bootenv handle.
+ * @param size maximum data size.
+ * @return 0
+ * @return or ERROR.
+ */
+int bootenv_read(FILE* fp, bootenv_t env, size_t size);
+
+/**
+ * @param ret_crc return value of crc of read data
+ */
+int bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t *ret_crc);
+
+/**
+ * @brief Read bootenv data from an text/ascii file.
+ * @param fp File pointer to ascii PDD file.
+ * @param env bootenv handle
+ * @return 0
+ * @return or ERROR.
+ */
+int bootenv_read_txt(FILE* fp, bootenv_t env);
+
+/**
+ * @brief Write a bootenv structure to the given location (binary).
+ * @param fp Filepointer to binary file.
+ * @param env Bootenv structure which shall be written.
+ * @return 0
+ * @return or error
+ */
+int bootenv_write(FILE* fp, bootenv_t env);
+
+/**
+ * @param ret_crc return value of crc of read data
+ */
+int bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc);
+
+/**
+ * @brief Write a bootenv structure to the given location (text).
+ * @param fp Filepointer to text file.
+ * @param env Bootenv structure which shall be written.
+ * @return 0
+ * @return or error
+ */
+int bootenv_write_txt(FILE* fp, bootenv_t env);
+
+/**
+ * @brief Compare bootenvs using memcmp().
+ * @param first First bootenv.
+ * @param second Second bootenv.
+ * @return 0 if bootenvs are equal
+ * @return < 0 if error
+ * @return > 0 if unequal
+ */
+int bootenv_compare(bootenv_t first, bootenv_t second);
+
+/**
+ * @brief Prototype for a PDD handling funtion
+ */
+
+/**
+ * @brief The PDD keep operation.
+ * @param env_old The old bootenv structure.
+ * @param env_new The new bootenv structure.
+ * @param env_res The result of PDD keep.
+ * @param warnings A flag which marks any warnings.
+ * @return 0
+ * @return or error
+ * @note For a complete documentation about the algorithm confer the
+ * PDD documentation.
+ */
+int bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new,
+ bootenv_t *env_res, int *warnings,
+ char *err_buf, size_t err_buf_size);
+
+
+/**
+ * @brief The PDD merge operation.
+ * @param env_old The old bootenv structure.
+ * @param env_new The new bootenv structure.
+ * @param env_res The result of merge-pdd.
+ * @param warnings A flag which marks any warnings.
+ * @return 0
+ * @return or error
+ * @note For a complete documentation about the algorithm confer the
+ * PDD documentation.
+ */
+int bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new,
+ bootenv_t *env_res, int *warnings,
+ char *err_buf, size_t err_buf_size);
+
+/**
+ * @brief The PDD overwrite operation.
+ * @param env_old The old bootenv structure.
+ * @param env_new The new bootenv structure.
+ * @param env_res The result of overwrite-pdd.
+ * @param warnings A flag which marks any warnings.
+ * @return 0
+ * @return or error
+ * @note For a complete documentation about the algorithm confer the
+ * PDD documentation.
+ */
+int bootenv_pdd_overwrite(bootenv_t env_new,
+ bootenv_t env_old, bootenv_t *env_res, int *warnings,
+ char *err_buf, size_t err_buf_size);
+
+/**
+ * @brief Dump a bootenv structure to stdout. (Debug)
+ * @param env Handle to a bootenv structure.
+ * @return 0
+ * @return or error
+ */
+int bootenv_dump(bootenv_t env);
+
+/**
+ * @brief Validate a bootenv structure.
+ * @param env Handle to a bootenv structure.
+ * @return 0
+ * @return or error
+ */
+int bootenv_valid(bootenv_t env);
+
+/**
+ * @brief Create a new bootenv list structure.
+ * @return NULL on error
+ * @return or a new list handle.
+ * @note This structure is used to store values in a list.
+ * A useful addition when handling PDD strings.
+ */
+int bootenv_list_create(bootenv_list_t *list);
+
+/**
+ * @brief Destroy a bootenv list structure
+ * @param list Handle to a bootenv list structure.
+ * @return 0
+ * @return or error
+ */
+int bootenv_list_destroy(bootenv_list_t *list);
+
+/**
+ * @brief Import a list from a comma seperated string
+ * @param list Handle to a bootenv list structure.
+ * @param str Comma seperated string list.
+ * @return 0
+ * @return or error
+ */
+int bootenv_list_import(bootenv_list_t list, const char *str);
+
+/**
+ * @brief Export a list to a string of comma seperated values.
+ * @param list Handle to a bootenv list structure.
+ * @return NULL one error
+ * @return or pointer to a newly allocated string.
+ * @warning Free the allocated memory by yourself!
+ */
+int bootenv_list_export(bootenv_list_t list, char **string);
+
+/**
+ * @brief Add an item to the list.
+ * @param list A handle of a list structure.
+ * @param item An item.
+ * @return 0
+ * @return or error
+ */
+int bootenv_list_add(bootenv_list_t list, const char *item);
+
+/**
+ * @brief Remove an item from the list.
+ * @param list A handle of a list structure.
+ * @param item An item.
+ * @return 0
+ * @return or error
+ */
+int bootenv_list_remove(bootenv_list_t list, const char *item);
+
+/**
+ * @brief Check if a given item is in a given list.
+ * @param list A handle of a list structure.
+ * @param item An item.
+ * @return 1 Item is in list.
+ * @return 0 Item is not in list.
+ */
+int bootenv_list_is_in(bootenv_list_t list, const char *item);
+
+
+/**
+ * @brief Convert a list into a vector of all values inside the list.
+ * @param list Handle to a bootenv structure.
+ * @param size The size of the allocated vector structure.
+ * @return 0
+ * @return or error
+ * @warning Free the allocate memory yourself!
+ */
+int bootenv_list_to_vector(bootenv_list_t list, size_t *size,
+ const char ***vector);
+
+/**
+ * @brief Convert a list into a vector of all values inside the list.
+ * @param list Handle to a bootenv structure.
+ * @param size The size of the allocated vector structure.
+ * @return 0
+ * @return or error
+ * @warning Free the allocate memory yourself!
+ */
+int bootenv_list_to_num_vector(bootenv_list_t list, size_t *size,
+ uint32_t **vector);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*__BOOTENV_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/config.h b/drivers/mtd/mtd-utils/ubi-utils/src/config.h
new file mode 100644
index 00000000000..55e60f31e8e
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/config.h
@@ -0,0 +1,28 @@
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Frank Haverkamp
+ */
+
+#define PACKAGE_BUGREPORT \
+ "haver@vnet.ibm.com, dedekind@linutronix.de, or tglx@linutronix.de"
+
+#define ubi_unused __attribute__((unused))
+
+#endif
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/crc32.c b/drivers/mtd/mtd-utils/ubi-utils/src/crc32.c
new file mode 100644
index 00000000000..666e2171f83
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/crc32.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Thomas Gleixner
+ */
+
+/*
+ * CRC32 functions
+ *
+ * Can be compiled as seperate object, but is included into the ipl source
+ * so gcc can inline the functions. We optimize for size so the omission of
+ * the function frame is helpful.
+ *
+ */
+
+#include <stdint.h>
+#include <crc32.h>
+
+/* CRC polynomial */
+#define CRC_POLY 0xEDB88320
+
+/**
+ * init_crc32_table - Initialize crc table
+ *
+ * @table: pointer to the CRC table which must be initialized
+ *
+ * Create CRC32 table for given polynomial. The table is created with
+ * the lowest order term in the highest order bit. So the x^32 term
+ * has to implied in the crc calculation function.
+ */
+void init_crc32_table(uint32_t *table)
+{
+ uint32_t crc;
+ int i, j;
+
+ for (i = 0; i < 256; i++) {
+ crc = i;
+ for (j = 8; j > 0; j--) {
+ if (crc & 1)
+ crc = (crc >> 1) ^ CRC_POLY;
+ else
+ crc >>= 1;
+ }
+ table[i] = crc;
+ }
+}
+
+/**
+ * clc_crc32 - Calculate CRC32 over a buffer
+ *
+ * @table: pointer to the CRC table
+ * @crc: initial crc value
+ * @buf: pointer to the buffer
+ * @len: number of bytes to calc
+ *
+ * Returns the updated crc value.
+ *
+ * The algorithm resembles a hardware shift register, but calculates 8
+ * bit at once.
+ */
+uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf,
+ int len)
+{
+ const unsigned char *p = buf;
+
+ while(--len >= 0)
+ crc = table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
+ return crc;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/crc32.h b/drivers/mtd/mtd-utils/ubi-utils/src/crc32.h
new file mode 100644
index 00000000000..31362b0944c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/crc32.h
@@ -0,0 +1,36 @@
+#ifndef __CRC32_H__
+#define __CRC32_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Author: Thomas Gleixner
+ *
+ * CRC32 functions
+ *
+ * Can be compiled as seperate object, but is included into the ipl source
+ * so gcc can inline the functions. We optimize for size so the omission of
+ * the function frame is helpful.
+ *
+ */
+#include <stdint.h>
+
+void init_crc32_table(uint32_t *table);
+uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, int len);
+
+#endif /* __CRC32_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c b/drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c
new file mode 100644
index 00000000000..da5c2e344c6
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Author: Drake Dowsett, dowsett@de.ibm.com
+ * Contact: Andreas Arnez, arnez@de.ibm.com
+ */
+
+/* see eb_chain.h */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mtd_swab.h>
+#include "unubi_analyze.h"
+#include "crc32.h"
+
+#define COPY(dst, src) \
+ do { \
+ dst = malloc(sizeof(*dst)); \
+ if (dst == NULL) \
+ return -ENOMEM; \
+ memcpy(dst, src, sizeof(*dst)); \
+ } while (0)
+
+
+/**
+ * inserts an eb_info into the chain starting at head, then searching
+ * linearly for the correct position;
+ * new should contain valid vid and ec headers and the data_crc should
+ * already have been checked before insertion, otherwise the chain
+ * could be have un an undesired manner;
+ * returns -ENOMEM if alloc fails, otherwise SHOULD always return 0,
+ * if not, the code reached the last line and returned -EAGAIN,
+ * meaning there is a bug or a case not being handled here;
+ **/
+int
+eb_chain_insert(struct eb_info **head, struct eb_info *new)
+{
+ uint32_t vol, num, ver;
+ uint32_t new_vol, new_num, new_ver;
+ struct eb_info *prev, *cur, *hist, *ins;
+ struct eb_info **prev_ptr;
+
+ if ((head == NULL) || (new == NULL))
+ return 0;
+
+ if (*head == NULL) {
+ COPY(*head, new);
+ (*head)->next = NULL;
+ return 0;
+ }
+
+ new_vol = be32_to_cpu(new->vid.vol_id);
+ new_num = be32_to_cpu(new->vid.lnum);
+ new_ver = be32_to_cpu(new->vid.leb_ver);
+
+ /** TRAVERSE HORIZONTALY **/
+
+ cur = *head;
+ prev = NULL;
+
+ /* traverse until vol_id/lnum align */
+ vol = be32_to_cpu(cur->vid.vol_id);
+ num = be32_to_cpu(cur->vid.lnum);
+ while ((new_vol > vol) || ((new_vol == vol) && (new_num > num))) {
+ /* insert new at end of chain */
+ if (cur->next == NULL) {
+ COPY(ins, new);
+ ins->next = NULL;
+ cur->next = ins;
+ return 0;
+ }
+
+ prev = cur;
+ cur = cur->next;
+ vol = be32_to_cpu(cur->vid.vol_id);
+ num = be32_to_cpu(cur->vid.lnum);
+ }
+
+ if (prev == NULL)
+ prev_ptr = head;
+ else
+ prev_ptr = &(prev->next);
+
+ /* insert new into the middle of chain */
+ if ((new_vol != vol) || (new_num != num)) {
+ COPY(ins, new);
+ ins->next = cur;
+ *prev_ptr = ins;
+ return 0;
+ }
+
+ /** TRAVERSE VERTICALY **/
+
+ hist = cur;
+ prev = NULL;
+
+ /* traverse until versions align */
+ ver = be32_to_cpu(cur->vid.leb_ver);
+ while (new_ver < ver) {
+ /* insert new at bottom of history */
+ if (hist->older == NULL) {
+ COPY(ins, new);
+ ins->next = NULL;
+ ins->older = NULL;
+ hist->older = ins;
+ return 0;
+ }
+
+ prev = hist;
+ hist = hist->older;
+ ver = be32_to_cpu(hist->vid.leb_ver);
+ }
+
+ if (prev == NULL) {
+ /* replace active version */
+ COPY(ins, new);
+ ins->next = hist->next;
+ *prev_ptr = ins;
+
+ /* place cur in vertical histroy */
+ ins->older = hist;
+ hist->next = NULL;
+ return 0;
+ }
+
+ /* insert between versions, beneath active version */
+ COPY(ins, new);
+ ins->next = NULL;
+ ins->older = prev->older;
+ prev->older = ins;
+ return 0;
+}
+
+
+/**
+ * sets the pointer at pos to the position of the first entry in the chain
+ * with of vol_id and, if given, with the same lnum as *lnum;
+ * if there is no entry in the chain, then *pos is NULL on return;
+ * always returns 0;
+ **/
+int
+eb_chain_position(struct eb_info **head, uint32_t vol_id, uint32_t *lnum,
+ struct eb_info **pos)
+{
+ uint32_t vol, num;
+ struct eb_info *cur;
+
+ if ((head == NULL) || (*head == NULL) || (pos == NULL))
+ return 0;
+
+ *pos = NULL;
+
+ cur = *head;
+ while (cur != NULL) {
+ vol = be32_to_cpu(cur->vid.vol_id);
+ num = be32_to_cpu(cur->vid.lnum);
+
+ if ((vol_id == vol) && ((lnum == NULL) || (*lnum == num))) {
+ *pos = cur;
+ return 0;
+ }
+
+ cur = cur->next;
+ }
+
+ return 0;
+}
+
+
+/**
+ * prints to stream, the vol_id, lnum and leb_ver for each entry in the
+ * chain, starting at head;
+ * this is intended for debuging purposes;
+ * always returns 0;
+ *
+ * FIXME I do not like the double list traversion ...
+ **/
+int
+eb_chain_print(FILE* stream, struct eb_info *head)
+{
+ struct eb_info *cur;
+
+ if (stream == NULL)
+ stream = stdout;
+
+ if (head == NULL) {
+ fprintf(stream, "EMPTY\n");
+ return 0;
+ }
+ /* 012345678012345678012345678012301230123 0123 01234567 0123457 01234567*/
+ fprintf(stream, "VOL_ID LNUM LEB_VER EC VID DAT PBLK PADDR DSIZE EC\n");
+ cur = head;
+ while (cur != NULL) {
+ struct eb_info *hist;
+
+ fprintf(stream, "%08x %-8u %08x %-4s%-4s",
+ be32_to_cpu(cur->vid.vol_id),
+ be32_to_cpu(cur->vid.lnum),
+ be32_to_cpu(cur->vid.leb_ver),
+ cur->ec_crc_ok ? "ok":"bad",
+ cur->vid_crc_ok ? "ok":"bad");
+ if (cur->vid.vol_type == UBI_VID_STATIC)
+ fprintf(stream, "%-4s", cur->data_crc_ok ? "ok":"bad");
+ else fprintf(stream, "%-4s", cur->data_crc_ok ? "ok":"ign");
+ fprintf(stream, " %-4d %08x %-8u %-8llu\n", cur->phys_block,
+ cur->phys_addr, be32_to_cpu(cur->vid.data_size),
+ (unsigned long long)be64_to_cpu(cur->ec.ec));
+
+ hist = cur->older;
+ while (hist != NULL) {
+ fprintf(stream, "%08x %-8u %08x %-4s%-4s",
+ be32_to_cpu(hist->vid.vol_id),
+ be32_to_cpu(hist->vid.lnum),
+ be32_to_cpu(hist->vid.leb_ver),
+ hist->ec_crc_ok ? "ok":"bad",
+ hist->vid_crc_ok ? "ok":"bad");
+ if (hist->vid.vol_type == UBI_VID_STATIC)
+ fprintf(stream, "%-4s", hist->data_crc_ok ? "ok":"bad");
+ else fprintf(stream, "%-4s", hist->data_crc_ok ? "ok":"ign");
+ fprintf(stream, " %-4d %08x %-8u %-8llu (*)\n",
+ hist->phys_block, hist->phys_addr,
+ be32_to_cpu(hist->vid.data_size),
+ (unsigned long long)be64_to_cpu(hist->ec.ec));
+
+ hist = hist->older;
+ }
+ cur = cur->next;
+ }
+
+ return 0;
+}
+
+
+/**
+ * frees the memory of the entire chain, starting at head;
+ * head will be NULL on return;
+ * always returns 0;
+ **/
+int
+eb_chain_destroy(struct eb_info **head)
+{
+ if (head == NULL)
+ return 0;
+
+ while (*head != NULL) {
+ struct eb_info *cur;
+ struct eb_info *hist;
+
+ cur = *head;
+ *head = (*head)->next;
+
+ hist = cur->older;
+ while (hist != NULL) {
+ struct eb_info *temp;
+
+ temp = hist;
+ hist = hist->older;
+ free(temp);
+ }
+ free(cur);
+ }
+ return 0;
+}
+
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/error.c b/drivers/mtd/mtd-utils/ubi-utils/src/error.c
new file mode 100644
index 00000000000..4aaedadbbe3
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/error.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <string.h>
+#include "error.h"
+
+#define MAXLINE 4096
+#define MAXWIDTH 80
+
+static FILE *logfp = NULL;
+
+static void err_doit(int, int, const char *, va_list);
+
+int
+read_procfile(FILE *fp_out, const char *procfile)
+{
+ FILE *fp;
+
+ if (!fp_out)
+ return -ENXIO;
+
+ fp = fopen(procfile, "r");
+ if (!fp)
+ return -ENOENT;
+
+ while(!feof(fp)) {
+ int c = fgetc(fp);
+
+ if (c == EOF)
+ return 0;
+
+ if (putc(c, fp_out) == EOF)
+ return -EIO;
+
+ if (ferror(fp))
+ return -EIO;
+ }
+ return fclose(fp);
+}
+
+void
+error_initlog(const char *logfile)
+{
+ if (!logfile)
+ return;
+
+ logfp = fopen(logfile, "a+");
+ read_procfile(logfp, "/proc/cpuinfo");
+}
+
+void
+info_msg(const char *fmt, ...)
+{
+ FILE* fpout;
+ char buf[MAXLINE + 1];
+ va_list ap;
+ int n;
+
+ fpout = stdout;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, MAXLINE, fmt, ap);
+ n = strlen(buf);
+ strcat(buf, "\n");
+
+ fputs(buf, fpout);
+ fflush(fpout);
+ if (fpout != stdout)
+ fclose(fpout);
+
+ va_end(ap);
+ return;
+}
+
+void
+__err_ret(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ err_doit(1, LOG_INFO, fmt, ap);
+ va_end(ap);
+ return;
+}
+
+void
+__err_sys(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ err_doit(1, LOG_ERR, fmt, ap);
+ va_end(ap);
+ exit(EXIT_FAILURE);
+}
+
+
+void
+__err_msg(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ err_doit(0, LOG_INFO, fmt, ap);
+ va_end(ap);
+
+ return;
+}
+
+void
+__err_quit(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ err_doit(0, LOG_ERR, fmt, ap);
+ va_end(ap);
+ exit(EXIT_FAILURE);
+}
+
+void
+__err_dump(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ err_doit(1, LOG_ERR, fmt, ap);
+ va_end(ap);
+ abort(); /* dump core and terminate */
+ exit(EXIT_FAILURE); /* shouldn't get here */
+}
+
+/**
+ * If a logfile is used we must not print on stderr and stdout
+ * anymore. Since pfilfash might be used in a server context, it is
+ * even dangerous to write to those descriptors.
+ */
+static void
+err_doit(int errnoflag, int level __attribute__((unused)),
+ const char *fmt, va_list ap)
+{
+ FILE* fpout;
+ int errno_save, n;
+ char buf[MAXLINE + 1];
+ fpout = stderr;
+
+ errno_save = errno; /* value caller might want printed */
+
+ vsnprintf(buf, MAXLINE, fmt, ap); /* safe */
+
+ n = strlen(buf);
+
+ if (errnoflag)
+ snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
+ strcat(buf, "\n");
+
+ if (logfp) {
+ fputs(buf, logfp);
+ fflush(logfp);
+ return; /* exit when logging completes */
+ }
+
+ if (fpout == stderr) {
+ /* perform line wrap when outputting to stderr */
+ int word_len, post_len, chars;
+ char *buf_ptr;
+ const char *frmt = "%*s%n %n";
+
+ chars = 0;
+ buf_ptr = buf;
+ while (sscanf(buf_ptr, frmt, &word_len, &post_len) != EOF) {
+ int i;
+ char word[word_len + 1];
+ char post[post_len + 1];
+
+ strncpy(word, buf_ptr, word_len);
+ word[word_len] = '\0';
+ buf_ptr += word_len;
+ post_len -= word_len;
+
+ if (chars + word_len > MAXWIDTH) {
+ fputc('\n', fpout);
+ chars = 0;
+ }
+ fputs(word, fpout);
+ chars += word_len;
+
+ if (post_len > 0) {
+ strncpy(post, buf_ptr, post_len);
+ post[post_len] = '\0';
+ buf_ptr += post_len;
+ }
+ for (i = 0; i < post_len; i++) {
+ int inc = 1, chars_new;
+
+ if (post[i] == '\t')
+ inc = 8;
+ if (post[i] == '\n') {
+ inc = 0;
+ chars_new = 0;
+ } else
+ chars_new = chars + inc;
+
+ if (chars_new > MAXWIDTH) {
+ fputc('\n', fpout);
+ chars_new = inc;
+ }
+ fputc(post[i], fpout);
+ chars = chars_new;
+ }
+ }
+ }
+ else
+ fputs(buf, fpout);
+ fflush(fpout);
+ if (fpout != stderr)
+ fclose(fpout);
+
+ return;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/error.h b/drivers/mtd/mtd-utils/ubi-utils/src/error.h
new file mode 100644
index 00000000000..05d807878e9
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/error.h
@@ -0,0 +1,84 @@
+#ifndef __ERROR_H__
+#define __ERROR_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+
+void error_initlog(const char *logfile);
+int read_procfile(FILE *fp_out, const char *procfile);
+
+void __err_ret(const char *fmt, ...);
+void __err_sys(const char *fmt, ...);
+void __err_msg(const char *fmt, ...);
+void __err_quit(const char *fmt, ...);
+void __err_dump(const char *fmt, ...);
+
+void info_msg(const char *fmt, ...);
+
+#ifdef DEBUG
+#define __loc_msg(str) do { \
+ __err_msg("[%s. FILE: %s FUNC: %s LINE: %d]\n", \
+ str, __FILE__, __FUNCTION__, __LINE__); \
+} while (0)
+#else
+#define __loc_msg(str)
+#endif
+
+
+#define err_dump(fmt, ...) do { \
+ __loc_msg("ErrDump"); \
+ __err_dump(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define err_quit(fmt, ...) do { \
+ __loc_msg("ErrQuit"); \
+ __err_quit(fmt, ##__VA_ARGS__); \
+} while (0)
+
+
+#define err_ret(fmt, ...) do { \
+ __loc_msg("ErrRet"); \
+ __err_ret(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define err_sys(fmt, ...) do { \
+ __loc_msg("ErrSys"); \
+ __err_sys(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define err_msg(fmt, ...) do { \
+ __loc_msg("ErrMsg"); \
+ __err_msg(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define log_msg(fmt, ...) do { \
+ /* __loc_msg("LogMsg"); */ \
+ __err_msg(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#ifdef DEBUG
+#define dbg_msg(fmt, ...) do { \
+ __loc_msg("DbgMsg"); \
+ __err_msg(fmt, ##__VA_ARGS__); \
+} while (0)
+#else
+#define dbg_msg(fmt, ...) do {} while (0)
+#endif
+
+#endif /* __ERROR_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h b/drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h
new file mode 100644
index 00000000000..23c7b54ef6a
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h
@@ -0,0 +1,28 @@
+#ifndef __EXAMPLE_UBI_H__
+#define __EXAMPLE_UBI_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ * Defaults for our cards.
+ */
+#define EXAMPLE_UBI_DEVICE 0
+#define EXAMPLE_BOOTENV_VOL_ID_1 4
+#define EXAMPLE_BOOTENV_VOL_ID_2 5
+
+#endif /* __EXAMPLE_UBI_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c b/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c
new file mode 100644
index 00000000000..3511d56c94c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "error.h"
+#include "hashmap.h"
+#define DEFAULT_BUCKETS 4096
+
+#if 0
+#define INFO_MSG(fmt...) do { \
+ info_msg(fmt); \
+} while (0)
+#else
+#define INFO_MSG(fmt...)
+#endif
+
+struct hashentry {
+ char* key; /* key '0' term. str */
+ char* value; /* payload '0' term. str */
+
+ hashentry_t next;
+};
+
+struct hashmap {
+ size_t entries; /* current #entries */
+ size_t maxsize; /* no. of hash buckets */
+ hashentry_t* data; /* array of buckets */
+};
+
+static int
+is_empty(hashentry_t l)
+{
+ return l == NULL ? 1 : 0;
+}
+
+hashmap_t
+hashmap_new(void)
+{
+ hashmap_t res;
+ res = (hashmap_t) calloc(1, sizeof(struct hashmap));
+
+ if (res == NULL)
+ return NULL;
+
+ res->maxsize = DEFAULT_BUCKETS;
+ res->entries = 0;
+
+ res->data = (hashentry_t*)
+ calloc(1, res->maxsize * sizeof(struct hashentry));
+
+ if (res->data == NULL)
+ return NULL;
+
+ return res;
+}
+
+static hashentry_t
+new_entry(const char* key, const char* value)
+{
+ hashentry_t res;
+
+ res = (hashentry_t) calloc(1, sizeof(struct hashentry));
+
+ if (res == NULL)
+ return NULL;
+
+ /* allocate key and value and copy them */
+ res->key = strdup(key);
+ if (res->key == NULL) {
+ free(res);
+ return NULL;
+ }
+
+ res->value = strdup(value);
+ if (res->value == NULL) {
+ free(res->key);
+ free(res);
+ return NULL;
+ }
+
+ res->next = NULL;
+
+ return res;
+}
+
+static hashentry_t
+free_entry(hashentry_t e)
+{
+ if (!is_empty(e)) {
+ if(e->key != NULL) {
+ free(e->key);
+ }
+ if(e->value != NULL)
+ free(e->value);
+ free(e);
+ }
+
+ return NULL;
+}
+
+static hashentry_t
+remove_entry(hashentry_t l, const char* key, size_t* entries)
+{
+ hashentry_t lnext;
+ if (is_empty(l))
+ return NULL;
+
+ if(strcmp(l->key,key) == 0) {
+ lnext = l->next;
+ l = free_entry(l);
+ (*entries)--;
+ return lnext;
+ }
+
+ l->next = remove_entry(l->next, key, entries);
+
+ return l;
+}
+
+static hashentry_t
+insert_entry(hashentry_t l, hashentry_t e, size_t* entries)
+{
+ if (is_empty(l)) {
+ (*entries)++;
+ return e;
+ }
+
+ /* check for update */
+ if (strcmp(l->key, e->key) == 0) {
+ e->next = l->next;
+ l = free_entry(l);
+ return e;
+ }
+
+ l->next = insert_entry(l->next, e, entries);
+ return l;
+}
+
+static hashentry_t
+remove_all(hashentry_t l, size_t* entries)
+{
+ hashentry_t lnext;
+ if (is_empty(l))
+ return NULL;
+
+ lnext = l->next;
+ free_entry(l);
+ (*entries)--;
+
+ return remove_all(lnext, entries);
+}
+
+static const char*
+value_lookup(hashentry_t l, const char* key)
+{
+ if (is_empty(l))
+ return NULL;
+
+ if (strcmp(l->key, key) == 0)
+ return l->value;
+
+ return value_lookup(l->next, key);
+}
+
+static void
+print_all(hashentry_t l)
+{
+ if (is_empty(l)) {
+ printf("\n");
+ return;
+ }
+
+ printf("%s=%s", l->key, l->value);
+ if (!is_empty(l->next)) {
+ printf(",");
+ }
+
+ print_all(l->next);
+}
+
+static void
+keys_to_array(hashentry_t l, const char** a, size_t* i)
+{
+ if (is_empty(l))
+ return;
+
+ a[*i] = l->key;
+ (*i)++;
+
+ keys_to_array(l->next, a, i);
+}
+
+uint32_t
+hash_str(const char* str, uint32_t mapsize)
+{
+ uint32_t hash = 0;
+ uint32_t x = 0;
+ uint32_t i = 0;
+ size_t len = strlen(str);
+
+ for(i = 0; i < len; str++, i++) {
+ hash = (hash << 4) + (*str);
+ if((x = hash & 0xF0000000L) != 0) {
+ hash ^= (x >> 24);
+ hash &= ~x;
+ }
+ }
+
+ return (hash & 0x7FFFFFFF) % mapsize;
+}
+
+
+int
+hashmap_is_empty(hashmap_t map)
+{
+ if (map == NULL)
+ return -EINVAL;
+
+ return map->entries > 0 ? 1 : 0;
+}
+
+const char*
+hashmap_lookup(hashmap_t map, const char* key)
+{
+ uint32_t i;
+
+ if ((map == NULL) || (key == NULL))
+ return NULL;
+
+ i = hash_str(key, map->maxsize);
+
+ return value_lookup(map->data[i], key);
+}
+
+int
+hashmap_add(hashmap_t map, const char* key, const char* value)
+{
+ uint32_t i;
+ hashentry_t entry;
+
+ if ((map == NULL) || (key == NULL) || (value == NULL))
+ return -EINVAL;
+
+ i = hash_str(key, map->maxsize);
+ entry = new_entry(key, value);
+ if (entry == NULL)
+ return -ENOMEM;
+
+ map->data[i] = insert_entry(map->data[i],
+ entry, &map->entries);
+
+ INFO_MSG("HASH_ADD: chain[%d] key:%s val:%s",i, key, value);
+ return 0;
+}
+
+int
+hashmap_remove(hashmap_t map, const char* key)
+{
+ uint32_t i;
+
+ if ((map == NULL) || (key == NULL))
+ return -EINVAL;
+
+ i = hash_str(key, map->maxsize);
+ map->data[i] = remove_entry(map->data[i], key, &map->entries);
+
+ return 0;
+}
+
+size_t
+hashmap_size(hashmap_t map)
+{
+ if (map != NULL)
+ return map->entries;
+ else
+ return 0;
+}
+
+int
+hashmap_free(hashmap_t map)
+{
+ size_t i;
+
+ if (map == NULL)
+ return -EINVAL;
+
+ /* "children" first */
+ for(i = 0; i < map->maxsize; i++) {
+ map->data[i] = remove_all(map->data[i], &map->entries);
+ }
+ free(map->data);
+ free(map);
+
+ return 0;
+}
+
+int
+hashmap_dump(hashmap_t map)
+{
+ size_t i;
+ if (map == NULL)
+ return -EINVAL;
+
+ for(i = 0; i < map->maxsize; i++) {
+ if (map->data[i] != NULL) {
+ printf("[%zd]: ", i);
+ print_all(map->data[i]);
+ }
+ }
+
+ return 0;
+}
+
+static const char**
+sort_key_vector(const char** a, size_t size)
+{
+ /* uses bubblesort */
+ size_t i, j;
+ const char* tmp;
+
+ if (size <= 0)
+ return a;
+
+ for (i = size - 1; i > 0; i--) {
+ for (j = 0; j < i; j++) {
+ if (strcmp(a[j], a[j+1]) > 0) {
+ tmp = a[j];
+ a[j] = a[j+1];
+ a[j+1] = tmp;
+ }
+ }
+ }
+ return a;
+}
+
+const char**
+hashmap_get_key_vector(hashmap_t map, size_t* size, int sort)
+{
+ const char** res;
+ size_t i, j;
+ *size = map->entries;
+
+ res = (const char**) malloc(*size * sizeof(char*));
+ if (res == NULL)
+ return NULL;
+
+ j = 0;
+ for(i=0; i < map->maxsize; i++) {
+ keys_to_array(map->data[i], res, &j);
+ }
+
+ if (sort)
+ res = sort_key_vector(res, *size);
+
+ return res;
+}
+
+int
+hashmap_key_is_in_vector(const char** vec, size_t size, const char* key)
+{
+ size_t i;
+ for (i = 0; i < size; i++) {
+ if (strcmp(vec[i], key) == 0) /* found */
+ return 1;
+ }
+
+ return 0;
+}
+
+const char**
+hashmap_get_update_key_vector(const char** vec1, size_t vec1_size,
+ const char** vec2, size_t vec2_size, size_t* res_size)
+{
+ const char** res;
+ size_t i, j;
+
+ *res_size = vec2_size;
+
+ res = (const char**) malloc(*res_size * sizeof(char*));
+ if (res == NULL)
+ return NULL;
+
+ /* get all keys from vec2 which are not set in vec1 */
+ j = 0;
+ for (i = 0; i < vec2_size; i++) {
+ if (!hashmap_key_is_in_vector(vec1, vec1_size, vec2[i]))
+ res[j++] = vec2[i];
+ }
+
+ *res_size = j;
+ return res;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h b/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h
new file mode 100644
index 00000000000..1b13e9533de
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h
@@ -0,0 +1,49 @@
+#ifndef __HASHMAP_H__
+#define __HASHMAP_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+typedef struct hashentry *hashentry_t;
+typedef struct hashmap *hashmap_t;
+
+hashmap_t hashmap_new(void);
+int hashmap_free(hashmap_t map);
+
+int hashmap_add(hashmap_t map, const char* key, const char* value);
+int hashmap_update(hashmap_t map, const char* key, const char* value);
+int hashmap_remove(hashmap_t map, const char* key);
+const char* hashmap_lookup(hashmap_t map, const char* key);
+
+const char** hashmap_get_key_vector(hashmap_t map, size_t* size, int sort);
+int hashmap_key_is_in_vector(const char** vec, size_t size, const char* key);
+const char** hashmap_get_update_key_vector(const char** vec1, size_t vec1_size,
+ const char** vec2, size_t vec2_size, size_t* res_size);
+
+int hashmap_dump(hashmap_t map);
+
+int hashmap_is_empty(hashmap_t map);
+size_t hashmap_size(hashmap_t map);
+
+uint32_t hash_str(const char* str, uint32_t mapsize);
+
+#endif /* __HASHMAP_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c b/drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c
new file mode 100644
index 00000000000..7e3d3b3ce98
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c
@@ -0,0 +1,1325 @@
+/*
+ * Copyright International Business Machines Corp., 2006, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Authors: Oliver Lohmann <oliloh@de.ibm.com>
+ * Drake Dowsett <dowsett@de.ibm.com>
+ * Contact: Andreas Arnez <anrez@de.ibm.com>
+ */
+
+/* TODO Compare data before writing it. This implies that the volume
+ * parameters are compared first: size, alignment, name, type, ...,
+ * this is the same, compare the data. Volume deletion is deffered
+ * until the difference has been found out.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#define __USE_GNU
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sys/ioctl.h>
+
+#include <libubi.h>
+#include <pfiflash.h>
+
+#include <mtd/ubi-user.h> /* FIXME Is this ok here? */
+#include <mtd/mtd-user.h>
+
+#include "pfiflash_error.h"
+#include "ubimirror.h"
+#include "error.h"
+#include "reader.h"
+#include "example_ubi.h"
+#include "bootenv.h"
+
+/* ubi-header.h and crc32.h needed for CRC checking */
+#include <mtd/ubi-header.h> /* FIXME Is this ok here? */
+#include "crc32.h"
+
+#define ubi_unused __attribute__((unused))
+
+#define COMPARE_BUFFER_SIZE 2048
+
+#define DEFAULT_DEV_PATTERN "/dev/ubi%d"
+#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d"
+
+static const char copyright [] ubi_unused =
+ "Copyright International Business Machines Corp., 2006, 2007";
+
+/* simply clear buffer, then write into front of it */
+#define EBUF(fmt...) \
+ snprintf(err_buf, err_buf_size, fmt);
+
+/* make a history of buffer and then prepend something in front */
+#define EBUF_PREPEND(fmt) \
+ do { \
+ int EBUF_HISTORY_LENGTH = strlen(err_buf); \
+ char EBUF_HISTORY[EBUF_HISTORY_LENGTH + 1]; \
+ strncpy(EBUF_HISTORY, err_buf, EBUF_HISTORY_LENGTH + 1);\
+ EBUF(fmt ": %s", EBUF_HISTORY); \
+ } while (0)
+
+/* An array of PDD function pointers indexed by the algorithm. */
+static pdd_func_t pdd_funcs[PDD_HANDLING_NUM] =
+ {
+ &bootenv_pdd_keep,
+ &bootenv_pdd_merge,
+ &bootenv_pdd_overwrite
+ };
+
+typedef enum ubi_update_process_t {
+ UBI_REMOVE = 0,
+ UBI_WRITE,
+ UBI_COMPARE,
+} ubi_update_process_t;
+
+
+/**
+ * skip_raw_volumes - reads data from pfi to advance fp past raw block
+ * @pfi: fp to pfi data
+ * @pfi_raws: header information
+ *
+ * Error handling):
+ * when early EOF in pfi data
+ * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err
+ * when file I/O error
+ * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err
+ **/
+static int
+skip_raw_volumes(FILE* pfi, list_t pfi_raws,
+ char* err_buf, size_t err_buf_size)
+{
+ int rc;
+ void *i;
+ list_t ptr;
+
+ if (is_empty(pfi_raws))
+ return 0;
+
+ rc = 0;
+ foreach(i, ptr, pfi_raws) {
+ size_t j;
+ pfi_raw_t raw;
+
+ raw = (pfi_raw_t)i;
+ for(j = 0; j < raw->data_size; j++) {
+ int c;
+
+ c = fgetc(pfi);
+ if (c == EOF)
+ rc = -PFIFLASH_ERR_EOF;
+ else if (ferror(pfi))
+ rc = -PFIFLASH_ERR_FIO;
+
+ if (rc != 0)
+ goto err;
+ }
+ }
+
+ err:
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ return rc;
+}
+
+
+/**
+ * my_ubi_mkvol - wraps the ubi_mkvol functions and impl. bootenv update hook
+ * @devno: UBI device number.
+ * @s: Current seqnum.
+ * @u: Information about the UBI volume from the PFI.
+ *
+ * Error handling:
+ * when UBI system couldn't be opened
+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ * when UBI system couldn't create a volume
+ * - returns -PFIFLASH_ERR_UBI_MKVOL, err_buf matches text to err
+ **/
+static int
+my_ubi_mkvol(int devno, int s, pfi_ubi_t u,
+ char *err_buf, size_t err_buf_size)
+{
+ int rc, type;
+ char path[PATH_MAX];
+ libubi_t ulib;
+ struct ubi_mkvol_request req;
+
+ rc = 0;
+ ulib = NULL;
+
+ log_msg("[ ubimkvol id=%d, size=%d, data_size=%d, type=%d, "
+ "alig=%d, nlen=%d, name=%s",
+ u->ids[s], u->size, u->data_size, u->type, u->alignment,
+ strnlen(u->names[s], PFI_UBI_VOL_NAME_LEN), u->names[s]);
+
+ ulib = libubi_open();
+ if (ulib == NULL) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+
+ switch (u->type) {
+ case pfi_ubi_static:
+ type = UBI_STATIC_VOLUME; break;
+ case pfi_ubi_dynamic:
+ default:
+ type = UBI_DYNAMIC_VOLUME;
+ }
+
+ snprintf(path, PATH_MAX, DEFAULT_DEV_PATTERN, devno);
+
+ req.vol_id = u->ids[s];
+ req.alignment = u->alignment;
+ req.bytes = u->size;
+ req.vol_type = type;
+ req.name = u->names[s];
+
+ rc = ubi_mkvol(ulib, path, &req);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_UBI_MKVOL;
+ EBUF(PFIFLASH_ERRSTR[-rc], u->ids[s]);
+ goto err;
+ }
+
+ err:
+ if (ulib != NULL)
+ libubi_close(ulib);
+
+ return rc;
+}
+
+
+/**
+ * my_ubi_rmvol - a wrapper around the UBI library function ubi_rmvol
+ * @devno UBI device number
+ * @id UBI volume id to remove
+ *
+ * If the volume does not exist, the function will return success.
+ *
+ * Error handling:
+ * when UBI system couldn't be opened
+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ * when UBI system couldn't update (truncate) a volume
+ * - returns -PFIFLASH_ERR_UBI_VOL_UPDATE, err_buf matches text to err
+ * when UBI system couldn't remove a volume
+ * - returns -PFIFLASH_ERR_UBI_RMVOL, err_buf matches text to err
+ **/
+static int
+my_ubi_rmvol(int devno, uint32_t id,
+ char *err_buf, size_t err_buf_size)
+{
+ int rc, fd;
+ char path[PATH_MAX];
+ libubi_t ulib;
+
+ rc = 0;
+ ulib = NULL;
+
+ log_msg("[ ubirmvol id=%d", id);
+
+ ulib = libubi_open();
+ if (ulib == NULL) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+
+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id);
+
+ /* truncate whether it exist or not */
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ libubi_close(ulib);
+ return 0; /* not existent, return 0 */
+ }
+
+ rc = ubi_update_start(ulib, fd, 0);
+ close(fd);
+ if (rc < 0) {
+ rc = -PFIFLASH_ERR_UBI_VOL_UPDATE;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
+ goto err; /* if EBUSY than empty device, continue */
+ }
+
+ snprintf(path, PATH_MAX, DEFAULT_DEV_PATTERN, devno);
+
+ rc = ubi_rmvol(ulib, path, id);
+ if (rc != 0) {
+#ifdef DEBUG
+ int rc_old = rc;
+ dbg_msg("Remove UBI volume %d returned with error: %d "
+ "errno=%d", id, rc_old, errno);
+#endif
+
+ rc = -PFIFLASH_ERR_UBI_RMVOL;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
+
+ /* TODO Define a ubi_rmvol return value which says
+ * sth like EUBI_NOSUCHDEV. In this case, a failed
+ * operation is acceptable. Everything else has to be
+ * classified as real error. But talk to Andreas Arnez
+ * before defining something odd...
+ */
+ /* if ((errno == EINVAL) || (errno == ENODEV))
+ return 0; */ /* currently it is EINVAL or ENODEV */
+
+ goto err;
+ }
+
+ err:
+ if (ulib != NULL)
+ libubi_close(ulib);
+
+ return rc;
+}
+
+
+/**
+ * read_bootenv_volume - reads the current bootenv data from id into be_old
+ * @devno UBI device number
+ * @id UBI volume id to remove
+ * @bootenv_old to hold old boot_env data
+ *
+ * Error handling:
+ * when UBI system couldn't be opened
+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ * when UBI system couldn't open a volume to read
+ * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err
+ * when couldn't read bootenv data
+ * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err
+ **/
+static int
+read_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old,
+ char *err_buf, size_t err_buf_size)
+{
+ int rc;
+ FILE* fp_in;
+ char path[PATH_MAX];
+ libubi_t ulib;
+
+ rc = 0;
+ fp_in = NULL;
+ ulib = NULL;
+
+ ulib = libubi_open();
+ if (ulib == NULL) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+
+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id);
+
+ fp_in = fopen(path, "r");
+ if (!fp_in) {
+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
+ goto err;
+ }
+
+ log_msg("[ reading old bootenvs ...");
+
+ /* Save old bootenvs for reference */
+ rc = bootenv_read(fp_in, bootenv_old, BOOTENV_MAXSIZE);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_READ;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+
+ err:
+ if (fp_in)
+ fclose(fp_in);
+ if (ulib)
+ libubi_close(ulib);
+
+ return rc;
+}
+
+
+/**
+ * write_bootenv_volume - writes data from PFI file int to bootenv UBI volume
+ * @devno UBI device number
+ * @id UBI volume id
+ * @bootend_old old PDD data from machine
+ * @pdd_f function to handle PDD with
+ * @fp_in new pdd data contained in PFI
+ * @fp_in_size data size of new pdd data in PFI
+ * @pfi_crc crc value from PFI header
+ *
+ * Error handling:
+ * when UBI system couldn't be opened
+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ * when bootenv can't be created
+ * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err
+ * when bootenv can't be read
+ * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err
+ * when PDD handling function returns and error
+ * - passes rc and err_buf data
+ * when CRC check fails
+ * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err
+ * when bootenv can't be resized
+ * - returns -PFIFLASH_ERR_BOOTENV_SIZE, err_buf matches text to err
+ * when UBI system couldn't open a volume
+ * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err
+ * when couldn't write bootenv data
+ * - returns -PFIFLASH_ERR_BOOTENV_WRITE, err_buf matches text to err
+ **/
+static int
+write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old,
+ pdd_func_t pdd_f, FILE* fp_in, size_t fp_in_size,
+ uint32_t pfi_crc,
+ char *err_buf, size_t err_buf_size)
+{
+ int rc, warnings, fd_out;
+ uint32_t crc;
+ char path[PATH_MAX];
+ size_t update_size;
+ FILE *fp_out;
+ bootenv_t bootenv_new, bootenv_res;
+ libubi_t ulib;
+
+ rc = 0;
+ warnings = 0;
+ crc = 0;
+ update_size = 0;
+ fp_out = NULL;
+ bootenv_new = NULL;
+ bootenv_res = NULL;
+ ulib = NULL;
+
+ log_msg("[ ubiupdatevol bootenv id=%d, fp_in=%p", id, fp_in);
+
+ /* Workflow:
+ * 1. Apply PDD operation and get the size of the returning
+ * bootenv_res section. Without the correct size it wouldn't
+ * be possible to call UBI update vol.
+ * 2. Call UBI update vol
+ * 3. Get FILE* to vol dev
+ * 4. Write to FILE*
+ */
+
+ ulib = libubi_open();
+ if (ulib == NULL) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+
+ rc = bootenv_create(&bootenv_new);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+ EBUF(PFIFLASH_ERRSTR[-rc], " 'new'");
+ goto err;
+ }
+
+ rc = bootenv_create(&bootenv_res);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+ EBUF(PFIFLASH_ERRSTR[-rc], " 'res'");
+ goto err;
+ }
+
+ rc = bootenv_read_crc(fp_in, bootenv_new, fp_in_size, &crc);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_READ;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ } else if (crc != pfi_crc) {
+ rc = -PFIFLASH_ERR_CRC_CHECK;
+ EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc);
+ goto err;
+ }
+
+ rc = pdd_f(bootenv_old, bootenv_new, &bootenv_res, &warnings,
+ err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("handling PDD");
+ goto err;
+ }
+ else if (warnings)
+ /* TODO do something with warnings */
+ dbg_msg("A warning in the PDD operation occured: %d",
+ warnings);
+
+ rc = bootenv_size(bootenv_res, &update_size);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_SIZE;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+
+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id);
+
+ fd_out = open(path, O_RDWR);
+ if (fd_out < 0) {
+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
+ goto err;
+ }
+ fp_out = fdopen(fd_out, "r+");
+ if (!fp_out) {
+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
+ goto err;
+ }
+ rc = ubi_update_start(ulib, fd_out, update_size);
+ if (rc < 0) {
+ rc = -PFIFLASH_ERR_UBI_VOL_UPDATE;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
+ goto err;
+ }
+
+ rc = bootenv_write(fp_out, bootenv_res);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_WRITE;
+ EBUF(PFIFLASH_ERRSTR[-rc], devno, id);
+ goto err;
+ }
+
+ err:
+ if (ulib != NULL)
+ libubi_close(ulib);
+ if (bootenv_new != NULL)
+ bootenv_destroy(&bootenv_new);
+ if (bootenv_res != NULL)
+ bootenv_destroy(&bootenv_res);
+ if (fp_out)
+ fclose(fp_out);
+
+ return rc;
+}
+
+
+/**
+ * write_normal_volume - writes data from PFI file int to regular UBI volume
+ * @devno UBI device number
+ * @id UBI volume id
+ * @update_size size of data stream
+ * @fp_in PFI data file pointer
+ * @pfi_crc CRC data from PFI header
+ *
+ * Error handling:
+ * when UBI system couldn't be opened
+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ * when UBI system couldn't open a volume
+ * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err
+ * when unexpected EOF is encountered
+ * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err
+ * when file I/O error
+ * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err
+ * when CRC check fails
+ * - retruns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err
+ **/
+static int
+write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in,
+ uint32_t pfi_crc,
+ char *err_buf, size_t err_buf_size)
+{
+ int rc, fd_out;
+ uint32_t crc, crc32_table[256];
+ char path[PATH_MAX];
+ size_t bytes_left;
+ FILE* fp_out;
+ libubi_t ulib;
+
+ rc = 0;
+ crc = UBI_CRC32_INIT;
+ bytes_left = update_size;
+ fp_out = NULL;
+ ulib = NULL;
+
+ log_msg("[ ubiupdatevol id=%d, update_size=%d fp_in=%p",
+ id, update_size, fp_in);
+
+ ulib = libubi_open();
+ if (ulib == NULL) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+
+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id);
+
+ fd_out = open(path, O_RDWR);
+ if (fd_out < 0) {
+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
+ goto err;
+ }
+ fp_out = fdopen(fd_out, "r+");
+ if (!fp_out) {
+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
+ goto err;
+ }
+ rc = ubi_update_start(ulib, fd_out, update_size);
+ if (rc < 0) {
+ rc = -PFIFLASH_ERR_UBI_VOL_UPDATE;
+ EBUF(PFIFLASH_ERRSTR[-rc], id);
+ goto err;
+ }
+
+ init_crc32_table(crc32_table);
+ while (bytes_left) {
+ char buf[1024];
+ size_t to_rw = sizeof buf > bytes_left ?
+ bytes_left : sizeof buf;
+ if (fread(buf, 1, to_rw, fp_in) != to_rw) {
+ rc = -PFIFLASH_ERR_EOF;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+ crc = clc_crc32(crc32_table, crc, buf, to_rw);
+ if (fwrite(buf, 1, to_rw, fp_out) != to_rw) {
+ rc = -PFIFLASH_ERR_FIO;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+ bytes_left -= to_rw;
+ }
+
+ if (crc != pfi_crc) {
+ rc = -PFIFLASH_ERR_CRC_CHECK;
+ EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc);
+ goto err;
+ }
+
+ err:
+ if (fp_out)
+ fclose(fp_out);
+ if (ulib)
+ libubi_close(ulib);
+
+ return rc;
+}
+
+static int compare_bootenv(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size,
+ uint32_t data_size, pdd_func_t pdd_f, char *err_buf,
+ size_t err_buf_size)
+{
+ int rc, warnings = 0;
+ unsigned int i;
+ bootenv_t bootenv_pfi, bootenv_res = NULL, bootenv_flash = NULL;
+
+ rc = bootenv_create(&bootenv_pfi);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+ goto err;
+ }
+
+ rc = bootenv_create(&bootenv_res);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+ goto err;
+ }
+
+ rc = bootenv_read(fp_pfi, bootenv_pfi, data_size);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_READ;
+ goto err;
+ }
+
+ for (i = 0; i < ids_size; i++) {
+ rc = bootenv_create(&bootenv_flash);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+ goto err;
+ }
+
+ rc = bootenv_read(fp_flash[i], bootenv_flash, BOOTENV_MAXSIZE);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_READ;
+ goto err;
+ }
+
+ rc = pdd_f(bootenv_flash, bootenv_pfi, &bootenv_res,
+ &warnings, err_buf, err_buf_size);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_PDD_UNKNOWN;
+ goto err;
+ }
+
+ rc = bootenv_compare(bootenv_flash, bootenv_res);
+ if (rc > 0) {
+ rc = -PFIFLASH_CMP_DIFF;
+ goto err;
+ } else if (rc < 0) {
+ rc = -PFIFLASH_ERR_COMPARE;
+ goto err;
+ }
+
+ bootenv_destroy(&bootenv_flash);
+ bootenv_flash = NULL;
+ }
+
+err:
+ if (bootenv_pfi)
+ bootenv_destroy(&bootenv_pfi);
+ if (bootenv_res)
+ bootenv_destroy(&bootenv_res);
+ if (bootenv_flash)
+ bootenv_destroy(&bootenv_flash);
+
+ return rc;
+}
+
+static int compare_data(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size,
+ uint32_t bytes_left)
+{
+ unsigned int i;
+ size_t read_bytes, rc = 0;
+ char buf_pfi[COMPARE_BUFFER_SIZE];
+ char *buf_flash[ids_size];
+
+ for (i = 0; i < ids_size; i++) {
+ buf_flash[i] = malloc(COMPARE_BUFFER_SIZE);
+ if (!buf_flash[i])
+ return -PFIFLASH_ERR_COMPARE;
+ }
+
+ while (bytes_left) {
+ if (bytes_left > COMPARE_BUFFER_SIZE)
+ read_bytes = COMPARE_BUFFER_SIZE;
+ else
+ read_bytes = bytes_left;
+
+ rc = fread(buf_pfi, 1, read_bytes, fp_pfi);
+ if (rc != read_bytes) {
+ rc = -PFIFLASH_ERR_COMPARE;
+ goto err;
+ }
+
+ for (i = 0; i < ids_size; i++) {
+ rc = fread(buf_flash[i], 1, read_bytes, fp_flash[i]);
+ if (rc != read_bytes) {
+ rc = -PFIFLASH_CMP_DIFF;
+ goto err;
+ }
+
+ rc = memcmp(buf_pfi, buf_flash[i], read_bytes);
+ if (rc != 0) {
+ rc = -PFIFLASH_CMP_DIFF;
+ goto err;
+ }
+ }
+
+ bytes_left -= read_bytes;
+ }
+
+err:
+ for (i = 0; i < ids_size; i++)
+ free(buf_flash[i]);
+
+ return rc;
+}
+
+static int compare_volumes(int devno, pfi_ubi_t u, FILE *fp_pfi,
+ pdd_func_t pdd_f, char *err_buf, size_t err_buf_size)
+{
+ int rc, is_bootenv = 0;
+ unsigned int i;
+ char path[PATH_MAX];
+ libubi_t ulib = NULL;
+ FILE *fp_flash[u->ids_size];
+
+ ulib = libubi_open();
+ if (ulib == NULL) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ goto err;
+ }
+
+ for (i = 0; i < u->ids_size; i++) {
+ if (u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_1 ||
+ u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_2)
+ is_bootenv = 1;
+
+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, u->ids[i]);
+
+ fp_flash[i] = fopen(path, "r");
+ if (fp_flash[i] == NULL) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ goto err;
+ }
+ }
+
+ if (is_bootenv)
+ rc = compare_bootenv(fp_pfi, fp_flash, u->ids_size,
+ u->data_size, pdd_f, err_buf, err_buf_size);
+ else
+ rc = compare_data(fp_pfi, fp_flash, u->ids_size, u->data_size);
+
+err:
+ if (rc < 0)
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+
+ for (i = 0; i < u->ids_size; i++)
+ fclose(fp_flash[i]);
+ if (ulib)
+ libubi_close(ulib);
+
+ return rc;
+}
+
+static int
+erase_mtd_region(FILE* file_p, int start, int length)
+{
+ int rc, fd;
+ erase_info_t erase;
+ mtd_info_t mtdinfo;
+ loff_t offset = start;
+ loff_t end = offset + length;
+
+ fd = fileno(file_p);
+ if (fd < 0)
+ return -PFIFLASH_ERR_MTD_ERASE;
+
+ rc = ioctl(fd, MEMGETINFO, &mtdinfo);
+ if (rc)
+ return -PFIFLASH_ERR_MTD_ERASE;
+
+ /* check for bad blocks in case of NAND flash */
+ if (mtdinfo.type == MTD_NANDFLASH) {
+ while (offset < end) {
+ rc = ioctl(fd, MEMGETBADBLOCK, &offset);
+ if (rc > 0) {
+ return -PFIFLASH_ERR_MTD_ERASE;
+ }
+
+ offset += mtdinfo.erasesize;
+ }
+ }
+
+ erase.start = start;
+ erase.length = length;
+
+ rc = ioctl(fd, MEMERASE, &erase);
+ if (rc) {
+ return -PFIFLASH_ERR_MTD_ERASE;
+ }
+
+ return rc;
+}
+
+/**
+ * process_raw_volumes - writes the raw sections of the PFI data
+ * @pfi PFI data file pointer
+ * @pfi_raws list of PFI raw headers
+ * @rawdev device to use to write raw data
+ *
+ * Error handling:
+ * when early EOF in PFI data
+ * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err
+ * when file I/O error
+ * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err
+ * when CRC check fails
+ * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err
+ * when opening MTD device fails
+ * - reutrns -PFIFLASH_ERR_MTD_OPEN, err_buf matches text to err
+ * when closing MTD device fails
+ * - returns -PFIFLASH_ERR_MTD_CLOSE, err_buf matches text to err
+ **/
+static int
+process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev,
+ char* err_buf, size_t err_buf_size)
+{
+ int rc;
+ char *pfi_data;
+ void *i;
+ uint32_t crc, crc32_table[256];
+ size_t j, k;
+ FILE* mtd = NULL;
+ list_t ptr;
+
+ if (is_empty(pfi_raws))
+ return 0;
+
+ if (rawdev == NULL)
+ return 0;
+
+ rc = 0;
+
+ pfi_data = NULL;
+
+ log_msg("[ rawupdate dev=%s", rawdev);
+
+ crc = UBI_CRC32_INIT;
+ init_crc32_table(crc32_table);
+
+ /* most likely only one element in list, but just in case */
+ foreach(i, ptr, pfi_raws) {
+ pfi_raw_t r = (pfi_raw_t)i;
+
+ /* read in pfi data */
+ if (pfi_data != NULL)
+ free(pfi_data);
+ pfi_data = malloc(r->data_size * sizeof(char));
+ for (j = 0; j < r->data_size; j++) {
+ int c = fgetc(pfi);
+ if (c == EOF) {
+ rc = -PFIFLASH_ERR_EOF;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ } else if (ferror(pfi)) {
+ rc = -PFIFLASH_ERR_FIO;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+ pfi_data[j] = (char)c;
+ }
+ crc = clc_crc32(crc32_table, crc, pfi_data, r->data_size);
+
+ /* check crc */
+ if (crc != r->crc) {
+ rc = -PFIFLASH_ERR_CRC_CHECK;
+ EBUF(PFIFLASH_ERRSTR[-rc], r->crc, crc);
+ goto err;
+ }
+
+ /* open device */
+ mtd = fopen(rawdev, "r+");
+ if (mtd == NULL) {
+ rc = -PFIFLASH_ERR_MTD_OPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc], rawdev);
+ goto err;
+ }
+
+ for (j = 0; j < r->starts_size; j++) {
+ rc = erase_mtd_region(mtd, r->starts[j], r->data_size);
+ if (rc) {
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+
+ fseek(mtd, r->starts[j], SEEK_SET);
+ for (k = 0; k < r->data_size; k++) {
+ int c = fputc((int)pfi_data[k], mtd);
+ if (c == EOF) {
+ fclose(mtd);
+ rc = -PFIFLASH_ERR_EOF;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+ if ((char)c != pfi_data[k]) {
+ fclose(mtd);
+ rc = -1;
+ goto err;
+ }
+ }
+ }
+ rc = fclose(mtd);
+ mtd = NULL;
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_MTD_CLOSE;
+ EBUF(PFIFLASH_ERRSTR[-rc], rawdev);
+ goto err;
+ }
+ }
+
+ err:
+ if (mtd != NULL)
+ fclose(mtd);
+ if (pfi_data != NULL)
+ free(pfi_data);
+ return rc;
+}
+
+
+/**
+ * erase_unmapped_ubi_volumes - skip volumes provided by PFI file, clear rest
+ * @devno UBI device number
+ * @pfi_ubis list of UBI header data
+ *
+ * Error handling:
+ * when UBI id is out of bounds
+ * - returns -PFIFLASH_ERR_UBI_VID_OOB, err_buf matches text to err
+ * when UBI volume can't be removed
+ * - passes rc, prepends err_buf with contextual aid
+ **/
+static int
+erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis,
+ char *err_buf, size_t err_buf_size)
+{
+ int rc;
+ uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES];
+ size_t i;
+ list_t ptr;
+ pfi_ubi_t u;
+
+ rc = 0;
+
+ for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++)
+ ubi_volumes[i] = 1;
+
+ foreach(u, ptr, pfi_ubis) {
+ /* iterate over each vol_id */
+ for(i = 0; i < u->ids_size; i++) {
+ if (u->ids[i] >= PFI_UBI_MAX_VOLUMES) {
+ rc = -PFIFLASH_ERR_UBI_VID_OOB;
+ EBUF(PFIFLASH_ERRSTR[-rc], u->ids[i]);
+ goto err;
+ }
+ /* remove from removal list */
+ ubi_volumes[u->ids[i]] = 0;
+ }
+ }
+
+ for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) {
+ if (ubi_volumes[i]) {
+ rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("remove volume failed");
+ goto err;
+ }
+ }
+ }
+
+ err:
+ return rc;
+}
+
+
+/**
+ * process_ubi_volumes - delegate tasks regarding UBI volumes
+ * @pfi PFI data file pointer
+ * @seqnum sequence number
+ * @pfi_ubis list of UBI header data
+ * @bootenv_old storage for current system PDD
+ * @pdd_f function to handle PDD
+ * @ubi_update_process whether reading or writing
+ *
+ * Error handling:
+ * when and unknown ubi_update_process is given
+ * - returns -PFIFLASH_ERR_UBI_UNKNOWN, err_buf matches text to err
+ * otherwise
+ * - passes rc and err_buf
+ **/
+static int
+process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis,
+ bootenv_t bootenv_old, pdd_func_t pdd_f,
+ ubi_update_process_t ubi_update_process,
+ char *err_buf, size_t err_buf_size)
+{
+ int rc;
+ pfi_ubi_t u;
+ list_t ptr;
+
+ rc = 0;
+
+ foreach(u, ptr, pfi_ubis) {
+ int s = seqnum;
+
+ if (s > ((int)u->ids_size - 1))
+ s = 0; /* per default use the first */
+ u->curr_seqnum = s;
+
+ switch (ubi_update_process) {
+ case UBI_REMOVE:
+ /* TODO are all these "EXAMPLE" vars okay? */
+ if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) ||
+ (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) {
+ rc = read_bootenv_volume(EXAMPLE_UBI_DEVICE,
+ u->ids[s], bootenv_old,
+ err_buf, err_buf_size);
+ /* it's okay if there is no bootenv
+ * we're going to write one */
+ if ((rc == -PFIFLASH_ERR_UBI_VOL_FOPEN) ||
+ (rc == -PFIFLASH_ERR_BOOTENV_READ))
+ rc = 0;
+ if (rc != 0)
+ goto err;
+ }
+
+ rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s],
+ err_buf, err_buf_size);
+ if (rc != 0)
+ goto err;
+
+ break;
+ case UBI_WRITE:
+ rc = my_ubi_mkvol(EXAMPLE_UBI_DEVICE, s, u,
+ err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("creating volume");
+ goto err;
+ }
+
+ if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) ||
+ (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) {
+ rc = write_bootenv_volume(EXAMPLE_UBI_DEVICE,
+ u->ids[s],
+ bootenv_old, pdd_f,
+ pfi,
+ u->data_size,
+ u->crc,
+ err_buf,
+ err_buf_size);
+ if (rc != 0)
+ EBUF_PREPEND("bootenv volume");
+ } else {
+ rc = write_normal_volume(EXAMPLE_UBI_DEVICE,
+ u->ids[s],
+ u->data_size, pfi,
+ u->crc,
+ err_buf,
+ err_buf_size);
+ if (rc != 0)
+ EBUF_PREPEND("normal volume");
+ }
+ if (rc != 0)
+ goto err;
+
+ break;
+ case UBI_COMPARE:
+ rc = compare_volumes(EXAMPLE_UBI_DEVICE, u, pfi, pdd_f,
+ err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("compare volume");
+ goto err;
+ }
+
+ break;
+ default:
+ rc = -PFIFLASH_ERR_UBI_UNKNOWN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+ }
+
+ err:
+ return rc;
+}
+
+
+/**
+ * mirror_ubi_volumes - mirror redundant pairs of volumes
+ * @devno UBI device number
+ * @pfi_ubis list of PFI header data
+ *
+ * Error handling:
+ * when UBI system couldn't be opened
+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err
+ **/
+static int
+mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis,
+ char *err_buf, size_t err_buf_size)
+{
+ int rc;
+ uint32_t j;
+ list_t ptr;
+ pfi_ubi_t i;
+ libubi_t ulib;
+
+ rc = 0;
+ ulib = NULL;
+
+ log_msg("[ mirror ...");
+
+ ulib = libubi_open();
+ if (ulib == NULL) {
+ rc = -PFIFLASH_ERR_UBI_OPEN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+
+ /**
+ * Execute all mirror operations on redundant groups.
+ * Create a volume within a redundant group if it does
+ * not exist already (this is a precondition of
+ * ubimirror).
+ */
+ foreach(i, ptr, pfi_ubis) {
+ for (j = 0; j < i->ids_size; j++) {
+ /* skip self-match */
+ if (i->ids[j] == i->ids[i->curr_seqnum])
+ continue;
+
+ rc = my_ubi_rmvol(devno, i->ids[j],
+ err_buf, err_buf_size);
+ if (rc != 0)
+ goto err;
+
+ rc = my_ubi_mkvol(devno, j, i,
+ err_buf, err_buf_size);
+ if (rc != 0)
+ goto err;
+ }
+ }
+
+ foreach(i, ptr, pfi_ubis) {
+ rc = ubimirror(devno, i->curr_seqnum, i->ids, i->ids_size,
+ err_buf, err_buf_size);
+ if (rc != 0)
+ goto err;
+ }
+
+
+ err:
+ if (ulib != NULL)
+ libubi_close(ulib);
+
+ return rc;
+}
+
+
+/**
+ * pfiflash_with_options - exposed func to flash memory with a PFI file
+ * @pfi PFI data file pointer
+ * @complete flag to erase unmapped volumes
+ * @seqnum sequence number
+ * @compare flag to compare
+ * @pdd_handling method to handle pdd (keep, merge, overwrite...)
+ *
+ * Error handling:
+ * when bootenv can't be created
+ * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err
+ * when PFI headers can't be read, or
+ * when fail to skip raw sections, or
+ * when error occurs while processing raw volumes, or
+ * when fail to erase unmapped UBI vols, or
+ * when error occurs while processing UBI volumes, or
+ * when error occurs while mirroring UBI volumes
+ * - passes rc, prepends err_buf with contextual aid
+ **/
+int
+pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare,
+ pdd_handling_t pdd_handling, const char* rawdev,
+ char *err_buf, size_t err_buf_size)
+{
+ int rc;
+ bootenv_t bootenv;
+ pdd_func_t pdd_f;
+
+ if (pfi == NULL)
+ return -EINVAL;
+
+ rc = 0;
+ pdd_f = NULL;
+
+ /* If the user didnt specify a seqnum we start per default
+ * with the index 0 */
+ int curr_seqnum = seqnum < 0 ? 0 : seqnum;
+
+ list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */
+ list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */
+
+ rc = bootenv_create(&bootenv);
+ if (rc != 0) {
+ rc = -PFIFLASH_ERR_BOOTENV_CREATE;
+ EBUF(PFIFLASH_ERRSTR[-rc], "");
+ goto err;
+ }
+
+ rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("reading PFI header");
+ goto err;
+ }
+
+ if (rawdev == NULL || compare)
+ rc = skip_raw_volumes(pfi, pfi_raws, err_buf, err_buf_size);
+ else
+ rc = process_raw_volumes(pfi, pfi_raws, rawdev, err_buf,
+ err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("handling raw section");
+ goto err;
+ }
+
+ if (complete && !compare) {
+ rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis,
+ err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("deleting unmapped UBI volumes");
+ goto err;
+ }
+ }
+
+ if (((int)pdd_handling >= 0) &&
+ (pdd_handling < PDD_HANDLING_NUM))
+ pdd_f = pdd_funcs[pdd_handling];
+ else {
+ rc = -PFIFLASH_ERR_PDD_UNKNOWN;
+ EBUF(PFIFLASH_ERRSTR[-rc]);
+ goto err;
+ }
+
+ if (!compare) {
+ rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv,
+ pdd_f, UBI_REMOVE, err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("removing UBI volumes");
+ goto err;
+ }
+
+ rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv,
+ pdd_f, UBI_WRITE, err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("writing UBI volumes");
+ goto err;
+ }
+
+ if (seqnum < 0) { /* mirror redundant pairs */
+ rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis,
+ err_buf, err_buf_size);
+ if (rc != 0) {
+ EBUF_PREPEND("mirroring UBI volumes");
+ goto err;
+ }
+ }
+ } else {
+ /* only compare volumes, don't alter the content */
+ rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv,
+ pdd_f, UBI_COMPARE, err_buf, err_buf_size);
+
+ if (rc == -PFIFLASH_CMP_DIFF)
+ /* update is necessary, return positive value */
+ rc = 1;
+
+ if (rc < 0) {
+ EBUF_PREPEND("comparing UBI volumes");
+ goto err;
+ }
+ }
+
+ err:
+ pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws);
+ pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis);
+ bootenv_destroy(&bootenv);
+ return rc;
+}
+
+
+/**
+ * pfiflash - passes to pfiflash_with_options
+ * @pfi PFI data file pointer
+ * @complete flag to erase unmapped volumes
+ * @seqnum sequence number
+ * @pdd_handling method to handle pdd (keep, merge, overwrite...)
+ **/
+int
+pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
+ char *err_buf, size_t err_buf_size)
+{
+ return pfiflash_with_options(pfi, complete, seqnum, 0, pdd_handling,
+ NULL, err_buf, err_buf_size);
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/libubi.c b/drivers/mtd/mtd-utils/ubi-utils/src/libubi.c
new file mode 100644
index 00000000000..a028fc6dde7
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/libubi.c
@@ -0,0 +1,915 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * UBI (Unsorted Block Images) library.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+#include "libubi.h"
+#include "libubi_int.h"
+
+libubi_t libubi_open(void)
+{
+ int fd, version;
+ struct libubi *lib;
+
+ lib = calloc(1, sizeof(struct libubi));
+ if (!lib)
+ return NULL;
+
+ /* TODO: this must be discovered instead */
+ lib->sysfs = strdup("/sys");
+ if (!lib->sysfs)
+ goto error;
+
+ lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI);
+ if (!lib->sysfs_ubi)
+ goto error;
+
+ /* Make sure UBI is present */
+ fd = open(lib->sysfs_ubi, O_RDONLY);
+ if (fd == -1)
+ goto error;
+ close(fd);
+
+ lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT);
+ if (!lib->ubi_dev)
+ goto error;
+
+ lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER);
+ if (!lib->ubi_version)
+ goto error;
+
+ lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV);
+ if (!lib->dev_dev)
+ goto error;
+
+ lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS);
+ if (!lib->dev_avail_ebs)
+ goto error;
+
+ lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS);
+ if (!lib->dev_total_ebs)
+ goto error;
+
+ lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT);
+ if (!lib->dev_bad_count)
+ goto error;
+
+ lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE);
+ if (!lib->dev_eb_size)
+ goto error;
+
+ lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC);
+ if (!lib->dev_max_ec)
+ goto error;
+
+ lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD);
+ if (!lib->dev_bad_rsvd)
+ goto error;
+
+ lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS);
+ if (!lib->dev_max_vols)
+ goto error;
+
+ lib->dev_min_io_size = mkpath(lib->ubi_dev, DEV_MIN_IO_SIZE);
+ if (!lib->dev_min_io_size)
+ goto error;
+
+ lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT);
+ if (!lib->ubi_vol)
+ goto error;
+
+ lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE);
+ if (!lib->vol_type)
+ goto error;
+
+ lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV);
+ if (!lib->vol_dev)
+ goto error;
+
+ lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT);
+ if (!lib->vol_alignment)
+ goto error;
+
+ lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES);
+ if (!lib->vol_data_bytes)
+ goto error;
+
+ lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS);
+ if (!lib->vol_rsvd_ebs)
+ goto error;
+
+ lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE);
+ if (!lib->vol_eb_size)
+ goto error;
+
+ lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED);
+ if (!lib->vol_corrupted)
+ goto error;
+
+ lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME);
+ if (!lib->vol_name)
+ goto error;
+
+ if (read_int(lib->ubi_version, &version))
+ goto error;
+ if (version != LIBUBI_UBI_VERSION) {
+ fprintf(stderr, "LIBUBI: this library was made for UBI version "
+ "%d, but UBI version %d is detected\n",
+ LIBUBI_UBI_VERSION, version);
+ goto error;
+ }
+
+ return lib;
+
+error:
+ free(lib->vol_corrupted);
+ free(lib->vol_eb_size);
+ free(lib->vol_rsvd_ebs);
+ free(lib->vol_data_bytes);
+ free(lib->vol_alignment);
+ free(lib->vol_dev);
+ free(lib->vol_type);
+ free(lib->ubi_vol);
+ free(lib->dev_min_io_size);
+ free(lib->dev_max_vols);
+ free(lib->dev_bad_rsvd);
+ free(lib->dev_max_ec);
+ free(lib->dev_eb_size);
+ free(lib->dev_bad_count);
+ free(lib->dev_total_ebs);
+ free(lib->dev_avail_ebs);
+ free(lib->dev_dev);
+ free(lib->ubi_version);
+ free(lib->ubi_dev);
+ free(lib->sysfs_ubi);
+ free(lib->sysfs);
+ free(lib);
+ return NULL;
+}
+
+void libubi_close(libubi_t desc)
+{
+ struct libubi *lib = (struct libubi *)desc;
+
+ free(lib->vol_name);
+ free(lib->vol_corrupted);
+ free(lib->vol_eb_size);
+ free(lib->vol_rsvd_ebs);
+ free(lib->vol_data_bytes);
+ free(lib->vol_alignment);
+ free(lib->vol_dev);
+ free(lib->vol_type);
+ free(lib->ubi_vol);
+ free(lib->dev_min_io_size);
+ free(lib->dev_max_vols);
+ free(lib->dev_bad_rsvd);
+ free(lib->dev_max_ec);
+ free(lib->dev_eb_size);
+ free(lib->dev_bad_count);
+ free(lib->dev_total_ebs);
+ free(lib->dev_avail_ebs);
+ free(lib->dev_dev);
+ free(lib->ubi_version);
+ free(lib->ubi_dev);
+ free(lib->sysfs_ubi);
+ free(lib->sysfs);
+ free(lib);
+}
+
+int ubi_get_info(libubi_t desc, struct ubi_info *info)
+{
+ DIR *sysfs_ubi;
+ struct dirent *dirent;
+ struct libubi *lib = (struct libubi *)desc;
+
+ memset(info, '\0', sizeof(struct ubi_info));
+
+ /*
+ * We have to scan the UBI sysfs directory to identify how many UBI
+ * devices are present.
+ */
+ sysfs_ubi = opendir(lib->sysfs_ubi);
+ if (!sysfs_ubi)
+ return -1;
+
+ info->lowest_dev_num = INT_MAX;
+ while ((dirent = readdir(sysfs_ubi))) {
+ char *name = &dirent->d_name[0];
+ int dev_num, ret;
+
+ ret = sscanf(name, UBI_DEV_NAME_PATT, &dev_num);
+ if (ret == 1) {
+ info->dev_count += 1;
+ if (dev_num > info->highest_dev_num)
+ info->highest_dev_num = dev_num;
+ if (dev_num < info->lowest_dev_num)
+ info->lowest_dev_num = dev_num;
+ }
+ }
+
+ if (info->lowest_dev_num == INT_MAX)
+ info->lowest_dev_num = 0;
+
+ if (read_int(lib->ubi_version, &info->version))
+ goto close;
+
+ return closedir(sysfs_ubi);
+
+close:
+ closedir(sysfs_ubi);
+ return -1;
+}
+
+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req)
+{
+ int fd, ret;
+ struct ubi_mkvol_req r;
+ size_t n;
+
+ desc = desc;
+ r.vol_id = req->vol_id;
+ r.alignment = req->alignment;
+ r.bytes = req->bytes;
+ r.vol_type = req->vol_type;
+
+ n = strlen(req->name);
+ if (n > UBI_MAX_VOLUME_NAME)
+ return -1;
+
+ strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME + 1);
+ r.name_len = n;
+
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ ret = ioctl(fd, UBI_IOCMKVOL, &r);
+ if (!ret)
+ req->vol_id = r.vol_id;
+
+ close(fd);
+ return ret;
+}
+
+int ubi_rmvol(libubi_t desc, const char *node, int vol_id)
+{
+ int fd, ret;
+
+ desc = desc;
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ ret = ioctl(fd, UBI_IOCRMVOL, &vol_id);
+ close(fd);
+ return ret;
+}
+
+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes)
+{
+ int fd, ret;
+ struct ubi_rsvol_req req;
+
+ desc = desc;
+ fd = open(node, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ req.bytes = bytes;
+ req.vol_id = vol_id;
+
+ ret = ioctl(fd, UBI_IOCRSVOL, &req);
+ close(fd);
+ return ret;
+}
+
+int ubi_update_start(libubi_t desc, int fd, long long bytes)
+{
+ desc = desc;
+ if (ioctl(fd, UBI_IOCVOLUP, &bytes))
+ return -1;
+ return 0;
+}
+
+int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info)
+{
+ int dev_num;
+ struct libubi *lib = (struct libubi *)desc;
+
+ dev_num = find_dev_num(lib, node);
+ if (dev_num == -1)
+ return -1;
+
+ return ubi_get_dev_info1(desc, dev_num, info);
+}
+
+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info)
+{
+ DIR *sysfs_ubi;
+ struct dirent *dirent;
+ struct libubi *lib = (struct libubi *)desc;
+
+ memset(info, '\0', sizeof(struct ubi_dev_info));
+ info->dev_num = dev_num;
+
+ sysfs_ubi = opendir(lib->sysfs_ubi);
+ if (!sysfs_ubi)
+ return -1;
+
+ info->lowest_vol_num = INT_MAX;
+ while ((dirent = readdir(sysfs_ubi))) {
+ char *name = &dirent->d_name[0];
+ int vol_id, ret, devno;
+
+ ret = sscanf(name, UBI_VOL_NAME_PATT, &devno, &vol_id);
+ if (ret == 2 && devno == dev_num) {
+ info->vol_count += 1;
+ if (vol_id > info->highest_vol_num)
+ info->highest_vol_num = vol_id;
+ if (vol_id < info->lowest_vol_num)
+ info->lowest_vol_num = vol_id;
+ }
+ }
+
+ closedir(sysfs_ubi);
+
+ if (info->lowest_vol_num == INT_MAX)
+ info->lowest_vol_num = 0;
+
+ if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_ebs))
+ return -1;
+ if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_ebs))
+ return -1;
+ if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count))
+ return -1;
+ if (dev_read_int(lib->dev_eb_size, dev_num, &info->eb_size))
+ return -1;
+ if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd))
+ return -1;
+ if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec))
+ return -1;
+ if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count))
+ return -1;
+ if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size))
+ return -1;
+
+ info->avail_bytes = info->avail_ebs * info->eb_size;
+ info->total_bytes = info->total_ebs * info->eb_size;
+
+ return 0;
+}
+
+int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info)
+{
+ int vol_id, dev_num;
+ struct libubi *lib = (struct libubi *)desc;
+
+ dev_num = find_dev_num_vol(lib, node);
+ if (dev_num == -1)
+ return -1;
+
+ vol_id = find_vol_num(lib, dev_num, node);
+ if (vol_id == -1)
+ return -1;
+
+ return ubi_get_vol_info1(desc, dev_num, vol_id, info);
+}
+
+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id,
+ struct ubi_vol_info *info)
+{
+ int ret;
+ struct libubi *lib = (struct libubi *)desc;
+ char buf[50];
+
+ memset(info, '\0', sizeof(struct ubi_vol_info));
+ info->dev_num = dev_num;
+ info->vol_id = vol_id;
+
+ ret = vol_read_data(lib->vol_type, dev_num, vol_id, &buf[0], 50);
+ if (ret < 0)
+ return -1;
+
+ if (strncmp(&buf[0], "static\n", ret) == 0)
+ info->type = UBI_STATIC_VOLUME;
+ else if (strncmp(&buf[0], "dynamic\n", ret) == 0)
+ info->type = UBI_DYNAMIC_VOLUME;
+ else {
+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = vol_read_int(lib->vol_alignment, dev_num, vol_id,
+ &info->alignment);
+ if (ret)
+ return -1;
+ ret = vol_read_ll(lib->vol_data_bytes, dev_num, vol_id,
+ &info->data_bytes);
+ if (ret)
+ return -1;
+ ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_ebs);
+ if (ret)
+ return -1;
+ ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->eb_size);
+ if (ret)
+ return -1;
+ ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id,
+ &info->corrupted);
+ if (ret)
+ return -1;
+ info->rsvd_bytes = info->eb_size * info->rsvd_ebs;
+
+ ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name,
+ UBI_VOL_NAME_MAX + 2);
+ if (ret < 0)
+ return -1;
+
+ info->name[ret - 1] = '\0';
+ return 0;
+}
+
+/**
+ * read_int - read an 'int' value from a file.
+ *
+ * @file the file to read from
+ * @value the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int read_int(const char *file, int *value)
+{
+ int fd, rd;
+ char buf[50];
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, &buf[0], 50);
+ if (rd == -1)
+ goto error;
+
+ if (sscanf(&buf[0], "%d\n", value) != 1) {
+ /* This must be a UBI bug */
+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+ errno = EINVAL;
+ goto error;
+ }
+
+ close(fd);
+ return 0;
+
+error:
+ close(fd);
+ return -1;
+}
+
+/**
+ * dev_read_int - read an 'int' value from an UBI device's sysfs file.
+ *
+ * @patt the file pattern to read from
+ * @dev_num UBI device number
+ * @value the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_int(const char *patt, int dev_num, int *value)
+{
+ int fd, rd;
+ char buf[50];
+ char file[strlen(patt) + 50];
+
+ sprintf(&file[0], patt, dev_num);
+ fd = open(&file[0], O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, &buf[0], 50);
+ if (rd == -1)
+ goto error;
+
+ if (sscanf(&buf[0], "%d\n", value) != 1) {
+ /* This must be a UBI bug */
+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+ errno = EINVAL;
+ goto error;
+ }
+
+ close(fd);
+ return 0;
+
+error:
+ close(fd);
+ return -1;
+}
+
+/**
+ * dev_read_ll - read a 'long long' value from an UBI device's sysfs file.
+ *
+ * @patt the file pattern to read from
+ * @dev_num UBI device number
+ * @value the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int dev_read_ll(const char *patt, int dev_num, long long *value)
+{
+ int fd, rd;
+ char buf[50];
+ char file[strlen(patt) + 50];
+
+ sprintf(&file[0], patt, dev_num);
+ fd = open(&file[0], O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, &buf[0], 50);
+ if (rd == -1)
+ goto error;
+
+ if (sscanf(&buf[0], "%lld\n", value) != 1) {
+ /* This must be a UBI bug */
+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+ errno = EINVAL;
+ goto error;
+ }
+
+ close(fd);
+ return 0;
+
+error:
+ close(fd);
+ return -1;
+}
+
+/**
+ * dev_read_data - read data from an UBI device's sysfs file.
+ *
+ * @patt the file pattern to read from
+ * @dev_num UBI device number
+ * @buf buffer to read data to
+ * @buf_len buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure.
+ */
+static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len)
+{
+ int fd, rd;
+ char file[strlen(patt) + 50];
+
+ sprintf(&file[0], patt, dev_num);
+ fd = open(&file[0], O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, buf, buf_len);
+ if (rd == -1) {
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return rd;
+}
+
+/**
+ * vol_read_int - read an 'int' value from an UBI volume's sysfs file.
+ *
+ * @patt the file pattern to read from
+ * @dev_num UBI device number
+ * @vol_id volume identifier
+ * @value the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value)
+{
+ int fd, rd;
+ char buf[50];
+ char file[strlen(patt) + 100];
+
+ sprintf(&file[0], patt, dev_num, vol_id);
+ fd = open(&file[0], O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, &buf[0], 50);
+ if (rd == -1)
+ goto error;
+
+ if (sscanf(&buf[0], "%d\n", value) != 1) {
+ /* This must be a UBI bug */
+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+ errno = EINVAL;
+ goto error;
+ }
+
+ close(fd);
+ return 0;
+
+error:
+ close(fd);
+ return -1;
+}
+
+/**
+ * vol_read_ll - read a 'long long' value from an UBI volume's sysfs file.
+ *
+ * @patt the file pattern to read from
+ * @dev_num UBI device number
+ * @vol_id volume identifier
+ * @value the result is stored here
+ *
+ * This function returns %0 in case of success and %-1 in case of failure.
+ */
+static int vol_read_ll(const char *patt, int dev_num, int vol_id,
+ long long *value)
+{
+ int fd, rd;
+ char buf[50];
+ char file[strlen(patt) + 100];
+
+ sprintf(&file[0], patt, dev_num, vol_id);
+ fd = open(&file[0], O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, &buf[0], 50);
+ if (rd == -1)
+ goto error;
+
+ if (sscanf(&buf[0], "%lld\n", value) != 1) {
+ /* This must be a UBI bug */
+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+ errno = EINVAL;
+ goto error;
+ }
+
+ close(fd);
+ return 0;
+
+error:
+ close(fd);
+ return -1;
+}
+
+/**
+ * vol_read_data - read data from an UBI volume's sysfs file.
+ *
+ * @patt the file pattern to read from
+ * @dev_num UBI device number
+ * @vol_id volume identifier
+ * @buf buffer to read to
+ * @buf_len buffer length
+ *
+ * This function returns number of read bytes in case of success and %-1 in
+ * case of failure.
+ */
+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
+ int buf_len)
+{
+ int fd, rd;
+ char file[strlen(patt) + 100];
+
+ sprintf(&file[0], patt, dev_num, vol_id);
+ fd = open(&file[0], O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rd = read(fd, buf, buf_len);
+ if (rd == -1) {
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return rd;
+}
+
+/**
+ * mkpath - compose full path from 2 given components.
+ *
+ * @path first component
+ * @name second component
+ *
+ * This function returns the resulting path in case of success and %NULL in
+ * case of failure.
+ */
+static char *mkpath(const char *path, const char *name)
+{
+ char *n;
+ int len1 = strlen(path);
+ int len2 = strlen(name);
+
+ n = malloc(len1 + len2 + 2);
+ if (!n)
+ return NULL;
+
+ memcpy(n, path, len1);
+ if (n[len1 - 1] != '/')
+ n[len1++] = '/';
+
+ memcpy(n + len1, name, len2 + 1);
+ return n;
+}
+
+/**
+ * find_dev_num - find UBI device number by its character device node.
+ *
+ * @lib UBI library descriptor
+ * @node UBI character device node name
+ *
+ * This function returns positive UBI device number in case of success and %-1
+ * in case of failure.
+ */
+static int find_dev_num(struct libubi *lib, const char *node)
+{
+ struct stat stat;
+ struct ubi_info info;
+ int i, major, minor;
+
+ if (lstat(node, &stat))
+ return -1;
+
+ if (!S_ISCHR(stat.st_mode)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ major = major(stat.st_rdev);
+ minor = minor(stat.st_rdev);
+
+ if (minor != 0) {
+ errno = -EINVAL;
+ return -1;
+ }
+
+ if (ubi_get_info((libubi_t *)lib, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ int major1, minor1, ret;
+ char buf[50];
+
+ ret = dev_read_data(lib->dev_dev, i, &buf[0], 50);
+ if (ret < 0)
+ return -1;
+
+ ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
+ if (ret != 2) {
+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (minor1 == minor && major1 == major)
+ return i;
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+/**
+ * find_dev_num_vol - find UBI device number by volume character device node.
+ *
+ * @lib UBI library descriptor
+ * @node UBI character device node name
+ *
+ * This function returns positive UBI device number in case of success and %-1
+ * in case of failure.
+ */
+static int find_dev_num_vol(struct libubi *lib, const char *node)
+{
+ struct stat stat;
+ struct ubi_info info;
+ int i, major;
+
+ if (lstat(node, &stat))
+ return -1;
+
+ if (!S_ISCHR(stat.st_mode)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ major = major(stat.st_rdev);
+
+ if (minor(stat.st_rdev) == 0) {
+ errno = -EINVAL;
+ return -1;
+ }
+
+ if (ubi_get_info((libubi_t *)lib, &info))
+ return -1;
+
+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
+ int major1, minor1, ret;
+ char buf[50];
+
+ ret = dev_read_data(lib->dev_dev, i, &buf[0], 50);
+ if (ret < 0)
+ return -1;
+
+ ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
+ if (ret != 2) {
+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (major1 == major)
+ return i;
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+/**
+ * find_vol_num - find UBI volume number by its character device node.
+ *
+ * @lib UBI library descriptor
+ * @dev_num UBI device number
+ * @node UBI volume character device node name
+ *
+ * This function returns positive UBI volume number in case of success and %-1
+ * in case of failure.
+ */
+static int find_vol_num(struct libubi *lib, int dev_num, const char *node)
+{
+ struct stat stat;
+ struct ubi_dev_info info;
+ int i, major, minor;
+
+ if (lstat(node, &stat))
+ return -1;
+
+ if (!S_ISCHR(stat.st_mode)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ major = major(stat.st_rdev);
+ minor = minor(stat.st_rdev);
+
+ if (minor == 0) {
+ errno = -EINVAL;
+ return -1;
+ }
+
+ if (ubi_get_dev_info1((libubi_t *)lib, dev_num, &info))
+ return -1;
+
+ for (i = info.lowest_vol_num; i <= info.highest_vol_num; i++) {
+ int major1, minor1, ret;
+ char buf[50];
+
+ ret = vol_read_data(lib->vol_dev, dev_num, i, &buf[0], 50);
+ if (ret < 0)
+ return -1;
+
+ ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1);
+ if (ret != 2) {
+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (minor1 == minor && major1 == major)
+ return i;
+ }
+
+ errno = ENOENT;
+ return -1;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h b/drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h
new file mode 100644
index 00000000000..e68b79121cb
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Artem B. Bityutskiy
+ *
+ * UBI (Unsorted Block Images) library.
+ */
+
+#ifndef __LIBUBI_INT_H__
+#define __LIBUBI_INT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * UBI heavily makes use of the sysfs file system to interact with users-pace.
+ * The below are pre-define UBI file and directory names.
+ */
+
+#define SYSFS_UBI "class/ubi"
+#define UBI_DEV_NAME_PATT "ubi%d"
+#define UBI_VER "version"
+#define DEV_DEV "dev"
+#define UBI_VOL_NAME_PATT "ubi%d_%d"
+#define DEV_AVAIL_EBS "avail_eraseblocks"
+#define DEV_TOTAL_EBS "total_eraseblocks"
+#define DEV_BAD_COUNT "bad_peb_count"
+#define DEV_EB_SIZE "eraseblock_size"
+#define DEV_MAX_EC "max_ec"
+#define DEV_MAX_RSVD "reserved_for_bad"
+#define DEV_MAX_VOLS "max_vol_count"
+#define DEV_MIN_IO_SIZE "min_io_size"
+#define VOL_TYPE "type"
+#define VOL_DEV "dev"
+#define VOL_ALIGNMENT "alignment"
+#define VOL_DATA_BYTES "data_bytes"
+#define VOL_RSVD_EBS "reserved_ebs"
+#define VOL_EB_SIZE "usable_eb_size"
+#define VOL_CORRUPTED "corrupted"
+#define VOL_NAME "name"
+
+/**
+ * libubi - UBI library description data structure.
+ *
+ * @sysfs sysfs file system path
+ * @sysfs_ubi UBI directory in sysfs
+ * @ubi_dev UBI device sysfs directory pattern
+ * @ubi_version UBI version file sysfs path
+ * @dev_dev UBI device's major/minor numbers file pattern
+ * @dev_avail_ebs count of available eraseblocks sysfs path pattern
+ * @dev_total_ebs total eraseblocks count sysfs path pattern
+ * @dev_bad_count count of bad eraseblocks sysfs path pattern
+ * @dev_eb_size size of UBI device's eraseblocks sysfs path pattern
+ * @dev_max_ec maximum erase counter sysfs path pattern
+ * @dev_bad_rsvd count of physical eraseblock reserved for bad eraseblocks
+ * handling
+ * @dev_max_vols maximum volumes number count sysfs path pattern
+ * @dev_min_io_size minimum I/O unit size sysfs path pattern
+ * @ubi_vol UBI volume sysfs directory pattern
+ * @vol_type volume type sysfs path pattern
+ * @vol_dev volume's major/minor numbers file pattern
+ * @vol_alignment volume alignment sysfs path pattern
+ * @vol_data_bytes volume data size sysfs path pattern
+ * @vol_rsvd_ebs volume reserved size sysfs path pattern
+ * @vol_eb_size volume eraseblock size sysfs path pattern
+ * @vol_corrupted volume corruption flag sysfs path pattern
+ * @vol_name volume name sysfs path pattern
+ */
+struct libubi
+{
+ char *sysfs;
+ char *sysfs_ubi;
+ char *ubi_dev;
+ char *ubi_version;
+ char *dev_dev;
+ char *dev_avail_ebs;
+ char *dev_total_ebs;
+ char *dev_bad_count;
+ char *dev_eb_size;
+ char *dev_max_ec;
+ char *dev_bad_rsvd;
+ char *dev_max_vols;
+ char *dev_min_io_size;
+ char *ubi_vol;
+ char *vol_type;
+ char *vol_dev;
+ char *vol_alignment;
+ char *vol_data_bytes;
+ char *vol_rsvd_ebs;
+ char *vol_eb_size;
+ char *vol_corrupted;
+ char *vol_name;
+ char *vol_max_count;
+};
+
+static int read_int(const char *file, int *value);
+static int dev_read_int(const char *patt, int dev_num, int *value);
+static int dev_read_ll(const char *patt, int dev_num, long long *value);
+static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len);
+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value);
+static int vol_read_ll(const char *patt, int dev_num, int vol_id,
+ long long *value);
+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf,
+ int buf_len);
+static char *mkpath(const char *path, const char *name);
+static int find_dev_num(struct libubi *lib, const char *node);
+static int find_dev_num_vol(struct libubi *lib, const char *node);
+static int find_vol_num(struct libubi *lib, int dev_num, const char *node);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__LIBUBI_INT_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c b/drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c
new file mode 100644
index 00000000000..1fce3f9c3e7
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ *
+ * Add UBI headers to binary data.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <mtd/ubi-header.h>
+#include <mtd_swab.h>
+
+#include "config.h"
+#include "ubigen.h"
+#include "crc32.h"
+
+#define UBI_NAME_SIZE 256
+#define DEFAULT_VID_OFFSET ((DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+static uint32_t crc32_table[256];
+
+struct ubi_info {
+ struct ubi_vid_hdr* v; /* Volume ID header */
+ struct ubi_ec_hdr* ec; /* Erase count header */
+
+ FILE* fp_in; /* Input Stream */
+ FILE* fp_out; /* Output stream */
+
+ size_t eb_size; /* Physical EB size in bytes */
+ size_t leb_size; /* Size of a logical EB in a physical EB */
+ size_t leb_total; /* Total input size in logical EB */
+ size_t alignment; /* Block alignment */
+ size_t data_pad; /* Size of padding in each physical EB */
+
+ size_t bytes_total; /* Total input size in bytes */
+ size_t bytes_read; /* Nymber of read bytes (total) */
+
+ uint32_t blks_written; /* Number of written logical EB */
+
+ uint8_t* buf; /* Allocated buffer */
+ uint8_t* ptr_ec_hdr; /* Pointer to EC hdr in buf */
+ uint8_t* ptr_vid_hdr; /* Pointer to VID hdr in buf */
+ uint8_t* ptr_data; /* Pointer to data region in buf */
+};
+
+
+static uint32_t
+byte_to_blk(uint64_t byte, uint32_t eb_size)
+{
+ return (byte % eb_size) == 0
+ ? (byte / eb_size)
+ : (byte / eb_size) + 1;
+}
+
+static int
+validate_ubi_info(ubi_info_t u)
+{
+ if ((u->v->vol_type != UBI_VID_DYNAMIC) &&
+ (u->v->vol_type != UBI_VID_STATIC)) {
+ return EUBIGEN_INVALID_TYPE;
+ }
+
+ if (be32_to_cpu(u->ec->vid_hdr_offset) < UBI_VID_HDR_SIZE) {
+ return EUBIGEN_INVALID_HDR_OFFSET;
+ }
+
+ return 0;
+}
+
+static int
+skip_blks(ubi_info_t u, uint32_t blks)
+{
+ uint32_t i;
+ size_t read = 0, to_read = 0;
+
+ /* Step to a maximum of leb_total - 1 to keep the
+ restrictions. */
+ for (i = 0; i < MIN(blks, u->leb_total-1); i++) {
+ /* Read in data */
+ to_read = MIN(u->leb_size,
+ (u->bytes_total - u->bytes_read));
+ read = fread(u->ptr_data, 1, to_read, u->fp_in);
+ if (read != to_read) {
+ return -EIO;
+ }
+ u->bytes_read += read;
+ u->blks_written++;
+ }
+
+ return 0;
+}
+
+static void
+clear_buf(ubi_info_t u)
+{
+ memset(u->buf, 0xff, u->eb_size);
+}
+
+static void
+write_ec_hdr(ubi_info_t u)
+{
+ memcpy(u->ptr_ec_hdr, u->ec, UBI_EC_HDR_SIZE);
+}
+
+static int
+fill_data_buffer_from_file(ubi_info_t u, size_t* read)
+{
+ size_t to_read = 0;
+
+ if (u-> fp_in == NULL)
+ return -EIO;
+
+ to_read = MIN(u->leb_size, (u->bytes_total - u->bytes_read));
+ *read = fread(u->ptr_data, 1, to_read, u->fp_in);
+ if (*read != to_read) {
+ return -EIO;
+ }
+ return 0;
+}
+
+static void
+add_static_info(ubi_info_t u, size_t data_size, ubigen_action_t action)
+{
+ uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT,
+ u->ptr_data, data_size);
+
+ u->v->data_size = cpu_to_be32(data_size);
+ u->v->data_crc = cpu_to_be32(crc);
+
+ if (action & BROKEN_DATA_CRC) {
+ u->v->data_crc =
+ cpu_to_be32(be32_to_cpu(u->v->data_crc) + 1);
+ }
+ if (action & BROKEN_DATA_SIZE) {
+ u->v->data_size =
+ cpu_to_be32(be32_to_cpu(u->v->data_size) + 1);
+ }
+}
+
+static void
+write_vid_hdr(ubi_info_t u, ubigen_action_t action)
+{
+ uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT,
+ u->v, UBI_VID_HDR_SIZE_CRC);
+ /* Write VID header */
+ u->v->hdr_crc = cpu_to_be32(crc);
+ if (action & BROKEN_HDR_CRC) {
+ u->v->hdr_crc = cpu_to_be32(be32_to_cpu(u->v->hdr_crc) + 1);
+ }
+ memcpy(u->ptr_vid_hdr, u->v, UBI_VID_HDR_SIZE);
+}
+
+static int
+write_to_output_stream(ubi_info_t u)
+{
+ size_t written;
+
+ written = fwrite(u->buf, 1, u->eb_size, u->fp_out);
+ if (written != u->eb_size) {
+ return -EIO;
+ }
+ return 0;
+}
+
+int
+ubigen_write_leb(ubi_info_t u, ubigen_action_t action)
+{
+ int rc = 0;
+ size_t read = 0;
+
+ clear_buf(u);
+ write_ec_hdr(u);
+
+ rc = fill_data_buffer_from_file(u, &read);
+ if (rc != 0)
+ return rc;
+
+ if (u->v->vol_type == UBI_VID_STATIC) {
+ add_static_info(u, read, action);
+ }
+
+ u->v->lnum = cpu_to_be32(u->blks_written);
+
+ if (action & MARK_AS_UPDATE) {
+ u->v->copy_flag = (u->v->copy_flag)++;
+ }
+
+ write_vid_hdr(u, action);
+ rc = write_to_output_stream(u);
+ if (rc != 0)
+ return rc;
+
+ /* Update current handle */
+ u->bytes_read += read;
+ u->blks_written++;
+ return 0;
+}
+
+int
+ubigen_write_complete(ubi_info_t u)
+{
+ size_t i;
+ int rc = 0;
+
+ for (i = 0; i < u->leb_total; i++) {
+ rc = ubigen_write_leb(u, NO_ERROR);
+ if (rc != 0)
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+ubigen_write_broken_update(ubi_info_t u, uint32_t blk)
+{
+ int rc = 0;
+
+ rc = skip_blks(u, blk);
+ if (rc != 0)
+ return rc;
+
+ rc = ubigen_write_leb(u, MARK_AS_UPDATE | BROKEN_DATA_CRC);
+ if (rc != 0)
+ return rc;
+
+
+ return 0;
+}
+
+void
+dump_info(ubi_info_t u ubi_unused)
+{
+#ifdef DEBUG
+ int err = 0;
+ if (!u) {
+ fprintf(stderr, "<empty>");
+ return;
+ }
+ if (!u->ec) {
+ fprintf(stderr, "<ec-empty>");
+ err = 1;
+ }
+ if (!u->v) {
+ fprintf(stderr, "<v-empty>");
+ err = 1;
+ }
+ if (err) return;
+
+ fprintf(stderr, "ubi volume\n");
+ fprintf(stderr, "version : %8d\n", u->v->version);
+ fprintf(stderr, "vol_id : %8d\n", be32_to_cpu(u->v->vol_id));
+ fprintf(stderr, "vol_type : %8s\n",
+ u->v->vol_type == UBI_VID_STATIC ?
+ "static" : "dynamic");
+ fprintf(stderr, "used_ebs : %8d\n",
+ be32_to_cpu(u->v->used_ebs));
+ fprintf(stderr, "eb_size : 0x%08x\n", u->eb_size);
+ fprintf(stderr, "leb_size : 0x%08x\n", u->leb_size);
+ fprintf(stderr, "data_pad : 0x%08x\n",
+ be32_to_cpu(u->v->data_pad));
+ fprintf(stderr, "leb_total : %8d\n", u->leb_total);
+ fprintf(stderr, "header offs : 0x%08x\n",
+ be32_to_cpu(u->ec->vid_hdr_offset));
+ fprintf(stderr, "bytes_total : %8d\n", u->bytes_total);
+ fprintf(stderr, " + in MiB : %8.2f M\n",
+ ((float)(u->bytes_total)) / 1024 / 1024);
+ fprintf(stderr, "-------------------------------\n\n");
+#else
+ return;
+#endif
+}
+
+int
+ubigen_destroy(ubi_info_t *u)
+{
+ if (u == NULL)
+ return -EINVAL;
+
+ ubi_info_t tmp = *u;
+
+ if (tmp) {
+ if (tmp->v)
+ free(tmp->v);
+ if (tmp->ec)
+ free(tmp->ec);
+ if (tmp->buf)
+ free(tmp->buf);
+ free(tmp);
+ }
+ *u = NULL;
+ return 0;
+}
+
+void
+ubigen_init(void)
+{
+ init_crc32_table(crc32_table);
+}
+
+int
+ubigen_create(ubi_info_t* u, uint32_t vol_id, uint8_t vol_type,
+ uint32_t eb_size, uint64_t ec, uint32_t alignment,
+ uint8_t version, uint32_t vid_hdr_offset, uint8_t compat_flag,
+ size_t data_size, FILE* fp_in, FILE* fp_out)
+{
+ int rc = 0;
+ ubi_info_t res = NULL;
+ uint32_t crc;
+ uint32_t data_offset;
+
+ if (alignment == 0) {
+ rc = EUBIGEN_INVALID_ALIGNMENT;
+ goto ubigen_create_err;
+ }
+ if ((fp_in == NULL) || (fp_out == NULL)) {
+ rc = -EINVAL;
+ goto ubigen_create_err;
+ }
+
+ res = (ubi_info_t) calloc(1, sizeof(struct ubi_info));
+ if (res == NULL) {
+ rc = -ENOMEM;
+ goto ubigen_create_err;
+ }
+
+ res->v = (struct ubi_vid_hdr*) calloc(1, sizeof(struct ubi_vid_hdr));
+ if (res->v == NULL) {
+ rc = -ENOMEM;
+ goto ubigen_create_err;
+ }
+
+ res->ec = (struct ubi_ec_hdr*) calloc(1, sizeof(struct ubi_ec_hdr));
+ if (res->ec == NULL) {
+ rc = -ENOMEM;
+ goto ubigen_create_err;
+ }
+
+ /* data which is needed in the general process */
+ vid_hdr_offset = vid_hdr_offset ? vid_hdr_offset : DEFAULT_VID_OFFSET;
+ data_offset = vid_hdr_offset + UBI_VID_HDR_SIZE;
+ res->bytes_total = data_size;
+ res->eb_size = eb_size ? eb_size : DEFAULT_BLOCKSIZE;
+ res->data_pad = (res->eb_size - data_offset) % alignment;
+ res->leb_size = res->eb_size - data_offset - res->data_pad;
+ res->leb_total = byte_to_blk(data_size, res->leb_size);
+ res->alignment = alignment;
+
+ if ((res->eb_size < (vid_hdr_offset + UBI_VID_HDR_SIZE))) {
+ rc = EUBIGEN_TOO_SMALL_EB;
+ goto ubigen_create_err;
+ }
+ res->fp_in = fp_in;
+ res->fp_out = fp_out;
+
+ /* vid hdr data which doesn't change */
+ res->v->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
+ res->v->version = version ? version : UBI_VERSION;
+ res->v->vol_type = vol_type;
+ res->v->vol_id = cpu_to_be32(vol_id);
+ res->v->compat = compat_flag;
+ res->v->data_pad = cpu_to_be32(res->data_pad);
+
+ /* static only: used_ebs */
+ if (res->v->vol_type == UBI_VID_STATIC) {
+ res->v->used_ebs = cpu_to_be32(byte_to_blk
+ (res->bytes_total,
+ res->leb_size));
+ }
+
+ /* ec hdr (fixed, doesn't change) */
+ res->ec->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
+ res->ec->version = version ? version : UBI_VERSION;
+ res->ec->ec = cpu_to_be64(ec);
+ res->ec->vid_hdr_offset = cpu_to_be32(vid_hdr_offset);
+
+ res->ec->data_offset = cpu_to_be32(data_offset);
+
+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, res->ec,
+ UBI_EC_HDR_SIZE_CRC);
+ res->ec->hdr_crc = cpu_to_be32(crc);
+
+ /* prepare a read buffer */
+ res->buf = (uint8_t*) malloc (res->eb_size * sizeof(uint8_t));
+ if (res->buf == NULL) {
+ rc = -ENOMEM;
+ goto ubigen_create_err;
+ }
+
+ /* point to distinct regions within the buffer */
+ res->ptr_ec_hdr = res->buf;
+ res->ptr_vid_hdr = res->buf + be32_to_cpu(res->ec->vid_hdr_offset);
+ res->ptr_data = res->buf + be32_to_cpu(res->ec->vid_hdr_offset)
+ + UBI_VID_HDR_SIZE;
+
+ rc = validate_ubi_info(res);
+ if (rc != 0) {
+ fprintf(stderr, "Volume validation failed: %d\n", rc);
+ goto ubigen_create_err;
+ }
+
+ dump_info(res);
+ *u = res;
+ return rc;
+
+ ubigen_create_err:
+ if (res) {
+ if (res->v)
+ free(res->v);
+ if (res->ec)
+ free(res->ec);
+ if (res->buf)
+ free(res->buf);
+ free(res);
+ }
+ *u = NULL;
+ return rc;
+}
+
+int
+ubigen_get_leb_size(ubi_info_t u, size_t* size)
+{
+ if (u == NULL)
+ return -EINVAL;
+
+ *size = u->leb_size;
+ return 0;
+}
+
+
+int
+ubigen_get_leb_total(ubi_info_t u, size_t* total)
+{
+ if (u == NULL)
+ return -EINVAL;
+
+ *total = u->leb_total;
+ return 0;
+}
+
+int
+ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes,
+ const char* vol_name, struct ubi_vtbl_record *lvol_rec)
+{
+ uint32_t crc;
+
+ if ((u == NULL) || (vol_name == NULL))
+ return -EINVAL;
+
+ memset(lvol_rec, 0x0, UBI_VTBL_RECORD_SIZE);
+
+ lvol_rec->reserved_pebs =
+ cpu_to_be32(byte_to_blk(reserved_bytes, u->leb_size));
+ lvol_rec->alignment = cpu_to_be32(u->alignment);
+ lvol_rec->data_pad = u->v->data_pad;
+ lvol_rec->vol_type = u->v->vol_type;
+
+ lvol_rec->name_len =
+ cpu_to_be16((uint16_t)strlen((const char*)vol_name));
+
+ memcpy(lvol_rec->name, vol_name, UBI_VOL_NAME_MAX + 1);
+
+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT,
+ lvol_rec, UBI_VTBL_RECORD_SIZE_CRC);
+ lvol_rec->crc = cpu_to_be32(crc);
+
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c b/drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c
new file mode 100644
index 00000000000..d06770edee5
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <memory.h>
+#include <limits.h>
+#include <fcntl.h>
+
+#include <libubi.h>
+#include "ubimirror.h"
+
+#define COMPARE_BUF_SIZE (128 * 1024)
+
+#define DEFAULT_DEV_PATTERN "/dev/ubi%d"
+#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d"
+
+#define EBUF(fmt...) do { \
+ snprintf(err_buf, err_buf_size, fmt); \
+} while (0)
+
+enum {
+ compare_error = -1,
+ seek_error = -2,
+ write_error = -3,
+ read_error = -4,
+ update_error = -5,
+ ubi_error = -6,
+ open_error = -7,
+ close_error = -8,
+ compare_equal = 0,
+ compare_different = 1
+};
+
+/*
+ * Read len number of bytes from fd.
+ * Return 0 on EOF, -1 on error.
+ */
+static ssize_t fill_buffer(int fd, unsigned char *buf, ssize_t len)
+{
+ ssize_t got, have = 0;
+
+ do {
+ got = read(fd, buf + have, len - have);
+ if (got == -1 && errno != EINTR)
+ return -1;
+ have += got;
+ } while (got > 0 && have < len);
+ return have;
+}
+
+/*
+ * Write len number of bytes to fd.
+ * Return bytes written (>= 0), -1 on error.
+ */
+static ssize_t flush_buffer(int fd, unsigned char *buf, ssize_t len)
+{
+ ssize_t done, have = 0;
+
+ do {
+ done = write(fd, buf + have, len - have);
+ if (done == -1 && errno != EINTR)
+ return -1;
+ have += done;
+ } while (done > 0 && have < len);
+ return have;
+}
+
+/*
+ * Compare two files. Return 0, 1, or -1, depending on whether the
+ * files are equal, different, or an error occured.
+ * Return compare-different when target volume can not be read. Might be
+ * an interrupted volume update and then the target device returns -EIO but
+ * can be updated.
+ *
+ * fd_a is source
+ * fd_b is destination
+ */
+static int compare_files(int fd_a, int fd_b)
+{
+ unsigned char buf_a[COMPARE_BUF_SIZE], buf_b[COMPARE_BUF_SIZE];
+ ssize_t len_a, len_b;
+ int rc;
+
+ for (;;) {
+ len_a = fill_buffer(fd_a, buf_a, sizeof(buf_a));
+ if (len_a == -1) {
+ rc = compare_error;
+ break;
+ }
+ len_b = fill_buffer(fd_b, buf_b, sizeof(buf_b));
+ if (len_b == -1) {
+ rc = compare_different;
+ break;
+ }
+ if (len_a != len_b) {
+ rc = compare_different;
+ break;
+ }
+ if (len_a == 0) { /* Size on both files equal and EOF */
+ rc = compare_equal;
+ break;
+ }
+ if (memcmp(buf_a, buf_b, len_a) != 0 ) {
+ rc = compare_different;
+ break;
+ }
+ }
+ /* Position both files at the beginning */
+ if (lseek(fd_a, 0, SEEK_SET) == -1 ||
+ lseek(fd_b, 0, SEEK_SET) == -1)
+ rc = seek_error;
+ return rc;
+}
+
+int vol_get_used_bytes(int vol_fd, unsigned long long *bytes)
+{
+ off_t res;
+
+ res = lseek(vol_fd, 0, SEEK_END);
+ if (res == (off_t)-1)
+ return -1;
+ *bytes = (unsigned long long) res;
+ res = lseek(vol_fd, 0, SEEK_SET);
+ return res == (off_t)-1 ? -1 : 0;
+}
+
+static int copy_files(libubi_t ulib, int fd_in, int fd_out)
+{
+ unsigned char buf_a[COMPARE_BUF_SIZE];
+ ssize_t len_a, len_b;
+ unsigned long long update_size, copied;
+
+ if (vol_get_used_bytes(fd_in, &update_size) == -1 ||
+ ubi_update_start(ulib, fd_out, update_size) == -1)
+ return update_error;
+ for (copied = 0; copied < update_size; copied += len_b ) {
+ len_a = fill_buffer(fd_in, buf_a, sizeof(buf_a));
+ if (len_a == -1)
+ return read_error;
+ if (len_a == 0) /* Reach EOF */
+ return 0;
+ len_b = flush_buffer(fd_out, buf_a, len_a);
+ if (len_b != len_a)
+ return write_error;
+ }
+ return 0;
+}
+
+int ubimirror(uint32_t devno, int seqnum, uint32_t *ids, ssize_t ids_size,
+ char *err_buf, size_t err_buf_size)
+{
+ int rc = 0;
+ uint32_t src_id;
+ char path[PATH_MAX];
+ libubi_t ulib;
+ int fd_in = -1, i = 0, fd_out = -1;
+
+ if (ids_size == 0)
+ return 0;
+ else {
+ if ((seqnum < 0) || (seqnum > (ids_size - 1))) {
+ EBUF("volume id %d out of range", seqnum);
+ return EUBIMIRROR_NO_SRC;
+ }
+ src_id = ids[seqnum];
+ }
+
+ ulib = libubi_open();
+ if (ulib == NULL)
+ return ubi_error;
+
+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, src_id);
+
+ fd_in = open(path, O_RDONLY);
+ if (fd_in == -1) {
+ EBUF("open error source volume %d", ids[i]);
+ rc = open_error;
+ goto err;
+ }
+
+ for (i = 0; i < ids_size; i++) {
+ if (ids[i] == src_id) /* skip self-mirror */
+ continue;
+
+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, ids[i]);
+
+ fd_out = open(path, O_RDWR);
+ if (fd_out < 0){
+ EBUF("open error destination volume %d", ids[i]);
+ rc = open_error;
+ goto err;
+ }
+ rc = compare_files(fd_in, fd_out);
+ if (rc < 0) {
+ EBUF("compare error volume %d and %d", src_id, ids[i]);
+ goto err;
+ } else if (rc == compare_different) {
+ rc = copy_files(ulib, fd_in, fd_out);
+ if (rc != 0) {
+ EBUF("mirror error volume %d to %d", src_id,
+ ids[i]);
+ goto err;
+ }
+ }
+ if ((rc = close(fd_out)) == -1) {
+ EBUF("close error volume %d", ids[i]);
+ rc = close_error;
+ goto err;
+ } else
+ fd_out = -1;
+ }
+err:
+ if (fd_out != -1)
+ close(fd_out);
+ if (fd_in != -1)
+ close(fd_in);
+ if (ulib != NULL)
+ libubi_close(ulib);
+ return rc;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/list.c b/drivers/mtd/mtd-utils/ubi-utils/src/list.c
new file mode 100644
index 00000000000..6eb716bc351
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/list.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include "list.h"
+
+list_t
+mk_empty(void)
+{
+ return (list_t) NULL;
+}
+
+int
+is_empty(list_t l)
+{
+ return l == NULL;
+}
+
+info_t
+head(list_t l)
+{
+ assert(!is_empty(l));
+ return l->info;
+}
+
+list_t
+tail(list_t l)
+{
+ assert(!is_empty(l));
+ return l->next;
+}
+
+list_t
+remove_head(list_t l)
+{
+ list_t res;
+ assert(!is_empty(l));
+
+ res = l->next;
+ free(l);
+ return res;
+}
+
+list_t
+cons(info_t e, list_t l)
+{
+ list_t res = malloc(sizeof(*l));
+ if (!res)
+ return NULL;
+ res->info = e;
+ res->next = l;
+
+ return res;
+}
+
+list_t
+prepend_elem(info_t e, list_t l)
+{
+ return cons(e,l);
+}
+
+list_t
+append_elem(info_t e, list_t l)
+{
+ if (is_empty(l)) {
+ return cons(e,l);
+ }
+ l->next = append_elem(e, l->next);
+
+ return l;
+}
+
+list_t
+insert_sorted(cmp_func_t cmp, info_t e, list_t l)
+{
+ if (is_empty(l))
+ return cons(e, l);
+
+ switch (cmp(e, l->info)) {
+ case -1:
+ case 0:
+ return l;
+ break;
+ case 1:
+ l->next = insert_sorted(cmp, e, l);
+ break;
+ default:
+ break;
+ }
+
+ /* never reached */
+ return NULL;
+}
+
+list_t
+remove_all(free_func_t free_func, list_t l)
+{
+ if (is_empty(l))
+ return l;
+ list_t lnext = l->next;
+
+ if (free_func && l->info) {
+ free_func(&(l->info));
+ }
+ free(l);
+
+ return remove_all(free_func, lnext);
+}
+
+
+info_t
+is_in(cmp_func_t cmp, info_t e, list_t l)
+{
+ return
+ (is_empty(l))
+ ? NULL
+ : (cmp(e, l->info)) == 0 ? l->info : is_in(cmp, e, l->next);
+}
+
+
+void
+apply(process_func_t process_func, list_t l)
+{
+ list_t ptr;
+ void *i;
+ foreach(i, ptr, l) {
+ process_func(i);
+ }
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/list.h b/drivers/mtd/mtd-utils/ubi-utils/src/list.h
new file mode 100644
index 00000000000..e8452a2c475
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/list.h
@@ -0,0 +1,56 @@
+#ifndef __LIST_H__
+#define __LIST_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ */
+
+#include <stdint.h>
+
+#define foreach(elem, ptr, list) \
+ for (elem = list != NULL ? (typeof(elem)) head(list) \
+ : NULL, ptr = list; \
+ ptr != NULL; \
+ ptr = tail(ptr), \
+ elem = (typeof(elem)) ptr ? head(ptr) : NULL)
+
+typedef struct node* list_t;
+typedef void* info_t;
+typedef int (*free_func_t)(info_t*);
+typedef int (*cmp_func_t)(info_t, info_t);
+typedef void (*process_func_t)(info_t);
+
+struct node {
+ list_t next;
+ info_t info;
+};
+
+list_t mk_empty(void);
+int is_empty(list_t l);
+info_t is_in(cmp_func_t cmp, info_t e, list_t l);
+info_t head(list_t l);
+list_t tail(list_t l);
+list_t remove_head(list_t l);
+list_t cons(info_t e, list_t l);
+list_t prepend_elem(info_t e, list_t);
+list_t append_elem(info_t e, list_t);
+list_t remove_all(free_func_t free_func, list_t l);
+list_t insert_sorted(cmp_func_t cmp_func, info_t e, list_t l);
+void apply(process_func_t process_func, list_t l);
+
+#endif /* __LIST_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c b/drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c
new file mode 100644
index 00000000000..952f651fadb
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ *
+ * Create boot-parameter/pdd data from an ASCII-text input file.
+ *
+ * 1.2 Removed argp because we want to use uClibc.
+ * 1.3 Minor cleanup
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <errno.h>
+#include <mtd/ubi-header.h>
+
+#include "config.h"
+#include "bootenv.h"
+#include "error.h"
+
+#define PROGRAM_VERSION "1.3"
+
+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
+ "mkbootenv - processes bootenv text files and convertes "
+ "them into a binary format.\n";
+
+static const char copyright [] __attribute__((unused)) =
+ "Copyright (c) International Business Machines Corp., 2006";
+
+static const char *optionsstr =
+" -c, --copyright Print copyright informatoin.\n"
+" -o, --output=<fname> Write the output data to <output> instead of\n"
+" stdout.\n"
+" -?, --help Give this help list\n"
+" --usage Give a short usage message\n"
+" -V, --version Print program version\n";
+
+static const char *usage =
+"Usage: mkbootenv [-c?V] [-o <output>] [--copyright] [--output=<output>]\n"
+" [--help] [--usage] [--version] [bootenv-txt-file]\n";
+
+struct option long_options[] = {
+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0}
+};
+
+typedef struct myargs {
+ FILE* fp_in;
+ FILE* fp_out;
+
+ char *arg1;
+ char **options; /* [STRING...] */
+} myargs;
+
+static int
+parse_opt(int argc, char **argv, myargs *args)
+{
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "co:?V", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'c':
+ fprintf(stderr, "%s\n", copyright);
+ exit(0);
+ break;
+ case 'o':
+ args->fp_out = fopen(optarg, "wb");
+ if ((args->fp_out) == NULL) {
+ fprintf(stderr, "Cannot open file %s "
+ "for output\n", optarg);
+ exit(1);
+ }
+ break;
+ case '?': /* help */
+ printf("%s", doc);
+ printf("%s", optionsstr);
+ printf("\nReport bugs to %s\n",
+ PACKAGE_BUGREPORT);
+ exit(0);
+ break;
+ case 'V':
+ printf("%s\n", PROGRAM_VERSION);
+ exit(0);
+ break;
+ default:
+ printf("%s", usage);
+ exit(-1);
+ }
+ }
+
+ if (optind < argc) {
+ args->fp_in = fopen(argv[optind++], "rb");
+ if ((args->fp_in) == NULL) {
+ fprintf(stderr, "Cannot open file %s for input\n",
+ argv[optind]);
+ exit(1);
+ }
+ }
+
+ return 0;
+}
+
+int
+main(int argc, char **argv) {
+ int rc = 0;
+ bootenv_t env;
+
+ myargs args = {
+ .fp_in = stdin,
+ .fp_out = stdout,
+ .arg1 = NULL,
+ .options = NULL,
+ };
+
+ parse_opt(argc, argv, &args);
+
+ rc = bootenv_create(&env);
+ if (rc != 0) {
+ err_msg("Cannot create bootenv handle.");
+ goto err;
+ }
+ rc = bootenv_read_txt(args.fp_in, env);
+ if (rc != 0) {
+ err_msg("Cannot read bootenv from input file.");
+ goto err;
+ }
+ rc = bootenv_write(args.fp_out, env);
+ if (rc != 0) {
+ err_msg("Cannot write bootenv to output file.");
+ goto err;
+ }
+
+ if (args.fp_in != stdin) {
+ fclose(args.fp_in);
+ }
+ if (args.fp_out != stdout) {
+ fclose(args.fp_out);
+ }
+
+err:
+ bootenv_destroy(&env);
+ return rc;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c b/drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c
new file mode 100644
index 00000000000..be62e307719
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Frank Haverkamp
+ *
+ * An utility to decompose NAND images and strip OOB off. Not yet finished ...
+ *
+ * 1.2 Removed argp because we want to use uClibc.
+ * 1.3 Minor cleanup
+ * 1.4 Fixed OOB output file
+ * 1.5 Added verbose output and option to set blocksize.
+ * Added split block mode for more convenient analysis.
+ * 1.6 Fixed ECC error detection and correction.
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "config.h"
+#include "nandecc.h"
+
+#define PROGRAM_VERSION "1.6"
+
+#define MAXPATH 1024
+#define MIN(x,y) ((x)<(y)?(x):(y))
+
+struct args {
+ const char *oob_file;
+ const char *output_file;
+ size_t pagesize;
+ size_t blocksize;
+ int split_blocks;
+ size_t in_len; /* size of input file */
+ int correct_ecc;
+
+ /* special stuff needed to get additional arguments */
+ char *arg1;
+ char **options; /* [STRING...] */
+};
+
+static struct args myargs = {
+ .output_file = "data.bin",
+ .oob_file = "oob.bin",
+ .pagesize = 2048,
+ .blocksize = 128 * 1024,
+ .in_len = 0,
+ .split_blocks = 0,
+ .correct_ecc = 0,
+ .arg1 = NULL,
+ .options = NULL,
+};
+
+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
+ "nand2bin - split data and OOB.\n";
+
+static const char *optionsstr =
+" -o, --output=<output> Data output file\n"
+" -O, --oob=<oob> OOB output file\n"
+" -p, --pagesize=<pagesize> NAND pagesize\n"
+" -b, --blocksize=<blocksize> NAND blocksize\n"
+" -s, --split-blocks generate binaries for each block\n"
+" -e, --correct-ecc Correct data according to ECC info\n"
+" -v, --verbose verbose output\n"
+" -?, --help Give this help list\n"
+" --usage Give a short usage message\n";
+
+static const char *usage =
+"Usage: nand2bin [-?] [-o <output>] [-O <oob>] [-p <pagesize>]\n"
+" [--output=<output>] [--oob=<oob>] [--pagesize=<pagesize>] [--help]\n"
+" [--usage] input.mif\n";
+
+static int verbose = 0;
+
+static struct option long_options[] = {
+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
+ { .name = "oob", .has_arg = 1, .flag = NULL, .val = 'O' },
+ { .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' },
+ { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'b' },
+ { .name = "split-blocks", .has_arg = 0, .flag = NULL, .val = 's' },
+ { .name = "correct-ecc", .has_arg = 0, .flag = NULL, .val = 'e' },
+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
+ { NULL, 0, NULL, 0}
+};
+
+/*
+ * str_to_num - Convert string into number and cope with endings like
+ * k, K, kib, KiB for kilobyte
+ * m, M, mib, MiB for megabyte
+ */
+static uint32_t str_to_num(char *str)
+{
+ char *s = str;
+ ulong num = strtoul(s, &s, 0);
+
+ if (*s != '\0') {
+ if (strcmp(s, "KiB") == 0)
+ num *= 1024;
+ else if (strcmp(s, "MiB") == 0)
+ num *= 1024*1024;
+ else {
+ fprintf(stderr, "WARNING: Wrong number format "
+ "\"%s\", check your paramters!\n", str);
+ }
+ }
+ return num;
+}
+
+/*
+ * @brief Parse the arguments passed into the test case.
+ *
+ * @param argc The number of arguments
+ * @param argv The argument list
+ * @param args Pointer to program args structure
+ *
+ * @return error
+ *
+ */
+static int parse_opt(int argc, char **argv, struct args *args)
+{
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "b:eo:O:p:sv?", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'p': /* --pagesize<pagesize> */
+ args->pagesize = str_to_num(optarg);
+ break;
+
+ case 'b': /* --blocksize<blocksize> */
+ args->blocksize = str_to_num(optarg);
+ break;
+
+ case 'v': /* --verbose */
+ verbose++;
+ break;
+
+ case 's': /* --split-blocks */
+ args->split_blocks = 1;
+ break;
+
+ case 'e': /* --correct-ecc */
+ args->correct_ecc = 1;
+ break;
+
+ case 'o': /* --output=<output.bin> */
+ args->output_file = optarg;
+ break;
+
+ case 'O': /* --oob=<oob.bin> */
+ args->oob_file = optarg;
+ break;
+
+ case '?': /* help */
+ printf("Usage: nand2bin [OPTION...] input.mif\n");
+ printf("%s", doc);
+ printf("%s", optionsstr);
+ printf("\nReport bugs to %s\n",
+ PACKAGE_BUGREPORT);
+ exit(0);
+ break;
+
+ case 'V':
+ printf("%s\n", PROGRAM_VERSION);
+ exit(0);
+ break;
+
+ default:
+ printf("%s", usage);
+ exit(-1);
+ }
+ }
+
+ if (optind < argc)
+ args->arg1 = argv[optind++];
+
+ return 0;
+}
+
+static int calc_oobsize(size_t pagesize)
+{
+ switch (pagesize) {
+ case 512: return 16;
+ case 2048: return 64;
+ default:
+ exit(EXIT_FAILURE);
+ }
+ return 0;
+}
+
+static inline void hexdump(FILE *fp, const uint8_t *buf, ssize_t size)
+{
+ int k;
+
+ for (k = 0; k < size; k++) {
+ fprintf(fp, "%02x ", buf[k]);
+ if ((k & 15) == 15)
+ fprintf(fp, "\n");
+ }
+}
+
+static int process_page(uint8_t* buf, uint8_t *oobbuf, size_t pagesize)
+{
+ int eccpoi, oobsize;
+ size_t i;
+
+ switch (pagesize) {
+ case 2048: oobsize = 64; eccpoi = 64 / 2; break;
+ case 512: oobsize = 16; eccpoi = 16 / 2; break;
+ default:
+ fprintf(stderr, "Unsupported page size: %zd\n", pagesize);
+ return -EINVAL;
+ }
+ memset(oobbuf, 0xff, oobsize);
+
+ for (i = 0; i < pagesize; i += 256, eccpoi += 3) {
+ oobbuf[eccpoi++] = 0x0;
+ /* Calculate ECC */
+ nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]);
+ }
+ return 0;
+}
+
+static int bad_marker_offs_in_oob(int pagesize)
+{
+ switch (pagesize) {
+ case 2048: return 0;
+ case 512: return 5;
+ }
+ return -EINVAL;
+}
+
+static int decompose_image(struct args *args, FILE *in_fp,
+ FILE *bin_fp, FILE *oob_fp)
+{
+ int read, rc, page = 0;
+ size_t oobsize = calc_oobsize(args->pagesize);
+ uint8_t *buf = malloc(args->pagesize);
+ uint8_t *oob = malloc(oobsize);
+ uint8_t *calc_oob = malloc(oobsize);
+ uint8_t *calc_buf = malloc(args->pagesize);
+ uint8_t *page_buf;
+ int pages_per_block = args->blocksize / args->pagesize;
+ int eccpoi = 0, eccpoi_start;
+ unsigned int i;
+ int badpos = bad_marker_offs_in_oob(args->pagesize);
+
+ switch (args->pagesize) {
+ case 2048: eccpoi_start = 64 / 2; break;
+ case 512: eccpoi_start = 16 / 2; break;
+ default: exit(EXIT_FAILURE);
+ }
+
+ if (!buf)
+ exit(EXIT_FAILURE);
+ if (!oob)
+ exit(EXIT_FAILURE);
+ if (!calc_oob)
+ exit(EXIT_FAILURE);
+ if (!calc_buf)
+ exit(EXIT_FAILURE);
+
+ while (!feof(in_fp)) {
+ /* read page by page */
+ read = fread(buf, 1, args->pagesize, in_fp);
+ if (ferror(in_fp)) {
+ fprintf(stderr, "I/O Error.");
+ exit(EXIT_FAILURE);
+ }
+ if (read != (ssize_t)args->pagesize)
+ break;
+
+ read = fread(oob, 1, oobsize, in_fp);
+ if (ferror(in_fp)) {
+ fprintf(stderr, "I/O Error.");
+ exit(EXIT_FAILURE);
+ }
+
+ page_buf = buf; /* default is unmodified data */
+
+ if ((page == 0 || page == 1) && (oob[badpos] != 0xff)) {
+ if (verbose)
+ printf("Block %d is bad\n",
+ page / pages_per_block);
+ goto write_data;
+ }
+ if (args->correct_ecc)
+ page_buf = calc_buf;
+
+ process_page(buf, calc_oob, args->pagesize);
+ memcpy(calc_buf, buf, args->pagesize);
+
+ /*
+ * Our oob format uses only the last 3 bytes out of 4.
+ * The first byte is 0x00 when the ECC is generated by
+ * our toolset and 0xff when generated by Linux. This
+ * is to be fixed when we want nand2bin work for other
+ * ECC layouts too.
+ */
+ for (i = 0, eccpoi = eccpoi_start; i < args->pagesize;
+ i += 256, eccpoi += 4)
+ oob[eccpoi] = calc_oob[eccpoi] = 0xff;
+
+ if (verbose && memcmp(oob, calc_oob, oobsize) != 0) {
+ printf("\nECC compare mismatch found at block %d page %d!\n",
+ page / pages_per_block, page % pages_per_block);
+
+ printf("Read out OOB Data:\n");
+ hexdump(stdout, oob, oobsize);
+
+ printf("Calculated OOB Data:\n");
+ hexdump(stdout, calc_oob, oobsize);
+ }
+
+ /* Do correction on subpage base */
+ for (i = 0, eccpoi = eccpoi_start; i < args->pagesize;
+ i += 256, eccpoi += 4) {
+ rc = nand_correct_data(calc_buf + i, &oob[eccpoi + 1],
+ &calc_oob[eccpoi + 1]);
+
+ if (rc == -1)
+ fprintf(stdout, "Uncorrectable ECC error at "
+ "block %d page %d/%d\n",
+ page / pages_per_block,
+ page % pages_per_block, i / 256);
+ else if (rc > 0)
+ fprintf(stdout, "Correctable ECC error at "
+ "block %d page %d/%d\n",
+ page / pages_per_block,
+ page % pages_per_block, i / 256);
+ }
+
+ write_data:
+ rc = fwrite(page_buf, 1, args->pagesize, bin_fp);
+ if (ferror(bin_fp)) {
+ fprintf(stderr, "I/O Error.");
+ exit(EXIT_FAILURE);
+ }
+ rc = fwrite(oob, 1, oobsize, oob_fp);
+ if (ferror(bin_fp)) {
+ fprintf(stderr, "I/O Error.");
+ exit(EXIT_FAILURE);
+ }
+
+ page++;
+ }
+ free(calc_buf);
+ free(calc_oob);
+ free(oob);
+ free(buf);
+ return 0;
+}
+
+static int split_blocks(struct args *args, FILE *in_fp)
+{
+ uint8_t *buf;
+ size_t oobsize = calc_oobsize(args->pagesize);
+ int pages_per_block = args->blocksize / args->pagesize;
+ int block_len = pages_per_block * (args->pagesize + oobsize);
+ int blocks = args->in_len / block_len;
+ char bname[256] = { 0, };
+ int badpos = bad_marker_offs_in_oob(args->pagesize);
+ int bad_blocks = 0, i, bad_block = 0;
+ ssize_t rc;
+ FILE *b;
+
+ buf = malloc(block_len);
+ if (!buf) {
+ perror("Not enough memory");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < blocks; i++) {
+ rc = fread(buf, 1, block_len, in_fp);
+ if (rc != block_len) {
+ fprintf(stderr, "cannot read enough data!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* do block analysis */
+ bad_block = 0;
+ if ((buf[args->pagesize + badpos] != 0xff) ||
+ (buf[2 * args->pagesize + oobsize + badpos] != 0xff)) {
+ bad_blocks++;
+ bad_block = 1;
+ }
+ if ((verbose && bad_block) || (verbose > 1)) {
+ printf("-- (block %d oob of page 0 and 1)\n", i);
+ hexdump(stdout, buf + args->pagesize, oobsize);
+ printf("--\n");
+ hexdump(stdout, buf + 2 * args->pagesize +
+ oobsize, oobsize);
+ }
+
+ /* write complete block out */
+ snprintf(bname, sizeof(bname) - 1, "%s.%d", args->arg1, i);
+ b = fopen(bname, "w+");
+ if (!b) {
+ perror("Cannot open file");
+ exit(EXIT_FAILURE);
+ }
+ rc = fwrite(buf, 1, block_len, b);
+ if (rc != block_len) {
+ fprintf(stderr, "could not write all data!\n");
+ exit(EXIT_FAILURE);
+ }
+ fclose(b);
+ }
+
+ free(buf);
+ if (bad_blocks || verbose)
+ fprintf(stderr, "%d blocks, %d bad blocks\n",
+ blocks, bad_blocks);
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ FILE *in, *bin = NULL, *oob = NULL;
+ struct stat file_info;
+
+ parse_opt(argc, argv, &myargs);
+
+ if (!myargs.arg1) {
+ fprintf(stderr, "Please specify input file!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (lstat(myargs.arg1, &file_info) != 0) {
+ perror("Cannot fetch file size from input file.\n");
+ exit(EXIT_FAILURE);
+ }
+ myargs.in_len = file_info.st_size;
+
+ in = fopen(myargs.arg1, "r");
+ if (!in) {
+ perror("Cannot open file");
+ exit(EXIT_FAILURE);
+ }
+
+ if (myargs.split_blocks) {
+ split_blocks(&myargs, in);
+ goto out;
+ }
+
+ bin = fopen(myargs.output_file, "w+");
+ if (!bin) {
+ perror("Cannot open file");
+ exit(EXIT_FAILURE);
+ }
+ oob = fopen(myargs.oob_file, "w+");
+ if (!oob) {
+ perror("Cannot open file");
+ exit(EXIT_FAILURE);
+ }
+ decompose_image(&myargs, in, bin, oob);
+
+ out:
+ if (in) fclose(in);
+ if (bin) fclose(bin);
+ if (oob) fclose(oob);
+ exit(EXIT_SUCCESS);
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c b/drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c
new file mode 100644
index 00000000000..caa07e2f227
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * ECC algorithm for NAND FLASH. Detects and corrects 1 bit errors in
+ * a 256 bytes of data.
+ *
+ * Reimplement by Thomas Gleixner after staring long enough at the
+ * mess in drivers/mtd/nand/nandecc.c
+ *
+ */
+
+#include "nandecc.h"
+
+static int countbits(uint32_t byte)
+{
+ int res = 0;
+
+ for (;byte; byte >>= 1)
+ res += byte & 0x01;
+ return res;
+}
+
+/**
+ * @dat: data which should be corrected
+ * @read_ecc: ecc information read from flash
+ * @calc_ecc: calculated ecc information from the data
+ * @return: number of corrected bytes
+ * or -1 when no correction is possible
+ */
+int nand_correct_data(uint8_t *dat, const uint8_t *read_ecc,
+ const uint8_t *calc_ecc)
+{
+ uint8_t s0, s1, s2;
+
+ /*
+ * Do error detection
+ *
+ * Be careful, the index magic is due to a pointer to a
+ * uint32_t.
+ */
+ s0 = calc_ecc[0] ^ read_ecc[0];
+ s1 = calc_ecc[1] ^ read_ecc[1];
+ s2 = calc_ecc[2] ^ read_ecc[2];
+
+ if ((s0 | s1 | s2) == 0)
+ return 0;
+
+ /* Check for a single bit error */
+ if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 &&
+ ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 &&
+ ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) {
+
+ uint32_t byteoffs, bitnum;
+
+ byteoffs = (s1 << 0) & 0x80;
+ byteoffs |= (s1 << 1) & 0x40;
+ byteoffs |= (s1 << 2) & 0x20;
+ byteoffs |= (s1 << 3) & 0x10;
+
+ byteoffs |= (s0 >> 4) & 0x08;
+ byteoffs |= (s0 >> 3) & 0x04;
+ byteoffs |= (s0 >> 2) & 0x02;
+ byteoffs |= (s0 >> 1) & 0x01;
+
+ bitnum = (s2 >> 5) & 0x04;
+ bitnum |= (s2 >> 4) & 0x02;
+ bitnum |= (s2 >> 3) & 0x01;
+
+ dat[byteoffs] ^= (1 << bitnum);
+
+ return 1;
+ }
+
+ if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
+ return 1;
+
+ return -1;
+}
+
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c b/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c
new file mode 100644
index 00000000000..71660eff5d2
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c
@@ -0,0 +1,159 @@
+/*
+ * This file contains an ECC algorithm from Toshiba that detects and
+ * corrects 1 bit errors in a 256 byte block of data.
+ *
+ * drivers/mtd/nand/nand_ecc.c
+ *
+ * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
+ * Toshiba America Electronics Components, Inc.
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 or (at your option) any
+ * later version.
+ *
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this file; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * As a special exception, if other files instantiate templates or use
+ * macros or inline functions from these files, or you compile these
+ * files and link them with other works to produce a work based on these
+ * files, these files do not by themselves cause the resulting work to be
+ * covered by the GNU General Public License. However the source code for
+ * these files must still be made available in accordance with section (3)
+ * of the GNU General Public License.
+ *
+ * This exception does not invalidate any other reasons why a work based on
+ * this file might be covered by the GNU General Public License.
+ */
+
+#include "nandecc.h"
+
+/*
+ * Pre-calculated 256-way 1 byte column parity
+ */
+static const uint8_t nand_ecc_precalc_table[] = {
+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+ 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+ 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+ 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+ 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+ 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+ 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+ 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+ 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+ 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+ 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+ 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+ 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+ 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+ 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
+};
+
+/**
+ * nand_trans_result - [GENERIC] create non-inverted ECC
+ * @reg2: line parity reg 2
+ * @reg3: line parity reg 3
+ * @ecc_code: ecc
+ *
+ * Creates non-inverted ECC code from line parity
+ */
+static void nand_trans_result(uint8_t reg2, uint8_t reg3,
+ uint8_t *ecc_code)
+{
+ uint8_t a, b, i, tmp1, tmp2;
+
+ /* Initialize variables */
+ a = b = 0x80;
+ tmp1 = tmp2 = 0;
+
+ /* Calculate first ECC byte */
+ for (i = 0; i < 4; i++) {
+ if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
+ tmp1 |= b;
+ b >>= 1;
+ if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */
+ tmp1 |= b;
+ b >>= 1;
+ a >>= 1;
+ }
+
+ /* Calculate second ECC byte */
+ b = 0x80;
+ for (i = 0; i < 4; i++) {
+ if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */
+ tmp2 |= b;
+ b >>= 1;
+ if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */
+ tmp2 |= b;
+ b >>= 1;
+ a >>= 1;
+ }
+
+ /* Store two of the ECC bytes */
+ ecc_code[1] = tmp1;
+ ecc_code[0] = tmp2;
+}
+
+/**
+ * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for
+ * 256 byte block
+ *
+ * @dat: raw data
+ * @ecc_code: buffer for ECC
+ */
+int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code)
+{
+ uint8_t idx, reg1, reg2, reg3;
+ int j;
+
+ /* Initialize variables */
+ reg1 = reg2 = reg3 = 0;
+ ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
+
+ /* Build up column parity */
+ for(j = 0; j < 256; j++) {
+
+ /* Get CP0 - CP5 from table */
+ idx = nand_ecc_precalc_table[dat[j]];
+ reg1 ^= (idx & 0x3f);
+
+ /* All bit XOR = 1 ? */
+ if (idx & 0x40) {
+ reg3 ^= (uint8_t) j;
+ reg2 ^= ~((uint8_t) j);
+ }
+ }
+
+ /* Create non-inverted ECC code from line parity */
+ nand_trans_result(reg2, reg3, ecc_code);
+
+ /* Calculate final ECC code */
+ ecc_code[0] = ~ecc_code[0];
+ ecc_code[1] = ~ecc_code[1];
+ ecc_code[2] = ((~reg1) << 2) | 0x03;
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h b/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h
new file mode 100644
index 00000000000..bcf198296d8
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h
@@ -0,0 +1,29 @@
+#ifndef _NAND_ECC_H
+#define _NAND_ECC_H
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * NAND ecc functions
+ */
+
+#include <stdint.h>
+
+int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code);
+int nand_correct_data(uint8_t *dat, const uint8_t *read_ecc,
+ const uint8_t *calc_ecc);
+
+#endif
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c b/drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c
new file mode 100644
index 00000000000..859346c579a
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ *
+ * PDD (platform description data) contains a set of system specific
+ * boot-parameters. Some of those parameters need to be handled
+ * special on updates, e.g. the MAC addresses. They must also be kept
+ * if the system is updated and one must be able to modify them when
+ * the system has booted the first time. This tool is intended to do
+ * PDD modification.
+ *
+ * 1.3 Removed argp because we want to use uClibc.
+ * 1.4 Minor cleanups
+ * 1.5 Migrated to new libubi
+ * 1.6 Fixed broken volume update
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <mtd/ubi-header.h>
+
+#include "config.h"
+#include "bootenv.h"
+#include "error.h"
+#include "example_ubi.h"
+#include "libubi.h"
+#include "ubimirror.h"
+
+#define PROGRAM_VERSION "1.6"
+
+#define DEFAULT_DEV_PATTERN "/dev/ubi%d"
+#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d"
+
+typedef enum action_t {
+ ACT_NORMAL = 0,
+ ACT_LIST,
+ ACT_ARGP_ABORT,
+ ACT_ARGP_ERR,
+} action_t;
+
+#define ABORT_ARGP do { \
+ args->action = ACT_ARGP_ABORT; \
+} while (0)
+
+#define ERR_ARGP do { \
+ args->action = ACT_ARGP_ERR; \
+} while (0)
+
+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
+ "pddcustomize - customize bootenv and pdd values.\n";
+
+static const char *optionsstr =
+" -b, --both Mirror updated PDD to redundand copy.\n"
+" -c, --copyright Print copyright information.\n"
+" -i, --input=<input> Binary input file. For debug purposes.\n"
+" -l, --list List card bootenv/pdd values.\n"
+" -o, --output=<output> Binary output file. For debug purposes.\n"
+" -s, --side=<seqnum> The side/seqnum to update.\n"
+" -x, --host use x86 platform for debugging.\n"
+" -?, --help Give this help list\n"
+" --usage Give a short usage message\n"
+" -V, --version Print program version\n";
+
+static const char *usage =
+"Usage: pddcustomize [-bclx?V] [-i <input>] [-o <output>] [-s <seqnum>]\n"
+" [--both] [--copyright] [--input=<input>] [--list]\n"
+" [--output=<output>] [--side=<seqnum>] [--host] [--help] [--usage]\n"
+" [--version] [key=value] [...]\n";
+
+struct option long_options[] = {
+ { .name = "both", .has_arg = 0, .flag = NULL, .val = 'b' },
+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
+ { .name = "input", .has_arg = 1, .flag = NULL, .val = 'i' },
+ { .name = "list", .has_arg = 0, .flag = NULL, .val = 'l' },
+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
+ { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' },
+ { .name = "host", .has_arg = 0, .flag = NULL, .val = 'x' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0}
+};
+
+static const char copyright [] __attribute__((unused)) =
+ "Copyright IBM Corp 2006";
+
+typedef struct myargs {
+ action_t action;
+ const char* file_in;
+ const char* file_out;
+ int both;
+ int side;
+ int x86; /* X86 host, use files for testing */
+ bootenv_t env_in;
+
+ char *arg1;
+ char **options; /* [STRING...] */
+} myargs;
+
+static int
+get_update_side(const char* str)
+{
+ uint32_t i = strtoul(str, NULL, 0);
+
+ if ((i != 0) && (i != 1)) {
+ return -1;
+ }
+
+ return i;
+}
+
+static int
+extract_pair(bootenv_t env, const char* str)
+{
+ int rc = 0;
+ char* key;
+ char* val;
+
+ key = strdup(str);
+ if (key == NULL)
+ return -ENOMEM;
+
+ val = strstr(key, "=");
+ if (val == NULL) {
+ err_msg("Wrong argument: %s\n"
+ "Expecting key=value pair.\n", str);
+ rc = -1;
+ goto err;
+ }
+
+ *val = '\0'; /* split strings */
+ val++;
+ rc = bootenv_set(env, key, val);
+
+err:
+ free(key);
+ return rc;
+}
+
+static int
+parse_opt(int argc, char **argv, myargs *args)
+{
+ int rc = 0;
+
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "clbxs:i:o:?V",
+ long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'c':
+ err_msg("%s\n", copyright);
+ ABORT_ARGP;
+ break;
+ case 'l':
+ args->action = ACT_LIST;
+ break;
+ case 'b':
+ args->both = 1;
+ break;
+ case 'x':
+ args->x86 = 1;
+ break;
+ case 's':
+ args->side = get_update_side(optarg);
+ if (args->side < 0) {
+ err_msg("Unsupported seqnum: %d.\n"
+ "Supported seqnums are "
+ "'0' and '1'\n",
+ args->side, optarg);
+ ERR_ARGP;
+ }
+ break;
+ case 'i':
+ args->file_in = optarg;
+ break;
+ case 'o':
+ args->file_out = optarg;
+ break;
+ case '?': /* help */
+ err_msg("Usage: pddcustomize [OPTION...] "
+ "[key=value] [...]");
+ err_msg("%s", doc);
+ err_msg("%s", optionsstr);
+ err_msg("\nReport bugs to %s",
+ PACKAGE_BUGREPORT);
+ exit(0);
+ break;
+ case 'V':
+ err_msg("%s", PROGRAM_VERSION);
+ exit(0);
+ break;
+ default:
+ err_msg("%s", usage);
+ exit(-1);
+ }
+ }
+
+ if (optind < argc) {
+ rc = extract_pair(args->env_in, argv[optind++]);
+ if (rc != 0)
+ ERR_ARGP;
+ }
+
+ return 0;
+}
+
+static int
+list_bootenv(bootenv_t env)
+{
+ int rc = 0;
+ rc = bootenv_write_txt(stdout, env);
+ if (rc != 0) {
+ err_msg("Cannot list bootenv/pdd. rc: %d\n", rc);
+ goto err;
+ }
+err:
+ return rc;
+}
+
+static int
+process_key_value(bootenv_t env_in, bootenv_t env)
+{
+ int rc = 0;
+ size_t size, i;
+ const char* tmp;
+ const char** key_vec = NULL;
+
+ rc = bootenv_get_key_vector(env_in, &size, 0, &key_vec);
+ if (rc != 0)
+ goto err;
+
+ for (i = 0; i < size; i++) {
+ rc = bootenv_get(env_in, key_vec[i], &tmp);
+ if (rc != 0) {
+ err_msg("Cannot read value to input key: %s. rc: %d\n",
+ key_vec[i], rc);
+ goto err;
+ }
+ rc = bootenv_set(env, key_vec[i], tmp);
+ if (rc != 0) {
+ err_msg("Cannot set value key: %s. rc: %d\n",
+ key_vec[i], rc);
+ goto err;
+ }
+ }
+
+err:
+ if (key_vec != NULL)
+ free(key_vec);
+ return rc;
+}
+
+static int
+read_bootenv(const char* file, bootenv_t env)
+{
+ int rc = 0;
+ FILE* fp_in = NULL;
+
+ fp_in = fopen(file, "rb");
+ if (fp_in == NULL) {
+ err_msg("Cannot open file: %s\n", file);
+ return -EIO;
+ }
+
+ rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE);
+ if (rc != 0) {
+ err_msg("Cannot read bootenv from file %s. rc: %d\n",
+ file, rc);
+ goto err;
+ }
+
+err:
+ fclose(fp_in);
+ return rc;
+}
+
+/*
+ * Read bootenv from ubi volume
+ */
+static int
+ubi_read_bootenv(uint32_t devno, uint32_t id, bootenv_t env)
+{
+ libubi_t ulib;
+ int rc = 0;
+ char path[PATH_MAX];
+ FILE* fp_in = NULL;
+
+ ulib = libubi_open();
+ if (ulib == NULL) {
+ err_msg("Cannot allocate ubi structure\n");
+ return -1;
+ }
+
+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id);
+
+ fp_in = fopen(path, "r");
+ if (fp_in == NULL) {
+ err_msg("Cannot open volume:%d number:%d\n", devno, id);
+ goto err;
+ }
+
+ rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE);
+ if (rc != 0) {
+ err_msg("Cannot read volume:%d number:%d\n", devno, id);
+ goto err;
+ }
+
+err:
+ if (fp_in)
+ fclose(fp_in);
+ libubi_close(ulib);
+ return rc;
+}
+
+static int
+write_bootenv(const char* file, bootenv_t env)
+{
+ int rc = 0;
+ FILE* fp_out;
+
+ fp_out = fopen(file, "wb");
+ if (fp_out == NULL) {
+ err_msg("Cannot open file: %s\n", file);
+ return -EIO;
+ }
+
+ rc = bootenv_write(fp_out, env);
+ if (rc != 0) {
+ err_msg("Cannot write bootenv to file %s. rc: %d\n", file, rc);
+ goto err;
+ }
+
+err:
+ fclose(fp_out);
+ return rc;
+}
+
+/*
+ * Read bootenv from ubi volume
+ */
+static int
+ubi_write_bootenv(uint32_t devno, uint32_t id, bootenv_t env)
+{
+ libubi_t ulib;
+ int rc = 0;
+ char path[PATH_MAX];
+ FILE* fp_out = NULL;
+ size_t nbytes;
+
+ rc = bootenv_size(env, &nbytes);
+ if (rc) {
+ err_msg("Cannot determine size of bootenv structure\n");
+ return rc;
+ }
+ ulib = libubi_open();
+ if (ulib == NULL) {
+ err_msg("Cannot allocate ubi structure\n");
+ return rc;
+ }
+
+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id);
+
+ fp_out = fopen(path, "r+");
+ if (fp_out == NULL) {
+ err_msg("Cannot fopen volume:%d number:%d\n", devno, id);
+ rc = -EBADF;
+ goto err;
+ }
+
+ rc = ubi_update_start(ulib, fileno(fp_out), nbytes);
+ if (rc != 0) {
+ err_msg("Cannot start update for %s\n", path);
+ goto err;
+ }
+
+ rc = bootenv_write(fp_out, env);
+ if (rc != 0) {
+ err_msg("Cannot write bootenv to volume %d number:%d\n",
+ devno, id);
+ goto err;
+ }
+err:
+ if( fp_out )
+ fclose(fp_out);
+ libubi_close(ulib);
+ return rc;
+}
+
+static int
+do_mirror(int volno)
+{
+ char errbuf[1024];
+ uint32_t ids[2];
+ int rc;
+ int src_volno_idx = 0;
+
+ ids[0] = EXAMPLE_BOOTENV_VOL_ID_1;
+ ids[1] = EXAMPLE_BOOTENV_VOL_ID_2;
+
+ if (volno == EXAMPLE_BOOTENV_VOL_ID_2)
+ src_volno_idx = 1;
+
+ rc = ubimirror(EXAMPLE_UBI_DEVICE, src_volno_idx, ids, 2, errbuf,
+ sizeof errbuf);
+ if( rc )
+ err_msg(errbuf);
+ return rc;
+}
+
+int
+main(int argc, char **argv) {
+ int rc = 0;
+ bootenv_t env = NULL;
+ uint32_t boot_volno;
+ myargs args = {
+ .action = ACT_NORMAL,
+ .file_in = NULL,
+ .file_out = NULL,
+ .side = -1,
+ .x86 = 0,
+ .both = 0,
+ .env_in = NULL,
+
+ .arg1 = NULL,
+ .options = NULL,
+ };
+
+ rc = bootenv_create(&env);
+ if (rc != 0) {
+ err_msg("Cannot create bootenv handle. rc: %d", rc);
+ goto err;
+ }
+
+ rc = bootenv_create(&(args.env_in));
+ if (rc != 0) {
+ err_msg("Cannot create bootenv handle. rc: %d", rc);
+ goto err;
+ }
+
+ parse_opt(argc, argv, &args);
+ if (args.action == ACT_ARGP_ERR) {
+ rc = -1;
+ goto err;
+ }
+ if (args.action == ACT_ARGP_ABORT) {
+ rc = 0;
+ goto out;
+ }
+
+ if ((args.side == 0) || (args.side == -1))
+ boot_volno = EXAMPLE_BOOTENV_VOL_ID_1;
+ else
+ boot_volno = EXAMPLE_BOOTENV_VOL_ID_2;
+
+ if( args.x86 )
+ rc = read_bootenv(args.file_in, env);
+ else
+ rc = ubi_read_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env);
+ if (rc != 0) {
+ goto err;
+ }
+
+ if (args.action == ACT_LIST) {
+ rc = list_bootenv(env);
+ if (rc != 0) {
+ goto err;
+ }
+ goto out;
+ }
+
+ rc = process_key_value(args.env_in, env);
+ if (rc != 0) {
+ goto err;
+ }
+
+ if( args.x86 )
+ rc = write_bootenv(args.file_in, env);
+ else
+ rc = ubi_write_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env);
+ if (rc != 0)
+ goto err;
+
+ if( args.both ) /* No side specified, update both */
+ rc = do_mirror(boot_volno);
+
+ out:
+ err:
+ bootenv_destroy(&env);
+ bootenv_destroy(&(args.env_in));
+ return rc;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/peb.c b/drivers/mtd/mtd-utils/ubi-utils/src/peb.c
new file mode 100644
index 00000000000..08b770f4301
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/peb.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "peb.h"
+
+int
+peb_cmp(peb_t eb_1, peb_t eb_2)
+{
+ assert(eb_1);
+ assert(eb_2);
+
+ return eb_1->num == eb_2->num ? 0
+ : eb_1->num > eb_2->num ? 1 : -1;
+}
+
+int
+peb_new(uint32_t eb_num, uint32_t eb_size, peb_t *peb)
+{
+ int rc = 0;
+
+ peb_t res = (peb_t) malloc(sizeof(struct peb));
+ if (!res) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ res->num = eb_num;
+ res->size = eb_size;
+ res->data = (uint8_t*) malloc(res->size * sizeof(uint8_t));
+ if (!res->data) {
+ rc = -ENOMEM;
+ goto err;
+ }
+ memset(res->data, 0xff, res->size);
+
+ *peb = res;
+ return 0;
+err:
+ if (res) {
+ if (res->data)
+ free(res->data);
+ free(res);
+ }
+ *peb = NULL;
+ return rc;
+}
+
+int
+peb_fill(peb_t peb, uint8_t* buf, size_t buf_size)
+{
+ if (!peb)
+ return -EINVAL;
+
+ if (buf_size > peb->size)
+ return -EINVAL;
+
+ memcpy(peb->data, buf, buf_size);
+ return 0;
+}
+
+int
+peb_write(FILE* fp_out, peb_t peb)
+{
+ size_t written = 0;
+
+ if (peb == NULL)
+ return -EINVAL;
+
+ written = fwrite(peb->data, 1, peb->size, fp_out);
+
+ if (written != peb->size)
+ return -EIO;
+
+ return 0;
+}
+
+int
+peb_free(peb_t* peb)
+{
+ peb_t tmp = *peb;
+ if (tmp) {
+ if (tmp->data)
+ free(tmp->data);
+ free(tmp);
+ }
+ *peb = NULL;
+
+ return 0;
+}
+
+void peb_dump(FILE* fp_out, peb_t peb)
+{
+ fprintf(fp_out, "num: %08d\tsize: 0x%08x\n", peb->num, peb->size);
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/peb.h b/drivers/mtd/mtd-utils/ubi-utils/src/peb.h
new file mode 100644
index 00000000000..246bce83296
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/peb.h
@@ -0,0 +1,41 @@
+#ifndef __RAW_BLOCK_H__
+#define __RAW_BLOCK_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+typedef struct peb *peb_t;
+struct peb {
+ uint32_t num; /* Physical eraseblock number
+ * in the RAW file. */
+ uint32_t size; /* Data Size (equals physical
+ * erase block size) */
+ uint8_t* data; /* Data buffer */
+};
+
+int peb_new(uint32_t peb_num, uint32_t peb_size, peb_t* peb);
+int peb_free(peb_t* peb);
+int peb_cmp(peb_t peb_1, peb_t peb_2);
+int peb_write(FILE* fp_out, peb_t peb);
+void peb_dump(FILE* fp_out, peb_t peb);
+
+#endif /* __RAW_BLOCK_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/pfi.c b/drivers/mtd/mtd-utils/ubi-utils/src/pfi.c
new file mode 100644
index 00000000000..fa835e20513
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/pfi.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * @file pfi.c
+ *
+ * @author Oliver Lohmann
+ * Andreas Arnez
+ * Joern Engel
+ * Frank Haverkamp
+ *
+ * @brief libpfi holds all code to create and process pfi files.
+ *
+ * <oliloh@de.ibm.com> Wed Feb 8 11:38:22 CET 2006: Initial creation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include "pfi.h"
+
+#define PFI_MAGIC "PFI!\n"
+#define PFI_DATA "DATA\n" /* The same size as PFI_MAGIC */
+#define PFI_MAGIC_LEN 5
+
+static const char copyright [] __attribute__((unused)) =
+ "Copyright (c) International Business Machines Corp., 2006";
+
+enum key_id {
+ /* version 1 */
+ key_version, /* must be index position 0! */
+ key_mode,
+ key_size,
+ key_crc,
+ key_label,
+ key_flags,
+ key_ubi_ids,
+ key_ubi_size,
+ key_ubi_type,
+ key_ubi_names,
+ key_ubi_alignment,
+ key_raw_starts,
+ key_raw_total_size,
+ num_keys,
+};
+
+struct pfi_header {
+ char defined[num_keys]; /* reserve all possible keys even if
+ version does not require this. */
+ int mode_no; /* current mode no. -> can only increase */
+ union {
+ char *str;
+ uint32_t num;
+ } value[num_keys];
+};
+
+
+#define PFI_MANDATORY 0x0001
+#define PFI_STRING 0x0002
+#define PFI_LISTVALUE 0x0004 /* comma seperated list of nums */
+#define PFI_MANDATORY_UBI 0x0008
+#define PFI_MANDATORY_RAW 0x0010
+
+struct key_descriptor {
+ enum key_id id;
+ const char *name;
+ uint32_t flags;
+};
+
+static const struct key_descriptor key_desc_v1[] = {
+ { key_version, "version", PFI_MANDATORY },
+ { key_mode, "mode", PFI_MANDATORY | PFI_STRING },
+ { key_size, "size", PFI_MANDATORY },
+ { key_crc, "crc", PFI_MANDATORY },
+ { key_label, "label", PFI_MANDATORY | PFI_STRING },
+ { key_flags, "flags", PFI_MANDATORY },
+ { key_ubi_ids, "ubi_ids", PFI_MANDATORY_UBI | PFI_STRING },
+ { key_ubi_size, "ubi_size", PFI_MANDATORY_UBI },
+ { key_ubi_type, "ubi_type", PFI_MANDATORY_UBI | PFI_STRING },
+ { key_ubi_names, "ubi_names", PFI_MANDATORY_UBI | PFI_STRING },
+ { key_ubi_alignment, "ubi_alignment", PFI_MANDATORY_UBI },
+ { key_raw_starts, "raw_starts", PFI_MANDATORY_RAW | PFI_STRING },
+ { key_raw_total_size, "raw_total_size", PFI_MANDATORY_RAW },
+};
+
+static const struct key_descriptor *key_descriptors[] = {
+ NULL,
+ key_desc_v1, /* version 1 */
+};
+
+static const int key_descriptors_max[] = {
+ 0, /* version 0 */
+ sizeof(key_desc_v1)/sizeof(struct key_descriptor), /* version 1 */
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+static const char* modes[] = {"raw", "ubi"}; /* order isn't arbitrary! */
+
+/* latest version contains all possible keys */
+static const struct key_descriptor *key_desc = key_desc_v1;
+
+#define PFI_IS_UBI(mode) \
+ (((mode) != NULL) && (strcmp("ubi", (mode)) == 0))
+
+#define PFI_IS_RAW(mode) \
+ (((mode) != NULL) && (strcmp("raw", (mode)) == 0))
+
+/**
+ * @return <0 On Error.
+ * >=0 Mode no.
+ */
+static int
+get_mode_no(const char* mode)
+{
+ int i;
+
+ for (i = 0; i < (int)ARRAY_SIZE(modes); i++)
+ if (strcmp(mode, modes[i]) == 0)
+ return i;
+ return -1;
+}
+
+static int
+find_key_by_name (const char *name)
+{
+ int i;
+
+ for (i = 0; i < num_keys; i++) {
+ if (strcmp(name, key_desc[i].name) == 0)
+ return i;
+ }
+ return -1;
+}
+
+static int
+check_valid (pfi_header head)
+{
+ int i;
+ int max_keys;
+ uint32_t version;
+ const char *mode;
+ const struct key_descriptor *desc;
+ uint32_t to_check = PFI_MANDATORY;
+
+ /*
+ * For the validity check the list of possible keys depends on
+ * the version of the PFI file used.
+ */
+ version = head->value[key_version].num;
+ if (version > PFI_HDRVERSION)
+ return PFI_ENOHEADER;
+
+ max_keys = key_descriptors_max[version];
+ desc = key_descriptors[version];
+
+ if (!desc)
+ return PFI_ENOVERSION;
+
+ mode = head->value[key_mode].str;
+ if (PFI_IS_UBI(mode)) {
+ to_check |= PFI_MANDATORY_UBI;
+ }
+ else if (PFI_IS_RAW(mode)) {
+ to_check |= PFI_MANDATORY_RAW;
+ }
+ else { /* neither UBI nor RAW == ERR */
+ return PFI_EINSUFF;
+ }
+
+ for (i = 0; i < max_keys; i++) {
+ if ((desc[i].flags & to_check) && !head->defined[i]) {
+ fprintf(stderr, "libpfi: %s missing\n", desc[i].name);
+ return PFI_EINSUFF;
+ }
+ }
+
+ return 0;
+}
+
+int pfi_header_init (pfi_header *head)
+{
+ int i;
+ pfi_header self = (pfi_header) malloc(sizeof(*self));
+
+ *head = self;
+ if (self == NULL)
+ return PFI_ENOMEM;
+
+ /* initialize maximum number of possible keys */
+ for (i = 0; i < num_keys; i++) {
+ memset(self, 0, sizeof(*self));
+ self->defined[i] = 0;
+ }
+
+ return 0;
+}
+
+int pfi_header_destroy (pfi_header *head)
+{
+ int i;
+ pfi_header self = *head;
+
+ for (i = 0; i < num_keys; i++) {
+ if (self->defined[i] && (key_desc[i].flags & PFI_STRING) &&
+ self->value[i].str) {
+ free(self->value[i].str);
+ }
+ }
+ free(*head);
+ *head = NULL;
+ return 0;
+}
+
+int pfi_header_setnumber (pfi_header head,
+ const char *key, uint32_t value)
+{
+ int key_id = find_key_by_name(key);
+
+ if (key_id < 0)
+ return PFI_EUNDEF;
+
+ if (key_desc[key_id].flags & PFI_STRING)
+ return PFI_EBADTYPE;
+
+ head->value[key_id].num = value;
+ head->defined[key_id] = 1;
+ return 0;
+}
+
+int pfi_header_setvalue (pfi_header head,
+ const char *key, const char *value)
+{
+ int key_id = find_key_by_name(key);
+
+ if (value == NULL)
+ return PFI_EINSUFF;
+
+ if ((key_id < 0) || (key_id >= num_keys))
+ return PFI_EUNDEF;
+
+ if (key_desc[key_id].flags & PFI_STRING) {
+ /*
+ * The value is a string. Copy to a newly allocated
+ * buffer. Delete the old value, if already set.
+ */
+ size_t len = strlen(value) + 1;
+ char *old_str = NULL;
+ char *str;
+
+ old_str = head->value[key_id].str;
+ if (old_str != NULL)
+ free(old_str);
+
+ str = head->value[key_id].str = (char *) malloc(len);
+ if (str == NULL)
+ return PFI_ENOMEM;
+
+ strcpy(str, value);
+ } else {
+ int len;
+ int ret;
+ /* FIXME: here we assume that the value is always
+ given in hex and starts with '0x'. */
+ ret = sscanf(value, "0x%x%n", &head->value[key_id].num, &len);
+ if (ret < 1 || value[len] != '\0')
+ return PFI_EBADTYPE;
+ }
+ head->defined[key_id] = 1;
+ return 0;
+}
+
+int pfi_header_getnumber (pfi_header head,
+ const char *key, uint32_t *value)
+{
+ int key_id = find_key_by_name(key);
+
+ if (key_id < 0)
+ return PFI_EUNDEF;
+
+ if (key_desc[key_id].flags & PFI_STRING)
+ return PFI_EBADTYPE;
+
+ if (!head->defined[key_id])
+ return PFI_EUNDEF;
+
+ *value = head->value[key_id].num;
+ return 0;
+}
+
+int pfi_header_getstring (pfi_header head,
+ const char *key, char *value, size_t size)
+{
+ int key_id = find_key_by_name(key);
+
+ if (key_id < 0)
+ return PFI_EUNDEF;
+
+ if (!(key_desc[key_id].flags & PFI_STRING))
+ return PFI_EBADTYPE;
+
+ if (!head->defined[key_id])
+ return PFI_EUNDEF;
+
+ strncpy(value, head->value[key_id].str, size-1);
+ value[size-1] = '\0';
+ return 0;
+}
+
+int pfi_header_write (FILE *out, pfi_header head)
+{
+ int i;
+ int ret;
+
+ pfi_header_setnumber(head, "version", PFI_HDRVERSION);
+
+ if ((ret = check_valid(head)) != 0)
+ return ret;
+
+ /* OK. Now write the header. */
+
+ ret = fwrite(PFI_MAGIC, 1, PFI_MAGIC_LEN, out);
+ if (ret < PFI_MAGIC_LEN)
+ return ret;
+
+
+ for (i = 0; i < num_keys; i++) {
+ if (!head->defined[i])
+ continue;
+
+ ret = fprintf(out, "%s=", key_desc[i].name);
+ if (ret < 0)
+ return PFI_EFILE;
+
+ if (key_desc[i].flags & PFI_STRING) {
+ ret = fprintf(out, "%s", head->value[i].str);
+ if (ret < 0)
+ return PFI_EFILE;
+ } else {
+ ret = fprintf(out, "0x%8x", head->value[i].num);
+ if (ret < 0)
+ return PFI_EFILE;
+
+ }
+ ret = fprintf(out, "\n");
+ if (ret < 0)
+ return PFI_EFILE;
+ }
+ ret = fprintf(out, "\n");
+ if (ret < 0)
+ return PFI_EFILE;
+
+ ret = fflush(out);
+ if (ret != 0)
+ return PFI_EFILE;
+
+ return 0;
+}
+
+int pfi_header_read (FILE *in, pfi_header head)
+{
+ char magic[PFI_MAGIC_LEN];
+ char mode[PFI_KEYWORD_LEN];
+ char buf[256];
+
+ if (PFI_MAGIC_LEN != fread(magic, 1, PFI_MAGIC_LEN, in))
+ return PFI_EFILE;
+ if (memcmp(magic, PFI_MAGIC, PFI_MAGIC_LEN) != 0) {
+ if (memcmp(magic, PFI_DATA, PFI_MAGIC_LEN) == 0) {
+ return PFI_DATA_START;
+ }
+ return PFI_ENOHEADER;
+ }
+
+ while (fgets(buf, sizeof(buf), in) != NULL && buf[0] != '\n') {
+ char *value;
+ char *end;
+ value = strchr(buf, '=');
+ if (value == NULL)
+ return PFI_ENOHEADER;
+
+ *value = '\0';
+ value++;
+ end = strchr(value, '\n');
+ if (end)
+ *end = '\0';
+
+ if (pfi_header_setvalue(head, buf, value))
+ return PFI_ENOHEADER;
+ }
+
+ if (check_valid(head) != 0)
+ return PFI_ENOHEADER;
+
+ /* set current mode no. in head */
+ pfi_header_getstring(head, "mode", mode, PFI_KEYWORD_LEN);
+ if (head->mode_no > get_mode_no(mode)) {
+ return PFI_EMODE;
+ }
+ head->mode_no = get_mode_no(mode);
+ return 0;
+}
+
+int pfi_header_dump (FILE *out, pfi_header head __attribute__((__unused__)))
+{
+ fprintf(out, "Sorry not implemented yet. Write mail to "
+ "Andreas Arnez and complain!\n");
+ return 0;
+}
+
+int pfi_read (FILE *in, pfi_read_func func, void *priv_data)
+{
+ int rc;
+ pfi_header header;
+
+ rc = pfi_header_init (&header);
+ if (0 != rc)
+ return rc;
+ if (!func)
+ return PFI_EINVAL;
+
+ while ((0 == rc) && !feof(in)) {
+ /*
+ * Read header and check consistency of the fields.
+ */
+ rc = pfi_header_read( in, header );
+ if (0 != rc)
+ break;
+ if (func) {
+ rc = func(in, header, priv_data);
+ if (rc != 0)
+ break;
+ }
+ }
+
+ pfi_header_destroy(&header);
+ return rc;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/pfi.h b/drivers/mtd/mtd-utils/ubi-utils/src/pfi.h
new file mode 100644
index 00000000000..8c5cc07b974
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/pfi.h
@@ -0,0 +1,244 @@
+#ifndef __pfi_h
+#define __pfi_h
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ * @file pfi.h
+ *
+ * @author Oliver Lohmann <oliloh@de.ibm.com>
+ * Andreas Arnez <arnez@de.ibm.com>
+ * Joern Engel <engeljoe@de.ibm.com>
+ * Frank Haverkamp <haverkam@de.ibm.com>
+ *
+ * @brief libpfi will hold all code to create and process pfi
+ * images. Definitions made in this file are equaly usable for the
+ * development host and the target system.
+ *
+ * @note This header additionally holds the official definitions for
+ * the pfi headers.
+ */
+
+#include <stdio.h> /* FILE */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Definitions. */
+
+#define PFI_HDRVERSION 1 /* current header version */
+
+#define PFI_ENOVERSION 1 /* unknown version */
+#define PFI_ENOHEADER 2 /* not a pfi header */
+#define PFI_EINSUFF 3 /* insufficient information */
+#define PFI_EUNDEF 4 /* key not defined */
+#define PFI_ENOMEM 5 /* out of memory */
+#define PFI_EBADTYPE 6 /* bad data type */
+#define PFI_EFILE 7 /* file I/O error: see errno */
+#define PFI_EFILEINVAL 8 /* file format not valid */
+#define PFI_EINVAL 9 /* invalid parameter */
+#define PFI_ERANGE 10 /* invalid range */
+#define PFI_EMODE 11 /* expecting other mode in this header */
+#define PFI_DATA_START 12 /* data section starts */
+#define PFI_EMAX 13 /* should be always larger as the largest
+ error code */
+
+#define PFI_LABEL_LEN 64 /* This is the maximum length for a
+ PFI header label */
+#define PFI_KEYWORD_LEN 32 /* This is the maximum length for an
+ entry in the mode and type fields */
+
+#define PFI_UBI_MAX_VOLUMES 128
+#define PFI_UBI_VOL_NAME_LEN 127
+
+/**
+ * @brief The pfi header allows to set flags which influence the flashing
+ * behaviour.
+ */
+#define PFI_FLAG_PROTECTED 0x00000001
+
+
+/**
+ * @brief Handle to pfi header. Used in most of the functions associated
+ * with pfi file handling.
+ */
+typedef struct pfi_header *pfi_header;
+
+
+/**
+ * @brief Initialize a pfi header object.
+ *
+ * @param head Pointer to handle. This function allocates memory
+ * for this data structure.
+ * @return 0 on success, otherwise:
+ * PFI_ENOMEM : no memory available for the handle.
+ */
+int pfi_header_init (pfi_header *head);
+
+
+/**
+ * @brief Destroy a pfi header object.
+ *
+ * @param head handle. head is invalid after calling this function.
+ * @return 0 always.
+ */
+int pfi_header_destroy (pfi_header *head);
+
+
+/**
+ * @brief Add a key/value pair to a pfi header object.
+ *
+ * @param head handle.
+ * @param key pointer to key string. Must be 0 terminated.
+ * @param value pointer to value string. Must be 0 terminated.
+ * @return 0 on success, otherwise:
+ * PFI_EUNDEF : key was not found.
+ * PFI_ENOMEM : no memory available for the handle.
+ * PFI_EBADTYPE : value is not an hex string. This happens
+ * when the key stores an integer and the
+ * new value is not convertable e.g. not in
+ * 0xXXXXXXXX format.
+ */
+int pfi_header_setvalue (pfi_header head,
+ const char *key, const char *value);
+
+
+/**
+ * @brief Add a key/value pair to a pfi header object. Provide the
+ * value as a number.
+ *
+ * @param head handle.
+ * @param key pointer to key string. Must be 0 terminated.
+ * @param value value to set.
+ * @return 0 on success, otherwise:
+ * PFI_EUNDEF : key was not found.
+ * PFI_EBADTYPE : value is not a string. This happens
+ * when the key stores a string.
+ */
+int pfi_header_setnumber (pfi_header head,
+ const char *key, uint32_t value);
+
+
+/**
+ * @brief For a given key, return the numerical value stored in a
+ * pfi header object.
+ *
+ * @param head handle.
+ * @param key pointer to key string. Must be 0 terminated.
+ * @param value pointer to value.
+ * @return 0 on success, otherwise:
+ * PFI_EUNDEF : key was not found.
+ * PFI_EBADTYPE : stored value is not an integer but a string.
+ */
+int pfi_header_getnumber (pfi_header head,
+ const char *key, uint32_t *value);
+
+
+static inline uint32_t
+pfi_getnumber(pfi_header head, const char *key)
+{
+ uint32_t value;
+ pfi_header_getnumber(head, key, &value);
+ return value;
+}
+
+/**
+ * @brief For a given key, return the string value stored in a pfi
+ * header object.
+ *
+ * @param head handle.
+ * @param key pointer to key string. Must be 0 terminated.
+ * @param value pointer to value string. Memory must be allocated by the user.
+ * @return 0 on success, otherwise:
+ * PFI_EUNDEF : key was not found.
+ * PFI_EBADTYPE : stored value is not a string but an integer.
+ */
+int pfi_header_getstring (pfi_header head,
+ const char *key, char *value, size_t size);
+
+
+/**
+ * @brief Write a pfi header object into a given file.
+ *
+ * @param out output stream.
+ * @param head handle.
+ * @return 0 on success, error values otherwise:
+ * PFI_EINSUFF : not all mandatory fields are filled.
+ * PFI_ENOHEADER : wrong header version or magic number.
+ * -E* : see <asm/errno.h>.
+ */
+int pfi_header_write (FILE *out, pfi_header head);
+
+
+/**
+ * @brief Read a pfi header object from a given file.
+ *
+ * @param in input stream.
+ * @param head handle.
+ * @return 0 on success, error values otherwise:
+ * PFI_ENOVERSION: unknown header version.
+ * PFI_EFILE : cannot read enough data.
+ * PFI_ENOHEADER : wrong header version or magic number.
+ * -E* : see <asm/errno.h>.
+ *
+ * If the header verification returned success the user can assume that
+ * all mandatory fields for a particular version are accessible. Checking
+ * the return code when calling the get-function for those keys is not
+ * required in those cases. For optional fields the checking must still be
+ * done.
+ */
+int pfi_header_read (FILE *in, pfi_header head);
+
+
+/**
+ * @brief Display a pfi header in human-readable form.
+ *
+ * @param out output stream.
+ * @param head handle.
+ * @return always 0.
+ *
+ * @note Prints out that it is not implemented and whom you should
+ * contact if you need it urgently!.
+ */
+int pfi_header_dump (FILE *out, pfi_header head);
+
+
+/*
+ * @brief Iterates over a stream of pfi files. The iterator function
+ * must advance the file pointer in FILE *in to the next pfi
+ * header. Function exists on feof(in).
+ *
+ * @param in input file descriptor, must be open and valid.
+ * @param func iterator function called when pfi header could be
+ * read and was validated. The function must return 0 on
+ * success.
+ * @return See pfi_header_init and pfi_header_read.
+ * PFI_EINVAL : func is not valid
+ * 0 ok.
+ */
+typedef int (* pfi_read_func)(FILE *in, pfi_header hdr, void *priv_data);
+
+int pfi_read (FILE *in, pfi_read_func func, void *priv_data);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __pfi_h */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c b/drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c
new file mode 100644
index 00000000000..a8c76a3dbe1
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c
@@ -0,0 +1,682 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ *
+ * Convert a PFI file (partial flash image) into a plain binary file.
+ * This tool can be used to prepare the data to be burned into flash
+ * chips in a manufacturing step where the flashes are written before
+ * being soldered onto the hardware. For NAND images another step is
+ * required to add the right OOB data to the binary image.
+ *
+ * 1.3 Removed argp because we want to use uClibc.
+ * 1.4 Minor cleanups
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <ubigen.h>
+#include <mtd/ubi-header.h>
+#include <mtd_swab.h>
+
+#include "config.h"
+#include "list.h"
+#include "error.h"
+#include "reader.h"
+#include "peb.h"
+#include "crc32.h"
+
+#define PROGRAM_VERSION "1.4"
+
+#define MAX_FNAME 255
+#define DEFAULT_ERASE_COUNT 0 /* Hmmm.... Perhaps */
+#define ERR_BUF_SIZE 1024
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+static uint32_t crc32_table[256];
+static char err_buf[ERR_BUF_SIZE];
+
+/*
+ * Data used to buffer raw blocks which have to be
+ * located at a specific point inside the generated RAW file
+ */
+
+typedef enum action_t {
+ ACT_NOTHING = 0x00000000,
+ ACT_RAW = 0x00000001,
+} action_t;
+
+static const char copyright [] __attribute__((unused)) =
+ "(c) Copyright IBM Corp 2006\n";
+
+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
+ "pfi2bin - a tool to convert PFI files into binary images.\n";
+
+static const char *optionsstr =
+" Common settings:\n"
+" -c, --copyright\n"
+" -v, --verbose Print more information.\n"
+"\n"
+" Input:\n"
+" -j, --platform=pdd-file PDD information which contains the card settings.\n"
+"\n"
+" Output:\n"
+" -o, --output=filename Outputfile, default: stdout.\n"
+"\n"
+" -?, --help Give this help list\n"
+" --usage Give a short usage message\n"
+" -V, --version Print program version\n";
+
+static const char *usage =
+"Usage: pfi2bin [-cv?V] [-j pdd-file] [-o filename] [--copyright]\n"
+" [--verbose] [--platform=pdd-file] [--output=filename] [--help]\n"
+" [--usage] [--version] pfifile\n";
+
+struct option long_options[] = {
+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
+ { .name = "platform", .has_arg = 1, .flag = NULL, .val = 'j' },
+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0}
+};
+
+typedef struct io {
+ FILE* fp_pdd; /* a FilePointer to the PDD data */
+ FILE* fp_pfi; /* a FilePointer to the PFI input stream */
+ FILE* fp_out; /* a FilePointer to the output stream */
+} *io_t;
+
+typedef struct myargs {
+ /* common settings */
+ action_t action;
+ int verbose;
+ const char *f_in_pfi;
+ const char *f_in_pdd;
+ const char *f_out;
+
+ /* special stuff needed to get additional arguments */
+ char *arg1;
+ char **options; /* [STRING...] */
+} myargs;
+
+static int
+parse_opt(int argc, char **argv, myargs *args)
+{
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "cvj:o:?V", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ /* common settings */
+ case 'v': /* --verbose=<level> */
+ args->verbose = 1;
+ break;
+
+ case 'c': /* --copyright */
+ fprintf(stderr, "%s\n", copyright);
+ exit(0);
+ break;
+
+ case 'j': /* --platform */
+ args->f_in_pdd = optarg;
+ break;
+
+ case 'o': /* --output */
+ args->f_out = optarg;
+ break;
+
+ case '?': /* help */
+ printf("pfi2bin [OPTION...] pfifile\n");
+ printf("%s", doc);
+ printf("%s", optionsstr);
+ printf("\nReport bugs to %s\n",
+ PACKAGE_BUGREPORT);
+ exit(0);
+ break;
+
+ case 'V':
+ printf("%s\n", PROGRAM_VERSION);
+ exit(0);
+ break;
+
+ default:
+ printf("%s", usage);
+ exit(-1);
+ }
+ }
+
+ if (optind < argc)
+ args->f_in_pfi = argv[optind++];
+
+ return 0;
+}
+
+
+static size_t
+byte_to_blk(size_t byte, size_t blk_size)
+{
+ return (byte % blk_size) == 0
+ ? byte / blk_size
+ : byte / blk_size + 1;
+}
+
+
+
+
+/**
+ * @precondition IO: File stream points to first byte of RAW data.
+ * @postcondition IO: File stream points to first byte of next
+ * or EOF.
+ */
+static int
+memorize_raw_eb(pfi_raw_t pfi_raw, pdd_data_t pdd, list_t *raw_pebs,
+ io_t io)
+{
+ int rc = 0;
+ uint32_t i;
+
+ size_t read, to_read, eb_num;
+ size_t bytes_left;
+ list_t pebs = *raw_pebs;
+ peb_t peb = NULL;
+
+ long old_file_pos = ftell(io->fp_pfi);
+ for (i = 0; i < pfi_raw->starts_size; i++) {
+ bytes_left = pfi_raw->data_size;
+ rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET);
+ if (rc != 0)
+ goto err;
+
+ eb_num = byte_to_blk(pfi_raw->starts[i], pdd->eb_size);
+ while (bytes_left) {
+ to_read = MIN(bytes_left, pdd->eb_size);
+ rc = peb_new(eb_num++, pdd->eb_size, &peb);
+ if (rc != 0)
+ goto err;
+ read = fread(peb->data, 1, to_read, io->fp_pfi);
+ if (read != to_read) {
+ rc = -EIO;
+ goto err;
+ }
+ pebs = append_elem(peb, pebs);
+ bytes_left -= read;
+ }
+
+ }
+ *raw_pebs = pebs;
+ return 0;
+err:
+ pebs = remove_all((free_func_t)&peb_free, pebs);
+ return rc;
+}
+
+static int
+convert_ubi_volume(pfi_ubi_t ubi, pdd_data_t pdd, list_t raw_pebs,
+ struct ubi_vtbl_record *vol_tab,
+ size_t *ebs_written, io_t io)
+{
+ int rc = 0;
+ uint32_t i, j;
+ peb_t raw_peb;
+ peb_t cmp_peb;
+ ubi_info_t u;
+ size_t leb_total = 0;
+ uint8_t vol_type;
+
+ switch (ubi->type) {
+ case pfi_ubi_static:
+ vol_type = UBI_VID_STATIC; break;
+ case pfi_ubi_dynamic:
+ vol_type = UBI_VID_DYNAMIC; break;
+ default:
+ vol_type = UBI_VID_DYNAMIC;
+ }
+
+ rc = peb_new(0, 0, &cmp_peb);
+ if (rc != 0)
+ goto err;
+
+ long old_file_pos = ftell(io->fp_pfi);
+ for (i = 0; i < ubi->ids_size; i++) {
+ rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET);
+ if (rc != 0)
+ goto err;
+ rc = ubigen_create(&u, ubi->ids[i], vol_type,
+ pdd->eb_size, DEFAULT_ERASE_COUNT,
+ ubi->alignment, UBI_VERSION,
+ pdd->vid_hdr_offset, 0, ubi->data_size,
+ io->fp_pfi, io->fp_out);
+ if (rc != 0)
+ goto err;
+
+ rc = ubigen_get_leb_total(u, &leb_total);
+ if (rc != 0)
+ goto err;
+
+ j = 0;
+ while(j < leb_total) {
+ cmp_peb->num = *ebs_written;
+ raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb,
+ raw_pebs);
+ if (raw_peb) {
+ rc = peb_write(io->fp_out, raw_peb);
+ }
+ else {
+ rc = ubigen_write_leb(u, NO_ERROR);
+ j++;
+ }
+ if (rc != 0)
+ goto err;
+ (*ebs_written)++;
+ }
+ /* memorize volume table entry */
+ rc = ubigen_set_lvol_rec(u, ubi->size,
+ ubi->names[i],
+ (void*) &vol_tab[ubi->ids[i]]);
+ if (rc != 0)
+ goto err;
+ ubigen_destroy(&u);
+ }
+
+ peb_free(&cmp_peb);
+ return 0;
+
+err:
+ peb_free(&cmp_peb);
+ ubigen_destroy(&u);
+ return rc;
+}
+
+
+static FILE*
+my_fmemopen (void *buf, size_t size, const char *opentype)
+{
+ FILE* f;
+ size_t ret;
+
+ assert(strcmp(opentype, "r") == 0);
+
+ f = tmpfile();
+ ret = fwrite(buf, 1, size, f);
+ rewind(f);
+
+ return f;
+}
+
+/**
+ * @brief Builds a UBI volume table from a volume entry list.
+ * @return 0 On success.
+ * else Error.
+ */
+static int
+write_ubi_volume_table(pdd_data_t pdd, list_t raw_pebs,
+ struct ubi_vtbl_record *vol_tab, size_t vol_tab_size,
+ size_t *ebs_written, io_t io)
+{
+ int rc = 0;
+ ubi_info_t u;
+ peb_t raw_peb;
+ peb_t cmp_peb;
+ size_t leb_size, leb_total, j = 0;
+ uint8_t *ptr = NULL;
+ FILE* fp_leb = NULL;
+ int vt_slots;
+ size_t vol_tab_size_limit;
+
+ rc = peb_new(0, 0, &cmp_peb);
+ if (rc != 0)
+ goto err;
+
+ /* @FIXME: Artem creates one volume with 2 LEBs.
+ * IMO 2 volumes would be more convenient. In order
+ * to get 2 reserved LEBs from ubigen, I have to
+ * introduce this stupid mechanism. Until no final
+ * decision of the VTAB structure is made... Good enough.
+ */
+ rc = ubigen_create(&u, UBI_LAYOUT_VOLUME_ID, UBI_VID_DYNAMIC,
+ pdd->eb_size, DEFAULT_ERASE_COUNT,
+ 1, UBI_VERSION,
+ pdd->vid_hdr_offset, UBI_COMPAT_REJECT,
+ vol_tab_size, stdin, io->fp_out);
+ /* @FIXME stdin for fp_in is a hack */
+ if (rc != 0)
+ goto err;
+ rc = ubigen_get_leb_size(u, &leb_size);
+ if (rc != 0)
+ goto err;
+ ubigen_destroy(&u);
+
+ /*
+ * The number of supported volumes is restricted by the eraseblock size
+ * and by the UBI_MAX_VOLUMES constant.
+ */
+ vt_slots = leb_size / UBI_VTBL_RECORD_SIZE;
+ if (vt_slots > UBI_MAX_VOLUMES)
+ vt_slots = UBI_MAX_VOLUMES;
+ vol_tab_size_limit = vt_slots * UBI_VTBL_RECORD_SIZE;
+
+ ptr = (uint8_t*) malloc(leb_size * sizeof(uint8_t));
+ if (ptr == NULL)
+ goto err;
+
+ memset(ptr, 0xff, leb_size);
+ memcpy(ptr, vol_tab, vol_tab_size_limit);
+ fp_leb = my_fmemopen(ptr, leb_size, "r");
+
+ rc = ubigen_create(&u, UBI_LAYOUT_VOLUME_ID, UBI_VID_DYNAMIC,
+ pdd->eb_size, DEFAULT_ERASE_COUNT,
+ 1, UBI_VERSION, pdd->vid_hdr_offset,
+ UBI_COMPAT_REJECT, leb_size * UBI_LAYOUT_VOLUME_EBS,
+ fp_leb, io->fp_out);
+ if (rc != 0)
+ goto err;
+ rc = ubigen_get_leb_total(u, &leb_total);
+ if (rc != 0)
+ goto err;
+
+ long old_file_pos = ftell(fp_leb);
+ while(j < leb_total) {
+ rc = fseek(fp_leb, old_file_pos, SEEK_SET);
+ if (rc != 0)
+ goto err;
+
+ cmp_peb->num = *ebs_written;
+ raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb,
+ raw_pebs);
+ if (raw_peb) {
+ rc = peb_write(io->fp_out, raw_peb);
+ }
+ else {
+ rc = ubigen_write_leb(u, NO_ERROR);
+ j++;
+ }
+
+ if (rc != 0)
+ goto err;
+ (*ebs_written)++;
+ }
+
+err:
+ free(ptr);
+ peb_free(&cmp_peb);
+ ubigen_destroy(&u);
+ fclose(fp_leb);
+ return rc;
+}
+
+static int
+write_remaining_raw_ebs(pdd_data_t pdd, list_t raw_blocks, size_t *ebs_written,
+ FILE* fp_out)
+{
+ int rc = 0;
+ uint32_t j, delta;
+ list_t ptr;
+ peb_t empty_eb, peb;
+
+ /* create an empty 0xff EB (for padding) */
+ rc = peb_new(0, pdd->eb_size, &empty_eb);
+
+ foreach(peb, ptr, raw_blocks) {
+ if (peb->num < *ebs_written) {
+ continue; /* omit blocks which
+ are already passed */
+ }
+
+ if (peb->num < *ebs_written) {
+ err_msg("eb_num: %d\n", peb->num);
+ err_msg("Bug: This should never happen. %d %s",
+ __LINE__, __FILE__);
+ goto err;
+ }
+
+ delta = peb->num - *ebs_written;
+ if (((delta + *ebs_written) * pdd->eb_size) > pdd->flash_size) {
+ err_msg("RAW block outside of flash_size.");
+ goto err;
+ }
+ for (j = 0; j < delta; j++) {
+ rc = peb_write(fp_out, empty_eb);
+ if (rc != 0)
+ goto err;
+ (*ebs_written)++;
+ }
+ rc = peb_write(fp_out, peb);
+ if (rc != 0)
+ goto err;
+ (*ebs_written)++;
+ }
+
+err:
+ peb_free(&empty_eb);
+ return rc;
+}
+
+static int
+init_vol_tab(struct ubi_vtbl_record **vol_tab, size_t *vol_tab_size)
+{
+ uint32_t crc;
+ size_t i;
+ struct ubi_vtbl_record* res = NULL;
+
+ *vol_tab_size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE;
+
+ res = (struct ubi_vtbl_record*) calloc(1, *vol_tab_size);
+ if (vol_tab == NULL) {
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < UBI_MAX_VOLUMES; i++) {
+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT,
+ &(res[i]), UBI_VTBL_RECORD_SIZE_CRC);
+ res[i].crc = cpu_to_be32(crc);
+ }
+
+ *vol_tab = res;
+ return 0;
+}
+
+static int
+create_raw(io_t io)
+{
+ int rc = 0;
+ size_t ebs_written = 0; /* eraseblocks written already... */
+ size_t vol_tab_size;
+ list_t ptr;
+
+ list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */
+ list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */
+ list_t raw_pebs = mk_empty(); /* list of raw eraseblocks */
+
+ struct ubi_vtbl_record *vol_tab = NULL;
+ pdd_data_t pdd = NULL;
+
+ rc = init_vol_tab (&vol_tab, &vol_tab_size);
+ if (rc != 0) {
+ err_msg("Cannot initialize volume table.");
+ goto err;
+ }
+
+ rc = read_pdd_data(io->fp_pdd, &pdd,
+ err_buf, ERR_BUF_SIZE);
+ if (rc != 0) {
+ err_msg("Cannot read necessary pdd_data: %s rc: %d",
+ err_buf, rc);
+ goto err;
+ }
+
+ rc = read_pfi_headers(&pfi_raws, &pfi_ubis, io->fp_pfi,
+ err_buf, ERR_BUF_SIZE);
+ if (rc != 0) {
+ err_msg("Cannot read pfi header: %s rc: %d",
+ err_buf, rc);
+ goto err;
+ }
+
+ pfi_raw_t pfi_raw;
+ foreach(pfi_raw, ptr, pfi_raws) {
+ rc = memorize_raw_eb(pfi_raw, pdd, &raw_pebs,
+ io);
+ if (rc != 0) {
+ err_msg("Cannot create raw_block in mem. rc: %d\n",
+ rc);
+ goto err;
+ }
+ }
+
+ pfi_ubi_t pfi_ubi;
+ foreach(pfi_ubi, ptr, pfi_ubis) {
+ rc = convert_ubi_volume(pfi_ubi, pdd, raw_pebs,
+ vol_tab, &ebs_written, io);
+ if (rc != 0) {
+ err_msg("Cannot convert UBI volume. rc: %d\n", rc);
+ goto err;
+ }
+ }
+
+ rc = write_ubi_volume_table(pdd, raw_pebs, vol_tab, vol_tab_size,
+ &ebs_written, io);
+ if (rc != 0) {
+ err_msg("Cannot write UBI volume table. rc: %d\n", rc);
+ goto err;
+ }
+
+ rc = write_remaining_raw_ebs(pdd, raw_pebs, &ebs_written, io->fp_out);
+ if (rc != 0)
+ goto err;
+
+ if (io->fp_out != stdout)
+ info_msg("Physical eraseblocks written: %8d\n", ebs_written);
+err:
+ free(vol_tab);
+ pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws);
+ pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis);
+ raw_pebs = remove_all((free_func_t)&peb_free, raw_pebs);
+ free_pdd_data(&pdd);
+ return rc;
+}
+
+
+/* ------------------------------------------------------------------------- */
+static void
+open_io_handle(myargs *args, io_t io)
+{
+ /* set PDD input */
+ io->fp_pdd = fopen(args->f_in_pdd, "r");
+ if (io->fp_pdd == NULL) {
+ err_sys("Cannot open: %s", args->f_in_pdd);
+ }
+
+ /* set PFI input */
+ io->fp_pfi = fopen(args->f_in_pfi, "r");
+ if (io->fp_pfi == NULL) {
+ err_sys("Cannot open PFI input file: %s", args->f_in_pfi);
+ }
+
+ /* set output prefix */
+ if (strcmp(args->f_out,"") == 0)
+ io->fp_out = stdout;
+ else {
+ io->fp_out = fopen(args->f_out, "wb");
+ if (io->fp_out == NULL) {
+ err_sys("Cannot open output file: %s", args->f_out);
+ }
+ }
+}
+
+static void
+close_io_handle(io_t io)
+{
+ if (fclose(io->fp_pdd) != 0) {
+ err_sys("Cannot close PDD file.");
+ }
+ if (fclose(io->fp_pfi) != 0) {
+ err_sys("Cannot close PFI file.");
+ }
+ if (io->fp_out != stdout) {
+ if (fclose(io->fp_out) != 0) {
+ err_sys("Cannot close output file.");
+ }
+ }
+
+ io->fp_pdd = NULL;
+ io->fp_pfi = NULL;
+ io->fp_out = NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int rc = 0;
+
+ ubigen_init();
+ init_crc32_table(crc32_table);
+
+ struct io io = {NULL, NULL, NULL};
+ myargs args = {
+ .action = ACT_RAW,
+ .verbose = 0,
+
+ .f_in_pfi = "",
+ .f_in_pdd = "",
+ .f_out = "",
+
+ /* arguments */
+ .arg1 = NULL,
+ .options = NULL,
+ };
+
+ /* parse arguments */
+ parse_opt(argc, argv, &args);
+
+ if (strcmp(args.f_in_pfi, "") == 0) {
+ err_quit("No PFI input file specified!");
+ }
+
+ if (strcmp(args.f_in_pdd, "") == 0) {
+ err_quit("No PDD input file specified!");
+ }
+
+ open_io_handle(&args, &io);
+
+ info_msg("[ Creating RAW...");
+ rc = create_raw(&io);
+ if (rc != 0) {
+ err_msg("Creating RAW failed.");
+ goto err;
+ }
+
+err:
+ close_io_handle(&io);
+ if (rc != 0) {
+ remove(args.f_out);
+ }
+
+ return rc;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c b/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c
new file mode 100644
index 00000000000..754fe333c73
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ * Frank Haverkamp
+ *
+ * Process a PFI (partial flash image) and write the data to the
+ * specified UBI volumes. This tool is intended to be used for system
+ * update using PFI files.
+ *
+ * 1.1 fixed output to stderr and stdout in logfile mode.
+ * 1.2 updated.
+ * 1.3 removed argp parsing to be able to use uClib.
+ * 1.4 Minor cleanups.
+ * 1.5 Forgot to delete raw block before updating it.
+ * 1.6 Migrated to new libubi.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <pfiflash.h>
+#undef DEBUG
+#include "error.h"
+#include "config.h"
+
+#define PROGRAM_VERSION "1.6"
+
+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
+ "pfiflash - a tool for updating a controller with PFI files.\n";
+
+static const char *optionsstr =
+" Standard options:\n"
+" -c, --copyright Print copyright information.\n"
+" -l, --logfile=<file> Write a logfile to <file>.\n"
+" -v, --verbose Be verbose during program execution.\n"
+"\n"
+" Process options:\n"
+" -C, --complete Execute a complete system update. Updates both\n"
+" sides.\n"
+" -p, --pdd-update=<type> Specify the pdd-update algorithm. <type> is either\n"
+" 'keep', 'merge' or 'overwrite'.\n"
+" -r, --raw-flash=<dev> Flash the raw data. Use the specified mtd device.\n"
+" -s, --side=<seqnum> Select the side which shall be updated.\n"
+" -x, --compare Only compare on-flash and pfi data, print info if\n"
+" an update is neccessary and return appropriate\n"
+" error code.\n"
+"\n"
+" -?, --help Give this help list\n"
+" --usage Give a short usage message\n"
+" -V, --version Print program version\n";
+
+static const char *usage =
+"Usage: pfiflash [-cvC?V] [-l <file>] [-p <type>] [-r <dev>] [-s <seqnum>]\n"
+" [--copyright] [--logfile=<file>] [--verbose] [--complete]\n"
+" [--pdd-update=<type>] [--raw-flash=<dev>] [--side=<seqnum>]\n"
+" [--compare] [--help] [--usage] [--version] [pfifile]\n";
+
+static const char copyright [] __attribute__((unused)) =
+ "Copyright IBM Corp 2006";
+
+struct option long_options[] = {
+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
+ { .name = "logfile", .has_arg = 1, .flag = NULL, .val = 'l' },
+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
+ { .name = "complete", .has_arg = 0, .flag = NULL, .val = 'C' },
+ { .name = "pdd-update", .has_arg = 1, .flag = NULL, .val = 'p' },
+ { .name = "raw-flash", .has_arg = 1, .flag = NULL, .val = 'r' },
+ { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' },
+ { .name = "compare", .has_arg = 0, .flag = NULL, .val = 'x' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0}
+};
+
+typedef struct myargs {
+ int verbose;
+ const char *logfile;
+ const char *raw_dev;
+
+ pdd_handling_t pdd_handling;
+ int seqnum;
+ int compare;
+ int complete;
+
+ FILE* fp_in;
+
+ /* special stuff needed to get additional arguments */
+ char *arg1;
+ char **options; /* [STRING...] */
+} myargs;
+
+static pdd_handling_t
+get_pdd_handling(const char* str)
+{
+ if (strcmp(str, "keep") == 0) {
+ return PDD_KEEP;
+ }
+ if (strcmp(str, "merge") == 0) {
+ return PDD_MERGE;
+ }
+ if (strcmp(str, "overwrite") == 0) {
+ return PDD_OVERWRITE;
+ }
+
+ return -1;
+}
+
+static int
+get_update_seqnum(const char* str)
+{
+ uint32_t i = strtoul(str, NULL, 0);
+
+ if ((i != 0) && (i != 1)) {
+ return -1;
+ }
+
+ return i;
+}
+
+
+static int
+parse_opt(int argc, char **argv, myargs *args)
+{
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "cl:vCp:r:s:x?V",
+ long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ /* standard options */
+ case 'c':
+ err_msg("%s\n", copyright);
+ exit(0);
+ break;
+ case 'v':
+ args->verbose = 1;
+ break;
+ case 'l':
+ args->logfile = optarg;
+ break;
+ /* process options */
+ case 'C':
+ args->complete = 1;
+ break;
+ case 'p':
+ args->pdd_handling = get_pdd_handling(optarg);
+ if ((int)args->pdd_handling < 0) {
+ err_quit("Unknown PDD handling: %s.\n"
+ "Please use either "
+ "'keep', 'merge' or"
+ "'overwrite'.\n'");
+ }
+ break;
+ case 's':
+ args->seqnum = get_update_seqnum(optarg);
+ if (args->seqnum < 0) {
+ err_quit("Unsupported side: %s.\n"
+ "Supported sides are '0' "
+ "and '1'\n", optarg);
+ }
+ break;
+ case 'x':
+ args->compare = 1;
+ break;
+ case 'r':
+ args->raw_dev = optarg;
+ break;
+ case '?': /* help */
+ err_msg("Usage: pfiflash [OPTION...] [pfifile]");
+ err_msg("%s", doc);
+ err_msg("%s", optionsstr);
+ err_msg("\nReport bugs to %s\n",
+ PACKAGE_BUGREPORT);
+ exit(0);
+ break;
+ case 'V':
+ err_msg("%s", PROGRAM_VERSION);
+ exit(0);
+ break;
+ default:
+ err_msg("%s", usage);
+ exit(-1);
+
+ }
+ }
+
+ if (optind < argc) {
+ args->fp_in = fopen(argv[optind++], "r");
+ if ((args->fp_in) == NULL) {
+ err_sys("Cannot open PFI file %s for input",
+ argv[optind]);
+ }
+ }
+
+ return 0;
+}
+
+int main (int argc, char** argv)
+{
+ int rc = 0;
+ char err_buf[PFIFLASH_MAX_ERR_BUF_SIZE];
+ memset(err_buf, '\0', PFIFLASH_MAX_ERR_BUF_SIZE);
+
+ myargs args = {
+ .verbose = 0,
+ .seqnum = -1,
+ .compare = 0,
+ .complete = 0,
+ .logfile = NULL, /* "/tmp/pfiflash.log", */
+ .pdd_handling = PDD_KEEP,
+ .fp_in = stdin,
+ .raw_dev = NULL,
+ };
+
+ parse_opt(argc, argv, &args);
+ error_initlog(args.logfile);
+
+ if (!args.fp_in) {
+ rc = -1;
+ snprintf(err_buf, PFIFLASH_MAX_ERR_BUF_SIZE,
+ "No PFI input file specified!\n");
+ goto err;
+ }
+
+ rc = pfiflash_with_options(args.fp_in, args.complete, args.seqnum,
+ args.compare, args.pdd_handling, args.raw_dev, err_buf,
+ PFIFLASH_MAX_ERR_BUF_SIZE);
+ if (rc < 0) {
+ goto err_fp;
+ }
+
+ err_fp:
+ if (args.fp_in != stdin)
+ fclose(args.fp_in);
+ err:
+ if (rc != 0)
+ err_msg("pfiflash: %s\nrc: %d\n", err_buf, rc);
+ return rc;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h b/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h
new file mode 100644
index 00000000000..039705de0d3
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h
@@ -0,0 +1,76 @@
+#ifndef __PFIFLASH_H__
+#define __PFIFLASH_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ *
+ * @file pfi.h
+ *
+ * @author Oliver Lohmann <oliloh@de.ibm.com>
+ *
+ * @brief The pfiflash library offers an interface for using the
+ * pfiflash * utility.
+ */
+
+#include <stdio.h> /* FILE */
+
+#define PFIFLASH_MAX_ERR_BUF_SIZE 1024
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum pdd_handling_t
+{
+ PDD_KEEP = 0,
+ PDD_MERGE,
+ PDD_OVERWRITE,
+ PDD_HANDLING_NUM, /* always the last item */
+} pdd_handling_t; /**< Possible PDD handle algorithms. */
+
+/**
+ * @brief Flashes a PFI file to UBI Device 0.
+ * @param complete [0|1] Do a complete system update.
+ * @param seqnum Index in a redundant group.
+ * @param compare [0|1] Compare contents.
+ * @param pdd_handling The PDD handling algorithm.
+ * @param rawdev Device to use for raw flashing
+ * @param err_buf An error buffer.
+ * @param err_buf_size Size of the error buffer.
+ */
+int pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare,
+ pdd_handling_t pdd_handling, const char* rawdev,
+ char *err_buf, size_t err_buf_size);
+
+/**
+ * @brief Flashes a PFI file to UBI Device 0.
+ * @param complete [0|1] Do a complete system update.
+ * @param seqnum Index in a redundant group.
+ * @param pdd_handling The PDD handling algorithm.
+ * @param err_buf An error buffer.
+ * @param err_buf_size Size of the error buffer.
+ */
+int pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling,
+ char *err_buf, size_t err_buf_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PFIFLASH_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h b/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h
new file mode 100644
index 00000000000..0f27f4ad5ff
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h
@@ -0,0 +1,75 @@
+#ifndef __PFIFLASH_ERROR_H__
+#define __PFIFLASH_ERROR_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Author: Drake Dowsett <dowsett@de.ibm.com>
+ * Contact: Andreas Arnez <arnez@de.ibm.com>
+ */
+
+enum pfiflash_err {
+ PFIFLASH_ERR_EOF = 1,
+ PFIFLASH_ERR_FIO,
+ PFIFLASH_ERR_UBI_OPEN,
+ PFIFLASH_ERR_UBI_CLOSE,
+ PFIFLASH_ERR_UBI_MKVOL,
+ PFIFLASH_ERR_UBI_RMVOL,
+ PFIFLASH_ERR_UBI_VOL_UPDATE,
+ PFIFLASH_ERR_UBI_VOL_FOPEN,
+ PFIFLASH_ERR_UBI_UNKNOWN,
+ PFIFLASH_ERR_UBI_VID_OOB,
+ PFIFLASH_ERR_BOOTENV_CREATE,
+ PFIFLASH_ERR_BOOTENV_READ,
+ PFIFLASH_ERR_BOOTENV_SIZE,
+ PFIFLASH_ERR_BOOTENV_WRITE,
+ PFIFLASH_ERR_PDD_UNKNOWN,
+ PFIFLASH_ERR_MTD_OPEN,
+ PFIFLASH_ERR_MTD_CLOSE,
+ PFIFLASH_ERR_CRC_CHECK,
+ PFIFLASH_ERR_MTD_ERASE,
+ PFIFLASH_ERR_COMPARE,
+ PFIFLASH_CMP_DIFF
+};
+
+const char *const PFIFLASH_ERRSTR[] = {
+ "",
+ "unexpected EOF",
+ "file I/O error",
+ "couldn't open UBI",
+ "couldn't close UBI",
+ "couldn't make UBI volume %d",
+ "couldn't remove UBI volume %d",
+ "couldn't update UBI volume %d",
+ "couldn't open UBI volume %d",
+ "unknown UBI operation",
+ "PFI data contains out of bounds UBI id %d",
+ "couldn't create bootenv%s",
+ "couldn't read bootenv",
+ "couldn't resize bootenv",
+ "couldn't write bootenv on ubi%d_%d",
+ "unknown PDD handling algorithm",
+ "couldn't open MTD device %s",
+ "couldn't close MTD device %s",
+ "CRC check failed: given=0x%08x, calculated=0x%08x",
+ "couldn't erase raw mtd region",
+ "couldn't compare volumes",
+ "on-flash data differ from pfi data, update is neccessary"
+};
+
+#endif /* __PFIFLASH_ERROR_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/reader.c b/drivers/mtd/mtd-utils/ubi-utils/src/reader.c
new file mode 100644
index 00000000000..0ea8c6d8466
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/reader.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ *
+ * Read in PFI (partial flash image) data and store it into internal
+ * data structures for further processing. Take also care about
+ * special handling if the data contains PDD (platform description
+ * data/boot-parameters).
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "bootenv.h"
+#include "reader.h"
+
+#define __unused __attribute__((unused))
+
+/* @FIXME hard coded offsets right now - get them from Artem? */
+#define NAND2048_DEFAULT_VID_HDR_OFF 1984
+#define NAND512_DEFAULT_VID_HDR_OFF 448
+#define NOR_DEFAULT_VID_HDR_OFF 64
+
+#define EBUF_PFI(fmt...) \
+ do { int i = snprintf(err_buf, err_buf_size, "%s\n", label); \
+ snprintf(err_buf + i, err_buf_size - i, fmt); \
+ } while (0)
+
+#define EBUF(fmt...) \
+ do { snprintf(err_buf, err_buf_size, fmt); } while (0)
+
+
+int
+read_pdd_data(FILE* fp_pdd, pdd_data_t* pdd_data,
+ char* err_buf, size_t err_buf_size)
+{
+ int rc = 0;
+ bootenv_t pdd = NULL;
+ pdd_data_t res = NULL;
+ const char* value;
+
+ res = (pdd_data_t) malloc(sizeof(struct pdd_data));
+ if (!res) {
+ rc = -ENOMEM;
+ goto err;
+ }
+ rc = bootenv_create(&pdd);
+ if (rc != 0) {
+ goto err;
+ }
+ rc = bootenv_read_txt(fp_pdd, pdd);
+ if (rc != 0) {
+ goto err;
+ }
+ rc = bootenv_get(pdd, "flash_type", &value);
+ if (rc != 0) {
+ goto err;
+ }
+
+ if (strcmp(value, "NAND") == 0) {
+
+ rc = bootenv_get_num(pdd, "flash_page_size",
+ &(res->flash_page_size));
+ if (rc != 0) {
+ EBUF("Cannot read 'flash_page_size' from pdd.");
+ goto err;
+ }
+ res->flash_type = NAND_FLASH;
+
+ switch (res->flash_page_size) {
+ case 512:
+ res->vid_hdr_offset = NAND512_DEFAULT_VID_HDR_OFF;
+ break;
+ case 2048:
+ res->vid_hdr_offset = NAND2048_DEFAULT_VID_HDR_OFF;
+ break;
+ default:
+ EBUF("Unsupported 'flash_page_size' %d.",
+ res->flash_page_size);
+ goto err;
+ }
+ }
+ else if (strcmp(value, "NOR") == 0){
+ res->flash_type = NOR_FLASH;
+ res->vid_hdr_offset = NOR_DEFAULT_VID_HDR_OFF;
+ }
+ else {
+ snprintf(err_buf, err_buf_size,
+ "Unkown flash type: %s", value);
+ goto err;
+ }
+
+ rc = bootenv_get_num(pdd, "flash_eraseblock_size",
+ &(res->eb_size));
+ if (rc != 0) {
+ EBUF("Cannot read 'flash_eraseblock_size' from pdd.");
+ goto err;
+ }
+
+ rc = bootenv_get_num(pdd, "flash_size",
+ &(res->flash_size));
+ if (rc != 0) {
+ EBUF("Cannot read 'flash_size' from pdd.");
+ goto err;
+ }
+
+ goto out;
+ err:
+ if (res) {
+ free(res);
+ res = NULL;
+ }
+ out:
+ bootenv_destroy(&pdd);
+ *pdd_data = res;
+ return rc;
+}
+
+int
+read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_raw_t* pfi_raw,
+ const char* label, char* err_buf, size_t err_buf_size)
+{
+ int rc = 0;
+ char tmp_str[PFI_KEYWORD_LEN];
+ bootenv_list_t raw_start_list = NULL;
+ pfi_raw_t res;
+ size_t size;
+
+ res = (pfi_raw_t) malloc(sizeof(struct pfi_raw));
+ if (!res)
+ return -ENOMEM;
+
+ rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size));
+ if (rc != 0) {
+ EBUF_PFI("Cannot read 'size' from PFI.");
+ goto err;
+ }
+
+ rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc));
+ if (rc != 0) {
+ EBUF_PFI("Cannot read 'crc' from PFI.");
+ goto err;
+ }
+
+ rc = pfi_header_getstring(pfi_hd, "raw_starts",
+ tmp_str, PFI_KEYWORD_LEN);
+ if (rc != 0) {
+ EBUF_PFI("Cannot read 'raw_starts' from PFI.");
+ goto err;
+ }
+
+ rc = bootenv_list_create(&raw_start_list);
+ if (rc != 0) {
+ goto err;
+ }
+
+ rc = bootenv_list_import(raw_start_list, tmp_str);
+ if (rc != 0) {
+ EBUF_PFI("Cannot translate PFI value: %s", tmp_str);
+ goto err;
+ }
+
+ rc = bootenv_list_to_num_vector(raw_start_list,
+ &size, &(res->starts));
+ res->starts_size = size;
+
+ if (rc != 0) {
+ EBUF_PFI("Cannot create numeric value array: %s", tmp_str);
+ goto err;
+ }
+
+ goto out;
+
+ err:
+ if (res) {
+ free(res);
+ res = NULL;
+ }
+ out:
+ bootenv_list_destroy(&raw_start_list);
+ *pfi_raw = res;
+ return rc;
+}
+
+int
+read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi,
+ const char *label, char* err_buf, size_t err_buf_size)
+{
+ int rc = 0;
+ const char** tmp_names = NULL;
+ char tmp_str[PFI_KEYWORD_LEN];
+ bootenv_list_t ubi_id_list = NULL;
+ bootenv_list_t ubi_name_list = NULL;
+ pfi_ubi_t res;
+ uint32_t i;
+ size_t size;
+
+ res = (pfi_ubi_t) calloc(1, sizeof(struct pfi_ubi));
+ if (!res)
+ return -ENOMEM;
+
+ rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size));
+ if (rc != 0) {
+ EBUF_PFI("Cannot read 'size' from PFI.");
+ goto err;
+ }
+
+ rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc));
+ if (rc != 0) {
+ EBUF_PFI("Cannot read 'crc' from PFI.");
+ goto err;
+ }
+
+ rc = pfi_header_getstring(pfi_hd, "ubi_ids", tmp_str, PFI_KEYWORD_LEN);
+ if (rc != 0) {
+ EBUF_PFI("Cannot read 'ubi_ids' from PFI.");
+ goto err;
+ }
+
+ rc = bootenv_list_create(&ubi_id_list);
+ if (rc != 0) {
+ goto err;
+ }
+ rc = bootenv_list_create(&ubi_name_list);
+ if (rc != 0) {
+ goto err;
+ }
+
+ rc = bootenv_list_import(ubi_id_list, tmp_str);
+ if (rc != 0) {
+ EBUF_PFI("Cannot translate PFI value: %s", tmp_str);
+ goto err;
+ }
+
+ rc = bootenv_list_to_num_vector(ubi_id_list, &size,
+ &(res->ids));
+ res->ids_size = size;
+ if (rc != 0) {
+ EBUF_PFI("Cannot create numeric value array: %s", tmp_str);
+ goto err;
+ }
+
+ if (res->ids_size == 0) {
+ rc = -1;
+ EBUF_PFI("Sanity check failed: No ubi_ids specified.");
+ goto err;
+ }
+
+ rc = pfi_header_getstring(pfi_hd, "ubi_type",
+ tmp_str, PFI_KEYWORD_LEN);
+ if (rc != 0) {
+ EBUF_PFI("Cannot read 'ubi_type' from PFI.");
+ goto err;
+ }
+ if (strcmp(tmp_str, "static") == 0)
+ res->type = pfi_ubi_static;
+ else if (strcmp(tmp_str, "dynamic") == 0)
+ res->type = pfi_ubi_dynamic;
+ else {
+ EBUF_PFI("Unknown ubi_type in PFI.");
+ goto err;
+ }
+
+ rc = pfi_header_getnumber(pfi_hd, "ubi_alignment", &(res->alignment));
+ if (rc != 0) {
+ EBUF_PFI("Cannot read 'ubi_alignment' from PFI.");
+ goto err;
+ }
+
+ rc = pfi_header_getnumber(pfi_hd, "ubi_size", &(res->size));
+ if (rc != 0) {
+ EBUF_PFI("Cannot read 'ubi_size' from PFI.");
+ goto err;
+ }
+
+ rc = pfi_header_getstring(pfi_hd, "ubi_names",
+ tmp_str, PFI_KEYWORD_LEN);
+ if (rc != 0) {
+ EBUF_PFI("Cannot read 'ubi_names' from PFI.");
+ goto err;
+ }
+
+ rc = bootenv_list_import(ubi_name_list, tmp_str);
+ if (rc != 0) {
+ EBUF_PFI("Cannot translate PFI value: %s", tmp_str);
+ goto err;
+ }
+ rc = bootenv_list_to_vector(ubi_name_list, &size,
+ &(tmp_names));
+ res->names_size = size;
+ if (rc != 0) {
+ EBUF_PFI("Cannot create string array: %s", tmp_str);
+ goto err;
+ }
+
+ if (res->names_size != res->ids_size) {
+ EBUF_PFI("Sanity check failed: ubi_ids list does not match "
+ "sizeof ubi_names list.");
+ rc = -1;
+ }
+
+ /* copy tmp_names to own structure */
+ res->names = (char**) calloc(1, res->names_size * sizeof (char*));
+ if (res->names == NULL)
+ goto err;
+
+ for (i = 0; i < res->names_size; i++) {
+ res->names[i] = calloc(PFI_UBI_VOL_NAME_LEN + 1, sizeof(char));
+ if (res->names[i] == NULL)
+ goto err;
+ strncpy(res->names[i], tmp_names[i], PFI_UBI_VOL_NAME_LEN + 1);
+ }
+
+ goto out;
+
+ err:
+ if (res) {
+ if (res->names) {
+ for (i = 0; i < res->names_size; i++) {
+ if (res->names[i]) {
+ free(res->names[i]);
+ }
+ }
+ free(res->names);
+ }
+ if (res->ids) {
+ free(res->ids);
+ }
+ free(res);
+ res = NULL;
+ }
+
+ out:
+ bootenv_list_destroy(&ubi_id_list);
+ bootenv_list_destroy(&ubi_name_list);
+ if (tmp_names != NULL)
+ free(tmp_names);
+ *pfi_ubi = res;
+ return rc;
+}
+
+
+int
+free_pdd_data(pdd_data_t* pdd_data)
+{
+ if (*pdd_data) {
+ free(*pdd_data);
+ }
+ *pdd_data = NULL;
+
+ return 0;
+}
+
+int
+free_pfi_raw(pfi_raw_t* pfi_raw)
+{
+ pfi_raw_t tmp = *pfi_raw;
+ if (tmp) {
+ if (tmp->starts)
+ free(tmp->starts);
+ free(tmp);
+ }
+ *pfi_raw = NULL;
+
+ return 0;
+}
+
+int
+free_pfi_ubi(pfi_ubi_t* pfi_ubi)
+{
+ size_t i;
+ pfi_ubi_t tmp = *pfi_ubi;
+ if (tmp) {
+ if (tmp->ids)
+ free(tmp->ids);
+ if (tmp->names) {
+ for (i = 0; i < tmp->names_size; i++) {
+ if (tmp->names[i]) {
+ free(tmp->names[i]);
+ }
+ }
+ free(tmp->names);
+ }
+ free(tmp);
+ }
+ *pfi_ubi = NULL;
+
+ return 0;
+}
+
+
+int
+read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi,
+ char* err_buf, size_t err_buf_size)
+{
+ int rc = 0;
+ char mode[PFI_KEYWORD_LEN];
+ char label[PFI_LABEL_LEN];
+
+ *pfi_raws = mk_empty(); pfi_raw_t raw = NULL;
+ *pfi_ubis = mk_empty(); pfi_ubi_t ubi = NULL;
+ pfi_header pfi_header = NULL;
+
+ /* read all headers from PFI and store them in lists */
+ rc = pfi_header_init(&pfi_header);
+ if (rc != 0) {
+ EBUF("Cannot initialize pfi header.");
+ goto err;
+ }
+ while ((rc == 0) && !feof(fp_pfi)) {
+ rc = pfi_header_read(fp_pfi, pfi_header);
+ if (rc != 0) {
+ if (rc == PFI_DATA_START) {
+ rc = 0;
+ break; /* data section starts,
+ all headers read */
+ }
+ else {
+ goto err;
+ }
+ }
+ rc = pfi_header_getstring(pfi_header, "label", label,
+ PFI_LABEL_LEN);
+ if (rc != 0) {
+ EBUF("Cannot read 'label' from PFI.");
+ goto err;
+ }
+ rc = pfi_header_getstring(pfi_header, "mode", mode,
+ PFI_KEYWORD_LEN);
+ if (rc != 0) {
+ EBUF("Cannot read 'mode' from PFI.");
+ goto err;
+ }
+ if (strcmp(mode, "ubi") == 0) {
+ rc = read_pfi_ubi(pfi_header, fp_pfi, &ubi, label,
+ err_buf, err_buf_size);
+ if (rc != 0) {
+ goto err;
+ }
+ *pfi_ubis = append_elem(ubi, *pfi_ubis);
+ }
+ else if (strcmp(mode, "raw") == 0) {
+ rc = read_pfi_raw(pfi_header, fp_pfi, &raw, label,
+ err_buf, err_buf_size);
+ if (rc != 0) {
+ goto err;
+ }
+ *pfi_raws = append_elem(raw, *pfi_raws);
+ }
+ else {
+ EBUF("Recvieved unknown mode from PFI: %s", mode);
+ goto err;
+ }
+ }
+ goto out;
+
+ err:
+ *pfi_raws = remove_all((free_func_t)&free_pfi_raw, *pfi_raws);
+ *pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, *pfi_ubis);
+ out:
+ pfi_header_destroy(&pfi_header);
+ return rc;
+
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/reader.h b/drivers/mtd/mtd-utils/ubi-utils/src/reader.h
new file mode 100644
index 00000000000..715e4641c83
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/reader.h
@@ -0,0 +1,87 @@
+#ifndef __READER_H__
+#define __READER_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ *
+ * Read Platform Description Data (PDD).
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "pfi.h"
+#include "bootenv.h"
+#include "list.h"
+
+typedef enum flash_type_t {
+ NAND_FLASH = 0,
+ NOR_FLASH,
+} flash_type_t;
+
+typedef struct pdd_data *pdd_data_t;
+typedef struct pfi_raw *pfi_raw_t;
+typedef struct pfi_ubi *pfi_ubi_t;
+
+struct pdd_data {
+ uint32_t flash_size;
+ uint32_t flash_page_size;
+ uint32_t eb_size;
+ uint32_t vid_hdr_offset;
+ flash_type_t flash_type;
+};
+
+struct pfi_raw {
+ uint32_t data_size;
+ uint32_t *starts;
+ uint32_t starts_size;
+ uint32_t crc;
+};
+
+struct pfi_ubi {
+ uint32_t data_size;
+ uint32_t alignment;
+ uint32_t *ids;
+ uint32_t ids_size;
+ char **names;
+ uint32_t names_size;
+ uint32_t size;
+ enum { pfi_ubi_dynamic, pfi_ubi_static } type;
+ int curr_seqnum; /* specifies the seqnum taken in an update,
+ default: 0 (used by pfiflash, ubimirror) */
+ uint32_t crc;
+};
+
+int read_pdd_data(FILE* fp_pdd, pdd_data_t *pdd_data,
+ char *err_buf, size_t err_buf_size);
+int read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi, pfi_raw_t *pfi_raw,
+ const char *label, char *err_buf, size_t err_buf_size);
+int read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi, pfi_ubi_t *pfi_ubi,
+ const char *label, char *err_buf, size_t err_buf_size);
+
+/**
+ * @brief Reads all pfi headers into list structures, separated by
+ * RAW and UBI sections.
+ */
+int read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi,
+ char* err_buf, size_t err_buf_size);
+int free_pdd_data(pdd_data_t *pdd_data);
+int free_pfi_raw(pfi_raw_t *raw_pfi);
+int free_pfi_ubi(pfi_ubi_t *pfi_ubi);
+
+#endif /* __READER_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c b/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c
new file mode 100644
index 00000000000..9fcafab84b9
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ *
+ * Tool to add UBI headers to binary images.
+ *
+ * 1.0 Initial version
+ * 1.1 Different CRC32 start value
+ * 1.2 Removed argp because we want to use uClibc.
+ * 1.3 Minor cleanups
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <mtd/ubi-header.h>
+
+#include "ubigen.h"
+#include "config.h"
+
+#define PROGRAM_VERSION "1.3"
+
+typedef enum action_t {
+ ACT_NORMAL = 0x00000001,
+ ACT_BROKEN_UPDATE = 0x00000002,
+} action_t;
+
+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
+ "ubigen - a tool for adding UBI information to a binary input file.\n";
+
+static const char *optionsstr =
+" Common settings:\n"
+" -c, --copyright Print copyright information.\n"
+" -d, --debug\n"
+" -v, --verbose Print more progress information.\n"
+"\n"
+" UBI Settings:\n"
+" -A, --alignment=<num> Set the alignment size to <num> (default 1).\n"
+" Values can be specified as bytes, 'ki' or 'Mi'.\n"
+" -B, --blocksize=<num> Set the eraseblock size to <num> (default 128\n"
+" KiB).\n"
+" Values can be specified as bytes, 'ki' or 'Mi'.\n"
+" -E, --erasecount=<num> Set the erase count to <num> (default 0)\n"
+" -I, --id=<num> The UBI volume id.\n"
+" -O, --offset=<num> Offset from start of an erase block to the UBI\n"
+" volume header.\n"
+" -T, --type=<num> The UBI volume type:\n"
+" 1 = dynamic, 2 = static\n"
+" -X, --setver=<num> Set UBI version number to <num> (default 1)\n"
+"\n"
+" Input/Output:\n"
+" -i, --infile=<filename> Read input from file.\n"
+" -o, --outfile=<filename> Write output to file (default is stdout).\n"
+"\n"
+" Special options:\n"
+" -U, --broken-update=<leb> Create an ubi image which simulates a broken\n"
+" update.\n"
+" <leb> specifies the logical eraseblock number to\n"
+" update.\n"
+"\n"
+" -?, --help Give this help list\n"
+" --usage Give a short usage message\n"
+" -V, --version Print program version\n";
+
+static const char *usage =
+"Usage: ubigen [-cdv?V] [-A <num>] [-B <num>] [-E <num>] [-I <num>]\n"
+" [-O <num>] [-T <num>] [-X <num>] [-i <filename>] [-o <filename>]\n"
+" [-U <leb>] [--copyright] [--debug] [--verbose] [--alignment=<num>]\n"
+" [--blocksize=<num>] [--erasecount=<num>] [--id=<num>]\n"
+" [--offset=<num>] [--type=<num>] [--setver=<num>]\n"
+" [--infile=<filename>] [--outfile=<filename>]\n"
+" [--broken-update=<leb>] [--help] [--usage] [--version]\n";
+
+struct option long_options[] = {
+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
+ { .name = "debug", .has_arg = 0, .flag = NULL, .val = 'd' },
+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
+ { .name = "alignment", .has_arg = 1, .flag = NULL, .val = 'A' },
+ { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'B' },
+ { .name = "erasecount", .has_arg = 1, .flag = NULL, .val = 'E' },
+ { .name = "id", .has_arg = 1, .flag = NULL, .val = 'I' },
+ { .name = "offset", .has_arg = 1, .flag = NULL, .val = 'O' },
+ { .name = "type", .has_arg = 1, .flag = NULL, .val = 'T' },
+ { .name = "setver", .has_arg = 1, .flag = NULL, .val = 'X' },
+ { .name = "infile", .has_arg = 1, .flag = NULL, .val = 'i' },
+ { .name = "outfile", .has_arg = 1, .flag = NULL, .val = 'o' },
+ { .name = "broken-update", .has_arg = 1, .flag = NULL, .val = 'U' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0}
+};
+
+static const char copyright [] __attribute__((unused)) =
+ "Copyright IBM Corp 2006";
+
+#define CHECK_ENDP(option, endp) do { \
+ if (*endp) { \
+ fprintf(stderr, \
+ "Parse error option \'%s\'. " \
+ "No correct numeric value.\n" \
+ , option); \
+ exit(EXIT_FAILURE); \
+ } \
+} while(0)
+
+typedef struct myargs {
+ /* common settings */
+ action_t action;
+ int verbose;
+
+ int32_t id;
+ uint8_t type;
+ uint32_t eb_size;
+ uint64_t ec;
+ uint8_t version;
+ uint32_t hdr_offset;
+ uint32_t update_block;
+ uint32_t alignment;
+
+ FILE* fp_in;
+ FILE* fp_out;
+
+ /* special stuff needed to get additional arguments */
+ char *arg1;
+ char **options; /* [STRING...] */
+} myargs;
+
+
+static int ustrtoul(const char *cp, char **endp, unsigned int base)
+{
+ unsigned long result = strtoul(cp, endp, base);
+
+ switch (**endp) {
+ case 'G':
+ result *= 1024;
+ case 'M':
+ result *= 1024;
+ case 'k':
+ case 'K':
+ result *= 1024;
+ /* "Ki", "ki", "Mi" or "Gi" are to be used. */
+ if ((*endp)[1] == 'i')
+ (*endp) += 2;
+ }
+ return result;
+}
+
+static int
+parse_opt(int argc, char **argv, myargs *args)
+{
+ int err = 0;
+ char* endp;
+
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "cdvA:B:E:I:O:T:X:i:o:U:?V",
+ long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'c':
+ fprintf(stderr, "%s\n", copyright);
+ exit(0);
+ break;
+ case 'o': /* output */
+ args->fp_out = fopen(optarg, "wb");
+ if ((args->fp_out) == NULL) {
+ fprintf(stderr, "Cannot open file %s "
+ "for output\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'i': /* input */
+ args->fp_in = fopen(optarg, "rb");
+ if ((args->fp_in) == NULL) {
+ fprintf(stderr, "Cannot open file %s "
+ "for input\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'v': /* verbose */
+ args->verbose = 1;
+ break;
+
+ case 'B': /* eb_size */
+ args->eb_size =
+ (uint32_t)ustrtoul(optarg, &endp, 0);
+ CHECK_ENDP("B", endp);
+ break;
+ case 'E': /* erasecount */
+ args->ec = (uint64_t)strtoul(optarg, &endp, 0);
+ CHECK_ENDP("E", endp);
+ break;
+ case 'I': /* id */
+ args->id = (uint16_t)strtoul(optarg, &endp, 0);
+ CHECK_ENDP("I", endp);
+ break;
+ case 'T': /* type */
+ args->type =
+ (uint16_t)strtoul(optarg, &endp, 0);
+ CHECK_ENDP("T", endp);
+ break;
+ case 'X': /* versionnr */
+ args->version =
+ (uint8_t)strtoul(optarg, &endp, 0);
+ CHECK_ENDP("X", endp);
+ break;
+ case 'O': /* offset for volume hdr */
+ args->hdr_offset =
+ (uint32_t) strtoul(optarg, &endp, 0);
+ CHECK_ENDP("O", endp);
+ break;
+
+ case 'U': /* broken update */
+ args->action = ACT_BROKEN_UPDATE;
+ args->update_block =
+ (uint32_t) strtoul(optarg, &endp, 0);
+ CHECK_ENDP("U", endp);
+ break;
+
+ case '?': /* help */
+ fprintf(stderr, "Usage: ubigen [OPTION...]\n");
+ fprintf(stderr, "%s", doc);
+ fprintf(stderr, "%s", optionsstr);
+ fprintf(stderr, "\nReport bugs to %s\n",
+ PACKAGE_BUGREPORT);
+ exit(0);
+ break;
+
+ case 'V':
+ fprintf(stderr, "%s\n", PROGRAM_VERSION);
+ exit(0);
+ break;
+
+ default:
+ fprintf(stderr, "%s", usage);
+ exit(-1);
+ }
+ }
+
+ if (optind < argc) {
+ if (!args->fp_in) {
+ args->fp_in = fopen(argv[optind++], "rb");
+ if ((args->fp_in) == NULL) {
+ fprintf(stderr, "Cannot open file %s for "
+ "input\n", argv[optind]);
+ exit(1);
+ }
+ }
+ }
+ if (args->id < 0) {
+ err = 1;
+ fprintf(stderr,
+ "Please specify an UBI Volume ID.\n");
+ }
+ if (args->type == 0) {
+ err = 1;
+ fprintf(stderr,
+ "Please specify an UBI Volume type.\n");
+ }
+ if (err) {
+ fprintf(stderr, "%s", usage);
+ exit(1);
+ }
+
+ return 0;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int rc = 0;
+ ubi_info_t u;
+ struct stat file_info;
+ off_t input_len = 0; /* only used in static volumes */
+
+ myargs args = {
+ .action = ACT_NORMAL,
+ .verbose = 0,
+
+ .id = -1,
+ .type = 0,
+ .eb_size = 0,
+ .update_block = 0,
+ .ec = 0,
+ .version = 0,
+ .hdr_offset = (DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE),
+ .alignment = 1,
+
+ .fp_in = NULL,
+ .fp_out = stdout,
+ /* arguments */
+ .arg1 = NULL,
+ .options = NULL,
+ };
+
+ ubigen_init(); /* Init CRC32 table in ubigen */
+
+ /* parse arguments */
+ parse_opt(argc, argv, &args);
+
+ if (fstat(fileno(args.fp_in), &file_info) != 0) {
+ fprintf(stderr, "Cannot fetch file size "
+ "from input file.\n");
+ }
+ input_len = file_info.st_size;
+
+ rc = ubigen_create(&u, (uint32_t)args.id, args.type,
+ args.eb_size, args.ec, args.alignment,
+ args.version, args.hdr_offset, 0 ,input_len,
+ args.fp_in, args.fp_out);
+
+ if (rc != 0) {
+ fprintf(stderr, "Cannot create UBI info handler rc: %d\n", rc);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!args.fp_in || !args.fp_out) {
+ fprintf(stderr, "Input/Output error.\n");
+ exit(EXIT_FAILURE);
+
+ }
+
+ if (args.action & ACT_NORMAL) {
+ rc = ubigen_write_complete(u);
+ }
+ else if (args.action & ACT_BROKEN_UPDATE) {
+ rc = ubigen_write_broken_update(u, args.update_block);
+ }
+ if (rc != 0) {
+ fprintf(stderr, "Error converting input data.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ rc = ubigen_destroy(&u);
+ return rc;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h b/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h
new file mode 100644
index 00000000000..0f43a464601
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h
@@ -0,0 +1,149 @@
+#ifndef __UBIGEN_H__
+#define __UBIGEN_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Frank Haverkamp
+ *
+ * An utility to update UBI volumes.
+ */
+
+#include <stdio.h> /* FILE */
+#include <stdint.h>
+#include <mtd/ubi-header.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DEFAULT_BLOCKSIZE (128 * 1024)
+#define DEFAULT_PAGESIZE (2*1024)
+
+#define EUBIGEN_INVALID_TYPE 1
+#define EUBIGEN_INVALID_HDR_OFFSET 2
+#define EUBIGEN_INVALID_ALIGNMENT 3
+#define EUBIGEN_TOO_SMALL_EB 4
+#define EUBIGEN_MAX_ERROR 5
+
+
+typedef enum action {
+ NO_ERROR = 0x00000000,
+ BROKEN_HDR_CRC = 0x00000001,
+ BROKEN_DATA_CRC = 0x00000002,
+ BROKEN_DATA_SIZE = 0x00000004,
+ BROKEN_OMIT_BLK = 0x00000008,
+ MARK_AS_UPDATE = 0x00000010,
+} ubigen_action_t;
+
+typedef struct ubi_info *ubi_info_t;
+
+/**
+ * @brief Initialize the internal CRC32 table.
+ * @note Necessary because of the used crc32 function in UBI.
+ * A usage of CRC32, from e.g. zlib will fail.
+ */
+void ubigen_init(void);
+
+/**
+ * @brief Create an ubigen handle.
+ * @param ...
+ * @return 0 On sucess.
+ * else Error.
+ * @note This parameterlist is ugly. But we have to use
+ * two big structs and meta information internally,
+ * filling them would be even uglier.
+ */
+int ubigen_create(ubi_info_t *u, uint32_t vol_id, uint8_t vol_type,
+ uint32_t eb_size, uint64_t ec, uint32_t alignment,
+ uint8_t version, uint32_t vid_hdr_offset,
+ uint8_t compat_flag, size_t data_size,
+ FILE* fp_in, FILE* fp_out);
+
+/**
+ * @brief Destroy an ubigen handle.
+ * @param u Handle to free.
+ * @return 0 On success.
+ * else Error.
+ */
+int ubigen_destroy(ubi_info_t *u);
+
+/**
+ * @brief Get number of total logical EBs, necessary for the
+ * complete storage of data in the handle.
+ * @param u The handle.
+ * @return 0 On success.
+ * else Error.
+ */
+int ubigen_get_leb_total(ubi_info_t u, size_t* total);
+
+/**
+ * @brief Get the size in bytes of one logical EB in the handle.
+ * @param u The handle.
+ * @return 0 On success.
+ * else Error.
+ */
+int ubigen_get_leb_size(ubi_info_t u, size_t* size);
+
+
+/**
+ * @brief Write a logical EB (fits exactly into 1 physical EB).
+ * @param u Handle which holds all necessary data.
+ * @param action Additional operations which shall be applied on this
+ * logical eraseblock. Mostly injecting artifical errors.
+ * @return 0 On success.
+ * else Error.
+ */
+int ubigen_write_leb(ubi_info_t u, ubigen_action_t action);
+
+/**
+ * @brief Write a complete array of logical eraseblocks at once.
+ * @param u Handle which holds all necessary data.
+ * @return 0 On success.
+ * else Error.
+ */
+int ubigen_write_complete(ubi_info_t u);
+
+/**
+ * @brief Write a single block which is extracted from the
+ * binary input data.
+ * @param u Handle which holds all necessary data.
+ * @param blk Logical eraseblock which shall hold a inc. copy entry
+ * and a bad data crc.
+ * @return 0 On success.
+ * else Error.
+ */
+int ubigen_write_broken_update(ubi_info_t u, uint32_t blk);
+
+/**
+ * @brief Use the current ubi_info data and some additional data
+ * to set an UBI volume table entry from it.
+ * @param u Handle which holds some of the necessary data.
+ * @param res_bytes Number of reserved bytes which is stored in the volume
+ * table entry.
+ * @param name A string which shall be used as a volume label.
+ * @param lvol_r A pointer to a volume table entry.
+ * @return 0 On success.
+ * else Error.
+ */
+int ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes,
+ const char* name, struct ubi_vtbl_record *lvol_rec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UBIGEN_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c b/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c
new file mode 100644
index 00000000000..2cc4596dea4
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ *
+ * 1.2 Removed argp because we want to use uClibc.
+ * 1.3 Minor cleanups
+ * 1.4 Migrated to new libubi
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <errno.h>
+#include <mtd/ubi-header.h>
+
+#include "config.h"
+#include "error.h"
+#include "example_ubi.h"
+#include "ubimirror.h"
+
+#define PROGRAM_VERSION "1.4"
+
+typedef enum action_t {
+ ACT_NORMAL = 0,
+ ACT_ARGP_ABORT,
+ ACT_ARGP_ERR,
+} action_t;
+
+#define ABORT_ARGP do { \
+ args->action = ACT_ARGP_ABORT; \
+} while (0)
+
+#define ERR_ARGP do { \
+ args->action = ACT_ARGP_ERR; \
+} while (0)
+
+#define VOL_ARGS_MAX 2
+
+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n"
+ "ubimirror - mirrors ubi volumes.\n";
+
+static const char *optionsstr =
+" -c, --copyright Print copyright information.\n"
+" -s, --side=<seqnum> Use the side <seqnum> as source.\n"
+" -?, --help Give this help list\n"
+" --usage Give a short usage message\n"
+" -V, --version Print program version\n";
+
+static const char *usage =
+"Usage: ubimirror [-c?V] [-s <seqnum>] [--copyright] [--side=<seqnum>]\n"
+" [--help] [--usage] [--version] <source> <destination>\n";
+
+static const char copyright [] __attribute__((unused)) =
+ "(C) IBM Coorporation 2007";
+
+struct option long_options[] = {
+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' },
+ { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0}
+};
+
+typedef struct myargs {
+ action_t action;
+ int side;
+ int vol_no; /* index of current volume */
+ /* @FIXME replace by bootenv_list, makes live easier */
+ /* @FIXME remove the constraint of two entries in the array */
+ const char* vol[VOL_ARGS_MAX]; /* comma separated list of src/dst
+ volumes */
+ char *arg1;
+ char **options; /* [STRING...] */
+} myargs;
+
+static int
+get_update_side(const char* str)
+{
+ uint32_t i = strtoul(str, NULL, 0);
+
+ if ((i != 0) && (i != 1)) {
+ return -1;
+ }
+ return i;
+}
+
+
+static int
+parse_opt(int argc, char **argv, myargs *args)
+{
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "cs:?V", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'c':
+ err_msg("%s", copyright);
+ ABORT_ARGP;
+ break;
+ case 's':
+ args->side = get_update_side(optarg);
+ if (args->side < 0) {
+ err_msg("Unsupported seqnum: %s.\n"
+ "Supported seqnums are '0' "
+ "and '1'\n", optarg);
+ ERR_ARGP;
+ }
+ break;
+ case '?': /* help */
+ err_msg("Usage: ubimirror [OPTION...] "
+ "<source> <destination>\n");
+ err_msg("%s", doc);
+ err_msg("%s", optionsstr);
+ err_msg("\nReport bugs to %s\n",
+ PACKAGE_BUGREPORT);
+ exit(0);
+ break;
+ case 'V':
+ err_msg("%s", PROGRAM_VERSION);
+ exit(0);
+ break;
+ default:
+ err_msg("%s", usage);
+ exit(-1);
+ }
+ }
+
+ while (optind < argc) {
+ /* only two entries allowed */
+ if (args->vol_no >= VOL_ARGS_MAX) {
+ err_msg("%s", usage);
+ ERR_ARGP;
+ }
+ args->vol[(args->vol_no)++] = argv[optind++];
+ }
+
+ return 0;
+}
+
+
+int
+main(int argc, char **argv) {
+ int rc = 0;
+ unsigned int ids[VOL_ARGS_MAX];
+ char err_buf[1024];
+
+ myargs args = {
+ .action = ACT_NORMAL,
+ .side = -1,
+ .vol_no = 0,
+ .vol = {"", ""},
+ .options = NULL,
+ };
+
+ parse_opt(argc, argv, &args);
+ if (args.action == ACT_ARGP_ERR) {
+ rc = 127;
+ goto err;
+ }
+ if (args.action == ACT_ARGP_ABORT) {
+ rc = 126;
+ goto out;
+ }
+ if (args.vol_no < VOL_ARGS_MAX) {
+ fprintf(stderr, "missing volume number for %s\n",
+ args.vol_no == 0 ? "source and target" : "target");
+ rc = 125;
+ goto out;
+ }
+ for( rc = 0; rc < args.vol_no; ++rc){
+ char *endp;
+ ids[rc] = strtoul(args.vol[rc], &endp, 0);
+ if( *endp != '\0' ){
+ fprintf(stderr, "invalid volume number %s\n",
+ args.vol[rc]);
+ rc = 125;
+ goto out;
+ }
+ }
+ rc = ubimirror(EXAMPLE_UBI_DEVICE, args.side, ids, args.vol_no,
+ err_buf, sizeof(err_buf));
+ if( rc ){
+ err_buf[sizeof err_buf - 1] = '\0';
+ fprintf(stderr, err_buf);
+ if( rc < 0 )
+ rc = -rc;
+ }
+ out:
+ err:
+ return rc;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h b/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h
new file mode 100644
index 00000000000..d7ae2adf4db
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h
@@ -0,0 +1,66 @@
+#ifndef __UBIMIRROR_H__
+#define __UBIMIRROR_H__
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Oliver Lohmann
+ *
+ * An utility to mirror UBI volumes.
+ */
+
+#include <stdint.h>
+
+/**
+ * @def EUBIMIRROR_SRC_EQ_DST
+ * @brief Given source volume is also in the set of destination volumes.
+ */
+#define EUBIMIRROR_SRC_EQ_DST 20
+
+/**
+ * @def EUBIMIRROR_NO_SRC
+ * @brief The given source volume does not exist.
+ */
+#define EUBIMIRROR_NO_SRC 21
+
+/**
+ * @def EUBIMIRROR_NO_DST
+ * @brief One of the given destination volumes does not exist.
+ */
+#define EUBIMIRROR_NO_DST 22
+
+/**
+ * @brief Mirrors UBI devices from a source device (specified by seqnum)
+ * to n target devices.
+ * @param devno Device number used by the UBI operations.
+ * @param seqnum An index into ids (defines the src_id).
+ * @param ids An array of ids.
+ * @param ids_size The number of entries in the ids array.
+ * @param err_buf A buffer to store verbose error messages.
+ * @param err_buf_size The size of the error buffer.
+ *
+ * @note A seqnum of value < 0 defaults to a seqnum of 0.
+ * @note A seqnum exceeding the range of ids_size defaults to 0.
+ * @note An empty ids list results in a empty stmt.
+ * @pre The UBI volume which shall be used as source volume exists.
+ * @pre The UBI volumes which are defined as destination volumes exist.
+ * @post The content of the UBI volume which was defined as source volume
+ * equals the content of the volumes which were defined as destination.
+ */
+int ubimirror(uint32_t devno, int seqnum, uint32_t* ids, ssize_t ids_size,
+ char *err_buf, size_t err_buf_size);
+
+#endif /* __UBIMIRROR_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/unubi.c b/drivers/mtd/mtd-utils/ubi-utils/src/unubi.c
new file mode 100644
index 00000000000..ebd527c070c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/unubi.c
@@ -0,0 +1,1024 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Authors: Drake Dowsett, dowsett@de.ibm.com
+ * Frank Haverkamp, haver@vnet.ibm.com
+ *
+ * 1.2 Removed argp because we want to use uClibc.
+ * 1.3 Minor cleanups.
+ * 1.4 Meanwhile Drake had done a lot of changes, syncing those.
+ * 1.5 Bugfixes, simplifications
+ */
+
+/*
+ * unubi reads an image file containing blocks of UBI headers and data
+ * (such as produced from nand2bin) and rebuilds the volumes within. The
+ * default operation (when no flags are given) is to rebuild all valid
+ * volumes found in the image. unubi can also read straight from the
+ * onboard MTD device (ex. /dev/mtdblock/NAND).
+ */
+
+/* TODO: consideration for dynamic vs. static volumes */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <mtd/ubi-header.h>
+#include <mtd_swab.h>
+
+#include "crc32.h"
+#include "unubi_analyze.h"
+
+#define EXEC "unubi"
+#define CONTACT "haver@vnet.ibm.com"
+#define VERSION "1.5"
+
+static char doc[] = "\nVersion: " VERSION "\n";
+static int debug = 0;
+
+static const char *optionsstr =
+"Extract volumes and/or analysis information from an UBI data file.\n"
+"When no parameters are flagged or given, the default operation is\n"
+"to rebuild all valid complete UBI volumes found within the image.\n"
+"\n"
+" OPERATIONS\n"
+" -a, --analyze Analyze image and create gnuplot graphs\n"
+" -i, --info-table Extract volume information tables\n"
+" -r, --rebuild=<volume-id> Extract and rebuild volume\n"
+"\n"
+" OPTIONS\n"
+" -b, --blocksize=<block-size> Specify size of eraseblocks in image in bytes\n"
+" (default 128KiB)\n"
+" -d, --dir=<output-dir> Specify output directory\n"
+" -D, --debug Enable debug output\n"
+" -s, --headersize=<header-size> Specify size reserved for metadata in eraseblock\n"
+ " in bytes (default 2048 Byte)\n"
+ /* the -s option might be insufficient when using different vid
+ offset than what we used when writing this tool ... Better would
+ probably be --vid-hdr-offset or alike */
+"\n"
+" ADVANCED\n"
+" -e, --eb-split Generate individual eraseblock images (all\n"
+" eraseblocks)\n"
+" -v, --vol-split Generate individual eraseblock images (valid\n"
+" eraseblocks only)\n"
+" -V, --vol-split! Raw split by eraseblock (valid eraseblocks only)\n"
+"\n"
+" -?, --help Give this help list\n"
+" --usage Give a short usage message\n"
+" --version Print program version\n"
+"\n";
+
+static const char *usage =
+"Usage: unubi [-aievV?] [-r <volume-id>] [-b <block-size>] [-d <output-dir>]\n"
+" [-s <header-size>] [--analyze] [--info-table]\n"
+" [--rebuild=<volume-id>] [--blocksize=<block-size>]\n"
+" [--dir=<output-dir>] [--headersize=<header-size>] [--eb-split]\n"
+" [--vol-split] [--vol-split!] [--help] [--usage] [--version]\n"
+" image-file\n";
+
+#define ERR_MSG(fmt...) \
+ fprintf(stderr, EXEC ": " fmt)
+
+#define SPLIT_DATA 1
+#define SPLIT_RAW 2
+
+#define DIR_FMT "unubi_%s"
+#define KIB 1024
+#define MIB (KIB * KIB)
+#define MAXPATH KIB
+
+/* filenames */
+#define FN_INVAL "%s/eb%04u%s" /* invalid eraseblock */
+#define FN_NSURE "%s/eb%04u_%03u_%03u_%03x%s" /* unsure eraseblock */
+#define FN_VALID "%s/eb%04u_%03u_%03u_%03x%s" /* valid eraseblock */
+#define FN_VOLSP "%s/vol%03u_%03u_%03u_%04zu" /* split volume */
+#define FN_VOLWH "%s/volume%03u" /* whole volume */
+#define FN_VITBL "%s/vol_info_table%zu" /* vol info table */
+
+static uint32_t crc32_table[256];
+
+/* struct args:
+ * bsize int, blocksize of image blocks
+ * hsize int, eraseblock header size
+ * analyze flag, when non-zero produce analysis
+ * eb_split flag, when non-zero output eb####
+ * note: SPLIT_DATA vs. SPLIT_RAW
+ * vol_split flag, when non-zero output vol###_####
+ * note: SPLIT_DATA vs. SPLIT_RAW
+ * odir_path string, directory to place volumes in
+ * img_path string, file to read as ubi image
+ * vols int array of size UBI_MAX_VOLUMES, where a 1 can be
+ * written for each --rebuild flag in the index specified
+ * then the array can be counted and collapsed using
+ * count_set() and collapse()
+ */
+struct args {
+ int analyze;
+ int itable;
+ uint32_t *vols;
+
+ size_t vid_hdr_offset;
+ size_t data_offset;
+ size_t bsize; /* FIXME replace by vid_hdr/data offs? */
+ size_t hsize;
+
+ char *odir_path;
+ int eb_split;
+ int vol_split;
+ char *img_path;
+
+ char **options;
+};
+
+struct option long_options[] = {
+ { .name = "rebuild", .has_arg = 1, .flag = NULL, .val = 'r' },
+ { .name = "dir", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "analyze", .has_arg = 0, .flag = NULL, .val = 'a' },
+ { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'b' },
+ { .name = "eb-split", .has_arg = 0, .flag = NULL, .val = 'e' },
+ { .name = "vol-split", .has_arg = 0, .flag = NULL, .val = 'v' },
+ { .name = "vol-split!", .has_arg = 0, .flag = NULL, .val = 'e' },
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' },
+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'J' },
+ { NULL, 0, NULL, 0}
+};
+
+/**
+ * parses out a numerical value from a string of numbers followed by:
+ * k, K, kib, KiB for kibibyte
+ * m, M, mib, MiB for mebibyte
+ **/
+static uint32_t
+str_to_num(char *str)
+{
+ char *s;
+ ulong num;
+
+ s = str;
+ num = strtoul(s, &s, 0);
+
+ if (*s != '\0') {
+ if ((strcmp(s, "KiB") == 0) || (strcmp(s, "K") == 0) ||
+ (strcmp(s, "kib") == 0) || (strcmp(s, "k") == 0))
+ num *= KIB;
+ else if ((strcmp(s, "MiB") == 0) || (strcmp(s, "M") == 0) ||
+ (strcmp(s, "mib") == 0) || (strcmp(s, "m") == 0))
+ num *= MIB;
+ else
+ ERR_MSG("couldn't parse '%s', assuming %lu\n",
+ s, num);
+ }
+ return num;
+}
+
+static int
+parse_opt(int argc, char **argv, struct args *args)
+{
+ uint32_t i;
+
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "ab:s:d:Deir:vV?J",
+ long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'a': /* --analyze */
+ args->analyze = 1;
+ break;
+ case 'b': /* --block-size=<block-size> */
+ args->bsize = str_to_num(optarg);
+ break;
+ case 's': /* --header-size=<header-size> */
+ args->hsize = str_to_num(optarg);
+ break;
+ case 'd': /* --dir=<output-dir> */
+ args->odir_path = optarg;
+ break;
+ case 'D': /* --debug */
+ /* I wanted to use -v but that was already
+ used ... */
+ debug = 1;
+ break;
+ case 'e': /* --eb-split */
+ args->eb_split = SPLIT_RAW;
+ break;
+ case 'i': /* --info-table */
+ args->itable = 1;
+ break;
+ case 'r': /* --rebuild=<volume-id> */
+ i = str_to_num(optarg);
+ if (i < UBI_MAX_VOLUMES)
+ args->vols[str_to_num(optarg)] = 1;
+ else {
+ ERR_MSG("volume-id out of bounds\n");
+ return -1;
+ }
+ break;
+ case 'v': /* --vol-split */
+ if (args->vol_split != SPLIT_RAW)
+ args->vol_split = SPLIT_DATA;
+ break;
+ case 'V': /* --vol-split! */
+ args->vol_split = SPLIT_RAW;
+ break;
+ case '?': /* help */
+ fprintf(stderr, "Usage: unubi [OPTION...] "
+ "image-file\n%s%s\nReport bugs to %s\n",
+ doc, optionsstr, CONTACT);
+ exit(0);
+ break;
+ case 'J':
+ fprintf(stderr, "%s\n", VERSION);
+ exit(0);
+ break;
+ default:
+ fprintf(stderr, "%s", usage);
+ exit(-1);
+ }
+ }
+
+ /* FIXME I suppose hsize should be replaced! */
+ args->vid_hdr_offset = args->hsize - UBI_VID_HDR_SIZE;
+ args->data_offset = args->hsize;
+
+ if (optind < argc)
+ args->img_path = argv[optind++];
+ return 0;
+}
+
+
+/**
+ * counts the number of indicies which are flagged in full_array;
+ * full_array is an array of flags (1/0);
+ **/
+static size_t
+count_set(uint32_t *full_array, size_t full_len)
+{
+ size_t count, i;
+
+ if (full_array == NULL)
+ return 0;
+
+ for (i = 0, count = 0; i < full_len; i++)
+ if (full_array[i] != 0)
+ count++;
+
+ return count;
+}
+
+
+/**
+ * generates coll_array from full_array;
+ * full_array is an array of flags (1/0);
+ * coll_array is an array of the indicies in full_array which are flagged (1);
+ **/
+static size_t
+collapse(uint32_t *full_array, size_t full_len,
+ uint32_t *coll_array, size_t coll_len)
+{
+ size_t i, j;
+
+ if ((full_array == NULL) || (coll_array == NULL))
+ return 0;
+
+ for (i = 0, j = 0; (i < full_len) && (j < coll_len); i++)
+ if (full_array[i] != 0) {
+ coll_array[j] = i;
+ j++;
+ }
+
+ return j;
+}
+
+/**
+ * data_crc: save the FILE* position, calculate the crc over a span,
+ * reset the position
+ * returns non-zero when EOF encountered
+ **/
+static int
+data_crc(FILE* fpin, size_t length, uint32_t *ret_crc)
+{
+ int rc;
+ size_t i;
+ char buf[length];
+ uint32_t crc;
+ fpos_t start;
+
+ rc = fgetpos(fpin, &start);
+ if (rc < 0)
+ return -1;
+
+ for (i = 0; i < length; i++) {
+ int c = fgetc(fpin);
+ if (c == EOF) {
+ ERR_MSG("unexpected EOF\n");
+ return -1;
+ }
+ buf[i] = (char)c;
+ }
+
+ rc = fsetpos(fpin, &start);
+ if (rc < 0)
+ return -1;
+
+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, length);
+ *ret_crc = crc;
+ return 0;
+}
+
+
+/**
+ * reads data of size len from fpin and writes it to path
+ **/
+static int
+extract_data(FILE* fpin, size_t len, const char *path)
+{
+ int rc;
+ size_t i;
+ FILE* fpout;
+
+ rc = 0;
+ fpout = NULL;
+
+ fpout = fopen(path, "wb");
+ if (fpout == NULL) {
+ ERR_MSG("couldn't open file for writing: %s\n", path);
+ rc = -1;
+ goto err;
+ }
+
+ for (i = 0; i < len; i++) {
+ int c = fgetc(fpin);
+ if (c == EOF) {
+ ERR_MSG("unexpected EOF while writing: %s\n", path);
+ rc = -2;
+ goto err;
+ }
+ c = fputc(c, fpout);
+ if (c == EOF) {
+ ERR_MSG("couldn't write: %s\n", path);
+ rc = -3;
+ goto err;
+ }
+ }
+
+ err:
+ if (fpout != NULL)
+ fclose(fpout);
+ return rc;
+}
+
+
+/**
+ * extract volume information table from block. saves and reloads fpin
+ * position
+ * returns -1 when a fpos set or get fails, otherwise <= -2 on other
+ * failure and 0 on success
+ **/
+static int
+extract_itable(FILE *fpin, struct eb_info *cur, size_t bsize, size_t num,
+ const char *path)
+{
+ char filename[MAXPATH + 1];
+ int rc;
+ size_t i, max;
+ fpos_t temp;
+ FILE* fpout = NULL;
+ struct ubi_vtbl_record rec;
+
+ if (fpin == NULL || cur == NULL || path == NULL)
+ return -2;
+
+ /* remember position */
+ rc = fgetpos(fpin, &temp);
+ if (rc < 0)
+ return -1;
+
+ /* jump to top of eraseblock, skip to data section */
+ fsetpos(fpin, &cur->eb_top);
+ if (rc < 0)
+ return -1;
+ fseek(fpin, be32_to_cpu(cur->ec.data_offset), SEEK_CUR);
+
+ /* prepare output file */
+ if (be32_to_cpu(cur->vid.vol_id) != UBI_LAYOUT_VOLUME_ID)
+ return -2;
+ memset(filename, 0, MAXPATH + 1);
+ snprintf(filename, MAXPATH, FN_VITBL, path, num);
+ fpout = fopen(filename, "w");
+ if (fpout == NULL)
+ return -2;
+
+ /* loop through entries */
+ fprintf(fpout,
+ "index\trpebs\talign\ttype\tcrc\t\tname\n");
+ max = bsize - be32_to_cpu(cur->ec.data_offset);
+ for (i = 0; i < (max / sizeof(rec)); i++) {
+ int blank = 1;
+ char *ptr, *base;
+ char name[UBI_VOL_NAME_MAX + 1];
+ const char *type = "unknown\0";
+ uint32_t crc;
+
+ /* read record */
+ rc = fread(&rec, 1, sizeof(rec), fpin);
+ if (rc == 0)
+ break;
+ if (rc != sizeof(rec)) {
+ ERR_MSG("reading volume information "
+ "table record failed\n");
+ rc = -3;
+ goto exit;
+ }
+
+ /* check crc */
+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &rec,
+ UBI_VTBL_RECORD_SIZE_CRC);
+ if (crc != be32_to_cpu(rec.crc))
+ continue;
+
+ /* check for empty */
+ base = (char *)&rec;
+ ptr = base;
+ while (blank &&
+ ((unsigned)(ptr - base) < UBI_VTBL_RECORD_SIZE_CRC)) {
+ if (*ptr != 0)
+ blank = 0;
+ ptr++;
+ }
+
+ if (blank)
+ continue;
+
+ /* prep type string */
+ if (rec.vol_type == UBI_VID_DYNAMIC)
+ type = "dynamic\0";
+ else if (rec.vol_type == UBI_VID_STATIC)
+ type = "static\0";
+
+ /* prep name string */
+ rec.name[be16_to_cpu(rec.name_len)] = '\0';
+ sprintf(name, "%s", rec.name);
+
+ /* print record line to fpout */
+ fprintf(fpout, "%zu\t%u\t%u\t%s\t0x%08x\t%s\n",
+ i,
+ be32_to_cpu(rec.reserved_pebs),
+ be32_to_cpu(rec.alignment),
+ type,
+ be32_to_cpu(rec.crc),
+ name);
+ }
+
+ exit:
+ /* reset position */
+ if (fsetpos(fpin, &temp) < 0)
+ rc = -1;
+
+ if (fpout != NULL)
+ fclose(fpout);
+
+ return rc;
+}
+
+
+/**
+ * using eb chain, tries to rebuild the data of volume at vol_id, or for all
+ * the known volumes, if vol_id is NULL;
+ **/
+static int
+rebuild_volume(FILE * fpin, uint32_t *vol_id, struct eb_info **head,
+ const char *path, size_t block_size, size_t header_size)
+{
+ char filename[MAXPATH];
+ int rc;
+ uint32_t vol, num, data_size;
+ FILE* fpout;
+ struct eb_info *cur;
+
+ rc = 0;
+
+ if ((fpin == NULL) || (head == NULL) || (*head == NULL))
+ return 0;
+
+ /* when vol_id is null, then do all */
+ if (vol_id == NULL) {
+ cur = *head;
+ vol = be32_to_cpu(cur->vid.vol_id);
+ } else {
+ vol = *vol_id;
+ eb_chain_position(head, vol, NULL, &cur);
+ if (cur == NULL) {
+ if (debug)
+ ERR_MSG("no valid volume %d was found\n", vol);
+ return -1;
+ }
+ }
+
+ num = 0;
+ snprintf(filename, MAXPATH, FN_VOLWH, path, vol);
+ fpout = fopen(filename, "wb");
+ if (fpout == NULL) {
+ ERR_MSG("couldn't open file for writing: %s\n", filename);
+ return -1;
+ }
+
+ while (cur != NULL) {
+ size_t i;
+
+ if (be32_to_cpu(cur->vid.vol_id) != vol) {
+ /* close out file */
+ fclose(fpout);
+
+ /* only stay around if that was the only volume */
+ if (vol_id != NULL)
+ goto out;
+
+ /* begin with next */
+ vol = be32_to_cpu(cur->vid.vol_id);
+ num = 0;
+ snprintf(filename, MAXPATH, FN_VOLWH, path, vol);
+ fpout = fopen(filename, "wb");
+ if (fpout == NULL) {
+ ERR_MSG("couldn't open file for writing: %s\n",
+ filename);
+ return -1;
+ }
+ }
+
+ while (num < be32_to_cpu(cur->vid.lnum)) {
+ /* FIXME haver: I hope an empty block is
+ written out so that the binary has no holes
+ ... */
+ if (debug)
+ ERR_MSG("missing valid block %d for volume %d\n",
+ num, vol);
+ num++;
+ }
+
+ rc = fsetpos(fpin, &(cur->eb_top));
+ if (rc < 0)
+ goto out;
+ fseek(fpin, be32_to_cpu(cur->ec.data_offset), SEEK_CUR);
+
+ if (cur->vid.vol_type == UBI_VID_DYNAMIC)
+ /* FIXME It might be that alignment has influence */
+ data_size = block_size - header_size;
+ else
+ data_size = be32_to_cpu(cur->vid.data_size);
+
+ for (i = 0; i < data_size; i++) {
+ int c = fgetc(fpin);
+ if (c == EOF) {
+ ERR_MSG("unexpected EOF while writing: %s\n",
+ filename);
+ rc = -2;
+ goto out;
+ }
+ c = fputc(c, fpout);
+ if (c == EOF) {
+ ERR_MSG("couldn't write: %s\n", filename);
+ rc = -3;
+ goto out;
+ }
+ }
+
+ cur = cur->next;
+ num++;
+ }
+
+ out:
+ if (vol_id == NULL)
+ fclose(fpout);
+ return rc;
+}
+
+
+/**
+ * traverses FILE* trying to load complete, valid and accurate header data
+ * into the eb chain;
+ **/
+static int
+unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a)
+{
+ char filename[MAXPATH + 1];
+ char reason[MAXPATH + 1];
+ int rc;
+ size_t i, count, itable_num;
+ /* relations:
+ * cur ~ head
+ * next ~ first */
+ struct eb_info *head, *cur, *first, *next;
+ struct eb_info **next_ptr;
+
+ rc = 0;
+ count = 0;
+ itable_num = 0;
+ head = NULL;
+ first = NULL;
+ next = NULL;
+ cur = malloc(sizeof(*cur));
+ if (cur == NULL) {
+ ERR_MSG("out of memory\n");
+ rc = -ENOMEM;
+ goto err;
+ }
+ memset(cur, 0, sizeof(*cur));
+
+ fgetpos(fpin, &(cur->eb_top));
+ while (1) {
+ const char *raw_path;
+ uint32_t crc;
+
+ cur->phys_addr = ftell(fpin);
+ cur->phys_block = cur->phys_addr / a->bsize;
+ cur->data_crc_ok = 0;
+ cur->ec_crc_ok = 0;
+ cur->vid_crc_ok = 0;
+
+ memset(filename, 0, MAXPATH + 1);
+ memset(reason, 0, MAXPATH + 1);
+
+ /* in case of an incomplete ec header */
+ raw_path = FN_INVAL;
+
+ /* read erasecounter header */
+ rc = fread(&cur->ec, 1, sizeof(cur->ec), fpin);
+ if (rc == 0)
+ goto out; /* EOF */
+ if (rc != sizeof(cur->ec)) {
+ ERR_MSG("reading ec-hdr failed\n");
+ rc = -1;
+ goto err;
+ }
+
+ /* check erasecounter header magic */
+ if (be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) {
+ snprintf(reason, MAXPATH, ".invalid.ec_magic");
+ goto invalid;
+ }
+
+ /* check erasecounter header crc */
+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &(cur->ec),
+ UBI_EC_HDR_SIZE_CRC);
+ if (be32_to_cpu(cur->ec.hdr_crc) != crc) {
+ snprintf(reason, MAXPATH, ".invalid.ec_hdr_crc");
+ goto invalid;
+ }
+
+ /* read volume id header */
+ rc = fsetpos(fpin, &(cur->eb_top));
+ if (rc != 0)
+ goto err;
+ fseek(fpin, be32_to_cpu(cur->ec.vid_hdr_offset), SEEK_CUR);
+ rc = fread(&cur->vid, 1, sizeof(cur->vid), fpin);
+ if (rc == 0)
+ goto out; /* EOF */
+ if (rc != sizeof(cur->vid)) {
+ ERR_MSG("reading vid-hdr failed\n");
+ rc = -1;
+ goto err;
+ }
+
+ /* if the magic number is 0xFFFFFFFF, then it's very likely
+ * that the volume is empty */
+ if (be32_to_cpu(cur->vid.magic) == 0xffffffff) {
+ snprintf(reason, MAXPATH, ".empty");
+ goto invalid;
+ }
+
+ /* vol_id should be in bounds */
+ if ((be32_to_cpu(cur->vid.vol_id) >= UBI_MAX_VOLUMES) &&
+ (be32_to_cpu(cur->vid.vol_id) <
+ UBI_INTERNAL_VOL_START)) {
+ snprintf(reason, MAXPATH, ".invalid");
+ goto invalid;
+ } else
+ raw_path = FN_NSURE;
+
+ /* check volume id header magic */
+ if (be32_to_cpu(cur->vid.magic) != UBI_VID_HDR_MAGIC) {
+ snprintf(reason, MAXPATH, ".invalid.vid_magic");
+ goto invalid;
+ }
+ cur->ec_crc_ok = 1;
+
+ /* check volume id header crc */
+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &(cur->vid),
+ UBI_VID_HDR_SIZE_CRC);
+ if (be32_to_cpu(cur->vid.hdr_crc) != crc) {
+ snprintf(reason, MAXPATH, ".invalid.vid_hdr_crc");
+ goto invalid;
+ }
+ cur->vid_crc_ok = 1;
+
+ /* check data crc, but only for a static volume */
+ if (cur->vid.vol_type == UBI_VID_STATIC) {
+ rc = data_crc(fpin, be32_to_cpu(cur->vid.data_size),
+ &crc);
+ if (rc < 0)
+ goto err;
+ if (be32_to_cpu(cur->vid.data_crc) != crc) {
+ snprintf(reason, MAXPATH, ".invalid.data_crc");
+ goto invalid;
+ }
+ cur->data_crc_ok = 1;
+ }
+
+ /* enlist this vol, it's valid */
+ raw_path = FN_VALID;
+ cur->linear = count;
+ rc = eb_chain_insert(&head, cur);
+ if (rc < 0) {
+ if (rc == -ENOMEM) {
+ ERR_MSG("out of memory\n");
+ goto err;
+ }
+ ERR_MSG("unknown and unexpected error, please contact "
+ CONTACT "\n");
+ goto err;
+ }
+
+ /* extract info-table */
+ if (a->itable &&
+ (be32_to_cpu(cur->vid.vol_id) == UBI_LAYOUT_VOLUME_ID)) {
+ extract_itable(fpin, cur, a->bsize,
+ itable_num, a->odir_path);
+ itable_num++;
+ }
+
+ /* split volumes */
+ if (a->vol_split) {
+ size_t size = 0;
+
+ rc = fsetpos(fpin, &(cur->eb_top));
+ if (rc != 0)
+ goto err;
+
+ /*
+ * FIXME For dynamic UBI volumes we must write
+ * the maximum available data. The
+ * vid.data_size field is not used in this
+ * case. The dynamic volume user is
+ * responsible for the content.
+ */
+ if (a->vol_split == SPLIT_DATA) {
+ /* Write only data section */
+ if (cur->vid.vol_type == UBI_VID_DYNAMIC) {
+ /* FIXME Formular is not
+ always right ... */
+ size = a->bsize - a->hsize;
+ } else
+ size = be32_to_cpu(cur->vid.data_size);
+
+ fseek(fpin,
+ be32_to_cpu(cur->ec.data_offset),
+ SEEK_CUR);
+ }
+ else if (a->vol_split == SPLIT_RAW)
+ /* write entire eraseblock */
+ size = a->bsize;
+
+ snprintf(filename, MAXPATH, FN_VOLSP,
+ a->odir_path,
+ be32_to_cpu(cur->vid.vol_id),
+ be32_to_cpu(cur->vid.lnum),
+ be32_to_cpu(cur->vid.leb_ver), count);
+ rc = extract_data(fpin, size, filename);
+ if (rc < 0)
+ goto err;
+ }
+
+ invalid:
+ /* split eraseblocks */
+ if (a->eb_split) {
+ /* jump to top of block */
+ rc = fsetpos(fpin, &(cur->eb_top));
+ if (rc != 0)
+ goto err;
+
+ if (strcmp(raw_path, FN_INVAL) == 0)
+ snprintf(filename, MAXPATH, raw_path,
+ a->odir_path, count, reason);
+ else
+ snprintf(filename, MAXPATH, raw_path,
+ a->odir_path,
+ count,
+ be32_to_cpu(cur->vid.vol_id),
+ be32_to_cpu(cur->vid.lnum),
+ be32_to_cpu(cur->vid.leb_ver),
+ reason);
+
+ rc = extract_data(fpin, a->bsize, filename);
+ if (rc < 0)
+ goto err;
+ }
+
+ /* append to simple linked list */
+ if (first == NULL)
+ next_ptr = &first;
+ else
+ next_ptr = &next->next;
+
+ *next_ptr = malloc(sizeof(**next_ptr));
+ if (*next_ptr == NULL) {
+ ERR_MSG("out of memory\n");
+ rc = -ENOMEM;
+ goto err;
+ }
+ memset(*next_ptr, 0, sizeof(**next_ptr));
+
+ next = *next_ptr;
+ memcpy(next, cur, sizeof(*next));
+ next->next = NULL;
+
+ count++;
+ rc = fsetpos(fpin, &(cur->eb_top));
+ if (rc != 0)
+ goto err;
+ fseek(fpin, a->bsize, SEEK_CUR);
+ memset(cur, 0, sizeof(*cur));
+
+ fgetpos(fpin, &(cur->eb_top));
+ }
+
+ out:
+ for (i = 0; i < vc; i++) {
+ rc = rebuild_volume(fpin, &vols[i], &head, a->odir_path,
+ a->bsize, a->hsize);
+ if (rc < 0)
+ goto err;
+ }
+
+ /* if there were no volumes specified, rebuild them all,
+ * UNLESS eb_ or vol_ split or analyze was specified */
+ if ((vc == 0) && (!a->eb_split) && (!a->vol_split) &&
+ (!a->analyze) && (!a->itable)) {
+ rc = rebuild_volume(fpin, NULL, &head, a->odir_path, a->bsize,
+ a->hsize);
+ if (rc < 0)
+ goto err;
+ }
+
+ err:
+ free(cur);
+
+ if (a->analyze) {
+ char fname[PATH_MAX];
+ FILE *fp;
+
+ unubi_analyze(&head, first, a->odir_path);
+
+ /* prepare output files */
+ memset(fname, 0, PATH_MAX + 1);
+ snprintf(fname, PATH_MAX, "%s/%s", a->odir_path, FN_EH_STAT);
+ fp = fopen(fname, "w");
+ if (fp != NULL) {
+ eb_chain_print(fp, head);
+ fclose(fp);
+ }
+ }
+ eb_chain_destroy(&head);
+ eb_chain_destroy(&first);
+
+ return rc;
+}
+
+
+/**
+ * handles command line arguments, then calls unubi_volumes
+ **/
+int
+main(int argc, char *argv[])
+{
+ int rc, free_a_odir;
+ size_t vols_len;
+ uint32_t *vols;
+ FILE* fpin;
+ struct args a;
+
+ rc = 0;
+ free_a_odir = 0;
+ vols_len = 0;
+ vols = NULL;
+ fpin = NULL;
+ init_crc32_table(crc32_table);
+
+ /* setup struct args a */
+ memset(&a, 0, sizeof(a));
+ a.bsize = 128 * KIB;
+ a.hsize = 2 * KIB;
+ a.vols = malloc(sizeof(*a.vols) * UBI_MAX_VOLUMES);
+ if (a.vols == NULL) {
+ ERR_MSG("out of memory\n");
+ rc = ENOMEM;
+ goto err;
+ }
+ memset(a.vols, 0, sizeof(*a.vols) * UBI_MAX_VOLUMES);
+
+ /* parse args and check for validity */
+ parse_opt(argc, argv, &a);
+ if (a.img_path == NULL) {
+ ERR_MSG("no image file specified\n");
+ rc = EINVAL;
+ goto err;
+ }
+ else if (a.odir_path == NULL) {
+ char *ptr;
+ int len;
+
+ ptr = strrchr(a.img_path, '/');
+ if (ptr == NULL)
+ ptr = a.img_path;
+ else
+ ptr++;
+
+ len = strlen(DIR_FMT) + strlen(ptr);
+ free_a_odir = 1;
+ a.odir_path = malloc(sizeof(*a.odir_path) * len);
+ if (a.odir_path == NULL) {
+ ERR_MSG("out of memory\n");
+ rc = ENOMEM;
+ goto err;
+ }
+ snprintf(a.odir_path, len, DIR_FMT, ptr);
+ }
+
+ fpin = fopen(a.img_path, "rb");
+ if (fpin == NULL) {
+ ERR_MSG("couldn't open file for reading: "
+ "%s\n", a.img_path);
+ rc = EINVAL;
+ goto err;
+ }
+
+ rc = mkdir(a.odir_path, 0777);
+ if ((rc < 0) && (errno != EEXIST)) {
+ ERR_MSG("couldn't create ouput directory: "
+ "%s\n", a.odir_path);
+ rc = -rc;
+ goto err;
+ }
+
+ /* fill in vols array */
+ vols_len = count_set(a.vols, UBI_MAX_VOLUMES);
+ if (vols_len > 0) {
+ vols = malloc(sizeof(*vols) * vols_len);
+ if (vols == NULL) {
+ ERR_MSG("out of memory\n");
+ rc = ENOMEM;
+ goto err;
+ }
+ collapse(a.vols, UBI_MAX_VOLUMES, vols, vols_len);
+ }
+
+ /* unubi volumes */
+ rc = unubi_volumes(fpin, vols, vols_len, &a);
+ if (rc < 0) {
+ /* ERR_MSG("error encountered while working on image file: "
+ "%s\n", a.img_path); */
+ rc = -rc;
+ goto err;
+ }
+
+ err:
+ free(a.vols);
+ if (free_a_odir != 0)
+ free(a.odir_path);
+ if (fpin != NULL)
+ fclose(fpin);
+ if (vols_len > 0)
+ free(vols);
+ return rc;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c b/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c
new file mode 100644
index 00000000000..ceaa85ff06c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Authors: Drake Dowsett, dowsett@de.ibm.com
+ * Contact: Andreas Arnez, arnez@de.ibm.com
+ *
+ * unubi uses the following functions to generate analysis output based on
+ * the header information in a raw-UBI image
+ */
+
+/*
+ * TODO: use OOB data to check for eraseblock validity in NAND images
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <mtd_swab.h>
+
+#include "unubi_analyze.h"
+#include "crc32.h"
+
+#define EC_X_INT 50
+
+/**
+ * intcmp - function needed by qsort to order integers
+ **/
+int intcmp(const void *a, const void *b)
+{
+ int A = *(int *)a;
+ int B = *(int *)b;
+ return A - B;
+}
+
+int longcmp(const void *a, const void *b)
+{
+ long long A = *(long long *)a;
+ long long B = *(long long *)b;
+ return A - B;
+}
+
+
+/**
+ * unubi_analyze_group_index - finds the normalized index in an array
+ * item: look for this item in the array
+ * array: array to search through
+ * size: length of the array
+ * array should be sorted for this algorithm to perform properly;
+ * if the item is not found returns -1, otherwise return value is the
+ * index in the array (note this contricts the array size to 2^32-1);
+ **/
+int
+norm_index(uint32_t item, uint32_t *array, size_t length)
+{
+ size_t i, index;
+
+ for (index = 0, i = 0; i < length; i++) {
+ if ((i != 0) && (array[i] != array[i - 1]))
+ index++;
+
+ if (item == array[i])
+ return index;
+ }
+
+ return -1;
+}
+
+
+/**
+ * unubi_analyze_ec_hdr - generate data table and plot script
+ * first: head of simple linked list
+ * path: folder to write into
+ * generates a data file containing the eraseblock index in the image
+ * and the erase counter found in its ec header;
+ * if the crc check fails, the line is commented out in the data file;
+ * also generates a simple gnuplot sript for quickly viewing one
+ * display of the data file;
+ **/
+int
+unubi_analyze_ec_hdr(struct eb_info *first, const char *path)
+{
+ char filename[PATH_MAX + 1];
+ size_t count, eraseblocks;
+ uint32_t crc, crc32_table[256];
+ uint64_t *erase_counts;
+ FILE* fpdata;
+ FILE* fpplot;
+ struct eb_info *cur;
+
+ if (first == NULL)
+ return -1;
+
+ /* crc check still needed for `first' linked list */
+ init_crc32_table(crc32_table);
+
+ /* prepare output files */
+ memset(filename, 0, PATH_MAX + 1);
+ snprintf(filename, PATH_MAX, "%s/%s", path, FN_EH_DATA);
+ fpdata = fopen(filename, "w");
+ if (fpdata == NULL)
+ return -1;
+
+ memset(filename, 0, PATH_MAX + 1);
+ snprintf(filename, PATH_MAX, "%s/%s", path, FN_EH_PLOT);
+ fpplot = fopen(filename, "w");
+ if (fpplot == NULL) {
+ fclose(fpdata);
+ return -1;
+ }
+
+ /* make executable */
+ chmod(filename, 0755);
+
+ /* first run: count elements */
+ count = 0;
+ cur = first;
+ while (cur != NULL) {
+ cur = cur->next;
+ count++;
+ }
+ eraseblocks = count;
+
+ erase_counts = malloc(eraseblocks * sizeof(*erase_counts));
+ if (!erase_counts) {
+ perror("out of memory");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(erase_counts, 0, eraseblocks * sizeof(*erase_counts));
+
+ /* second run: populate array to sort */
+ count = 0;
+ cur = first;
+ while (cur != NULL) {
+ erase_counts[count] = be64_to_cpu(cur->ec.ec);
+ cur = cur->next;
+ count++;
+ }
+ qsort(erase_counts, eraseblocks, sizeof(*erase_counts),
+ (void *)longcmp);
+
+ /* third run: generate data file */
+ count = 0;
+ cur = first;
+ fprintf(fpdata, "# eraseblock_no actual_erase_count "
+ "sorted_erase_count\n");
+ while (cur != NULL) {
+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &cur->ec,
+ UBI_EC_HDR_SIZE_CRC);
+
+ if ((be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) ||
+ (crc != be32_to_cpu(cur->ec.hdr_crc)))
+ fprintf(fpdata, "# ");
+
+ fprintf(fpdata, "%zu %llu %llu", count,
+ (unsigned long long)be64_to_cpu(cur->ec.ec),
+ (unsigned long long)erase_counts[count]);
+
+ if (be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC)
+ fprintf(fpdata, " ## bad magic: %08x",
+ be32_to_cpu(cur->ec.magic));
+
+ if (crc != be32_to_cpu(cur->ec.hdr_crc))
+ fprintf(fpdata, " ## CRC mismatch: given=%08x, "
+ "calc=%08x", be32_to_cpu(cur->ec.hdr_crc),
+ crc);
+
+ fprintf(fpdata, "\n");
+
+ cur = cur->next;
+ count++;
+ }
+ fclose(fpdata);
+
+ fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n");
+ fprintf(fpplot, "set xlabel \"eraseblock\"\n");
+
+ /* fourth run: generate plot file xtics */
+ count = 0;
+ cur = first;
+ fprintf(fpplot, "set xtics (");
+ while (cur != NULL) {
+ if ((count % EC_X_INT) == 0) {
+ if (count > 0)
+ fprintf(fpplot, ", ");
+ fprintf(fpplot, "%zd", count);
+ }
+
+ cur = cur->next;
+ count++;
+ }
+ fprintf(fpplot, ")\n");
+
+ fprintf(fpplot, "set ylabel \"erase count\"\n");
+ fprintf(fpplot, "set xrange [-1:%zu]\n", eraseblocks + 1);
+ fprintf(fpplot, "# set yrange [-1:%llu]\n",
+ (unsigned long long)erase_counts[eraseblocks - 1] + 1);
+ fprintf(fpplot, "plot \"%s\" u 1:2 t \"unsorted: %s\" with boxes\n",
+ FN_EH_DATA, FN_EH_DATA);
+ fprintf(fpplot, "# replot \"%s\" u 1:3 t \"sorted: %s\" with lines\n",
+ FN_EH_DATA, FN_EH_DATA);
+ fprintf(fpplot, "pause -1 \"press ENTER\"\n");
+
+ fclose(fpplot);
+
+ return 0;
+}
+
+
+/**
+ * unubi_analyze_vid_hdr - generate data table and plot script
+ * head: head of complex linked list (eb_chain)
+ * path: folder to write into
+ * generates a data file containing the volume id, logical number, leb version,
+ * and data size from the vid header;
+ * all eraseblocks listed in the eb_chain are valid (checked in unubi);
+ * also generates a simple gnuplot sript for quickly viewing one
+ * display of the data file;
+ **/
+int
+unubi_analyze_vid_hdr(struct eb_info **head, const char *path)
+{
+ char filename[PATH_MAX + 1];
+ int rc, y1, y2;
+ size_t count, step, breadth;
+ uint32_t *leb_versions, *data_sizes;
+ FILE* fpdata;
+ FILE* fpplot;
+ struct eb_info *cur;
+
+ if (head == NULL || *head == NULL)
+ return -1;
+
+ rc = 0;
+ fpdata = NULL;
+ fpplot = NULL;
+ data_sizes = NULL;
+ leb_versions = NULL;
+
+ /* prepare output files */
+ memset(filename, 0, PATH_MAX + 1);
+ snprintf(filename, PATH_MAX, "%s/%s", path, FN_VH_DATA);
+ fpdata = fopen(filename, "w");
+ if (fpdata == NULL) {
+ rc = -1;
+ goto exit;
+ }
+
+ memset(filename, 0, PATH_MAX + 1);
+ snprintf(filename, PATH_MAX, "%s/%s", path, FN_VH_PLOT);
+ fpplot = fopen(filename, "w");
+ if (fpplot == NULL) {
+ rc = -1;
+ goto exit;
+ }
+
+ /* make executable */
+ chmod(filename, 0755);
+
+ /* first run: count elements */
+ count = 0;
+ cur = *head;
+ while (cur != NULL) {
+ cur = cur->next;
+ count++;
+ }
+ breadth = count;
+
+ leb_versions = malloc(breadth * sizeof(uint32_t));
+ if (leb_versions == NULL) {
+ rc = -1;
+ goto exit;
+ }
+ memset(leb_versions, 0, breadth * sizeof(uint32_t));
+
+ data_sizes = malloc(breadth * sizeof(uint32_t));
+ if (data_sizes == NULL) {
+ rc = -1;
+ goto exit;
+ }
+ memset(data_sizes, 0, breadth * sizeof(*data_sizes));
+
+ /* second run: populate arrays to sort */
+ count = 0;
+ cur = *head;
+ while (cur != NULL) {
+ leb_versions[count] = be32_to_cpu(cur->vid.leb_ver);
+ data_sizes[count] = be32_to_cpu(cur->vid.data_size);
+ cur = cur->next;
+ count++;
+ }
+ qsort(leb_versions, breadth, sizeof(*leb_versions), (void *)intcmp);
+ qsort(data_sizes, breadth, sizeof(*data_sizes), (void *)intcmp);
+
+ /* third run: generate data file */
+ count = 0;
+ cur = *head;
+ fprintf(fpdata, "# x_axis vol_id lnum y1_axis leb_ver "
+ "y2_axis data_size\n");
+ while (cur != NULL) {
+ y1 = norm_index(be32_to_cpu(cur->vid.leb_ver), leb_versions,
+ breadth);
+ y2 = norm_index(be32_to_cpu(cur->vid.data_size), data_sizes,
+ breadth);
+
+ if ((y1 == -1) || (y2 == -1)) {
+ rc = -1;
+ goto exit;
+ }
+
+ fprintf(fpdata, "%zu %u %u %u %u %u %u\n",
+ count,
+ be32_to_cpu(cur->vid.vol_id),
+ be32_to_cpu(cur->vid.lnum),
+ y1,
+ be32_to_cpu(cur->vid.leb_ver),
+ y2,
+ be32_to_cpu(cur->vid.data_size));
+ cur = cur->next;
+ count++;
+ }
+
+ fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n");
+ fprintf(fpplot, "set xlabel \"volume\"\n");
+
+ /* fourth run: generate plot file xtics */
+ count = 0;
+ step = 0;
+ cur = *head;
+ fprintf(fpplot, "set xtics (");
+ while (cur != NULL) {
+ if (count > 0)
+ fprintf(fpplot, ", ");
+ if (step != be32_to_cpu(cur->vid.vol_id)) {
+ step = be32_to_cpu(cur->vid.vol_id);
+ fprintf(fpplot, "\"%zd\" %zd 0", step, count);
+ }
+ else
+ fprintf(fpplot, "\"%d\" %zd 1",
+ be32_to_cpu(cur->vid.lnum), count);
+ cur = cur->next;
+ count++;
+ }
+ fprintf(fpplot, ")\n");
+ fprintf(fpplot, "set nox2tics\n");
+
+ /* fifth run: generate plot file ytics */
+ count = 0;
+ cur = *head;
+ fprintf(fpplot, "set ylabel \"leb version\"\n");
+ fprintf(fpplot, "set ytics (");
+ while (cur->next != NULL) {
+ y1 = norm_index(be32_to_cpu(cur->vid.leb_ver), leb_versions,
+ breadth);
+
+ if (y1 == -1) {
+ rc = -1;
+ goto exit;
+ }
+
+ if (count > 0)
+ fprintf(fpplot, ", ");
+
+ fprintf(fpplot, "\"%u\" %u", be32_to_cpu(cur->vid.leb_ver),
+ y1);
+
+ cur = cur->next;
+ count++;
+ }
+ fprintf(fpplot, ")\n");
+
+ /* sixth run: generate plot file y2tics */
+ count = 0;
+ cur = *head;
+ fprintf(fpplot, "set y2label \"data size\"\n");
+ fprintf(fpplot, "set y2tics (");
+ while (cur != NULL) {
+ y2 = norm_index(be32_to_cpu(cur->vid.data_size),
+ data_sizes, breadth);
+
+ if (y2 == -1) {
+ rc = -1;
+ goto exit;
+ }
+
+ if (count > 0)
+ fprintf(fpplot, ", ");
+
+ fprintf(fpplot, "\"%u\" %u", be32_to_cpu(cur->vid.data_size),
+ y2);
+
+ cur = cur->next;
+ count++;
+ }
+ fprintf(fpplot, ")\n");
+
+ y1 = norm_index(leb_versions[breadth - 1], leb_versions, breadth);
+ y2 = norm_index(data_sizes[breadth - 1], data_sizes, breadth);
+ fprintf(fpplot, "set xrange [-1:%zu]\n", count + 1);
+ fprintf(fpplot, "set yrange [-1:%u]\n", y1 + 1);
+ fprintf(fpplot, "set y2range [-1:%u]\n", y2 + 1);
+ fprintf(fpplot, "plot \"%s\" u 1:4 t \"leb version: %s\" "
+ "axes x1y1 with lp\n", FN_VH_DATA, FN_VH_DATA);
+ fprintf(fpplot, "replot \"%s\" u 1:6 t \"data size: %s\" "
+ "axes x1y2 with lp\n", FN_VH_DATA, FN_VH_DATA);
+ fprintf(fpplot, "pause -1 \"press ENTER\"\n");
+
+ exit:
+ if (fpdata != NULL)
+ fclose(fpdata);
+ if (fpplot != NULL)
+ fclose(fpplot);
+ if (data_sizes != NULL)
+ free(data_sizes);
+ if (leb_versions != NULL)
+ free(leb_versions);
+
+ return rc;
+}
+
+
+/**
+ * unubi_analyze - run all analyses
+ * head: eb_chain head
+ * first: simple linked list of eraseblock headers (use .next)
+ * path: directory (without trailing slash) to output to
+ * returns 0 upon successful completion, or -1 otherwise
+ **/
+int
+unubi_analyze(struct eb_info **head, struct eb_info *first, const char *path)
+{
+ int ec_rc, vid_rc;
+
+ if (path == NULL)
+ return -1;
+
+ ec_rc = unubi_analyze_ec_hdr(first, path);
+ vid_rc = unubi_analyze_vid_hdr(head, path);
+ if (ec_rc < 0 || vid_rc < 0)
+ return -1;
+
+ return 0;
+}
diff --git a/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h b/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h
new file mode 100644
index 00000000000..8588219732c
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __UNUBI_ANALYZE_H__
+#define __UNUBI_ANALYZE_H__
+
+/*
+ * Author: Drake Dowsett
+ * Contact: Andreas Arnez (arnez@de.ibm.com)
+ *
+ * Eraseblock Chain
+ *
+ * A linked list structure to order eraseblocks by volume and logical number
+ * and to update by version number. Doesn't contain actual eraseblock data
+ * but rather the erasecounter and volume id headers as well as a position
+ * indicator.
+ *
+ * Diagram Example:
+ *
+ * [V1.0v0]->[V1.1v2]->[V1.2v1]->[V2.0v2]->[V2.1v0]->[V2.2v1]->NULL
+ * | | | | | |
+ * NULL [V1.1v1] [V1.2v0] [V2.0v1] NULL [V2.2v0]
+ * | | | |
+ * [V1.1v0] NULL [V2.0v0] NULL
+ * | |
+ * NULL NULL
+ *
+ * [VA.BvC] represents the eb_info for the eraseblock with the vol_id A,
+ * lnum B and leb_ver C
+ * -> represents the `next' pointer
+ * | represents the `older' pointer
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <mtd/ubi-header.h>
+
+#define FN_EH_STAT "analysis_blocks.txt"
+#define FN_EH_DATA "analysis_ec_hdr.data"
+#define FN_EH_PLOT "analysis_ec_hdr.plot"
+#define FN_VH_DATA "analysis_vid_hdr.data"
+#define FN_VH_PLOT "analysis_vid_hdr.plot"
+
+struct eb_info {
+ struct ubi_ec_hdr ec;
+ struct ubi_vid_hdr vid;
+
+ fpos_t eb_top;
+ uint32_t linear;
+ int ec_crc_ok;
+ int vid_crc_ok;
+ int data_crc_ok;
+ uint32_t phys_addr;
+ int phys_block;
+
+ struct eb_info *next;
+ struct eb_info *older;
+};
+
+int eb_chain_insert(struct eb_info **head, struct eb_info *item);
+
+int eb_chain_position(struct eb_info **head, uint32_t vol_id, uint32_t *lnum,
+ struct eb_info **pos);
+
+int eb_chain_print(FILE *stream, struct eb_info *head);
+
+int eb_chain_destroy(struct eb_info **head);
+
+int unubi_analyze(struct eb_info **head, struct eb_info *first,
+ const char *path);
+
+#endif /* __UNUBI_ANALYZE_H__ */
diff --git a/drivers/mtd/mtd-utils/ubi-utils/testcases.txt b/drivers/mtd/mtd-utils/ubi-utils/testcases.txt
new file mode 100644
index 00000000000..dcc1c35a264
--- /dev/null
+++ b/drivers/mtd/mtd-utils/ubi-utils/testcases.txt
@@ -0,0 +1,9 @@
+1. Start some large update, but write there byte-by-byte
+
+2. start update for N bytes, write N-x bytes, then write y bytes, y>x.
+ You have to see that at the last write only x bytes were written,
+ but y-x bytes were not. we may vary x a bit. good number would be
+ 1, 128, 128Ki-128...
+
+3. Try to start update for x bytes, write x bytes, then try to write more.
+ Check that it is impossible to write more.
diff --git a/drivers/mtd/mtdblock-jz.c b/drivers/mtd/mtdblock-jz.c
new file mode 100644
index 00000000000..25bd79876e2
--- /dev/null
+++ b/drivers/mtd/mtdblock-jz.c
@@ -0,0 +1,1320 @@
+/*
+ * Direct MTD block device access
+ *
+ * (C) Nancy <yrtan@ingenic.cn>
+ * Regen <lhhuang@ingenic.cn>
+ * Lucifer <yliu@ingenic.cn>
+ * Betty <xyzhang@ingenic.cn>
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/hdreg.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/blktrans.h>
+#include <linux/mutex.h>
+#include <asm/jzsoc.h>
+
+//#define MTDBLOCK_DEBUG
+#ifdef MTDBLOCK_DEBUG
+#define dprintk(a...) printk(a)
+#else
+#define dprintk(a...) while(0){}
+#endif
+
+#define MTDBLOCK_BIT_VALID_ENTRY 0x80000000
+#define MTDBLOCK_BIT_BLOCK_ADDR 0x7FFFFFFF
+
+#define MTDBLOCK_BIT_FREE_BLOCK 0x01
+#define MTDBLOCK_BIT_BAD_BLOCK 0x02
+#define MTDBLOCK_BIT_EMPTY_BLOCK 0x04
+#define MTDBLOCK_NAND_BLK_STATUS_NORMAL 0xFF
+
+#define WRITE_VERIFY_ENABLE 0
+#define ECC_FAILD_RETRY 5
+#define SECTOR_SIZE 512
+#define SECTOR_SHIFT 9
+
+#define Left(i) ((i) << 1)
+#define Right(i) (((i) << 1) + 1)
+
+struct mtdblk_block_info{
+ unsigned int lifetime;
+ unsigned char tag;
+};
+
+struct mtdblk_fake_fsbuf{
+ unsigned int block_addr_field1;
+ unsigned int block_addr_field2;
+ unsigned int lifetime;
+};
+
+struct mtdblk_zone_t {
+ int total_phys_block;
+ int total_virt_block;
+ int bad_block_num;
+
+ int free_phys_block;
+ int free_virt_block;
+ unsigned int used_block;
+ unsigned int bad_block;
+ unsigned int *block_lookup; //index: virt_block value:block_info's index->phy_block
+ struct mtdblk_block_info *block_info;
+};
+
+static struct mtdblk_dev {
+ struct mtd_info *mtd;
+ int virt_block;
+ int new_phys_block;
+ int old_phys_block;
+
+ int count;
+ struct mutex cache_mutex;
+ /* block_cache */
+ unsigned char *block_cache_data;
+ unsigned char *page_state;
+ unsigned char *page_offset_state;
+ enum { STATE_UNUSED, STATE_USED } block_cache_state;
+ /* page cache */
+ unsigned char *page_cache_data;
+ unsigned long page_num;
+ /* temporary page buffer */
+ unsigned char *g_page_buf;
+
+ /* address mapping & wear-levelling used */
+ struct mtdblk_zone_t *zone;
+} *mtdblks[MAX_MTD_DEVICES];
+
+extern unsigned char **jz_mtdblock_cache; /* defined in nand_base.c for allocating a block cache early */
+
+static struct mtdblk_fake_fsbuf fsoobbuf;
+static struct mtdblk_dev *g_udc_mtdblk;
+static struct mtd_info *g_udc_mtd;
+
+static int mtd_blk[8] = {0}; /* Get from cmdline. Specify which blocks work over mtdblock-jz. */
+static int mtd_blkn[8] = {0}; /* Get from cmdline. Specify which blocks don't work over mtdblock-jz. */
+static int mtdblklog = 0; /* Get from cmdline. Specify whether some log is printed. */
+
+/* address mapping & bad-block managment */
+static int mtdblock_find_free_block (struct mtdblk_dev *mtdblk, int *free_phys_block);
+static int mtdblock_block_info_map_bad_block (struct mtdblk_dev *mtdblk,int phys_block);
+static int mtdblock_mark_bad_block_to_nand(struct mtdblk_dev *mtdblk, int phys_block);
+static int mtdblock_block_lookup_map_entry (struct mtdblk_dev *mtdblk, int virt_block, int phys_block);
+static int mtdblock_block_lookup_unmap_entry (struct mtdblk_dev *mtdblk, int virt_block);
+static int mtdblock_address_translate (struct mtdblk_dev *mtdblk, int virt_block, int *phys_block);
+
+/* block-cache operation */
+static void inline mtdblock_init_block_cache (struct mtdblk_dev *mtdblk);
+static void mtdblock_setup_block_cache (struct mtdblk_dev *mtdblk, int virt_block, int new_phys_block, int old_phys_block);
+static int mtdblock_fill_block_cache(struct mtdblk_dev *mtdblk);
+static int mtdblock_erase_block(struct mtdblk_dev *mtdblk, int phys_block);
+static int mtdblock_program_block(struct mtdblk_dev *mtdblk, int phys_block);
+static int mtdblock_move_to_another_block(struct mtdblk_dev *mtdblk, int old_phys_block);
+static int erase_block (struct mtd_info *mtd, int phys_block);
+static void erase_callback(struct erase_info *done);
+
+/* init */
+static int mtdblock_zone_init(struct mtdblk_dev *mtdblk, int dev);
+static int mtdblock_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo);
+
+extern int *get_jz_badblock_table(void);
+extern unsigned short get_mtdblock_oob_copies(void);
+extern unsigned short get_mtdblock_write_verify_enable(void);
+
+static int mtdblock_move_to_another_block(struct mtdblk_dev *mtdblk, int old_phys_block)
+{
+ struct mtd_info *mtd = mtdblk->mtd;
+ struct nand_chip *this = (struct nand_chip *)mtd->priv;
+ struct mtdblk_block_info *block_info = mtdblk->zone->block_info;
+ struct mtd_oob_ops oobops;
+ unsigned char *tmp_block_cache;
+ unsigned long long pos;
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift) );
+ int new_phys_block, phys_block, i , ret, readfail=0;
+
+// tmp_block_cache = kmalloc(mtdblk->mtd->erasesize, GFP_KERNEL);
+ tmp_block_cache = mtdblk->block_cache_data;
+
+ if(!tmp_block_cache)
+ return -ENOMEM;
+
+ /* read a block from old block */
+ pos = (unsigned long long)old_phys_block<<this->phys_erase_shift;
+ memset(&oobops, 0, sizeof(oobops));
+ oobops.mode = MTD_OOB_AUTO;
+ oobops.len = mtd->writesize;
+ oobops.ooboffs = 2;
+ oobops.ooblen = sizeof(fsoobbuf);
+ oobops.oobbuf = (unsigned char *)&fsoobbuf;
+
+ for(i=0; i<ppb; i++) {
+ do {
+ oobops.datbuf = &tmp_block_cache[i<<this->page_shift];
+ ret = mtd->read_oob(mtd, pos, &oobops);
+ if(ret){
+ readfail ++;
+ if (readfail < ECC_FAILD_RETRY)
+ continue;
+ else {
+ printk("%s WARNING: uncorretable ecc or too many bit error cause bad block\n",__FILE__);
+ readfail = 0;
+ break;
+ }
+ } else {
+ if (readfail != 0)
+ printk("%s: uncorretable ecc ---> correctable ecc due to %d times read retry\n",__FILE__, readfail);
+ readfail = 0;
+ break;
+ }
+ } while(1);
+ pos += mtd->writesize;
+ }
+
+ new_phys_block = mtdblock_mark_bad_block_to_nand(mtdblk, old_phys_block);
+ /* write old block to a new free block */
+ phys_block = new_phys_block;
+ write_retry:
+ do {
+ ret = erase_block(mtd, phys_block);
+ block_info[phys_block].lifetime++;
+
+ /* if erase process error, tagged to be bad block,
+ * and find a new free phys_block to program
+ */
+ if( ret < 0 ) {
+ printk("%s: erase failed , mark to bad block: 0x%x \n",__FILE__, phys_block);
+ phys_block = mtdblock_mark_bad_block_to_nand(mtdblk, phys_block);
+ }
+
+ }while(ret < 0);
+
+ //go for write
+ pos = (unsigned long long)phys_block<<this->phys_erase_shift;
+ for(i=0; i<ppb; i++){
+
+ oobops.datbuf = &tmp_block_cache[i<<this->page_shift];
+ ret =mtd->write_oob(mtd, pos, &oobops);
+ if (ret ){
+ printk("%s: write failed , mark to bad block: 0x%x \n",__FILE__, phys_block);
+ phys_block = mtdblock_mark_bad_block_to_nand(mtdblk, phys_block);
+ goto write_retry;
+ }
+ pos += mtd->writesize;
+ }
+// kfree(tmp_block_cache);
+ new_phys_block = phys_block;
+ return new_phys_block;
+}
+
+static int mtdblock_find_free_block (struct mtdblk_dev *mtdblk, int *free_phys_block)
+{
+ struct mtdblk_zone_t *zone = mtdblk->zone;
+ struct mtdblk_block_info *block_info_table;
+ int i,phys_block;
+ struct mtd_info *mtd = mtdblk->mtd;
+ struct mtd_oob_ops oobops;
+ struct nand_chip *this = mtdblk->mtd->priv;
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ unsigned long long pos;
+
+ phys_block = -1;
+ block_info_table = zone->block_info;
+ for (i = 0; i < zone->total_phys_block; i++)
+ if ((block_info_table[i].tag & MTDBLOCK_BIT_FREE_BLOCK) &&
+ !(block_info_table[i].tag & MTDBLOCK_BIT_BAD_BLOCK)) {
+ phys_block = i;
+ break;
+ }
+ if (phys_block < 0)
+ return -ENOMEM;
+ for (i = phys_block + 1; i < zone->total_phys_block; i++) {
+ if ((block_info_table[i].tag & MTDBLOCK_BIT_FREE_BLOCK) &&
+ !(block_info_table[i].tag & MTDBLOCK_BIT_BAD_BLOCK) &&
+ (block_info_table[i].lifetime < block_info_table[phys_block].lifetime))
+ phys_block = i;
+ }
+
+ *free_phys_block = phys_block;
+ //dprintk("find free phys block: %d,free blocks: %d\n", phys_block,zone->free_phys_block);
+
+ memset(&oobops, 0, sizeof(oobops));
+ oobops.mode = MTD_OOB_AUTO;
+ oobops.ooblen = sizeof(fsoobbuf);
+ oobops.ooboffs = 2;
+ oobops.oobbuf = (unsigned char *)&fsoobbuf;
+ pos = ((unsigned long long)phys_block << this->phys_erase_shift) + ((ppb - 1) << this->page_shift);
+ mtd->read_oob(mtd, pos, &oobops);
+ if (fsoobbuf.block_addr_field1 == 0xFFFFFFFF) {
+ block_info_table[phys_block].tag |= MTDBLOCK_BIT_EMPTY_BLOCK;
+ } else {
+ block_info_table[phys_block].tag &= ~MTDBLOCK_BIT_EMPTY_BLOCK;
+ }
+
+ return 0;
+}
+
+static int mtdblock_block_info_map_bad_block (struct mtdblk_dev *mtdblk, int phys_block)
+{
+ struct mtdblk_zone_t *zone_ptr = mtdblk->zone;
+
+ if(NULL == zone_ptr)
+ printk("zone_ptr is null\n");
+ if(NULL == zone_ptr->block_info)
+ printk("zone_ptr->block_info is null\n");
+
+ zone_ptr->block_info[phys_block].tag |= MTDBLOCK_BIT_BAD_BLOCK;
+ zone_ptr->bad_block++;
+ zone_ptr->free_phys_block--;
+ zone_ptr->free_virt_block--;
+
+ if (zone_ptr->bad_block > zone_ptr->bad_block_num ) {
+ printk("%s Warning: too many bad blocks: %d, nand flash is un-useable\n", __FILE__, zone_ptr->bad_block);
+ return -EIO;
+ } else if (mtdblklog)
+ printk("%s: total bad block num=%d, current bad phys_block=%d\n", __FILE__, zone_ptr->bad_block, phys_block);
+ return 0;
+}
+
+static int mtdblock_block_lookup_map_entry (struct mtdblk_dev *mtdblk, int virt_block, int phys_block)
+{
+ struct mtdblk_zone_t *zone_ptr = mtdblk->zone;
+
+ if(NULL == zone_ptr)
+ printk("%s: zone_ptr is null\n",__FUNCTION__);
+
+ if(virt_block >= zone_ptr->total_virt_block || virt_block < 0){
+ dprintk("virt_block address Abnormal\n");
+ return -EINVAL;
+ }
+ if (!(zone_ptr->block_lookup[virt_block] & MTDBLOCK_BIT_VALID_ENTRY)) {
+ dprintk("map %d -> %d free %d\n", virt_block, phys_block,zone_ptr->free_phys_block);
+ zone_ptr->block_lookup[virt_block] = phys_block;
+ zone_ptr->block_lookup[virt_block] |= MTDBLOCK_BIT_VALID_ENTRY;
+ zone_ptr->block_info[phys_block].tag &= ~MTDBLOCK_BIT_FREE_BLOCK;
+ zone_ptr->free_phys_block--;
+ zone_ptr->free_virt_block--;
+ zone_ptr->used_block++;
+ return 0;
+ } else {
+ dprintk("Error: map block address 0x%x -> (new) 0x%x, (old) 0x%x\n",
+ virt_block, phys_block, zone_ptr->block_lookup[virt_block] & MTDBLOCK_BIT_BLOCK_ADDR);
+ return -EINVAL;
+ }
+}
+
+static int mtdblock_block_lookup_unmap_entry (struct mtdblk_dev *mtdblk, int virt_block)
+{
+ struct mtdblk_zone_t *zone_ptr = mtdblk->zone;
+ int phys_block;
+
+ if (zone_ptr->block_lookup[virt_block] & MTDBLOCK_BIT_VALID_ENTRY) {
+ //dprintk("unmap %d -> %d\n", virt_block, zone_ptr->block_lookup[virt_block] & MTDBLOCK_BIT_BLOCK_ADDR);
+ zone_ptr->block_lookup[virt_block] &= ~MTDBLOCK_BIT_VALID_ENTRY;
+ phys_block = zone_ptr->block_lookup[virt_block] & MTDBLOCK_BIT_BLOCK_ADDR;
+ zone_ptr->block_info[phys_block].tag |= MTDBLOCK_BIT_FREE_BLOCK;
+ zone_ptr->free_phys_block++;
+ zone_ptr->free_virt_block++;
+ zone_ptr->used_block--;
+ return 0;
+ } else {
+ printk("%s Error: unmap block address 0x%x -> NULL\n", __FILE__, virt_block);
+ return -EINVAL;
+ }
+}
+
+static int mtdblock_address_translate (struct mtdblk_dev *mtdblk, int virt_block, int *phys_block)
+{
+ struct mtdblk_zone_t *zone_ptr = mtdblk->zone;
+ unsigned int entry;
+
+ entry = zone_ptr->block_lookup[virt_block];
+ if (!(entry & MTDBLOCK_BIT_VALID_ENTRY))
+ return -EINVAL;
+
+ *phys_block = entry & MTDBLOCK_BIT_BLOCK_ADDR;
+ //dprintk("found valid block mapping virt_block: %d -> phys_block: %d\n", virt_block, *phys_block);
+ return 0;
+}
+
+
+static void mtdblock_init_block_cache(struct mtdblk_dev *mtdblk)
+{
+ struct nand_chip *this = mtdblk->mtd->priv;
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ unsigned short spp = mtdblk->mtd->writesize >> 9 ; //spp : sectors per page
+
+ mtdblk->block_cache_state = STATE_UNUSED;
+ memset(mtdblk->page_state, 0, ppb);
+ memset(mtdblk->page_offset_state, 0, ppb*spp);
+
+ //must clear write buffer before using it.
+ mtdblk->page_num = -1;
+ memset(mtdblk->block_cache_data, 0xFF, mtdblk->mtd->erasesize);
+}
+
+static void mtdblock_setup_block_cache ( struct mtdblk_dev *mtdblk, int virt_block, int new_phys_block, int old_phys_block)
+{
+ struct nand_chip *this = mtdblk->mtd->priv;
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ unsigned short spp = mtdblk->mtd->writesize >> 9 ; //spp : sectors per page
+
+ mtdblk->old_phys_block = old_phys_block;
+ mtdblk->new_phys_block = new_phys_block;
+ mtdblk->virt_block = virt_block;
+ mtdblk->page_num = -1;
+
+ mtdblk->block_cache_state = STATE_USED;
+ memset(mtdblk->page_state, 0, ppb);
+ memset(mtdblk->page_offset_state, 0, ppb*spp);
+
+ //must clear write buffer before using it.
+ memset(mtdblk->block_cache_data, 0xFF, mtdblk->mtd->erasesize);
+}
+
+static int mtdblock_fill_block_cache(struct mtdblk_dev *mtdblk)
+{
+ struct mtd_info *mtd = mtdblk->mtd;
+ struct nand_chip *this = mtd->priv;
+ struct mtd_oob_ops oobops;
+ int phys_block, ret;
+ unsigned short page, sector;
+ unsigned long phys_page;
+ unsigned long long pos;
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ unsigned short sectors_per_page = mtd->writesize >> 9;
+ unsigned char *page_buf = mtdblk->g_page_buf;
+ static int fill_block1 = 0;
+ static int fill_block2 = 0;
+
+ if (mtdblk->old_phys_block == mtdblk->new_phys_block){
+ //dprintk("Needn't read from new block %d to fill cache.\n",mtdblk->new_phys_block);
+ return 0;
+ }
+
+ if (!page_buf)
+ return -ENOMEM;
+
+ memset(&oobops, 0, sizeof(oobops));
+ oobops.mode = MTD_OOB_AUTO;
+ oobops.len = mtd->writesize;
+
+ phys_block = mtdblk->old_phys_block;
+ for (page = 0; page < ppb; page++) {
+ if ( ! mtdblk->page_state[page]) {
+ phys_page = (phys_block * ppb) + page;
+ pos = (unsigned long long)phys_page << this->page_shift;
+page_retry:
+ oobops.datbuf = &mtdblk->block_cache_data[page<<this->page_shift];
+ ret = mtd->read_oob(mtd, pos, &oobops);
+
+ if(ret ){
+ printk("%s: fill_block1 phys_block:%d,page:%d,retry:%d \n",__FILE__,
+ phys_block, page, fill_block1);
+
+ fill_block1++;
+ if(fill_block1 < ECC_FAILD_RETRY)
+ goto page_retry;
+ else
+ printk("%s: reading error when modifying phys_block %d\n!",
+ __FILE__, phys_block);
+ }
+ fill_block1 = 0;
+ }else{
+ for(sector = 0; sector < sectors_per_page; sector++)
+ if( !mtdblk->page_offset_state[(page*sectors_per_page)+sector] )
+ break;
+
+ if(sector != sectors_per_page){
+ phys_page = (phys_block * ppb) + page;
+ pos = (unsigned long long)phys_page<<this->page_shift;
+page_offset_retry:
+ oobops.datbuf = page_buf;
+ ret = mtd->read_oob(mtd, pos, &oobops);
+
+ if(ret ){
+ printk("%s: fill_block2 phys_block:%d,page:%d,retry:%d \n",__FILE__,
+ phys_block, page, fill_block2);
+
+ fill_block2++;
+ if(fill_block2 < ECC_FAILD_RETRY)
+ goto page_offset_retry;
+ else
+ printk("%s: reading error when modifying phys_block %d\n!",
+ __FILE__, phys_block);
+ }
+ fill_block2 = 0;
+ for(; sector < sectors_per_page; sector++)
+ if(!mtdblk->page_offset_state[(page*sectors_per_page) + sector])
+ memcpy(&mtdblk->block_cache_data[(page<<this->page_shift)+(sector<<9)], &page_buf[sector<<9], 512);
+ }
+ }
+ }
+ return 0;
+}
+
+static int mtdblock_erase_block(struct mtdblk_dev *mtdblk, int phys_block)
+{
+ struct mtdblk_zone_t *zone_ptr = mtdblk->zone;
+ struct mtdblk_block_info *block_info = zone_ptr->block_info;
+ struct mtd_info *mtd = mtdblk->mtd;
+ struct nand_chip *this = mtd->priv;
+ unsigned long long pos;
+ int ret;
+
+ struct mtd_oob_ops oobops;
+ memset(&oobops, 0, sizeof(oobops));
+ oobops.mode = MTD_OOB_AUTO;
+ oobops.ooblen = sizeof(fsoobbuf);
+ oobops.ooboffs = 2;
+ oobops.oobbuf = (unsigned char *)&fsoobbuf;
+
+ ret = erase_block(mtd, phys_block);
+ if(ret)
+ return ret;
+
+ /* write info need to be changed Nancy mark! */
+ memset(&fsoobbuf, 0xff, sizeof(fsoobbuf));
+
+ block_info[phys_block].lifetime++;
+ fsoobbuf.lifetime = block_info[phys_block].lifetime;
+
+ pos = (unsigned long long)phys_block << this->phys_erase_shift;
+ mtd->write_oob(mtd, pos, &oobops);
+
+ return ret;
+}
+
+static int mtdblock_program_block(struct mtdblk_dev *mtdblk, int phys_block)
+{
+ struct mtd_info *mtd = mtdblk->mtd;
+ struct nand_chip *this = mtd->priv;
+ struct mtdblk_block_info *block_info = mtdblk->zone->block_info;
+ struct mtd_oob_ops oobops;
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ unsigned long long pos;
+ int ret,i;
+
+ dprintk("W %d-%d\n", mtdblk->virt_block,phys_block);
+ memset(&oobops, 0, sizeof(oobops));
+ oobops.mode = MTD_OOB_AUTO;
+ oobops.len = mtd->writesize;
+ oobops.ooblen = sizeof(fsoobbuf);
+ oobops.ooboffs = 2;
+ oobops.oobbuf = (unsigned char *)&fsoobbuf;
+
+ /* spare area mark need to be changed Nancy mark */
+ memset((unsigned char *)&fsoobbuf, 0xff, sizeof(fsoobbuf));
+ fsoobbuf.block_addr_field1 = mtdblk->virt_block;
+ fsoobbuf.block_addr_field2 = mtdblk->virt_block;
+ fsoobbuf.lifetime = block_info[phys_block].lifetime;
+ for(i=0; i<ppb; i++){
+ pos = ((unsigned long long)phys_block << this->phys_erase_shift) + (i << this->page_shift);
+ oobops.datbuf = &mtdblk->block_cache_data[i<<this->page_shift];
+ /* clear page cache if it is out of time! */
+ if (mtdblk->page_num == (phys_block * ppb) + i)
+ mtdblk->page_num = ~0;
+
+ ret = mtd->write_oob(mtd, pos, &oobops);
+ if (ret)
+ return -1;
+ }
+ return 0;
+}
+
+int mtdblock_flush_cache (struct mtdblk_dev *mtdblk)
+{
+ struct mtd_info *mtd = mtdblk->mtd;
+ struct nand_chip *this = mtd->priv;
+ struct mtd_oob_ops oobops;
+ struct mtdblk_block_info *block_info = mtdblk->zone->block_info;
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ unsigned long phys_page;
+ unsigned long long pos;
+ unsigned char *buf = mtdblk->g_page_buf;
+ int phys_block, page;
+ int ret = 0;
+
+ if (STATE_UNUSED == mtdblk->block_cache_state)
+ return 0;
+
+ memset(&oobops, 0, sizeof(oobops));
+ oobops.mode = MTD_OOB_AUTO;
+ oobops.len = mtd->writesize;
+ oobops.ooblen = sizeof(fsoobbuf);
+ oobops.ooboffs = 2 ;
+ oobops.oobbuf = (unsigned char *)&fsoobbuf;
+
+ /* un-dirty data read from old block */
+ mtdblock_fill_block_cache(mtdblk);
+
+ /* erase a free block */
+ phys_block = mtdblk->new_phys_block;
+
+restart:
+ do {
+ if (!(block_info[phys_block].tag & MTDBLOCK_BIT_EMPTY_BLOCK)) {
+ ret = erase_block(mtd, phys_block);
+ block_info[phys_block].lifetime++;
+
+ /* if erase process error, tagged to be bad block,
+ * and find a new free phys_block to program
+ */
+ if( ret < 0 ) {
+ mtdblk->new_phys_block = mtdblock_mark_bad_block_to_nand(mtdblk, phys_block);
+ printk("%s: phys_block 0x%x erasing failed, marked bad, and find new block 0x%x\n",
+ __FILE__, phys_block, mtdblk->new_phys_block);
+ phys_block = mtdblk->new_phys_block;
+ }
+ }
+ else
+ ret = 1;
+ } while(ret < 0);
+
+ ret = mtdblock_program_block(mtdblk, phys_block);
+ /* if write process error, tagged to be bad block,
+ * and find a new free phys_block to program
+ */
+ if(ret < 0){
+ mtdblk->new_phys_block = mtdblock_mark_bad_block_to_nand(mtdblk, phys_block);
+ printk("%s: phys_block 0x%x programing failed, marked bad, and find new block 0x%x\n",
+ __FILE__, phys_block, mtdblk->new_phys_block);
+ phys_block = mtdblk->new_phys_block;
+ goto restart;
+ }
+ /* Now, program new block done correctly */
+
+ /* if write_verify_enable, read the block back with ECC check,
+ * if Ecc check fail, do Re-programming( back to restart )
+ */
+ if( get_mtdblock_write_verify_enable() ){
+ for (page = 0; page < ppb; page++) {
+ phys_page = (phys_block * ppb) + page;
+ pos = (unsigned long long)phys_page<<this->page_shift;
+
+ oobops.datbuf = buf;
+ ret = mtd->read_oob(mtd, pos, &oobops);
+ if (ret ){
+ phys_block = mtdblock_mark_bad_block_to_nand(mtdblk, phys_block);
+ mtdblk->new_phys_block = phys_block;
+ goto restart;
+ }
+ }
+ }
+ if (mtdblk->old_phys_block != mtdblk->new_phys_block) {
+ phys_block = mtdblk->old_phys_block;
+ ret = mtdblock_erase_block(mtdblk, phys_block);
+ if (ret)
+ {
+ mtdblock_block_info_map_bad_block(mtdblk, phys_block);
+ pos = (unsigned long long)phys_block << this->phys_erase_shift;
+
+ mtd->block_markbad(mtd, pos);
+ printk("%s:erase old_phys_block %d faild,mark it bad\n",__FUNCTION__,phys_block);
+ }
+ }
+ mtdblock_init_block_cache(mtdblk);
+ return 0;
+}
+
+static int mtdblock_mark_bad_block_to_nand(struct mtdblk_dev *mtdblk, int phys_block)
+{
+ struct mtd_info *mtd = mtdblk->mtd;
+ struct nand_chip *this = mtd->priv;
+ unsigned long long pos;
+ int ret;
+
+ /* TODO: when reading error, there is no need to unmap mtdblk->virt_block which
+ will be written, unmapping is just needed when programming occurs error. */
+ mtdblock_block_lookup_unmap_entry(mtdblk, mtdblk->virt_block);
+ mtdblock_block_info_map_bad_block(mtdblk, phys_block);
+
+ ret = erase_block(mtd, phys_block);
+ if(ret)
+ printk("%s erase block %d for marking bad failed\n", __FILE__, phys_block);
+
+ pos = (unsigned long long)phys_block << this->phys_erase_shift;
+
+ mtd->block_markbad(mtd, pos);
+
+ if (mtdblock_find_free_block(mtdblk, &phys_block))
+ printk("%s ERROR: can't find_free_block!!\n", __FILE__);
+
+ mtdblock_block_lookup_map_entry(mtdblk, mtdblk->virt_block, phys_block);
+
+ return phys_block;
+}
+
+/*
+ * Cache stuff...
+ *
+ * Since typical flash erasable sectors are much larger than what Linux's
+ * buffer cache can handle, we must implement read-modify-write on flash
+ * sectors for each block write requests. To avoid over-erasing flash sectors
+ * and to speed things up, we locally cache a whole flash sector while it is
+ * being written to until a different sector is required.
+ */
+
+static void erase_callback(struct erase_info *done)
+{
+ wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
+ wake_up(wait_q);
+}
+
+static int erase_block (struct mtd_info *mtd, int phys_block )
+{
+ struct nand_chip *this = mtd->priv;
+ struct erase_info erase;
+ DECLARE_WAITQUEUE(wait, current);
+ wait_queue_head_t wait_q;
+ int ret;
+
+ dprintk("E %d\n", phys_block);
+ /*
+ * First, let's erase the flash block.
+ */
+ init_waitqueue_head(&wait_q);
+ erase.mtd = mtd;
+ erase.callback = erase_callback;
+ erase.addr = ((unsigned long long)phys_block << this->phys_erase_shift); //pos;
+ erase.len = mtd->erasesize; //len;
+ erase.priv = (u_long)&wait_q;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&wait_q, &wait);
+
+ ret = mtd->erase(mtd, &erase);
+ if (ret) {
+ printk("%s: erase %d block failed\n", __FILE__, phys_block);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&wait_q, &wait);
+ return ret;
+ }
+ schedule(); /* Wait for erase to finish. */
+ remove_wait_queue(&wait_q, &wait);
+ return 0;
+}
+
+static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long sector,
+ int len, const char *buf)
+{
+ struct mtd_info *mtd = mtdblk->mtd;
+ struct nand_chip *this = mtd->priv;
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ unsigned long virt_page;
+ int virt_block, old_phys_block, new_phys_block, page_offset;
+ int page_num_in_block;
+ unsigned short sectors_per_page = mtd->writesize >> 9;
+
+ virt_page = sector / sectors_per_page;
+ page_offset = sector % sectors_per_page;
+ virt_block = virt_page / ppb;
+ page_num_in_block = virt_page % ppb;
+
+ if (mtdblock_address_translate(mtdblk, virt_block, &old_phys_block) < 0) {
+ //dprintk("virtual block 0x%x not mapped\n",virt_block);
+
+ mutex_lock(&mtdblk->cache_mutex);
+ mtdblock_flush_cache(mtdblk);
+ mutex_unlock(&mtdblk->cache_mutex);
+
+ if (mtdblock_find_free_block(mtdblk, &new_phys_block)) {
+ printk("%s ERROR: can't find_free_block!!", __FILE__);
+ return -1;
+ }
+ mtdblock_setup_block_cache(mtdblk, virt_block, new_phys_block, new_phys_block);
+ mtdblock_block_lookup_map_entry(mtdblk, virt_block, new_phys_block);
+ } else {
+ if ( STATE_USED == mtdblk->block_cache_state ) {
+ if ( mtdblk->virt_block!= virt_block) {
+ // Commit before we start a new cache.
+ mutex_lock(&mtdblk->cache_mutex);
+ mtdblock_flush_cache(mtdblk);
+ mutex_unlock(&mtdblk->cache_mutex);
+
+ if (mtdblock_find_free_block(mtdblk, &new_phys_block)) {
+ printk("%s ERROR: can't find_free_block!!", __FILE__);
+ return -1;
+ }
+ mtdblock_block_lookup_unmap_entry(mtdblk, virt_block);
+ mtdblock_setup_block_cache(mtdblk, virt_block, new_phys_block,
+ old_phys_block);
+ mtdblock_block_lookup_map_entry(mtdblk, virt_block, new_phys_block);
+ } else {
+ //dprintk("cache hit: 0x%x\n", virt_page);
+ }
+ } else {
+ //dprintk("in else:with existing mapping: 0x%x -> 0x%x\n", virt_block, old_phys_block);
+
+ if (mtdblock_find_free_block(mtdblk, &new_phys_block)) {
+ printk("%s ERROR: can't find_free_block!!", __FILE__);
+ return -1;
+ }
+ mtdblock_block_lookup_unmap_entry(mtdblk, virt_block);
+ mtdblock_setup_block_cache(mtdblk, virt_block, new_phys_block,
+ old_phys_block);
+ mtdblock_block_lookup_map_entry(mtdblk, virt_block,
+ new_phys_block);
+ }
+ }
+ mtdblk->page_state[page_num_in_block] = 1;
+ mtdblk->page_offset_state[(page_num_in_block*sectors_per_page) + page_offset] = 1;
+ memcpy(&mtdblk->block_cache_data[(page_num_in_block<<this->page_shift) +(page_offset<<9)],
+ buf,512);
+ return 0;
+}
+
+
+
+static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long sector,
+ int len, char *buf)
+{
+ struct mtd_info *mtd = mtdblk->mtd;
+ struct nand_chip *this = mtd->priv;
+ struct mtd_oob_ops oobops;
+ unsigned short ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ int ret, virt_block, phys_block, page_offset;
+ unsigned long virt_page, phys_page, page_num_in_block;
+ unsigned long long pos;
+ unsigned short sectors_per_page = mtd->writesize >> 9;
+ int readfail=0;
+
+ virt_page = sector / sectors_per_page;
+ page_offset = sector % sectors_per_page;
+ virt_block = virt_page / ppb;
+
+ if (virt_block == mtdblk->virt_block) { /* if block already in cache */
+ page_num_in_block = virt_page % ppb;
+ if (mtdblk->page_offset_state[(page_num_in_block*sectors_per_page) + page_offset])
+ memcpy(buf, &mtdblk->block_cache_data[(page_num_in_block<<this->page_shift) + (page_offset<<SECTOR_SHIFT)], len);
+ else {
+ memset(&oobops, 0, sizeof(oobops));
+ oobops.mode = MTD_OOB_AUTO;
+ oobops.len = mtd->writesize;
+ oobops.datbuf = mtdblk->page_cache_data;
+
+ phys_page = (mtdblk->old_phys_block * ppb) + (virt_page % ppb);
+ if(phys_page != mtdblk->page_num) {
+ pos = (unsigned long long)phys_page << this->page_shift;
+read_retry:
+ ret = mtd->read_oob(mtd, pos, &oobops);
+ if(ret){
+ readfail ++;
+ if (readfail < ECC_FAILD_RETRY)
+ goto read_retry;
+ else {
+ printk("%s %s WARNING: page %d uncorretable ecc or too many bit error cause bad block,move this block\n",
+ __FILE__,__FUNCTION__,(int)phys_page);
+ mutex_lock(&mtdblk->cache_mutex);
+ mtdblock_flush_cache(mtdblk); //It has completed "move to another block" function
+ mutex_unlock(&mtdblk->cache_mutex);
+ }
+ }
+
+ if (readfail != 0){
+ printk("%s: page %d uncorretable ecc ---> correctable ecc due to %d times read retry,but still move this block\n",
+ __FILE__,(int)phys_page,readfail);
+ mutex_lock(&mtdblk->cache_mutex);
+ mtdblock_flush_cache(mtdblk); //It has completed "move to another block" function
+ mutex_unlock(&mtdblk->cache_mutex);
+ readfail = 0;
+ }
+
+ mtdblk->page_num = phys_page;
+ }
+ memcpy(buf, &mtdblk->page_cache_data[page_offset<<SECTOR_SHIFT],len);
+ }
+ } else {
+ do {
+ if ( mtdblock_address_translate( mtdblk, virt_block, &phys_block) < 0) {
+ // In a Flash Memory device, there might be a logical block that is
+ // not allcated to a physical block due to the block not being used.
+ // All data returned should be set to 0xFF when accessing this logical
+ // block.
+ memset(buf, 0xFF, SECTOR_SIZE);
+ break;
+ } else {
+ memset(&oobops, 0, sizeof(oobops));
+ oobops.mode = MTD_OOB_AUTO;
+ oobops.len = mtd->writesize;
+ oobops.datbuf = mtdblk->page_cache_data;
+
+ phys_page = (phys_block * ppb) + (virt_page % ppb);
+ if(phys_page != mtdblk->page_num ) {
+ pos = (unsigned long long)phys_page << this->page_shift;
+ ret = mtd->read_oob(mtd, pos, &oobops);
+ if(ret){
+ readfail ++;
+ if (readfail < ECC_FAILD_RETRY)
+ goto read_retry;
+ else {
+ printk("%s WARNING: page %d uncorretable ecc or too many bit error cause bad block,move this block\n",
+ __FILE__,(int)phys_page);
+ mutex_lock(&mtdblk->cache_mutex);
+ mtdblock_flush_cache(mtdblk);
+ mutex_unlock(&mtdblk->cache_mutex);
+
+ printk("--%s %s: move to another block\n",
+ __FILE__, __FUNCTION__);
+ mtdblock_move_to_another_block(mtdblk, phys_block);
+
+ }
+ }
+
+ if (readfail != 0){
+ printk("%s: page %d uncorretable ecc ---> correctable ecc due to %d times read retry,but still move this block\n",
+ __FILE__,(int)phys_page, readfail);
+ mutex_lock(&mtdblk->cache_mutex);
+ mtdblock_flush_cache(mtdblk); //It has completed "move to another block" function
+ mutex_unlock(&mtdblk->cache_mutex);
+ printk("--%s %s: move to another block\n", __FILE__, __FUNCTION__);
+ mtdblock_move_to_another_block(mtdblk, phys_block);
+ readfail = 0;
+ }
+
+ mtdblk->page_num = phys_page;
+ }
+ memcpy(buf, &mtdblk->page_cache_data[page_offset<<SECTOR_SHIFT],len);
+ break;
+ }
+ } while(1);
+ }
+
+ return 0;
+}
+
+
+static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
+ unsigned long block, char *buf)
+{
+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
+ if (unlikely(dev->mtd->flags & MTD_MTDBLOCK_JZ_INVALID)) {
+ return 0;
+ }
+ return do_cached_read(mtdblk, block, SECTOR_SIZE, buf);
+}
+
+static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
+ unsigned long block, char *buf)
+{
+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
+ if (unlikely(dev->mtd->flags & MTD_MTDBLOCK_JZ_INVALID)) {
+ return 0;
+ }
+
+ return do_cached_write(mtdblk, block, SECTOR_SIZE, buf);
+}
+
+#if defined(CONFIG_UDC_USE_LB_CACHE)
+int udc_mtdblock_readsect(struct mtdblk_dev *mtdblk,
+ unsigned long block, char *buf, int size)
+{
+ do_cached_read(mtdblk, block, SECTOR_SIZE, buf);
+ return size;
+}
+
+int udc_mtdblock_writesect(struct mtdblk_dev *mtdblk,
+ unsigned long block, char *buf)
+{
+ do_cached_write(mtdblk, block, SECTOR_SIZE, buf);
+ return SECTOR_SIZE;
+}
+
+struct mtdblk_dev *udc_get_mtdblk(void)
+{
+ return g_udc_mtdblk;
+}
+
+struct mtd_info *udc_get_mtd(void)
+{
+ return g_udc_mtd;
+}
+
+void udc_flush_cache(struct mtdblk_dev *mtdblk)
+{
+ mutex_lock(&mtdblk->cache_mutex);
+ mtdblock_flush_cache(mtdblk);
+ mutex_unlock(&mtdblk->cache_mutex);
+
+ if (mtdblk->mtd->sync)
+ mtdblk->mtd->sync(mtdblk->mtd);
+}
+
+EXPORT_SYMBOL_GPL(udc_mtdblock_readsect);
+EXPORT_SYMBOL_GPL(udc_mtdblock_writesect);
+EXPORT_SYMBOL_GPL(udc_get_mtdblk);
+EXPORT_SYMBOL_GPL(udc_get_mtd);
+EXPORT_SYMBOL_GPL(udc_flush_cache);
+#endif
+
+static int mtdblock_init_mtdblk(int dev, struct mtd_info *mtd)
+{
+ struct mtdblk_dev *mtdblk;
+ struct nand_chip *this = mtd->priv;
+ unsigned short ppb, spp;
+ int ret;
+
+ mtdblk = kzalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
+ if (!mtdblk)
+ return -ENOMEM;
+
+ memset(mtdblk, 0, sizeof(*mtdblk));
+ mtdblk->count = 1;
+ mtdblk->mtd = mtd;
+ mutex_init(&mtdblk->cache_mutex);
+ ppb = (1 << (this->phys_erase_shift - this->page_shift));
+ spp = mtdblk->mtd->writesize >> 9 ; //spp : sectors per page
+
+ if (!jz_mtdblock_cache || !jz_mtdblock_cache[dev]) {
+ if ((mtd->flags) & MTD_NAND_CPU_MODE) {
+ mtdblk->block_cache_data = vmalloc(mtdblk->mtd->erasesize);
+ printk(" vmalloc 0x%x bytes for jz_mtdblock%d.\n", mtd->erasesize, dev);
+ } else {
+ mtdblk->block_cache_data = kmalloc(mtdblk->mtd->erasesize, GFP_KERNEL);
+ printk(" kmalloc 0x%x bytes for jz_mtdblock%d.\n", mtd->erasesize, dev);
+ }
+ if(!mtdblk->block_cache_data) {
+ printk(" Allocating block cache in mtdblock-jz.c failed.\n");
+ }
+ } else {
+ printk(" Use the block cache allocated early in nand_base.c.\n");
+ mtdblk->block_cache_data = jz_mtdblock_cache[dev]; /* allocated in nand_base.c */
+ }
+
+ mtdblk->page_state = kmalloc(ppb, GFP_KERNEL);
+ mtdblk->page_offset_state = kmalloc(ppb*spp, GFP_KERNEL);
+ mtdblk->page_cache_data = kmalloc(mtdblk->mtd->writesize, GFP_KERNEL);
+ mtdblk->g_page_buf = kmalloc(mtdblk->mtd->writesize, GFP_KERNEL);
+
+ if(!mtdblk->page_state ||
+ !mtdblk->page_offset_state ||
+ !mtdblk->page_cache_data ||
+ !mtdblk->g_page_buf)
+ return -ENOMEM;
+
+ mtdblock_init_block_cache(mtdblk);
+
+ /* alloc & init zone information */
+ ret = mtdblock_zone_init(mtdblk, dev);
+ if(ret)
+ return -ENOMEM;
+
+ mtdblk->virt_block = -1;
+ mtdblks[dev] = mtdblk;
+ g_udc_mtdblk = mtdblk;
+ g_udc_mtd = mtdblk->mtd;
+ return 0;
+}
+
+static int mtdblock_zone_init(struct mtdblk_dev *mtdblk, int dev)
+{
+ struct mtd_info *mtd = mtdblk->mtd;
+ struct nand_chip *this = mtd->priv;
+ struct mtdblk_zone_t *zone_ptr;
+ struct mtd_oob_ops oobops;
+ int *badblock_table = NULL;
+ int i,virt_block, phys_block;
+ unsigned long long pos;
+
+ memset(&oobops, 0, sizeof(oobops));
+ oobops.mode = MTD_OOB_AUTO;
+ oobops.oobbuf = (unsigned char *)&fsoobbuf;
+ oobops.ooboffs = 2;
+ oobops.ooblen = sizeof(fsoobbuf);
+
+ zone_ptr = kmalloc(sizeof(struct mtdblk_zone_t), GFP_KERNEL);
+ if(!zone_ptr)
+ return -ENOMEM;
+ memset(zone_ptr, 0, sizeof(*zone_ptr));
+
+ badblock_table = get_jz_badblock_table();
+ zone_ptr->total_phys_block = mtd->size >> this->phys_erase_shift;
+ zone_ptr->bad_block_num = badblock_table[dev];
+ zone_ptr->total_virt_block = zone_ptr->total_phys_block - zone_ptr->bad_block_num;
+
+ if( zone_ptr->total_virt_block <= 0 ){
+ printk("ERROR 1: bad block allowed set error!!!\n");
+ printk("current partiton totoal_phys_block: %d, bad block allowed set is %d \n",zone_ptr->total_phys_block, zone_ptr->bad_block_num);
+ printk("NOTICE: If you are using Yaffs2 or Jffs2, you can ignore ERROR 1 \n\n");
+ zone_ptr->total_virt_block = zone_ptr->total_phys_block - 1;
+ }
+ zone_ptr->free_phys_block = zone_ptr->total_phys_block;
+ zone_ptr->free_virt_block = zone_ptr->total_virt_block;
+
+ zone_ptr->block_lookup = kzalloc(sizeof(unsigned int) * zone_ptr->total_virt_block, GFP_KERNEL);
+ zone_ptr->block_info = kmalloc(sizeof(struct mtdblk_block_info) * zone_ptr->total_phys_block, GFP_KERNEL);
+
+ if(!zone_ptr->block_lookup ||
+ !zone_ptr->block_info)
+ return -ENOMEM;
+
+ mtdblk->zone = zone_ptr;
+
+ for (phys_block = 0; phys_block < zone_ptr->total_phys_block; phys_block++) {
+ i = 0;
+ pos = (unsigned long long)phys_block<<this->phys_erase_shift;
+ do {
+ mtd->read_oob(mtd, pos, &oobops);
+ pos += (1<<this->page_shift);
+ i++;
+ } while(fsoobbuf.block_addr_field1 != fsoobbuf.block_addr_field2
+ && i < get_mtdblock_oob_copies());
+
+ zone_ptr->block_info[phys_block].tag = MTDBLOCK_BIT_FREE_BLOCK;
+ if( fsoobbuf.lifetime == 0xFFFFFFFF )
+ zone_ptr->block_info[phys_block].lifetime = 0;
+ else
+ zone_ptr->block_info[phys_block].lifetime = fsoobbuf.lifetime;
+
+ virt_block = fsoobbuf.block_addr_field1;
+
+ /*bad block scan. notice: badblock mark is in the last page of eraseblock*/
+ pos = (unsigned long long)phys_block<<this->phys_erase_shift;
+ if(mtd->block_isbad(mtd, pos) ){
+ mtdblock_block_info_map_bad_block(mtdblk, phys_block);
+ dprintk("found bad block 0x%x -> 0x%x\n",
+ virt_block, phys_block);
+ continue;
+ }
+ mtdblock_block_lookup_map_entry(mtdblk, virt_block, phys_block);
+ }
+
+ return 0;
+}
+
+static int mtdblock_open(struct mtd_blktrans_dev *mbd)
+{
+ struct mtd_info *mtd = mbd->mtd;
+ struct nand_chip *this = mtd->priv;
+ int dev = mbd->devnum;
+ int res, i;
+
+ DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
+ /* If the partition doesn't work over mtdblock-jz, just return! */
+ for (i = 1; mtd_blkn[i]; i++) {
+ if (dev == mtd_blkn[i])
+ return 0;
+ }
+ if (mtd_blk[0]) { /* mtd_blk[0] is the num of blocks specified in cmdline */
+ for (i = 1; mtd_blk[i]; i++) {
+ if (dev == mtd_blk[i])
+ break;
+ }
+ if (!mtd_blk[i])
+ return 0;
+ }
+
+ if (mtd->flags & MTD_MTDBLOCK_JZ_INVALID) {
+ dprintk(" mtdblock%d doesn't work over mtdblock-jz.\n",dev);
+ return 0;
+ }
+
+ //dprintk(" mtdblock%d works over mtdblock-jz.\n",dev);
+
+ if (mtdblks[dev]) {
+ mtdblks[dev]->count++;
+ if (mtdblklog)
+ printk("%s: increase use count\n",__FUNCTION__);
+ return 0;
+ }
+
+ /* OK, it's not open. Create cache info for it */
+ if(this == NULL)
+ printk("this is part mtd info\n");
+
+ res = mtdblock_init_mtdblk(dev, mtd);
+
+ return res;
+}
+
+static int mtdblock_release(struct mtd_blktrans_dev *mbd)
+{
+ struct mtd_info *mtd = mbd->mtd;
+ int dev = mbd->devnum;
+ struct mtdblk_dev *mtdblk;
+ struct mtdblk_zone_t *zone_ptr;
+ int i;
+
+ /* If the partition doesn't work over mtdblock-jz, just return! */
+ for (i = 1; mtd_blkn[i]; i++) {
+ if (dev == mtd_blkn[i])
+ return 0;
+ }
+ if (mtd_blk[0]) {
+ for (i = 1; mtd_blk[i]; i++) {
+ if (dev == mtd_blk[i])
+ break;
+ }
+ if (!mtd_blk[i])
+ return 0;
+ }
+
+ if (mtd->flags & MTD_MTDBLOCK_JZ_INVALID) {
+ return 0;
+ }
+
+ mtdblk = mtdblks[dev];
+ zone_ptr = mtdblk->zone;
+
+ mutex_lock(&mtdblk->cache_mutex);
+ mtdblock_flush_cache(mtdblk);
+ mutex_unlock(&mtdblk->cache_mutex);
+
+ if (!--mtdblk->count) {
+ /* It was the last usage. Free the device */
+ if (mtdblk->mtd->sync)
+ mtdblk->mtd->sync(mtdblk->mtd);
+
+ kfree(zone_ptr->block_info);
+ kfree(zone_ptr->block_lookup);
+ kfree(zone_ptr);
+
+ /* If it was allocated in mtdblock-jz itself, free it here. */
+ if (!jz_mtdblock_cache || !jz_mtdblock_cache[dev]) {
+ if ((mtd->flags) & MTD_NAND_CPU_MODE) {
+ vfree(mtdblk->block_cache_data);
+ printk(" vfree 0x%x bytes for jz_mtdblock%d.\n", mtd->erasesize, dev);
+ } else {
+ kfree(mtdblk->block_cache_data);
+ printk(" kfree 0x%x bytes for jz_mtdblock%d.\n", mtd->erasesize, dev);
+ }
+ }
+ kfree(mtdblk->page_state);
+ kfree(mtdblk->page_offset_state);
+ kfree(mtdblk->page_cache_data);
+ kfree(mtdblk->g_page_buf);
+ kfree(mtdblk);
+ mtdblks[dev] = NULL;
+
+ } else if (mtdblklog) {
+ printk("%s: decrease use count\n", __FUNCTION__);
+ }
+
+ return 0;
+}
+
+static int mtdblock_flush(struct mtd_blktrans_dev *dev)
+{
+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
+
+ mutex_lock(&mtdblk->cache_mutex);
+ mtdblock_flush_cache(mtdblk);
+ mutex_unlock(&mtdblk->cache_mutex);
+
+ if (mtdblk->mtd->sync)
+ mtdblk->mtd->sync(mtdblk->mtd);
+ return 0;
+}
+
+static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
+{
+ struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ struct nand_chip *this = mtd->priv;
+ int *badblock_table = NULL;
+ int reserved_sectors;
+
+ if (!dev)
+ return;
+
+ memset(dev, 0, sizeof(*dev));
+ dev->mtd = mtd;
+ dev->devnum = mtd->index;
+
+ badblock_table = get_jz_badblock_table();
+ reserved_sectors = badblock_table[dev->devnum ] << (this->phys_erase_shift - 9) ;
+ dev->size = (mtd->size >> 9) - reserved_sectors;
+ dev->tr = tr;
+
+ if (!(mtd->flags & MTD_WRITEABLE))
+ dev->readonly = 1;
+
+ add_mtd_blktrans_dev(dev);
+}
+
+static int mtdblock_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
+{
+ memset(geo, 0, sizeof(*geo));
+ geo->heads = 4;
+ geo->sectors = 16;
+ geo->cylinders = dev->size/(4*16);
+ return 0;
+}
+
+static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
+{
+ del_mtd_blktrans_dev(dev);
+ kfree(dev);
+}
+
+static int __init mtdblk_setup(char *str)
+{
+ str = get_options(str, ARRAY_SIZE(mtd_blk), mtd_blk);
+ if (!str || !*str)
+ return 0;
+
+ return 1;
+}
+
+__setup("mtdblk=", mtdblk_setup);
+
+static int __init mtdblkn_setup(char *str)
+{
+ str = get_options(str, ARRAY_SIZE(mtd_blkn), mtd_blkn);
+ if (!str || !*str)
+ return 0;
+
+ return 1;
+}
+
+__setup("mtdblkn=", mtdblkn_setup);
+
+static int __init mtdblklog_setup(char *str)
+{
+ if (*str)
+ return 0;
+ mtdblklog = 1;
+ return 1;
+}
+
+__setup("mtdblklog", mtdblklog_setup);
+
+
+static struct mtd_blktrans_ops mtdblock_tr = {
+ .name = "mtdblock",
+ .major = 31,
+ .part_bits = 0,
+ .blksize = 512,
+ .open = mtdblock_open,
+ .flush = mtdblock_flush,
+ .getgeo = mtdblock_getgeo,
+ .release = mtdblock_release,
+ .readsect = mtdblock_readsect,
+ .writesect = mtdblock_writesect,
+ .add_mtd = mtdblock_add_mtd,
+ .remove_dev = mtdblock_remove_dev,
+ .owner = THIS_MODULE,
+};
+
+static int __init init_mtdblock(void)
+{
+ return register_mtd_blktrans(&mtdblock_tr);
+}
+
+static void __exit cleanup_mtdblock(void)
+{
+ deregister_mtd_blktrans(&mtdblock_tr);
+}
+
+module_init(init_mtdblock);
+module_exit(cleanup_mtdblock);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nancy <yrtan@ingenic.cn> et al.");
+MODULE_DESCRIPTION("Caching read/erase/writeback block device emulation access to MTD devices");
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 77db5ce24d9..70fe1e7c19f 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -1,6 +1,8 @@
/*
* Direct MTD block device access
*
+ * $Id: mtdblock.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $
+ *
* (C) 2000-2003 Nicolas Pitre <nico@cam.org>
* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
*/
@@ -13,7 +15,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
-
+#include <linux/hdreg.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/blktrans.h>
#include <linux/mutex.h>
@@ -29,8 +31,6 @@ static struct mtdblk_dev {
enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
} *mtdblks[MAX_MTD_DEVICES];
-static struct mutex mtdblks_lock;
-
/*
* Cache stuff...
*
@@ -135,10 +135,12 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",
mtd->name, pos, len);
-
+
if (!sect_size)
return mtd->write(mtd, pos, len, &retlen, buf);
+ DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: walk cache way.\n");
+
while (len > 0) {
unsigned long sect_start = (pos/sect_size)*sect_size;
unsigned int offset = pos - sect_start;
@@ -147,6 +149,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
size = len;
if (size == sect_size) {
+ DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: walk erase_write path.\n");
/*
* We are covering a whole sector. Thus there is no
* need to bother with the cache while it may still be
@@ -156,11 +159,14 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
if (ret)
return ret;
} else {
+ DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: walk partial path.\n");
/* Partial sector: need to use the cache */
if (mtdblk->cache_state == STATE_DIRTY &&
- mtdblk->cache_offset != sect_start) {
+ mtdblk->cache_offset != sect_start) {
+ DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: before write_cached_data.\n");
ret = write_cached_data(mtdblk);
+ DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: after write_cached_data.\n");
if (ret)
return ret;
}
@@ -169,8 +175,13 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
mtdblk->cache_offset != sect_start) {
/* fill the cache with the current sector */
mtdblk->cache_state = STATE_EMPTY;
+
+ DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: before mtd->read.\n");
+
ret = mtd->read(mtd, sect_start, sect_size,
&retlen, mtdblk->cache_data);
+
+ DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: after mtd->read.\n");
if (ret)
return ret;
if (retlen != sect_size)
@@ -209,6 +220,8 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
if (!sect_size)
return mtd->read(mtd, pos, len, &retlen, buf);
+ DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: walk cache way.\n");
+
while (len > 0) {
unsigned long sect_start = (pos/sect_size)*sect_size;
unsigned int offset = pos - sect_start;
@@ -226,7 +239,9 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
mtdblk->cache_offset == sect_start) {
memcpy (buf, mtdblk->cache_data + offset, size);
} else {
+ DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: before mtd->read.\n");
ret = mtd->read(mtd, pos, size, &retlen, buf);
+ DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: after mtd->read.\n");
if (ret)
return ret;
if (retlen != size)
@@ -272,19 +287,15 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
- mutex_lock(&mtdblks_lock);
if (mtdblks[dev]) {
mtdblks[dev]->count++;
- mutex_unlock(&mtdblks_lock);
return 0;
}
/* OK, it's not open. Create cache info for it */
mtdblk = kzalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
- if (!mtdblk) {
- mutex_unlock(&mtdblks_lock);
+ if (!mtdblk)
return -ENOMEM;
- }
mtdblk->count = 1;
mtdblk->mtd = mtd;
@@ -297,7 +308,6 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
}
mtdblks[dev] = mtdblk;
- mutex_unlock(&mtdblks_lock);
DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
@@ -311,8 +321,6 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd)
DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
- mutex_lock(&mtdblks_lock);
-
mutex_lock(&mtdblk->cache_mutex);
write_cached_data(mtdblk);
mutex_unlock(&mtdblk->cache_mutex);
@@ -325,9 +333,6 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd)
vfree(mtdblk->cache_data);
kfree(mtdblk);
}
-
- mutex_unlock(&mtdblks_lock);
-
DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
return 0;
@@ -371,12 +376,25 @@ static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
kfree(dev);
}
+
+static int mtdblock_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
+{
+ memset(geo, 0, sizeof(*geo));
+
+ geo->heads = 4;
+ geo->sectors = 16;
+ geo->cylinders = dev->size/(4*16);
+
+ return 0;
+}
+
static struct mtd_blktrans_ops mtdblock_tr = {
.name = "mtdblock",
.major = 31,
.part_bits = 0,
.blksize = 512,
.open = mtdblock_open,
+ .getgeo = mtdblock_getgeo,
.flush = mtdblock_flush,
.release = mtdblock_release,
.readsect = mtdblock_readsect,
@@ -388,8 +406,6 @@ static struct mtd_blktrans_ops mtdblock_tr = {
static int __init init_mtdblock(void)
{
- mutex_init(&mtdblks_lock);
-
return register_mtd_blktrans(&mtdblock_tr);
}
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 5b081cb8435..aff4f6e52b0 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -141,7 +141,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
{
struct mtd_file_info *mfi = file->private_data;
struct mtd_info *mtd = mfi->mtd;
- size_t retlen=0;
+ size_mtd_t retlen=0;
size_t total_retlen=0;
int ret=0;
int len;
@@ -235,7 +235,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
struct mtd_file_info *mfi = file->private_data;
struct mtd_info *mtd = mfi->mtd;
char *kbuf;
- size_t retlen;
+ size_mtd_t retlen;
size_t total_retlen=0;
int ret=0;
int len;
@@ -686,9 +686,9 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
case MEMGETBADBLOCK:
{
- loff_t offs;
+ loff_mtd_t offs;
- if (copy_from_user(&offs, argp, sizeof(loff_t)))
+ if (copy_from_user(&offs, argp, sizeof(loff_mtd_t)))
return -EFAULT;
if (!mtd->block_isbad)
ret = -EOPNOTSUPP;
@@ -699,9 +699,9 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
case MEMSETBADBLOCK:
{
- loff_t offs;
+ loff_mtd_t offs;
- if (copy_from_user(&offs, argp, sizeof(loff_t)))
+ if (copy_from_user(&offs, argp, sizeof(loff_mtd_t)))
return -EFAULT;
if (!mtd->block_markbad)
ret = -EOPNOTSUPP;
@@ -815,6 +815,72 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
break;
}
+ case MEMWRITEPAGE:
+ {
+ struct mtd_page_buf buf;
+ struct mtd_oob_ops ops;
+
+ memset(&ops, 0, sizeof(ops));
+#if 1
+ if(!(file->f_mode & 2))
+ return -EPERM;
+#endif
+
+ if (copy_from_user(&buf, argp, sizeof(struct mtd_page_buf)))
+ return -EFAULT;
+
+ if (buf.ooblength > mtd->oobsize)
+ return -EINVAL;
+
+ if (!mtd->write_oob)
+ ret = -EOPNOTSUPP;
+ else
+ ret = access_ok(VERIFY_READ, buf.oobptr,
+ buf.ooblength) ? 0 : EFAULT;
+
+ if (ret)
+ return ret;
+
+ ops.len = mtd->writesize;
+ ops.ooblen = buf.ooblength;
+ ops.ooboffs = buf.start & (mtd->oobsize - 1);
+ ops.mode = MTD_OOB_PLACE;
+
+ if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
+ return -EINVAL;
+
+ /* alloc memory and copy oob data from user mode to kernel mode */
+ ops.oobbuf = kmalloc(buf.ooblength, GFP_KERNEL);
+ if (!ops.oobbuf)
+ return -ENOMEM;
+
+ if (copy_from_user(ops.oobbuf, buf.oobptr, buf.ooblength)) {
+ kfree(ops.oobbuf);
+ return -EFAULT;
+ }
+
+ /* alloc memory and copy page data from user mode to kernel mode */
+ ops.datbuf = kmalloc(mtd->writesize, GFP_KERNEL);
+ if (!ops.datbuf)
+ return -ENOMEM;
+
+ if (copy_from_user(ops.datbuf, buf.datptr, mtd->writesize)) {
+ kfree(ops.datbuf);
+ return -EFAULT;
+ }
+
+ buf.start &= ~(mtd->oobsize - 1);
+ ret = mtd->write_oob(mtd, buf.start, &ops);
+
+ if (copy_to_user(argp + 2*sizeof(uint32_t), &ops.retlen,
+ sizeof(uint32_t)))
+ ret = -EFAULT;
+
+ kfree(ops.oobbuf);
+ kfree(ops.datbuf);
+ break;
+ }
+
default:
ret = -ENOTTY;
}
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 00ebf7af746..b3639d2cac4 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -541,10 +541,10 @@ void put_mtd_device(struct mtd_info *mtd)
*/
int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen)
+ unsigned long count, loff_mtd_t to, size_mtd_t *retlen)
{
unsigned long i;
- size_t totlen = 0, thislen;
+ size_mtd_t totlen = 0, thislen;
int ret = 0;
if(!mtd->write) {
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 349fcbe5cc0..5275911d4e9 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -42,8 +42,8 @@ struct mtd_part {
* to the _real_ device.
*/
-static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
+static int part_read(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len,
+ size_mtd_t *retlen, u_char *buf)
{
struct mtd_part *part = PART(mtd);
struct mtd_ecc_stats stats;
@@ -66,8 +66,8 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
return res;
}
-static int part_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, void **virt, resource_size_t *phys)
+static int part_point(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len,
+ size_mtd_t *retlen, void **virt, resource_size_t *phys)
{
struct mtd_part *part = PART(mtd);
if (from >= mtd->size)
@@ -78,7 +78,7 @@ static int part_point(struct mtd_info *mtd, loff_t from, size_t len,
len, retlen, virt, phys);
}
-static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+static void part_unpoint(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len)
{
struct mtd_part *part = PART(mtd);
@@ -97,7 +97,7 @@ static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
flags);
}
-static int part_read_oob(struct mtd_info *mtd, loff_t from,
+static int part_read_oob(struct mtd_info *mtd, loff_mtd_t from,
struct mtd_oob_ops *ops)
{
struct mtd_part *part = PART(mtd);
@@ -118,8 +118,8 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
return res;
}
-static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
- size_t len, size_t *retlen, u_char *buf)
+static int part_read_user_prot_reg(struct mtd_info *mtd, loff_mtd_t from,
+ size_mtd_t len, size_mtd_t *retlen, u_char *buf)
{
struct mtd_part *part = PART(mtd);
return part->master->read_user_prot_reg(part->master, from,
@@ -127,14 +127,14 @@ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
}
static int part_get_user_prot_info(struct mtd_info *mtd,
- struct otp_info *buf, size_t len)
+ struct otp_info *buf, size_mtd_t len)
{
struct mtd_part *part = PART(mtd);
return part->master->get_user_prot_info(part->master, buf, len);
}
-static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
- size_t len, size_t *retlen, u_char *buf)
+static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_mtd_t from,
+ size_mtd_t len, size_mtd_t *retlen, u_char *buf)
{
struct mtd_part *part = PART(mtd);
return part->master->read_fact_prot_reg(part->master, from,
@@ -142,14 +142,14 @@ static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
}
static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
- size_t len)
+ size_mtd_t len)
{
struct mtd_part *part = PART(mtd);
return part->master->get_fact_prot_info(part->master, buf, len);
}
-static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
+static int part_write(struct mtd_info *mtd, loff_mtd_t to, size_mtd_t len,
+ size_mtd_t *retlen, const u_char *buf)
{
struct mtd_part *part = PART(mtd);
if (!(mtd->flags & MTD_WRITEABLE))
@@ -162,8 +162,8 @@ static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
len, retlen, buf);
}
-static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
+static int part_panic_write(struct mtd_info *mtd, loff_mtd_t to, size_mtd_t len,
+ size_mtd_t *retlen, const u_char *buf)
{
struct mtd_part *part = PART(mtd);
if (!(mtd->flags & MTD_WRITEABLE))
@@ -176,7 +176,7 @@ static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
len, retlen, buf);
}
-static int part_write_oob(struct mtd_info *mtd, loff_t to,
+static int part_write_oob(struct mtd_info *mtd, loff_mtd_t to,
struct mtd_oob_ops *ops)
{
struct mtd_part *part = PART(mtd);
@@ -191,23 +191,23 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to,
return part->master->write_oob(part->master, to + part->offset, ops);
}
-static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
- size_t len, size_t *retlen, u_char *buf)
+static int part_write_user_prot_reg(struct mtd_info *mtd, loff_mtd_t from,
+ size_mtd_t len, size_mtd_t *retlen, u_char *buf)
{
struct mtd_part *part = PART(mtd);
return part->master->write_user_prot_reg(part->master, from,
len, retlen, buf);
}
-static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
- size_t len)
+static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_mtd_t from,
+ size_mtd_t len)
{
struct mtd_part *part = PART(mtd);
return part->master->lock_user_prot_reg(part->master, from, len);
}
static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen)
+ unsigned long count, loff_mtd_t to, size_mtd_t *retlen)
{
struct mtd_part *part = PART(mtd);
if (!(mtd->flags & MTD_WRITEABLE))
@@ -248,7 +248,7 @@ void mtd_erase_callback(struct erase_info *instr)
}
EXPORT_SYMBOL_GPL(mtd_erase_callback);
-static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+static int part_lock(struct mtd_info *mtd, loff_mtd_t ofs, uint64_t len)
{
struct mtd_part *part = PART(mtd);
if ((len + ofs) > mtd->size)
@@ -256,7 +256,7 @@ static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
return part->master->lock(part->master, ofs + part->offset, len);
}
-static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+static int part_unlock(struct mtd_info *mtd, loff_mtd_t ofs, uint64_t len)
{
struct mtd_part *part = PART(mtd);
if ((len + ofs) > mtd->size)
@@ -282,7 +282,7 @@ static void part_resume(struct mtd_info *mtd)
part->master->resume(part->master);
}
-static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
+static int part_block_isbad(struct mtd_info *mtd, loff_mtd_t ofs)
{
struct mtd_part *part = PART(mtd);
if (ofs >= mtd->size)
@@ -291,7 +291,7 @@ static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
return part->master->block_isbad(part->master, ofs);
}
-static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int part_block_markbad(struct mtd_info *mtd, loff_mtd_t ofs)
{
struct mtd_part *part = PART(mtd);
int res;
@@ -346,6 +346,11 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
/* set up the MTD object for this partition */
slave->mtd.type = master->type;
slave->mtd.flags = master->flags & ~part->mask_flags;
+ if (part->mtdblock_jz_invalid)
+ slave->mtd.flags |= MTD_MTDBLOCK_JZ_INVALID;
+ if (part->cpu_mode)
+ slave->mtd.flags |= MTD_NAND_CPU_MODE;
+
slave->mtd.size = part->size;
slave->mtd.writesize = master->writesize;
slave->mtd.oobsize = master->oobsize;
@@ -356,6 +361,8 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
slave->mtd.owner = master->owner;
slave->mtd.backing_dev_info = master->backing_dev_info;
+ slave->mtd.priv = master->priv; /* Added by River. - For JZSOC MTD FTL. */
+
/* NOTE: we don't arrange MTDs as a tree; it'd be error-prone
* to have the same data be in two different partitions.
*/
@@ -424,10 +431,15 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
}
if (slave->mtd.size == MTDPART_SIZ_FULL)
slave->mtd.size = master->size - slave->offset;
-
+#if 0
printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset,
(unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name);
-
+#else
+ printk (KERN_NOTICE "0x%09llx-0x%09llx : \"%s\" \"%s\" \"%s\"\n", slave->offset,
+ slave->offset + slave->mtd.size, slave->mtd.name,
+ ((slave->mtd.flags)&MTD_NAND_CPU_MODE)?"cpu_mode":"dma_mode",
+ ((slave->mtd.flags)&MTD_MTDBLOCK_JZ_INVALID)?"jz_mtdblock_invalid":"jz_mtdblock_valid");
+#endif
/* let's do some sanity checks */
if (slave->offset >= master->size) {
/* let's register it anyway to preserve ordering */
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index ce96c091f01..b04c829b217 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -11,6 +11,136 @@ menuconfig MTD_NAND
if MTD_NAND
+config MTD_NAND_JZ4730
+ tristate "Support NAND Flash device on Jz4730 board"
+ depends on SOC_JZ4730
+ help
+ Support NAND Flash device on Jz4730 board
+
+config MTD_NAND_JZ4740
+ tristate "Support NAND Flash device on Jz4740 board"
+ depends on SOC_JZ4740
+ help
+ Support NAND Flash device on Jz4740 board
+
+config MTD_NAND_JZ4750
+ tristate "Support NAND Flash device on Jz4750 board"
+ depends on SOC_JZ4750 || SOC_JZ4750D || SOC_JZ4750L
+ help
+ Support NAND Flash device on Jz4750 board
+
+config MTD_NAND_CS2
+ depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4750
+ bool 'Use NAND on CS2_N of JZSOC'
+ default n
+
+config MTD_NAND_CS3
+ depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4750
+ bool 'Use NAND on CS3_N of JZSOC'
+ default n
+
+config MTD_NAND_CS4
+ depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4750
+ bool 'Use NAND on CS4_N of JZSOC'
+ default n
+
+config MTD_NAND_MULTI_PLANE
+ depends on MTD_NAND_JZ4730 || MTD_NAND_JZ4740 || MTD_NAND_JZ4750
+ bool 'Use multiple planes if the NAND supports'
+ default y
+ help
+ It is just supported on jz4740 now.
+
+if MTD_NAND_JZ4740 || MTD_NAND_JZ4730 || MTD_NAND_JZ4750
+choice
+ prompt "ECC type"
+ default CONFIG_MTD_SW_HM_ECC
+
+config MTD_HW_HM_ECC
+ depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4730
+ bool 'Select hardware HM ECC'
+
+config MTD_SW_HM_ECC
+ bool 'Select software HM ECC'
+
+config MTD_HW_RS_ECC
+ depends on MTD_NAND_JZ4740
+ bool 'Select hardware RS ECC'
+
+config MTD_HW_BCH_ECC
+ depends on MTD_NAND_JZ4750
+ bool 'Select hardware BCH ECC'
+endchoice
+
+choice
+ prompt "4 bit or 8 bit BCH ecc"
+ depends on MTD_HW_BCH_ECC
+ default CONFIG_MTD_HW_BCH_4BIT
+
+config MTD_HW_BCH_4BIT
+ bool '4 bit'
+
+config MTD_HW_BCH_8BIT
+ bool '8 bit'
+
+endchoice
+
+config MTD_NAND_DMA
+ depends on MTD_HW_BCH_ECC || MTD_HW_RS_ECC
+ bool 'Use DMA mode'
+ help
+ This enables using DMA for reading and writing NAND flash, if not selected,
+ then CPU mode is used. DMA is only used for two planes for jz4740.
+
+config MTD_NAND_DMABUF
+ depends on MTD_NAND_DMA && MTD_HW_BCH_ECC
+ bool 'use DMA buffer in NAND driver'
+ help
+ It's better to say NO. If saying yes, DMA buffers will be allocated for
+ NAND reading and writing in NAND driver instead of upper layer. It's
+ slower. Just usable on CS1_N now. By saying NO, upper buffers will be
+ used as DMA buffer. It's faster, but kmalloc instead of vmalloc is required.
+endif
+
+config ALLOCATE_MTDBLOCK_JZ_EARLY
+ bool "Allocate memory for mtdblock-jz early"
+ default n
+ help
+ Allocate memory (a nand block cache) for mtdblock-jz.c early in nand_base.c,
+ Especially for the vfat partition which will be used as USB disk by PC.
+
+config MTD_MTDBLOCK_WRITE_VERIFY_ENABLE
+ bool "MTDBLOCK write verify enable"
+ default n
+ help
+ This will enable the write verification, which will read back data to check
+ after doing a write opetaion.
+
+ It will be used by the JZ mtdblock driver (mtdblock-jz.c).
+
+config MTD_OOB_COPIES
+ int "how many copies of the fs info in the oob area"
+ default 3
+ range 0 128
+ depends on MTD
+ help
+ This defines the copies of the fs info in the oob area inside a block.
+ Value ranges from 0 to (pages_per_block - 1).
+
+ It will be used by the JZ mtdblock driver (mtdblock-jz.c).
+
+config MTD_BADBLOCK_FLAG_PAGE
+ int "which page inside a block will store the badblock mark"
+ default 0
+ range 0 127
+ depends on MTD
+ help
+ This defines which page of a block will store the badblock mark.
+ Value ranges from 0 to (pages_per_block - 1).
+
+ Old SLC NANDs store the badblock mark in the first page of a block, but
+ most modern MLC NANDs store it in the last page of a block.
+
config MTD_NAND_VERIFY_WRITE
bool "Verify NAND page writes"
help
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index f3a786b3cff..673c15ce1b3 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -40,5 +40,8 @@ obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
+obj-$(CONFIG_MTD_NAND_JZ4730) += jz4730_nand.o
+obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
+obj-$(CONFIG_MTD_NAND_JZ4750) += jz4750_nand.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/jz4730_nand.c b/drivers/mtd/nand/jz4730_nand.c
new file mode 100644
index 00000000000..f3e57f75efc
--- /dev/null
+++ b/drivers/mtd/nand/jz4730_nand.c
@@ -0,0 +1,367 @@
+/*
+ * linux/drivers/mtd/nand/jz4730_nand.c
+ *
+ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Ingenic JZ4730 NAND driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/jzsoc.h>
+
+#define NAND_DATA_PORT 0xB4000000 /* read-write area */
+#define __nand_ecc() (REG_EMC_NFECC & 0x00ffffff)
+#define __nand_ecc_enable() (REG_EMC_NFCSR |= EMC_NFCSR_ECCE | EMC_NFCSR_ERST)
+#define __nand_ecc_disable() (REG_EMC_NFCSR &= ~EMC_NFCSR_ECCE)
+
+/*
+ * MTD structure for JzSOC board
+ */
+static struct mtd_info *jz_mtd = NULL;
+
+/*
+ * Define partitions for flash devices
+ */
+#ifdef CONFIG_JZ4730_PMP
+static struct mtd_partition partition_info[] = {
+ { name: "NAND BOOT partition",
+ offset: 0 * 0x100000,
+ size: 4 * 0x100000 },
+ { name: "NAND KERNEL partition",
+ offset: 4 * 0x100000,
+ size: 4 * 0x100000 },
+ { name: "NAND ROOTFS partition",
+ offset: 8 * 0x100000,
+ size: 56 * 0x100000 },
+ { name: "NAND SSFDC partition",
+ offset: 64 * 0x100000,
+ size: 64 * 0x100000 },
+};
+
+/* Define max reserved bad blocks for each partition.
+ * This is used by the mtdblock-jz.c NAND FTL driver only.
+ *
+ * The NAND FTL driver reserves some good blocks which can't be
+ * seen by the upper layer. When the bad block number of a partition
+ * exceeds the max reserved blocks, then there is no more reserved
+ * good blocks to be used by the NAND FTL driver when another bad
+ * block generated.
+ */
+static int partition_reserved_badblocks[]= {
+ 2, /* reserved blocks of mtd0 */
+ 2, /* reserved blocks of mtd1 */
+ 10, /* reserved blocks of mtd2 */
+ 10}; /* reserved blocks of mtd3 */
+#elif CONFIG_JZ4730_PMPV1
+static struct mtd_partition partition_info[] = {
+ { name: "NAND ROOTFS partition",
+ offset: 3 * 0x100000,
+ size: (32-3) * 0x100000 },
+ { name: "NAND DATAFS partition",
+ offset: 32 * 0x100000,
+ size: 32 * 0x100000 },
+};
+static int partition_reserved_badblocks[]={
+ 10,
+ 10};
+#else
+static struct mtd_partition partition_info[] = {
+ { name: "NAND ROOTFS partition",
+ offset: 3 * 0x100000,
+ size: (128-3) * 0x100000 },
+};
+static int partition_reserved_badblocks[]={
+ 20};
+#endif
+
+/*-------------------------------------------------------------------------
+ * Following three functions are exported and used by the mtdblock-jz.c
+ * NAND FTL driver only.
+ */
+
+unsigned short get_mtdblock_write_verify_enable(void)
+{
+#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE
+ return 1;
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(get_mtdblock_write_verify_enable);
+
+unsigned short get_mtdblock_oob_copies(void)
+{
+ return CONFIG_MTD_OOB_COPIES;
+}
+EXPORT_SYMBOL(get_mtdblock_oob_copies);
+
+int *get_jz_badblock_table(void)
+{
+ return partition_reserved_badblocks;
+}
+EXPORT_SYMBOL(get_jz_badblock_table);
+
+/*-------------------------------------------------------------------------*/
+
+static void jz_hwcontrol(struct mtd_info *mtd, int dat,
+ unsigned int ctrl)
+{
+ struct nand_chip *this = (struct nand_chip *)(mtd->priv);
+ unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ if ( ctrl & NAND_ALE )
+ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) | 0x00080000);
+ else
+ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) & ~0x00080000);
+
+ if ( ctrl & NAND_CLE )
+ nandaddr = nandaddr | 0x00040000;
+ else
+ nandaddr = nandaddr & ~0x00040000;
+ if ( ctrl & NAND_NCE )
+ REG_EMC_NFCSR |= EMC_NFCSR_FCE;
+ else
+ REG_EMC_NFCSR &= ~EMC_NFCSR_FCE;
+ }
+
+ this->IO_ADDR_W = (void __iomem *)nandaddr;
+ if (dat != NAND_CMD_NONE)
+ writeb(dat , this->IO_ADDR_W);
+
+}
+
+static int jz_device_ready(struct mtd_info *mtd)
+{
+ int ready;
+ ready = (REG_EMC_NFCSR & EMC_NFCSR_RB) ? 1 : 0;
+ return ready;
+}
+
+/*
+ * EMC setup
+ */
+static void jz_device_setup(void)
+{
+ /* Set NFE bit */
+ REG_EMC_NFCSR |= EMC_NFCSR_NFE;
+}
+
+static void jzsoc_nand_enable_hwecc(struct mtd_info* mtd, int mode)
+{
+ __nand_ecc_enable();
+}
+
+static int jzsoc_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat,
+ u_char* ecc_code)
+{
+ unsigned int calc_ecc;
+ unsigned char *tmp;
+
+ __nand_ecc_disable();
+
+ calc_ecc = ~(__nand_ecc()) | 0x00030000;
+
+ tmp = (unsigned char *)&calc_ecc;
+
+ ecc_code[0] = tmp[1];
+ ecc_code[1] = tmp[0];
+ ecc_code[2] = tmp[2];
+
+ return 0;
+}
+
+/* ECC handling functions */
+
+static int jzsoc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ u_char a, b, c, d1, d2, d3, add, bit, i;
+
+ /* Do error detection */
+ d1 = calc_ecc[0] ^ read_ecc[0];
+ d2 = calc_ecc[1] ^ read_ecc[1];
+ d3 = calc_ecc[2] ^ read_ecc[2];
+
+ if ((d1 | d2 | d3) == 0) {
+ /* No errors */
+ return 0;
+ }
+ else {
+ a = (d1 ^ (d1 >> 1)) & 0x55;
+ b = (d2 ^ (d2 >> 1)) & 0x55;
+ c = (d3 ^ (d3 >> 1)) & 0x54;
+
+ /* Found and will correct single bit error in the data */
+ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
+ c = 0x80;
+ add = 0;
+ a = 0x80;
+ for (i=0; i<4; i++) {
+ if (d1 & c)
+ add |= a;
+ c >>= 2;
+ a >>= 1;
+ }
+ c = 0x80;
+ for (i=0; i<4; i++) {
+ if (d2 & c)
+ add |= a;
+ c >>= 2;
+ a >>= 1;
+ }
+ bit = 0;
+ b = 0x04;
+ c = 0x80;
+ for (i=0; i<3; i++) {
+ if (d3 & c)
+ bit |= b;
+ c >>= 2;
+ b >>= 1;
+ }
+ b = 0x01;
+ a = dat[add];
+ a ^= (b << bit);
+ dat[add] = a;
+ return 0;
+ }
+ else {
+ i = 0;
+ while (d1) {
+ if (d1 & 0x01)
+ ++i;
+ d1 >>= 1;
+ }
+ while (d2) {
+ if (d2 & 0x01)
+ ++i;
+ d2 >>= 1;
+ }
+ while (d3) {
+ if (d3 & 0x01)
+ ++i;
+ d3 >>= 1;
+ }
+ if (i == 1) {
+ /* ECC Code Error Correction */
+ read_ecc[0] = calc_ecc[0];
+ read_ecc[1] = calc_ecc[1];
+ read_ecc[2] = calc_ecc[2];
+ return 0;
+ }
+ else {
+ /* Uncorrectable Error */
+ printk("uncorrectable ECC error\n");
+ return -1;
+ }
+ }
+ }
+
+ /* Should never happen */
+ return -1;
+}
+
+
+/*
+ * Main initialization routine
+ */
+int __init jznand_init(void)
+{
+ struct nand_chip *this;
+ int nr_partitions;
+
+ /* Allocate memory for MTD device structure and private data */
+ jz_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
+ GFP_KERNEL);
+ if (!jz_mtd) {
+ printk ("Unable to allocate JzSOC NAND MTD device structure.\n");
+ return -ENOMEM;
+ }
+
+ /* Get pointer to private data */
+ this = (struct nand_chip *) (&jz_mtd[1]);
+
+ /* Initialize structures */
+ memset((char *) jz_mtd, 0, sizeof(struct mtd_info));
+ memset((char *) this, 0, sizeof(struct nand_chip));
+
+ /* Link the private data with the MTD structure */
+ jz_mtd->priv = this;
+
+ /* Set & initialize NAND Flash controller */
+ jz_device_setup();
+
+ /* Set address of NAND IO lines */
+ this->IO_ADDR_R = (void __iomem *) NAND_DATA_PORT;
+ this->IO_ADDR_W = (void __iomem *) NAND_DATA_PORT;
+ this->cmd_ctrl = jz_hwcontrol;
+ this->dev_ready = jz_device_ready;
+
+#ifdef CONFIG_MTD_HW_HM_ECC
+ this->ecc.calculate = jzsoc_nand_calculate_ecc;
+ this->ecc.correct = jzsoc_nand_correct_data;
+ this->ecc.hwctl = jzsoc_nand_enable_hwecc;
+ this->ecc.mode = NAND_ECC_HW;
+ this->ecc.size = 256;
+ this->ecc.bytes = 3;
+
+#endif
+
+#ifdef CONFIG_MTD_SW_HM_ECC
+ this->eccmode = NAND_ECC_SOFT;
+#endif
+
+ /* 20 us command delay time */
+ this->chip_delay = 20;
+
+ /* Scan to find existance of the device */
+ if (nand_scan(jz_mtd, 1)) {
+ kfree (jz_mtd);
+ return -ENXIO;
+ }
+
+ /* Register the partitions */
+ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition);
+ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name);
+ add_mtd_partitions(jz_mtd, partition_info, nr_partitions);
+
+ return 0;
+}
+module_init(jznand_init);
+
+/*
+ * Clean up routine
+ */
+#ifdef MODULE
+static void __exit jznand_cleanup(void)
+{
+ struct nand_chip *this = (struct nand_chip *) &jz_mtd[1];
+
+ /* Unregister partitions */
+ del_mtd_partitions(jz_mtd);
+
+ /* Unregister the device */
+ del_mtd_device (jz_mtd);
+
+ /* Free internal data buffers */
+ kfree (this->data_buf);
+
+ /* Free the MTD device structure */
+ kfree (jz_mtd);
+}
+module_exit(jznand_cleanup);
+#endif
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
new file mode 100644
index 00000000000..6e1c2c182e1
--- /dev/null
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -0,0 +1,1076 @@
+/*
+ * linux/drivers/mtd/nand/jz4740_nand.c
+ *
+ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc.
+ *
+ * Ingenic JZ4740 NAND driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/jzsoc.h>
+
+#define NAND_DATA_PORT1 0xB8000000 /* read-write area in static bank 1 */
+#define NAND_DATA_PORT2 0xB4000000 /* read-write area in static bank 2 */
+#define NAND_DATA_PORT3 0xAC000000 /* read-write area in static bank 3 */
+#define NAND_DATA_PORT4 0xA8000000 /* read-write area in static bank 4 */
+
+#define PAR_SIZE 9
+
+#define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1)
+#define __nand_disable() (REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1)
+
+#define __nand_ecc_enable() (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST )
+#define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE)
+
+#define __nand_select_hm_ecc() (REG_EMC_NFECR &= ~EMC_NFECR_RS )
+#define __nand_select_rs_ecc() (REG_EMC_NFECR |= EMC_NFECR_RS)
+
+#define __nand_read_hm_ecc() (REG_EMC_NFECC & 0x00ffffff)
+
+#define __nand_rs_ecc_encoding() (REG_EMC_NFECR |= EMC_NFECR_RS_ENCODING)
+#define __nand_rs_ecc_decoding() (REG_EMC_NFECR &= ~EMC_NFECR_RS_ENCODING)
+#define __nand_ecc_encode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_ENCF))
+#define __nand_ecc_decode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_DECF))
+
+/*
+ * MTD structure for JzSOC board
+ */
+static struct mtd_info *jz_mtd = NULL;
+extern struct mtd_info *jz_mtd1;
+extern char all_use_planes;
+extern int global_page; /* for two-plane operations */
+
+int nr_partitions; /* Number of partitions */
+
+/*
+ * Define partitions for flash devices
+ */
+#ifdef CONFIG_JZ4740_PAVO
+struct mtd_partition partition_info[] = {
+ {name:"NAND BOOT partition",
+ offset:0 * 0x100000,
+ size:4 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1},
+ {name:"NAND KERNEL partition",
+ offset:4 * 0x100000,
+ size:4 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1},
+ {name:"NAND ROOTFS partition",
+ offset:8 * 0x100000,
+ size:504 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1},
+ {name:"NAND VFAT partition",
+ offset:512 * 0x100000,
+ size:512 * 0x100000,
+ use_planes: 1,
+ mtdblock_jz_invalid: 0},
+};
+
+
+/* Define max reserved bad blocks for each partition.
+ * This is used by the mtdblock-jz.c NAND FTL driver only.
+ *
+ * The NAND FTL driver reserves some good blocks which can't be
+ * seen by the upper layer. When the bad block number of a partition
+ * exceeds the max reserved blocks, then there is no more reserved
+ * good blocks to be used by the NAND FTL driver when another bad
+ * block generated.
+ */
+static int partition_reserved_badblocks[] = {
+ 2, /* reserved blocks of mtd0 */
+ 2, /* reserved blocks of mtd1 */
+ 10, /* reserved blocks of mtd2 */
+ 10, /* reserved blocks of mtd3 */
+ 20, /* reserved blocks of mtd4 */
+ 20}; /* reserved blocks of mtd5 */
+#endif /* CONFIG_JZ4740_PAVO */
+
+#ifdef CONFIG_JZ4740_LEO
+struct mtd_partition partition_info[] = {
+ { name: "NAND BOOT partition",
+ offset: 0 * 0x100000,
+ size: 4 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND KERNEL partition",
+ offset: 4 * 0x100000,
+ size: 4 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND ROOTFS partition",
+ offset: 8 * 0x100000,
+ size: 56 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND VFAT partition",
+ offset: 64 * 0x100000,
+ size: 64 * 0x100000,
+ use_planes: 1,
+ mtdblock_jz_invalid: 0 },
+};
+static int partition_reserved_badblocks[] = {
+ 2, /* reserved blocks of mtd0 */
+ 2, /* reserved blocks of mtd1 */
+ 10, /* reserved blocks of mtd2 */
+ 10}; /* reserved blocks of mtd3 */
+#endif /* CONFIG_JZ4740_LEO */
+
+#ifdef CONFIG_JZ4740_LYRA
+struct mtd_partition partition_info[] = {
+ { name: "NAND BOOT partition",
+ offset: 0 * 0x100000,
+ size: 4 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND KERNEL partition",
+ offset: 4 * 0x100000,
+ size: 4 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND ROOTFS partition",
+ offset: 8 * 0x100000,
+ size: 120 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND DATA1 partition",
+ offset: 128 * 0x100000,
+ size: 128 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND DATA2 partition",
+ offset: 256 * 0x100000,
+ size: 256 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND VFAT partition",
+ offset: 512 * 0x100000,
+ size: 512 * 0x100000,
+ use_planes: 1,
+ mtdblock_jz_invalid: 0 },
+};
+
+/* Define max reserved bad blocks for each partition.
+ * This is used by the mtdblock-jz.c NAND FTL driver only.
+ *
+ * The NAND FTL driver reserves some good blocks which can't be
+ * seen by the upper layer. When the bad block number of a partition
+ * exceeds the max reserved blocks, then there is no more reserved
+ * good blocks to be used by the NAND FTL driver when another bad
+ * block generated.
+ */
+static int partition_reserved_badblocks[] = {
+ 2, /* reserved blocks of mtd0 */
+ 2, /* reserved blocks of mtd1 */
+ 10, /* reserved blocks of mtd2 */
+ 10, /* reserved blocks of mtd3 */
+ 20, /* reserved blocks of mtd4 */
+ 20}; /* reserved blocks of mtd5 */
+#endif /* CONFIG_JZ4740_LYRA */
+
+#ifdef CONFIG_JZ4725_DIPPER
+struct mtd_partition partition_info[] = {
+ { name: "NAND BOOT partition",
+ offset: 0 * 0x100000,
+ size: 4 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND KERNEL partition",
+ offset: 4 * 0x100000,
+ size: 4 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND ROOTFS partition",
+ offset: 8 * 0x100000,
+ size: 56 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND VFAT partition",
+ offset: 64 * 0x100000,
+ size: 64 * 0x100000,
+ use_planes: 1,
+ mtdblock_jz_invalid: 0 },
+};
+
+/* Define max reserved bad blocks for each partition.
+ * This is used by the mtdblock-jz.c NAND FTL driver only.
+ *
+ * The NAND FTL driver reserves some good blocks which can't be
+ * seen by the upper layer. When the bad block number of a partition
+ * exceeds the max reserved blocks, then there is no more reserved
+ * good blocks to be used by the NAND FTL driver when another bad
+ * block generated.
+ */
+static int partition_reserved_badblocks[] = {
+ 2, /* reserved blocks of mtd0 */
+ 2, /* reserved blocks of mtd1 */
+ 10, /* reserved blocks of mtd2 */
+ 10}; /* reserved blocks of mtd3 */
+#endif /* CONFIG_JZ4740_DIPPER */
+
+#ifdef CONFIG_JZ4720_VIRGO
+struct mtd_partition partition_info[] = {
+ { name: "NAND BOOT partition",
+ offset: 0 * 0x100000,
+ size: 4 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND KERNEL partition",
+ offset: 4 * 0x100000,
+ size: 4 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND ROOTFS partition",
+ offset: 8 * 0x100000,
+ size: 120 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND DATA1 partition",
+ offset: 128 * 0x100000,
+ size: 128 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND DATA2 partition",
+ offset: 256 * 0x100000,
+ size: 256 * 0x100000,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1 },
+ { name: "NAND VFAT partition",
+ offset: 512 * 0x100000,
+ size: 512 * 0x100000,
+ use_planes: 1,
+ mtdblock_jz_invalid: 0 },
+};
+
+
+/* Define max reserved bad blocks for each partition.
+ * This is used by the mtdblock-jz.c NAND FTL driver only.
+ *
+ * The NAND FTL driver reserves some good blocks which can't be
+ * seen by the upper layer. When the bad block number of a partition
+ * exceeds the max reserved blocks, then there is no more reserved
+ * good blocks to be used by the NAND FTL driver when another bad
+ * block generated.
+ */
+static int partition_reserved_badblocks[] = {
+ 2, /* reserved blocks of mtd0 */
+ 2, /* reserved blocks of mtd1 */
+ 10, /* reserved blocks of mtd2 */
+ 10, /* reserved blocks of mtd3 */
+ 20, /* reserved blocks of mtd4 */
+ 20}; /* reserved blocks of mtd5 */
+#endif /* CONFIG_JZ4720_VIRGO */
+/*-------------------------------------------------------------------------
+ * Following three functions are exported and used by the mtdblock-jz.c
+ * NAND FTL driver only.
+ */
+
+unsigned short get_mtdblock_write_verify_enable(void)
+{
+#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE
+ return 1;
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(get_mtdblock_write_verify_enable);
+
+unsigned short get_mtdblock_oob_copies(void)
+{
+ return CONFIG_MTD_OOB_COPIES;
+}
+EXPORT_SYMBOL(get_mtdblock_oob_copies);
+
+int *get_jz_badblock_table(void)
+{
+ return partition_reserved_badblocks;
+}
+EXPORT_SYMBOL(get_jz_badblock_table);
+
+/*-------------------------------------------------------------------------*/
+
+static void jz_hwcontrol(struct mtd_info *mtd, int dat,
+ unsigned int ctrl)
+{
+ struct nand_chip *this = (struct nand_chip *)(mtd->priv);
+ unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
+ extern u8 nand_nce; /* in nand_base.c, indicates which chip select is used for current nand chip */
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ if (ctrl & NAND_NCE) {
+ switch (nand_nce) {
+ case NAND_NCE1:
+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4;
+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE1;
+ break;
+ case NAND_NCE2:
+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT2;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4;
+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE2;
+ break;
+ case NAND_NCE3:
+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT3;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4;
+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE3;
+ break;
+ case NAND_NCE4:
+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT4;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3;
+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE4;
+ break;
+ default:
+ printk("error: no nand_nce 0x%x\n",nand_nce);
+ break;
+ }
+ } else {
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4;
+ }
+
+ if ( ctrl & NAND_ALE )
+ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) | 0x00010000);
+ else
+ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) & ~0x00010000);
+
+ if ( ctrl & NAND_CLE )
+ nandaddr = nandaddr | 0x00008000;
+ else
+ nandaddr = nandaddr & ~0x00008000;
+ }
+
+ this->IO_ADDR_W = (void __iomem *)nandaddr;
+ if (dat != NAND_CMD_NONE)
+ writeb(dat, this->IO_ADDR_W);
+}
+
+static int jz_device_ready(struct mtd_info *mtd)
+{
+ int ready, wait = 10;
+ while (wait--);
+ ready = __gpio_get_pin(94);
+ return ready;
+}
+
+/*
+ * EMC setup
+ */
+static void jz_device_setup(void)
+{
+// PORT 0:
+// ...
+// PORT 1:
+// PIN/BIT N FUNC0 FUNC1
+// 25 CS1# -
+// 26 CS2# -
+// 27 CS3# -
+// 28 CS4# -
+#define GPIO_CS2_N (32+26)
+#define GPIO_CS3_N (32+27)
+#define GPIO_CS4_N (32+28)
+#define SMCR_VAL 0x0d221200
+
+ /* Set NFE bit */
+ REG_EMC_NFCSR |= EMC_NFCSR_NFE1;
+ /* Read/Write timings */
+ REG_EMC_SMCR1 = SMCR_VAL;
+
+#if defined(CONFIG_MTD_NAND_CS2)
+ /* Set CS2# pin as function 0 */
+ __gpio_as_func0(GPIO_CS2_N);
+ REG_EMC_NFCSR |= EMC_NFCSR_NFE2;
+ REG_EMC_SMCR2 = SMCR_VAL;
+#endif
+
+#if defined(CONFIG_MTD_NAND_CS3)
+ __gpio_as_func0(GPIO_CS3_N);
+ REG_EMC_NFCSR |= EMC_NFCSR_NFE3;
+ REG_EMC_SMCR3 = SMCR_VAL;
+#endif
+
+#if defined(CONFIG_MTD_NAND_CS4)
+ __gpio_as_func0(GPIO_CS4_N);
+ REG_EMC_NFCSR |= EMC_NFCSR_NFE4;
+ REG_EMC_SMCR4 = SMCR_VAL;
+#endif
+}
+
+#ifdef CONFIG_MTD_HW_HM_ECC
+
+static int jzsoc_nand_calculate_hm_ecc(struct mtd_info* mtd,
+ const u_char* dat, u_char* ecc_code)
+{
+ unsigned int calc_ecc;
+ unsigned char *tmp;
+
+ __nand_ecc_disable();
+
+ calc_ecc = ~(__nand_read_hm_ecc()) | 0x00030000;
+
+ tmp = (unsigned char *)&calc_ecc;
+ //adjust eccbytes order for compatible with software ecc
+ ecc_code[0] = tmp[1];
+ ecc_code[1] = tmp[0];
+ ecc_code[2] = tmp[2];
+
+ return 0;
+}
+
+static void jzsoc_nand_enable_hm_hwecc(struct mtd_info* mtd, int mode)
+{
+ __nand_ecc_enable();
+ __nand_select_hm_ecc();
+}
+
+static int jzsoc_nand_hm_correct_data(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ u_char a, b, c, d1, d2, d3, add, bit, i;
+
+ /* Do error detection */
+ d1 = calc_ecc[0] ^ read_ecc[0];
+ d2 = calc_ecc[1] ^ read_ecc[1];
+ d3 = calc_ecc[2] ^ read_ecc[2];
+
+ if ((d1 | d2 | d3) == 0) {
+ /* No errors */
+ return 0;
+ }
+ else {
+ a = (d1 ^ (d1 >> 1)) & 0x55;
+ b = (d2 ^ (d2 >> 1)) & 0x55;
+ c = (d3 ^ (d3 >> 1)) & 0x54;
+
+ /* Found and will correct single bit error in the data */
+ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
+ c = 0x80;
+ add = 0;
+ a = 0x80;
+ for (i=0; i<4; i++) {
+ if (d1 & c)
+ add |= a;
+ c >>= 2;
+ a >>= 1;
+ }
+ c = 0x80;
+ for (i=0; i<4; i++) {
+ if (d2 & c)
+ add |= a;
+ c >>= 2;
+ a >>= 1;
+ }
+ bit = 0;
+ b = 0x04;
+ c = 0x80;
+ for (i=0; i<3; i++) {
+ if (d3 & c)
+ bit |= b;
+ c >>= 2;
+ b >>= 1;
+ }
+ b = 0x01;
+ a = dat[add];
+ a ^= (b << bit);
+ dat[add] = a;
+ return 0;
+ }
+ else {
+ i = 0;
+ while (d1) {
+ if (d1 & 0x01)
+ ++i;
+ d1 >>= 1;
+ }
+ while (d2) {
+ if (d2 & 0x01)
+ ++i;
+ d2 >>= 1;
+ }
+ while (d3) {
+ if (d3 & 0x01)
+ ++i;
+ d3 >>= 1;
+ }
+ if (i == 1) {
+ /* ECC Code Error Correction */
+ read_ecc[0] = calc_ecc[0];
+ read_ecc[1] = calc_ecc[1];
+ read_ecc[2] = calc_ecc[2];
+ return 0;
+ }
+ else {
+ /* Uncorrectable Error */
+ printk("NAND: uncorrectable ECC error\n");
+ return -1;
+ }
+ }
+ }
+
+ /* Should never happen */
+ return -1;
+}
+
+#endif /* CONFIG_MTD_HW_HM_ECC */
+
+#ifdef CONFIG_MTD_HW_RS_ECC
+
+static void jzsoc_nand_enable_rs_hwecc(struct mtd_info* mtd, int mode)
+{
+ REG_EMC_NFINTS = 0x0;
+ __nand_ecc_enable();
+ __nand_select_rs_ecc();
+
+ if (mode == NAND_ECC_READ)
+ __nand_rs_ecc_decoding();
+
+ if (mode == NAND_ECC_WRITE)
+ __nand_rs_ecc_encoding();
+}
+
+static void jzsoc_rs_correct(unsigned char *dat, int idx, int mask)
+{
+ int i;
+
+ idx--;
+
+ i = idx + (idx >> 3);
+ if (i >= 512)
+ return;
+
+ mask <<= (idx & 0x7);
+
+ dat[i] ^= mask & 0xff;
+ if (i < 511)
+ dat[i+1] ^= (mask >> 8) & 0xff;
+}
+
+/*
+ * calc_ecc points to oob_buf for us
+ */
+static int jzsoc_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0;
+ short k;
+ u32 stat;
+
+ /* Set PAR values */
+ for (k = 0; k < PAR_SIZE; k++) {
+ *paraddr++ = read_ecc[k];
+ }
+
+ /* Set PRDY */
+ REG_EMC_NFECR |= EMC_NFECR_PRDY;
+
+ /* Wait for completion */
+ __nand_ecc_decode_sync();
+ __nand_ecc_disable();
+
+ /* Check decoding */
+ stat = REG_EMC_NFINTS;
+
+ if (stat & EMC_NFINTS_ERR) {
+ /* Error occurred */
+ if (stat & EMC_NFINTS_UNCOR) {
+ printk("NAND: Uncorrectable ECC error\n");
+ return -1;
+ } else {
+ u32 errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT;
+ switch (errcnt) {
+ case 4:
+ jzsoc_rs_correct(dat, (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
+ /* FALL-THROUGH */
+ case 3:
+ jzsoc_rs_correct(dat, (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
+ /* FALL-THROUGH */
+ case 2:
+ jzsoc_rs_correct(dat, (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
+ /* FALL-THROUGH */
+ case 1:
+ jzsoc_rs_correct(dat, (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
+ return 0;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int jzsoc_nand_calculate_rs_ecc(struct mtd_info* mtd, const u_char* dat,
+ u_char* ecc_code)
+{
+ volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0;
+ short i;
+
+ __nand_ecc_encode_sync();
+ __nand_ecc_disable();
+
+ for(i = 0; i < PAR_SIZE; i++) {
+ ecc_code[i] = *paraddr++;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_MTD_HW_RS_ECC */
+
+/* Nand optimized functions */
+static int dma_chan;
+static unsigned int dma_src_phys_addr, dma_dst_phys_addr;
+extern int jz_request_dma(int dev_id, const char *dev_str,
+ irqreturn_t (*irqhandler)(int, void *),
+ unsigned long irqflags, void *irq_dev_id);
+
+static void dma_setup(void)
+{
+ /* Request DMA channel and setup irq handler */
+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", NULL, IRQF_DISABLED, NULL);
+ if (dma_chan < 0) {
+ printk("Setup irq for nand failed!\n");
+ return;
+ } else
+ printk("Nand DMA request channel %d.\n",dma_chan);
+}
+
+static void jz4740_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ int i;
+ struct nand_chip *chip = mtd->priv;
+
+ if ((len <= 32) || (len & 0xf) || ((u32)buf >= (u32)high_memory))
+ {
+ for (i = 0; i < len; i++)
+ buf[i] = readb(chip->IO_ADDR_R);
+ } else {
+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
+ dma_src_phys_addr = CPHYSADDR(chip->IO_ADDR_R);
+ dma_dst_phys_addr = CPHYSADDR(buf);
+ dma_cache_inv((u32)buf, len);
+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr;
+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr;
+ REG_DMAC_DTCR(dma_chan) = len / 16;
+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE;
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
+ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */
+
+ while(!(REG_DMAC_DCCSR(dma_chan) & DMAC_DCCSR_TT));
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ __dmac_channel_clear_transmit_end(dma_chan);
+ }
+}
+
+static void jz4740_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ int i;
+ struct nand_chip *chip = mtd->priv;
+
+ if ((len <= 32) || (len & 0xf) || ((u32)buf >= (u32)high_memory))
+ {
+ for (i = 0; i < len; i++)
+ writeb(buf[i], chip->IO_ADDR_W);
+ } else {
+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
+ dma_dst_phys_addr = CPHYSADDR(chip->IO_ADDR_R);
+ dma_src_phys_addr = CPHYSADDR(buf);
+ dma_cache_wback((unsigned long)buf, len);
+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr;
+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr;
+ REG_DMAC_DTCR(dma_chan) = len / 16;
+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_16BYTE ;
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
+ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */
+
+ while(!(REG_DMAC_DCCSR(dma_chan) & DMAC_DCCSR_TT));
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ __dmac_channel_clear_transmit_end(dma_chan);
+ }
+}
+
+static int nand_read_page_hwecc_rs_planes(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps >> 1;
+ uint8_t *p;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ uint32_t page;
+ uint8_t flag = 0;
+ int oobsize = mtd->oobsize >> 1;
+ int ppb = mtd->erasesize / mtd->writesize;
+ int ecctotal = chip->ecc.total >> 1;
+
+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
+
+ /* Read first page */
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ chip->read_buf(mtd, chip->oob_poi, oobsize);
+ for (i = 0; i < ecctotal; i++) {
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+ if (ecc_code[i] != 0xff) flag = 1;
+ }
+
+ p = buf;
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1);
+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ int stat;
+ if (flag) {
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+ }
+ else {
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+ }
+ }
+ /* Read second page */
+ page += ppb;
+ flag = 0;
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ chip->read_buf(mtd, chip->oob_poi + oobsize, oobsize);
+ for (i = 0; i < ecctotal; i++) {
+ ecc_code[i] = chip->oob_poi[oobsize + eccpos[i]];
+ if (ecc_code[i] != 0xff) flag = 1;
+ }
+
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1);
+ eccsteps = chip->ecc.steps >> 1;
+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ int stat;
+ if (flag) {
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+ }
+ else {
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+ }
+ }
+
+ return 0;
+}
+
+static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip,
+ int global_page, int sndcmd)
+{
+ int page;
+ int oobsize = mtd->oobsize >> 1;
+ int ppb = mtd->erasesize / mtd->writesize;
+
+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
+
+ /* Read first page OOB */
+ if (sndcmd) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ }
+ chip->read_buf(mtd, chip->oob_poi, oobsize);
+ /* Read second page OOB */
+ page += ppb;
+ if (sndcmd) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ sndcmd = 0;
+ }
+ chip->read_buf(mtd, chip->oob_poi+oobsize, oobsize);
+ return 0;
+}
+
+static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip,
+ int global_page)
+{
+ int status = 0,page;
+ int pagesize = mtd->writesize >> 1;
+ int oobsize = mtd->oobsize >> 1;
+ int ppb = mtd->erasesize / mtd->writesize;
+ const uint8_t *buf = chip->oob_poi;
+
+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
+
+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */
+ if (chip->realplanenum == 2)
+ chip->cmdfunc(mtd, 0x80, pagesize, 0x00);
+ else
+ chip->cmdfunc(mtd, 0x80, pagesize, page & (1 << (chip->chip_shift - chip->page_shift)));
+
+ chip->write_buf(mtd, buf, oobsize);
+ /* Send first command to program the OOB data */
+ chip->cmdfunc(mtd, 0x11, -1, -1);
+ ndelay(100);
+ status = chip->waitfunc(mtd, chip);
+
+ page += ppb;
+ buf += oobsize;
+ chip->cmdfunc(mtd, 0x81, pagesize, page);
+ chip->write_buf(mtd, buf, oobsize);
+ /* Send command to program the OOB data */
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ /* Wait long R/B */
+ ndelay(100);
+ status = chip->waitfunc(mtd, chip);
+
+ return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+static void nand_write_page_hwecc_planes(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps >> 1;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *p = (uint8_t *)buf;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ int oobsize = mtd->oobsize >> 1;
+ int ppb = mtd->erasesize / mtd->writesize;
+ int ecctotal = chip->ecc.total >> 1;
+ int page;
+
+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
+
+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */
+ if (chip->realplanenum == 2)
+ chip->cmdfunc(mtd, 0x80, 0x00, 0x00);
+ else
+ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift)));
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->write_buf(mtd, p, eccsize);
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ }
+ for (i = 0; i < ecctotal; i++)
+ chip->oob_poi[eccpos[i]] = ecc_calc[i];
+
+ chip->write_buf(mtd, chip->oob_poi, oobsize);
+
+ chip->cmdfunc(mtd, 0x11, -1, -1); /* send cmd 0x11 */
+ ndelay(100);
+ while(!chip->dev_ready(mtd));
+
+ page += ppb;
+ chip->cmdfunc(mtd, 0x81, 0x00, page); /* send cmd 0x81 */
+ eccsteps = chip->ecc.steps >> 1;
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->write_buf(mtd, p, eccsize);
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ }
+
+ for (i = 0; i < ecctotal; i++)
+ chip->oob_poi[eccpos[i]] = ecc_calc[i];
+
+ chip->write_buf(mtd, chip->oob_poi, oobsize);
+}
+
+static void single_erase_cmd_planes(struct mtd_info *mtd, int global_page)
+{
+ struct nand_chip *chip = mtd->priv;
+
+ /* Send commands to erase a block */
+ int page;
+ int ppb = mtd->erasesize / mtd->writesize;
+
+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
+
+ /* send cmd 0x60, the MSB should be valid if realplane is 4 */
+ if (chip->realplanenum == 2)
+ chip->cmdfunc(mtd, 0x60, -1, 0x00);
+ else
+ chip->cmdfunc(mtd, 0x60, -1, page & (1 << (chip->chip_shift - chip->page_shift)));
+
+ page += ppb;
+ chip->cmdfunc(mtd, 0x60, -1, page & (~(ppb-1))); /* send cmd 0x60 */
+
+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); /* send cmd 0xd0 */
+ /* Do not need wait R/B or check status */
+}
+
+/*
+ * Main initialization routine
+ */
+int __init jznand_init(void)
+{
+ struct nand_chip *this;
+ int ret, i;
+
+ /* Allocate memory for MTD device structure and private data */
+ jz_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
+ GFP_KERNEL);
+ if (!jz_mtd) {
+ printk ("Unable to allocate JzSOC NAND MTD device structure.\n");
+ return -ENOMEM;
+ }
+
+ jz_mtd1 = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
+ GFP_KERNEL);
+ if (!jz_mtd1) {
+ printk ("Unable to allocate JzSOC NAND MTD device structure 1.\n");
+ kfree(jz_mtd);
+ return -ENOMEM;
+ }
+
+ /* Get pointer to private data */
+ this = (struct nand_chip *) (&jz_mtd[1]);
+
+ /* Initialize structures */
+ memset((char *) jz_mtd, 0, sizeof(struct mtd_info));
+ memset((char *) this, 0, sizeof(struct nand_chip));
+
+ /* Link the private data with the MTD structure */
+ jz_mtd->priv = this;
+
+ /* Set & initialize NAND Flash controller */
+ jz_device_setup();
+
+ /* Set address of NAND IO lines */
+ this->IO_ADDR_R = (void __iomem *) NAND_DATA_PORT1;
+ this->IO_ADDR_W = (void __iomem *) NAND_DATA_PORT1;
+ this->cmd_ctrl = jz_hwcontrol;
+ this->dev_ready = jz_device_ready;
+
+#ifdef CONFIG_MTD_HW_HM_ECC
+ this->ecc.calculate = jzsoc_nand_calculate_hm_ecc;
+ this->ecc.correct = jzsoc_nand_hm_correct_data;
+ this->ecc.hwctl = jzsoc_nand_enable_hm_hwecc;
+ this->ecc.mode = NAND_ECC_HW;
+ this->ecc.size = 256;
+ this->ecc.bytes = 3;
+
+#endif
+
+#ifdef CONFIG_MTD_HW_RS_ECC
+ this->ecc.calculate = jzsoc_nand_calculate_rs_ecc;
+ this->ecc.correct = jzsoc_nand_rs_correct_data;
+ this->ecc.hwctl = jzsoc_nand_enable_rs_hwecc;
+ this->ecc.mode = NAND_ECC_HW;
+ this->ecc.size = 512;
+ this->ecc.bytes = 9;
+#endif
+
+#ifdef CONFIG_MTD_SW_HM_ECC
+ this->ecc.mode = NAND_ECC_SOFT;
+#endif
+ /* 20 us command delay time */
+ this->chip_delay = 20;
+
+#ifdef CONFIG_MTD_NAND_DMA
+ dma_setup();
+#endif
+ /* Scan to find existance of the device */
+ ret = nand_scan_ident(jz_mtd, NAND_MAX_CHIPS);
+ if (!ret) {
+ if (this->planenum == 2) {
+ /* reset nand functions */
+ this->erase_cmd = single_erase_cmd_planes;
+ this->ecc.read_page = nand_read_page_hwecc_rs_planes; //Muti planes read
+ this->ecc.write_page = nand_write_page_hwecc_planes;
+ this->ecc.read_oob = nand_read_oob_std_planes;
+ this->ecc.write_oob = nand_write_oob_std_planes;
+#ifdef CONFIG_MTD_NAND_DMA
+ this->write_buf = jz4740_nand_write_buf;
+ this->read_buf = jz4740_nand_read_buf;
+#endif
+ printk(KERN_INFO "Nand using two-plane mode, "
+ "and resized to writesize:%d oobsize:%d blocksize:0x%x \n",
+ jz_mtd->writesize, jz_mtd->oobsize, jz_mtd->erasesize);
+ }
+ }
+
+ /* Determine whether all the partitions will use multiple planes if supported */
+ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition);
+ all_use_planes = 1;
+ for (i = 0; i < nr_partitions; i++) {
+ all_use_planes &= partition_info[i].use_planes;
+ }
+
+ if (!ret)
+ ret = nand_scan_tail(jz_mtd);
+
+ if (ret){
+ kfree (jz_mtd1);
+ kfree (jz_mtd);
+ return -ENXIO;
+ }
+
+ /* Register the partitions */
+ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name);
+
+ if ((this->planenum == 2) && !all_use_planes) {
+ for (i = 0; i < nr_partitions; i++) {
+ if (partition_info[i].use_planes)
+ add_mtd_partitions(jz_mtd, &partition_info[i], 1);
+ else
+ add_mtd_partitions(jz_mtd1, &partition_info[i], 1);
+ }
+ } else {
+ kfree(jz_mtd1);
+ add_mtd_partitions(jz_mtd, partition_info, nr_partitions);
+ }
+ return 0;
+}
+module_init(jznand_init);
+
+/*
+ * Clean up routine
+ */
+#ifdef MODULE
+static void __exit jznand_cleanup(void)
+{
+ struct nand_chip *this = (struct nand_chip *) &jz_mtd[1];
+
+ /* Unregister partitions */
+ del_mtd_partitions(jz_mtd);
+
+ /* Unregister the device */
+ del_mtd_device (jz_mtd);
+
+ /* Free internal data buffers */
+ kfree (this->data_buf);
+
+ /* Free the MTD device structure */
+ if ((this->planenum == 2) && !all_use_planes)
+ kfree (jz_mtd1);
+ kfree (jz_mtd);
+}
+module_exit(jznand_cleanup);
+#endif
diff --git a/drivers/mtd/nand/jz4750_nand.c b/drivers/mtd/nand/jz4750_nand.c
new file mode 100644
index 00000000000..18a56c85a90
--- /dev/null
+++ b/drivers/mtd/nand/jz4750_nand.c
@@ -0,0 +1,1900 @@
+/*
+ * linux/drivers/mtd/nand/jz4750_nand.c
+ *
+ * JZ4750 NAND driver
+ *
+ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc.
+ * Author: <lhhuang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/jzsoc.h>
+
+/* 32bit instead of 16byte burst is used by DMA to read or
+ write NAND and BCH avoiding grabbing bus for too long */
+#define DMAC_DCMD_DS_NAND DMAC_DCMD_DS_32BIT
+#define DIV_DS_NAND 4
+
+#define DMAC_DCMD_DS_BCH DMAC_DCMD_DS_32BIT
+#define DIV_DS_BCH 4
+
+#define DEBUG1 0
+#if DEBUG1
+#define dprintk(n,x...) printk(n,##x)
+#else
+#define dprintk(n,x...)
+#endif
+
+#if defined(CONFIG_MTD_HW_BCH_8BIT)
+#define __ECC_ENCODING __ecc_encoding_8bit
+#define __ECC_DECODING __ecc_decoding_8bit
+#define ERRS_SIZE 5 /* 5 words */
+#else
+#define __ECC_ENCODING __ecc_encoding_4bit
+#define __ECC_DECODING __ecc_decoding_4bit
+#define ERRS_SIZE 3 /* 3 words */
+#endif
+
+#define NAND_DATA_PORT1 0xB8000000 /* read-write area in static bank 1 */
+#define NAND_DATA_PORT2 0xB4000000 /* read-write area in static bank 2 */
+#define NAND_DATA_PORT3 0xAC000000 /* read-write area in static bank 3 */
+#define NAND_DATA_PORT4 0xA8000000 /* read-write area in static bank 4 */
+
+#define NAND_ADDR_OFFSET0 0x00010000 /* address port offset for share mode */
+#define NAND_CMD_OFFSET0 0x00008000 /* command port offset for share mode */
+#define NAND_ADDR_OFFSET1 0x00000010 /* address port offset for unshare mode */
+#define NAND_CMD_OFFSET1 0x00000008 /* command port offset for unshare mode */
+
+#if defined(CONFIG_MTD_NAND_DMA)
+#define USE_IRQ 1
+enum {
+ NAND_NONE,
+ NAND_PROG,
+ NAND_READ
+};
+static volatile u8 nand_status;
+static volatile int dma_ack = 0;
+static volatile int dma_ack1 = 0;
+static char nand_dma_chan; /* automatically select a free channel */
+static char bch_dma_chan = 0; /* fixed to channel 0 */
+static u32 *errs;
+static jz_dma_desc_8word *dma_desc_enc, *dma_desc_enc1, *dma_desc_dec, *dma_desc_dec1, *dma_desc_dec2,
+ *dma_desc_nand_prog, *dma_desc_nand_read;
+static u32 *pval_nand_ddr;
+static u8 *pval_nand_cmd_pgprog; /* for sending 0x11 or 0x10 when programing*/
+#if defined(CONFIG_MTD_NAND_DMABUF)
+u8 *prog_buf, *read_buf;
+#endif
+DECLARE_WAIT_QUEUE_HEAD(nand_prog_wait_queue);
+DECLARE_WAIT_QUEUE_HEAD(nand_read_wait_queue);
+#endif
+
+struct buf_be_corrected {
+ u8 *data;
+ u8 *oob;
+};
+
+static u32 addr_offset;
+static u32 cmd_offset;
+static int nand_chips = 1; /* Number of nand chips to be scanned */
+extern int global_page; /* for two-plane operations */
+extern int global_mafid; /* ID of manufacture */
+
+/*
+ * MTD structure for JzSOC board
+ */
+static struct mtd_info *jz_mtd = NULL;
+extern struct mtd_info *jz_mtd1;
+extern char all_use_planes;
+
+int nr_partitions; /* Number of partitions */
+
+/*
+ * Define partitions for flash devices
+ */
+#if defined(CONFIG_JZ4750_FUWA) || defined(CONFIG_JZ4750D_FUWA1)
+struct mtd_partition partition_info[] = {
+ {name:"NAND BOOT partition",
+ offset:0 * 0x100000,
+ size:4 * 0x100000,
+ cpu_mode: 1,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1},
+ {name:"NAND KERNEL partition",
+ offset:4 * 0x100000,
+ size:4 * 0x100000,
+ cpu_mode: 1,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1},
+ {name:"NAND ROOTFS partition",
+ offset:8 * 0x100000,
+ size:120 * 0x100000,
+ cpu_mode: 1,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1},
+ {name:"NAND DATA1 partition",
+ offset:128 * 0x100000,
+ size:128 * 0x100000,
+ cpu_mode: 1,
+ use_planes: 1,
+ mtdblock_jz_invalid: 1},
+ {name:"NAND DATA2 partition",
+ offset:256 * 0x100000,
+ size:256 * 0x100000,
+ cpu_mode: 1,
+ use_planes: 1,
+ mtdblock_jz_invalid: 1},
+ {name:"NAND VFAT partition",
+ offset:512 * 0x100000,
+ size:512 * 0x100000,
+ cpu_mode: 0,
+ use_planes: 1,
+ mtdblock_jz_invalid: 0},
+};
+
+/* Define max reserved bad blocks for each partition.
+ * This is used by the mtdblock-jz.c NAND FTL driver only.
+ *
+ * The NAND FTL driver reserves some good blocks which can't be
+ * seen by the upper layer. When the bad block number of a partition
+ * exceeds the max reserved blocks, then there is no more reserved
+ * good blocks to be used by the NAND FTL driver when another bad
+ * block generated.
+ */
+static int partition_reserved_badblocks[] = {
+ 2, /* reserved blocks of mtd0 */
+ 2, /* reserved blocks of mtd1 */
+ 10, /* reserved blocks of mtd2 */
+ 10, /* reserved blocks of mtd3 */
+ 20, /* reserved blocks of mtd4 */
+ 20
+}; /* reserved blocks of mtd5 */
+#endif /* CONFIG_JZ4750_FUWA */
+
+#if defined(CONFIG_JZ4750_APUS) || defined(CONFIG_JZ4750D_CETUS)
+struct mtd_partition partition_info[] = {
+ {name:"NAND BOOT partition",
+ offset:0 * 0x100000LL,
+ size:4 * 0x100000LL,
+ cpu_mode: 0,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1},
+ {name:"NAND KERNEL partition",
+ offset:4 * 0x100000LL,
+ size:4 * 0x100000LL,
+ cpu_mode: 0,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1},
+ {name:"NAND ROOTFS partition",
+ offset:8 * 0x100000LL,
+ size:504 * 0x100000LL,
+ cpu_mode: 1,
+ use_planes: 0,
+ mtdblock_jz_invalid: 1},
+ {name:"NAND DATA partition",
+ offset:512 * 0x100000LL,
+ size:512 * 0x100000LL,
+ cpu_mode: 0,
+ use_planes: 1,
+ mtdblock_jz_invalid: 1},
+ {name:"NAND VFAT partition",
+ offset:1024 * 0x100000LL,
+ size:1024 * 0x100000LL,
+ cpu_mode: 0,
+ use_planes: 1,
+ mtdblock_jz_invalid: 0},
+};
+
+
+/* Define max reserved bad blocks for each partition.
+ * This is used by the mtdblock-jz.c NAND FTL driver only.
+ *
+ * The NAND FTL driver reserves some good blocks which can't be
+ * seen by the upper layer. When the bad block number of a partition
+ * exceeds the max reserved blocks, then there is no more reserved
+ * good blocks to be used by the NAND FTL driver when another bad
+ * block generated.
+ */
+static int partition_reserved_badblocks[] = {
+ 2, /* reserved blocks of mtd0 */
+ 2, /* reserved blocks of mtd1 */
+ 10, /* reserved blocks of mtd2 */
+ 10, /* reserved blocks of mtd3 */
+ 10, /* reserved blocks of mtd4 */
+};
+#endif /* CONFIG_JZ4750_APUS */
+
+/*-------------------------------------------------------------------------
+ * Following three functions are exported and used by the mtdblock-jz.c
+ * NAND FTL driver only.
+ */
+
+unsigned short get_mtdblock_write_verify_enable(void)
+{
+#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE
+ return 1;
+#endif
+ return 0;
+}
+
+EXPORT_SYMBOL(get_mtdblock_write_verify_enable);
+
+unsigned short get_mtdblock_oob_copies(void)
+{
+ return CONFIG_MTD_OOB_COPIES;
+}
+
+EXPORT_SYMBOL(get_mtdblock_oob_copies);
+
+int *get_jz_badblock_table(void)
+{
+ if (sizeof(partition_reserved_badblocks) / sizeof(int) != nr_partitions)
+ printk("partition_reserved_badblocks setting error!\n");
+
+ return partition_reserved_badblocks;
+}
+
+EXPORT_SYMBOL(get_jz_badblock_table);
+
+/*-------------------------------------------------------------------------*/
+
+static void jz_hwcontrol(struct mtd_info *mtd, int dat, u32 ctrl)
+{
+ struct nand_chip *this = (struct nand_chip *)(mtd->priv);
+ u32 nandaddr = (u32)this->IO_ADDR_W;
+ extern u8 nand_nce; /* defined in nand_base.c, indicates which chip select is used for current nand chip */
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ if (ctrl & NAND_NCE) {
+ switch (nand_nce) {
+ case NAND_NCE1:
+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4;
+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE1;
+ break;
+ case NAND_NCE2:
+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT2;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4;
+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE2;
+ break;
+ case NAND_NCE3:
+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT3;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4;
+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE3;
+ break;
+ case NAND_NCE4:
+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT4;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3;
+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE4;
+ break;
+ default:
+ printk("error: no nand_nce 0x%x\n",nand_nce);
+ break;
+ }
+ } else {
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3;
+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4;
+ }
+
+ if (ctrl & NAND_ALE)
+ nandaddr = (u32)((u32)(this->IO_ADDR_W) | addr_offset);
+ else
+ nandaddr = (u32)((u32)(this->IO_ADDR_W) & ~addr_offset);
+ if (ctrl & NAND_CLE)
+ nandaddr = (u32)(nandaddr | cmd_offset);
+ else
+ nandaddr = (u32)(nandaddr & ~cmd_offset);
+ }
+
+ this->IO_ADDR_W = (void __iomem *)nandaddr;
+ if (dat != NAND_CMD_NONE) {
+ writeb(dat, this->IO_ADDR_W);
+ /* printk("write cmd:0x%x to 0x%x\n",dat,(u32)this->IO_ADDR_W); */
+ }
+}
+
+static int jz_device_ready(struct mtd_info *mtd)
+{
+ int ready, wait = 10;
+ while (wait--);
+ ready = __gpio_get_pin(91);
+ return ready;
+}
+
+/*
+ * EMC setup
+ */
+static void jz_device_setup(void)
+{
+// PORT 0:
+// PORT 1:
+// PORT 2:
+// PIN/BIT N FUNC0 FUNC1
+// 21 CS1# -
+// 22 CS2# -
+// 23 CS3# -
+// 24 CS4# -
+#define GPIO_CS2_N (32*2+22)
+#define GPIO_CS3_N (32*2+23)
+#define GPIO_CS4_N (32*2+24)
+#define SMCR_VAL 0x0d444400
+//#define SMCR_VAL 0x05221100
+
+ __gpio_as_nand_8bit(1);
+ /* Set NFE bit */
+ REG_EMC_NFCSR |= EMC_NFCSR_NFE1;
+ /* Read/Write timings */
+ REG_EMC_SMCR1 = SMCR_VAL;
+
+#if defined(CONFIG_MTD_NAND_CS2)
+ __gpio_as_func0(GPIO_CS2_N);
+ /* Set NFE bit */
+ REG_EMC_NFCSR |= EMC_NFCSR_NFE2;
+ /* Read/Write timings */
+ REG_EMC_SMCR2 = SMCR_VAL;
+ nand_chips++;
+#endif
+
+#if defined(CONFIG_MTD_NAND_CS3)
+ __gpio_as_func0(GPIO_CS3_N);
+ /* Set NFE bit */
+ REG_EMC_NFCSR |= EMC_NFCSR_NFE3;
+ /* Read/Write timings */
+ REG_EMC_SMCR3 = SMCR_VAL;
+ nand_chips++;
+#endif
+
+#if defined(CONFIG_MTD_NAND_CS4)
+ __gpio_as_func0(GPIO_CS4_N);
+ /* Set NFE bit */
+ REG_EMC_NFCSR |= EMC_NFCSR_NFE4;
+ /* Read/Write timings */
+ REG_EMC_SMCR4 = SMCR_VAL;
+ nand_chips++;
+#endif
+}
+
+#ifdef CONFIG_MTD_HW_BCH_ECC
+
+static void jzsoc_nand_enable_bch_hwecc(struct mtd_info *mtd, int mode)
+{
+ struct nand_chip *this = (struct nand_chip *)(mtd->priv);
+ int eccsize = this->ecc.size;
+ int eccbytes = this->ecc.bytes;
+ int eccsteps = this->ecc.steps / this->planenum;
+ int oob_per_eccsize = this->ecc.layout->eccpos[0] / eccsteps;
+
+ REG_BCH_INTS = 0xffffffff;
+ if (mode == NAND_ECC_READ) {
+ __ECC_DECODING();
+ __ecc_cnt_dec(eccsize + oob_per_eccsize + eccbytes);
+
+ if (!(mtd->flags & MTD_NAND_CPU_MODE))
+ __ecc_dma_enable();
+ else
+ __ecc_dma_disable();
+ }
+
+ if (mode == NAND_ECC_WRITE) {
+ __ECC_ENCODING();
+ __ecc_cnt_enc(eccsize + oob_per_eccsize);
+
+ if (!(mtd->flags & MTD_NAND_CPU_MODE))
+ __ecc_dma_enable();
+ else
+ __ecc_dma_disable();
+ }
+}
+
+/**
+ * bch_correct
+ * @dat: data to be corrected
+ * @idx: the index of error bit in an eccsize
+ */
+static void bch_correct(struct mtd_info *mtd, u8 * dat, int idx)
+{
+ struct nand_chip *this = (struct nand_chip *)(mtd->priv);
+ int eccsize = this->ecc.size;
+ int eccsteps = this->ecc.steps / this->planenum;
+ int ecc_pos = this->ecc.layout->eccpos[0];
+ int oob_per_eccsize = ecc_pos / eccsteps;
+ int i, bit; /* the 'bit' of i byte is error */
+
+ i = (idx - 1) >> 3;
+ bit = (idx - 1) & 0x7;
+
+ dprintk("error:i=%d, bit=%d\n",i,bit);
+
+ if (i < eccsize){
+ ((struct buf_be_corrected *)dat)->data[i] ^= (1 << bit);
+ } else if (i < eccsize + oob_per_eccsize) {
+ ((struct buf_be_corrected *)dat)->oob[i-eccsize] ^= (1 << bit);
+ }
+}
+
+#if defined(CONFIG_MTD_NAND_DMA)
+
+/**
+ * jzsoc_nand_bch_correct_data
+ * @mtd: mtd info structure
+ * @dat: data to be corrected
+ * @errs0: pointer to the dma target buffer of bch decoding which stores BHINTS and
+ * BHERR0~3(8-bit BCH) or BHERR0~1(4-bit BCH)
+ * @calc_ecc: no used
+ */
+static int jzsoc_nand_bch_correct_data(struct mtd_info *mtd, u_char * dat, u_char * errs0, u_char * calc_ecc)
+{
+ u32 stat;
+ u32 *errs = (u32 *)errs0;
+
+ if (REG_DMAC_DCCSR(0) & DMAC_DCCSR_BERR) {
+ stat = errs[0];
+ dprintk("stat=%x err0:%x err1:%x \n", stat, errs[1], errs[2]);
+
+ if (stat & BCH_INTS_ERR) {
+ if (stat & BCH_INTS_UNCOR) {
+ printk("NAND: Uncorrectable ECC error\n");
+ return -1;
+ } else {
+ u32 errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT;
+ switch (errcnt) {
+#if defined(CONFIG_MTD_HW_BCH_8BIT)
+ case 8:
+ bch_correct(mtd, dat, (errs[4] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT);
+ case 7:
+ bch_correct(mtd, dat, (errs[4] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT);
+ case 6:
+ bch_correct(mtd, dat, (errs[3] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT);
+ case 5:
+ bch_correct(mtd, dat, (errs[3] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT);
+#endif
+ case 4:
+ bch_correct(mtd, dat, (errs[2] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT);
+ case 3:
+ bch_correct(mtd, dat, (errs[2] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT);
+ case 2:
+ bch_correct(mtd, dat, (errs[1] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT);
+ case 1:
+ bch_correct(mtd, dat, (errs[1] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT);
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_MTD_NAND_DMA */
+
+/**
+ * jzsoc_nand_bch_correct_data_cpu
+ * @mtd: mtd info structure
+ * @dat: data to be corrected
+ * @read_ecc: pointer to ecc buffer calculated when nand writing
+ * @calc_ecc: no used
+ */
+static int jzsoc_nand_bch_correct_data_cpu(struct mtd_info *mtd, u_char * dat, u_char * read_ecc, u_char * calc_ecc)
+{
+ struct nand_chip *this = (struct nand_chip *)(mtd->priv);
+ int eccsize = this->ecc.size;
+ int eccbytes = this->ecc.bytes;
+ int eccsteps = this->ecc.steps / this->planenum;
+ int ecc_pos = this->ecc.layout->eccpos[0];
+ int oob_per_eccsize = ecc_pos / eccsteps;
+ short k;
+ u32 stat;
+
+ /* Write data to REG_BCH_DR */
+ for (k = 0; k < eccsize; k++) {
+ REG_BCH_DR = ((struct buf_be_corrected *)dat)->data[k];
+ }
+ /* Write oob to REG_BCH_DR */
+ for (k = 0; k < oob_per_eccsize; k++) {
+ REG_BCH_DR = ((struct buf_be_corrected *)dat)->oob[k];
+ }
+ /* Write parities to REG_BCH_DR */
+ for (k = 0; k < eccbytes; k++) {
+ REG_BCH_DR = read_ecc[k];
+ }
+
+ /* Wait for completion */
+ __ecc_decode_sync();
+ __ecc_disable();
+
+ /* Check decoding */
+ stat = REG_BCH_INTS;
+
+ if (stat & BCH_INTS_ERR) {
+ /* Error occurred */
+ if (stat & BCH_INTS_UNCOR) {
+ printk("NAND: Uncorrectable ECC error--\n");
+ return -1;
+ } else {
+ u32 errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT;
+ switch (errcnt) {
+#if defined(CONFIG_MTD_HW_BCH_8BIT)
+ case 8:
+ bch_correct(mtd, dat, (REG_BCH_ERR3 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT);
+ /* FALL-THROUGH */
+ case 7:
+ bch_correct(mtd, dat, (REG_BCH_ERR3 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT);
+ /* FALL-THROUGH */
+ case 6:
+ bch_correct(mtd, dat, (REG_BCH_ERR2 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT);
+ /* FALL-THROUGH */
+ case 5:
+ bch_correct(mtd, dat, (REG_BCH_ERR2 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT);
+ /* FALL-THROUGH */
+#endif
+ case 4:
+ bch_correct(mtd, dat, (REG_BCH_ERR1 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT);
+ /* FALL-THROUGH */
+ case 3:
+ bch_correct(mtd, dat, (REG_BCH_ERR1 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT);
+ /* FALL-THROUGH */
+ case 2:
+ bch_correct(mtd, dat, (REG_BCH_ERR0 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT);
+ /* FALL-THROUGH */
+ case 1:
+ bch_correct(mtd, dat, (REG_BCH_ERR0 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT);
+ return 0;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static int jzsoc_nand_calculate_bch_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
+{
+ struct nand_chip *this = (struct nand_chip *)(mtd->priv);
+ int eccsize = this->ecc.size;
+ int eccbytes = this->ecc.bytes;
+ int eccsteps = this->ecc.steps / this->planenum;
+ int ecc_pos = this->ecc.layout->eccpos[0];
+ int oob_per_eccsize = ecc_pos / eccsteps;
+ volatile u8 *paraddr = (volatile u8 *)BCH_PAR0;
+ short i;
+
+ /* Write data to REG_BCH_DR */
+ for (i = 0; i < eccsize; i++) {
+ REG_BCH_DR = ((struct buf_be_corrected *)dat)->data[i];
+ }
+ /* Write oob to REG_BCH_DR */
+ for (i = 0; i < oob_per_eccsize; i++) {
+ REG_BCH_DR = ((struct buf_be_corrected *)dat)->oob[i];
+ }
+ __ecc_encode_sync();
+ __ecc_disable();
+
+ for (i = 0; i < eccbytes; i++) {
+ ecc_code[i] = *paraddr++;
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_MTD_NAND_DMA)
+
+/**
+ * nand_write_page_hwecc_bch - [REPLACABLE] hardware ecc based page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ */
+static void nand_write_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf, u8 cmd_pgprog)
+{
+ int eccsize = chip->ecc.size;
+ int eccsteps = chip->ecc.steps / chip->planenum;
+ int eccbytes = chip->ecc.bytes;
+ int ecc_pos = chip->ecc.layout->eccpos[0];
+ int oob_per_eccsize = ecc_pos / eccsteps;
+ int pagesize = mtd->writesize / chip->planenum;
+ int oobsize = mtd->oobsize / chip->planenum;
+ int i, err, timeout;
+ const u8 *databuf;
+ u8 *oobbuf;
+ jz_dma_desc_8word *desc;
+
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ memcpy(prog_buf, buf, pagesize);
+ memcpy(prog_buf + pagesize, chip->oob_poi, oobsize);
+ dma_cache_wback_inv((u32)prog_buf, pagesize + oobsize);
+#else
+ databuf = buf;
+ oobbuf = chip->oob_poi;
+
+ /* descriptors for encoding data blocks */
+ desc = dma_desc_enc;
+ for (i = 0; i < eccsteps; i++) {
+ desc->dsadr = CPHYSADDR((u32)databuf) + i * eccsize; /* DMA source address */
+ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */
+ dprintk("dma_desc_enc:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr,
+ desc->ddadr);
+ desc++;
+ }
+
+ /* descriptors for encoding oob blocks */
+ desc = dma_desc_enc1;
+ for (i = 0; i < eccsteps; i++) {
+ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address, 28/4 = 7bytes */
+ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */
+ dprintk("dma_desc_enc1:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr,
+ desc->ddadr);
+ desc++;
+ }
+
+ /* descriptor for nand programing data block */
+ desc = dma_desc_nand_prog;
+ desc->dsadr = CPHYSADDR((u32)databuf); /* DMA source address */
+ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_W); /* It will be changed when using multiply chip select */
+ dprintk("dma_desc_nand_prog:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr,
+ desc->ddadr);
+
+ /* descriptor for nand programing oob block */
+ desc++;
+ desc->dsadr = CPHYSADDR((u32)oobbuf); /* DMA source address */
+ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_W); /* It will be changed when using multiply chip select */
+ dprintk("dma_desc_oob_prog:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr,
+ desc->ddadr);
+
+ /* descriptor for __nand_cmd(CMD_PGPROG) */
+ desc++;
+ *pval_nand_cmd_pgprog = cmd_pgprog;
+ desc->dsadr = CPHYSADDR((u32)pval_nand_cmd_pgprog);
+ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_R | cmd_offset); /* DMA target address: cmdport */
+ if (cmd_pgprog == 0x10)
+ desc->dcmd |= DMAC_DCMD_LINK; /* __nand_sync() by a DMA descriptor */
+ else if (cmd_pgprog == 0x11)
+ desc->dcmd &= ~DMAC_DCMD_LINK; /* __nand_sync() by polling */
+
+ dma_cache_wback_inv((u32)dma_desc_enc, (eccsteps * 2 + 2 + 1) * (sizeof(jz_dma_desc_8word)));
+ dma_cache_wback_inv((u32)databuf, pagesize);
+ dma_cache_wback_inv((u32)oobbuf, oobsize);
+ /* 4*6: pval_nand_ddr, pval_nand_dcs, pval_bch_ddr, pval_bch_dcs, dummy, pval_nand_cmd_pgprog */
+ dma_cache_wback_inv((u32)pval_nand_ddr, 4 * 8); /* 8 words, a cache line */
+#endif
+
+ REG_DMAC_DCCSR(bch_dma_chan) = 0;
+ REG_DMAC_DCCSR(nand_dma_chan) = 0;
+
+ /* Setup DMA descriptor address */
+ REG_DMAC_DDA(bch_dma_chan) = CPHYSADDR((u32)dma_desc_enc);
+ REG_DMAC_DDA(nand_dma_chan) = CPHYSADDR((u32)dma_desc_nand_prog);
+
+ /* Setup request source */
+ REG_DMAC_DRSR(bch_dma_chan) = DMAC_DRSR_RS_BCH_ENC;
+ REG_DMAC_DRSR(nand_dma_chan) = DMAC_DRSR_RS_AUTO;
+
+ /* Setup DMA channel control/status register */
+ REG_DMAC_DCCSR(bch_dma_chan) = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */
+
+ /* Enable DMA */
+ REG_DMAC_DMACR(0) |= DMAC_DMACR_DMAE;
+ REG_DMAC_DMACR(nand_dma_chan/HALF_DMA_NUM) |= DMAC_DMACR_DMAE;
+
+ /* Enable BCH encoding */
+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+
+ dma_ack1 = 0;
+ nand_status = NAND_PROG;
+
+ /* DMA doorbell set -- start DMA now ... */
+ __dmac_channel_set_doorbell(bch_dma_chan);
+
+#if USE_IRQ
+ if (cmd_pgprog == 0x10) {
+ dprintk("nand prog before wake up\n");
+ do {
+ err = wait_event_interruptible_timeout(nand_prog_wait_queue, dma_ack1, 3 * HZ);
+ }while(err == -ERESTARTSYS);
+
+ nand_status = NAND_NONE;
+ dprintk("nand prog after wake up\n");
+ if (!err) {
+ printk("*** NAND WRITE, Warning, wait event 3s timeout!\n");
+ dump_jz_dma_channel(0);
+ dump_jz_dma_channel(nand_dma_chan);
+ printk("REG_BCH_CR=%x REG_BCH_CNT=0x%x REG_BCH_INTS=%x\n", REG_BCH_CR, REG_BCH_CNT, REG_BCH_INTS);
+ }
+ dprintk("timeout remain = %d\n", err);
+ } else if (cmd_pgprog == 0x11) {
+ timeout = 100000;
+ while ((!__dmac_channel_transmit_end_detected(nand_dma_chan)) && (timeout--));
+ if (timeout <= 0)
+ printk("two-plane prog 0x11 timeout!\n");
+ }
+#else
+ timeout = 100000;
+ while ((!__dmac_channel_transmit_end_detected(nand_dma_chan)) && (timeout--));
+ while(!chip->dev_ready(mtd));
+ if (timeout <= 0)
+ printk("not use irq, prog timeout!\n");
+#endif
+}
+
+static void nand_write_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf)
+{
+ nand_write_page_hwecc_bch0(mtd, chip, buf, 0x10);
+}
+
+static void nand_write_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf)
+{
+ int page;
+ int pagesize = mtd->writesize >> 1;
+ int ppb = mtd->erasesize / mtd->writesize;
+
+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
+
+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */
+ if (chip->realplanenum == 2)
+ {
+ if(global_mafid == 0x2c)
+ chip->cmdfunc(mtd, 0x80, 0x00, page);
+ else
+ chip->cmdfunc(mtd, 0x80, 0x00, 0x00);
+ }
+ else
+ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift)));
+
+ nand_write_page_hwecc_bch0(mtd, chip, buf, 0x11);
+ chip->cmdfunc(mtd, 0x81, 0x00, page + ppb);
+ nand_write_page_hwecc_bch0(mtd, chip, buf + pagesize, 0x10);
+}
+
+#endif /* CONFIG_MTD_NAND_DMA */
+
+static void nand_write_page_hwecc_bch_cpu(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps / chip->planenum;
+ int oob_per_eccsize = chip->ecc.layout->eccpos[0] / eccsteps;
+ int oobsize = mtd->oobsize / chip->planenum;
+ int ecctotal = chip->ecc.total / chip->planenum;
+ uint8_t *p = (uint8_t *)buf;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ static struct buf_be_corrected buf_calc0;
+ struct buf_be_corrected *buf_calc = &buf_calc0;
+
+ for (i = 0; i < eccsteps; i++, p += eccsize) {
+ buf_calc->data = (u8 *)buf + eccsize * i;
+ buf_calc->oob = chip->oob_poi + oob_per_eccsize * i;
+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->ecc.calculate(mtd, (u8 *)buf_calc, &ecc_calc[eccbytes*i]);
+ chip->write_buf(mtd, p, eccsize);
+ }
+
+ for (i = 0; i < ecctotal; i++)
+ chip->oob_poi[eccpos[i]] = ecc_calc[i];
+
+ chip->write_buf(mtd, chip->oob_poi, oobsize);
+}
+
+/* nand write using two-plane mode with cpu mode */
+static void nand_write_page_hwecc_bch_planes_cpu(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+{
+ int pagesize = mtd->writesize >> 1;
+ int ppb = mtd->erasesize / mtd->writesize;
+ int page;
+
+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
+
+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */
+ if (chip->realplanenum == 2)
+ {
+ if(global_mafid == 0x2c)
+ chip->cmdfunc(mtd, 0x80, 0x00, page);
+ else
+ chip->cmdfunc(mtd, 0x80, 0x00, 0x00);
+ }
+ else
+ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift)));
+
+ nand_write_page_hwecc_bch_cpu(mtd, chip, buf);
+
+ chip->cmdfunc(mtd, 0x11, -1, -1); /* send cmd 0x11 */
+ ndelay(100);
+ while(!chip->dev_ready(mtd));
+
+ chip->cmdfunc(mtd, 0x81, 0x00, page + ppb); /* send cmd 0x81 */
+ nand_write_page_hwecc_bch_cpu(mtd, chip, buf + pagesize);
+}
+
+/**
+ * nand_read_page_hwecc_bch - [REPLACABLE] hardware ecc based page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ *
+ * Not for syndrome calculating ecc controllers which need a special oob layout
+ */
+#if defined(CONFIG_MTD_NAND_DMA)
+static int nand_read_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf, u32 page)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccsteps = chip->ecc.steps / chip->planenum;
+ int eccbytes = chip->ecc.bytes;
+ int ecc_pos = chip->ecc.layout->eccpos[0];
+ int oob_per_eccsize = ecc_pos / eccsteps;
+ int pagesize = mtd->writesize / chip->planenum;
+ int oobsize = mtd->oobsize / chip->planenum;
+ u8 *databuf, *oobbuf;
+ jz_dma_desc_8word *desc;
+ int err;
+ u32 addrport, cmdport;
+ static struct buf_be_corrected buf_correct0;
+
+ addrport = (u32)(chip->IO_ADDR_R) | addr_offset;
+ cmdport = (u32)(chip->IO_ADDR_R) | cmd_offset;
+
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ databuf = read_buf;
+ oobbuf = read_buf + pagesize;
+
+ dma_cache_inv((u32)read_buf, pagesize + oobsize); // databuf should be invalidated.
+ memset(errs, 0, eccsteps * ERRS_SIZE * 4);
+ dma_cache_wback_inv((u32)errs, eccsteps * ERRS_SIZE * 4);
+#else
+
+ databuf = buf;
+ oobbuf = chip->oob_poi;
+
+ /* descriptor for nand reading data block */
+ desc = dma_desc_nand_read;
+ desc->dsadr = CPHYSADDR((u32)chip->IO_ADDR_R); /* It will be changed when using multiply chip select */
+ desc->dtadr = CPHYSADDR((u32)databuf); /* DMA target address */
+
+ dprintk("desc_nand_read:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr,
+ desc->ddadr);
+
+ /* descriptor for nand reading oob block */
+ desc++;
+ desc->dsadr = CPHYSADDR((u32)chip->IO_ADDR_R); /* It will be changed when using multiply chip select */
+ desc->dtadr = CPHYSADDR((u32)oobbuf); /* DMA target address */
+ dprintk("desc_oob_read:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr,
+ desc->ddadr);
+
+ /* descriptors for data to be written to bch */
+ desc = dma_desc_dec;
+ for (i = 0; i < eccsteps; i++) {
+ desc->dsadr = CPHYSADDR((u32)databuf) + i * eccsize; /* DMA source address */
+ dprintk("dma_desc_dec:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr,
+ desc->ddadr);
+ desc++;
+ }
+
+ /* descriptors for oob to be written to bch */
+ desc = dma_desc_dec1;
+ for (i = 0; i < eccsteps; i++) {
+ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address */
+ dprintk("dma_desc_dec1:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr,
+ desc->ddadr);
+ desc++;
+ }
+
+ /* descriptors for parities to be written to bch */
+ desc = dma_desc_dec2;
+ for (i = 0; i < eccsteps; i++) {
+ desc->dsadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA source address */
+ dprintk("dma_desc_dec2:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr,
+ desc->ddadr);
+ desc++;
+ }
+
+ dma_cache_wback_inv((u32)dma_desc_nand_read, (2 + eccsteps * 3) * (sizeof(jz_dma_desc_8word)));
+
+ memset(errs, 0, eccsteps * ERRS_SIZE * 4);
+ dma_cache_inv((u32)databuf, pagesize); // databuf should be invalidated.
+ dma_cache_inv((u32)oobbuf, oobsize); // oobbuf should be invalidated too
+ dma_cache_wback_inv((u32)errs, eccsteps * ERRS_SIZE * 4);
+#endif
+ REG_DMAC_DCCSR(bch_dma_chan) = 0;
+ REG_DMAC_DCCSR(nand_dma_chan) = 0;
+
+ /* Setup DMA descriptor address */
+ REG_DMAC_DDA(nand_dma_chan) = CPHYSADDR((u32)dma_desc_nand_read);
+ REG_DMAC_DDA(bch_dma_chan) = CPHYSADDR((u32)dma_desc_dec);
+
+ /* Setup request source */
+ REG_DMAC_DRSR(nand_dma_chan) = DMAC_DRSR_RS_NAND;
+ REG_DMAC_DRSR(bch_dma_chan) = DMAC_DRSR_RS_BCH_DEC;
+
+ /* Enable DMA */
+ REG_DMAC_DMACR(0) |= DMAC_DMACR_DMAE;
+ REG_DMAC_DMACR(nand_dma_chan/HALF_DMA_NUM) |= DMAC_DMACR_DMAE;
+
+ /* Enable BCH decoding */
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+
+ dma_ack = 0;
+ nand_status = NAND_READ;
+ /* DMA doorbell set -- start nand DMA now ... */
+ __dmac_channel_set_doorbell(nand_dma_chan);
+
+ /* Setup DMA channel control/status register */
+ REG_DMAC_DCCSR(nand_dma_chan) = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN;
+
+#define __nand_cmd(n) (REG8(cmdport) = (n))
+#define __nand_addr(n) (REG8(addrport) = (n))
+
+ __nand_cmd(NAND_CMD_READ0);
+
+ __nand_addr(0);
+ if (pagesize != 512)
+ __nand_addr(0);
+
+ __nand_addr(page & 0xff);
+ __nand_addr((page >> 8) & 0xff);
+
+ /* One more address cycle for the devices whose number of page address bits > 16 */
+ if (((chip->chipsize >> chip->page_shift) >> 16) - 1 > 0)
+ __nand_addr((page >> 16) & 0xff);
+
+ if (pagesize != 512)
+ __nand_cmd(NAND_CMD_READSTART);
+
+#if USE_IRQ
+ do {
+ err = wait_event_interruptible_timeout(nand_read_wait_queue, dma_ack, 3 * HZ);
+ }while(err == -ERESTARTSYS);
+ nand_status = NAND_NONE;
+
+ if (!err) {
+ printk("*** NAND READ, Warning, wait event 3s timeout!\n");
+ dump_jz_dma_channel(0);
+ dump_jz_dma_channel(nand_dma_chan);
+ printk("REG_BCH_CR=%x REG_BCH_CNT=0x%x REG_BCH_INTS=%x\n", REG_BCH_CR, REG_BCH_CNT, REG_BCH_INTS);
+ printk("databuf[0]=%x\n", databuf[0]);
+ }
+ dprintk("timeout remain = %d\n", err);
+#else
+ int timeout;
+ timeout = 100000;
+ while ((!__dmac_channel_transmit_end_detected(bch_dma_chan)) && (timeout--));
+ if (timeout <= 0) {
+ printk("not use irq, NAND READ timeout!\n");
+ }
+#endif
+
+ for (i = 0; i < eccsteps; i++) {
+ int stat;
+ struct buf_be_corrected *buf_correct = &buf_correct0;
+
+ buf_correct->data = databuf + eccsize * i;
+ buf_correct->oob = oobbuf + oob_per_eccsize * i;
+
+ stat = chip->ecc.correct(mtd, (u8 *)buf_correct, (u8 *)&errs[i * ERRS_SIZE], NULL);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+ }
+
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ memcpy(buf, read_buf, pagesize);
+ memcpy(chip->oob_poi, read_buf + pagesize, oobsize);
+#endif
+ return 0;
+}
+
+static int nand_read_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf)
+{
+ u32 page = global_page;
+
+ nand_read_page_hwecc_bch0(mtd, chip, buf, page);
+ return 0;
+}
+
+static int nand_read_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf)
+{
+ u32 page;
+ int pagesize = mtd->writesize >> 1;
+ int ppb = mtd->erasesize / mtd->writesize;
+
+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
+
+ /* read 1st page */
+ nand_read_page_hwecc_bch0(mtd, chip, buf, page);
+
+ /* read 2nd page */
+ nand_read_page_hwecc_bch0(mtd, chip, buf + pagesize, page + ppb);
+ return 0;
+}
+
+#endif /* CONFIG_MTD_NAND_DMA */
+
+static int nand_read_page_hwecc_bch_cpu(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps / chip->planenum;
+ int ecc_pos = chip->ecc.layout->eccpos[0];
+ int oob_per_eccsize = ecc_pos / eccsteps;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ int pagesize = mtd->writesize / chip->planenum;
+ int oobsize = mtd->oobsize / chip->planenum;
+ int ecctotal = chip->ecc.total / chip->planenum;
+ static struct buf_be_corrected buf_correct0;
+
+ chip->read_buf(mtd, buf, pagesize);
+ chip->read_buf(mtd, chip->oob_poi, oobsize);
+
+ for (i = 0; i < ecctotal; i++) {
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+ }
+
+ for (i = 0; i < eccsteps; i++) {
+ int stat;
+ struct buf_be_corrected *buf_correct = &buf_correct0;
+
+ buf_correct->data = buf + eccsize * i;
+ buf_correct->oob = chip->oob_poi + oob_per_eccsize * i;
+
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ stat = chip->ecc.correct(mtd, (u8 *)buf_correct, &ecc_code[eccbytes*i], &ecc_calc[eccbytes*i]);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+ }
+
+ return 0;
+}
+
+static int nand_read_page_hwecc_bch_planes_cpu(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf)
+{
+ int pagesize = mtd->writesize >> 1;
+ int ppb = mtd->erasesize / mtd->writesize;
+ uint32_t page;
+
+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
+
+ /* Read first page */
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+ nand_read_page_hwecc_bch_cpu(mtd, chip, buf);
+
+ /* Read 2nd page */
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page + ppb);
+ nand_read_page_hwecc_bch_cpu(mtd, chip, buf+pagesize);
+ return 0;
+}
+
+#endif /* CONFIG_MTD_HW_BCH_ECC */
+
+/* read oob using two-plane mode */
+static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip,
+ int global_page, int sndcmd)
+{
+ int page;
+ int oobsize = mtd->oobsize >> 1;
+ int ppb = mtd->erasesize / mtd->writesize;
+
+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
+
+ /* Read first page OOB */
+ if (sndcmd) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ }
+ chip->read_buf(mtd, chip->oob_poi, oobsize);
+ /* Read second page OOB */
+ page += ppb;
+ if (sndcmd) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ sndcmd = 0;
+ }
+ chip->read_buf(mtd, chip->oob_poi+oobsize, oobsize);
+ return 0;
+}
+
+/* write oob using two-plane mode */
+static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip,
+ int global_page)
+{
+ int status = 0, page;
+ const uint8_t *buf = chip->oob_poi;
+ int pagesize = mtd->writesize >> 1;
+ int oobsize = mtd->oobsize >> 1;
+ int ppb = mtd->erasesize / mtd->writesize;
+
+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
+
+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */
+ if (chip->realplanenum == 2)
+ {
+ if(global_mafid == 0x2c)
+ chip->cmdfunc(mtd, 0x80, pagesize, page);
+ else
+ chip->cmdfunc(mtd, 0x80, pagesize, 0x00);
+ }
+ else
+ chip->cmdfunc(mtd, 0x80, pagesize, page & (1 << (chip->chip_shift - chip->page_shift)));
+
+ chip->write_buf(mtd, buf, oobsize);
+ /* Send first command to program the OOB data */
+ chip->cmdfunc(mtd, 0x11, -1, -1);
+ ndelay(100);
+ status = chip->waitfunc(mtd, chip);
+
+ page += ppb;
+ buf += oobsize;
+ chip->cmdfunc(mtd, 0x81, pagesize, page);
+ chip->write_buf(mtd, buf, oobsize);
+ /* Send command to program the OOB data */
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ /* Wait long R/B */
+ ndelay(100);
+ status = chip->waitfunc(mtd, chip);
+
+ return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+/* nand erase using two-plane mode */
+static void single_erase_cmd_planes(struct mtd_info *mtd, int global_page)
+{
+ struct nand_chip *chip = mtd->priv;
+ int page, ppb = mtd->erasesize / mtd->writesize;
+
+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */
+
+ /* send cmd 0x60, the MSB should be valid if realplane is 4 */
+ if (chip->realplanenum == 2)
+ {
+ if(global_mafid == 0x2c)
+ chip->cmdfunc(mtd, 0x60, -1, page);
+ else
+ chip->cmdfunc(mtd, 0x60, -1, 0x00);
+ }
+ else
+ chip->cmdfunc(mtd, 0x60, -1, page & (1 << (chip->chip_shift - chip->page_shift)));
+
+ page += ppb;
+ chip->cmdfunc(mtd, 0x60, -1, page & (~(ppb-1))); /* send cmd 0x60 */
+
+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); /* send cmd 0xd0 */
+ /* Do not need wait R/B or check status */
+}
+
+#if defined(CONFIG_MTD_NAND_DMA)
+
+#if USE_IRQ
+static irqreturn_t nand_dma_irq(int irq, void *dev_id)
+{
+ u8 dma_chan;
+ volatile int wakeup = 0;
+
+ dma_chan = irq - IRQ_DMA_0;
+
+ dprintk("jz4750_dma_irq %d, channel %d\n", irq, dma_chan);
+
+ if (__dmac_channel_transmit_halt_detected(dma_chan)) {
+ __dmac_channel_clear_transmit_halt(dma_chan);
+ wakeup = 1;
+ printk("DMA HALT\n");
+ }
+
+ if (__dmac_channel_address_error_detected(dma_chan)) {
+
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ __dmac_channel_clear_address_error(dma_chan);
+
+ REG_DMAC_DSAR(dma_chan) = 0; /* reset source address register */
+ REG_DMAC_DTAR(dma_chan) = 0; /* reset destination address register */
+
+ /* clear address error in DMACR */
+ REG_DMAC_DMACR((dma_chan / HALF_DMA_NUM)) &= ~(1 << 2);
+ wakeup = 1;
+ printk("DMA address error!\n");
+ }
+
+ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) {
+ __dmac_channel_clear_descriptor_invalid(dma_chan);
+ wakeup = 1;
+ printk("DMA DESC INVALID\n");
+ }
+#if 1
+
+ while (!__dmac_channel_transmit_end_detected(dma_chan));
+
+ if (__dmac_channel_count_terminated_detected(dma_chan)) {
+ dprintk("DMA CT\n");
+ __dmac_channel_clear_count_terminated(dma_chan);
+ wakeup = 0;
+ }
+#endif
+
+ if (__dmac_channel_transmit_end_detected(dma_chan)) {
+ dprintk("DMA TT\n");
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ __dmac_channel_clear_transmit_end(dma_chan);
+ wakeup = 1;
+ }
+
+ if (wakeup) {
+ dprintk("ack %d irq , wake up dma_chan %d nand_status %d\n", dma_ack, dma_chan, nand_status);
+ /* wakeup wait event */
+ if ((dma_chan == nand_dma_chan) && (nand_status == NAND_PROG)) {
+ dprintk("nand prog dma irq, wake up----\n");
+ dma_ack1 = 1;
+ wake_up_interruptible(&nand_prog_wait_queue);
+ }
+
+ if ((dma_chan == bch_dma_chan) && (nand_status == NAND_READ)) {
+ dprintk("nand read irq, wake up----\n");
+ dma_ack = 1;
+ wake_up_interruptible(&nand_read_wait_queue);
+ }
+ wakeup = 0;
+ }
+
+ return IRQ_HANDLED;
+}
+#endif /* USE_IRQ */
+
+static int jz4750_nand_dma_init(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ int eccsize = chip->ecc.size;
+ int eccsteps = chip->ecc.steps / chip->planenum;
+ int eccbytes = chip->ecc.bytes;
+ int ecc_pos = chip->ecc.layout->eccpos[0];
+ int oob_per_eccsize = ecc_pos / eccsteps;
+ int pagesize = mtd->writesize / chip->planenum;
+ int oobsize = mtd->oobsize / chip->planenum;
+ int i, err;
+ jz_dma_desc_8word *desc, *dma_desc_bch_ddr, *dma_desc_nand_ddr, *dma_desc_nand_cmd_pgprog;
+ u32 *pval_nand_dcs, *pval_bch_ddr, *pval_bch_dcs, *dummy;
+ u32 next;
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ u8 *oobbuf;
+#endif
+
+#if USE_IRQ
+ if ((nand_dma_chan = jz_request_dma(DMA_ID_NAND, "nand read or write", nand_dma_irq, IRQF_DISABLED, NULL)) < 0) {
+ printk("can't reqeust DMA nand channel.\n");
+ return 0;
+ }
+ dprintk("nand dma channel:%d----\n", nand_dma_chan);
+
+ if ((err = request_irq(IRQ_DMA_0 + bch_dma_chan, nand_dma_irq, IRQF_DISABLED, "bch_dma", NULL))) {
+ printk("bch_dma irq request err\n");
+ return 0;
+ }
+#else
+ if ((nand_dma_chan = jz_request_dma(DMA_ID_NAND, "nand read or write", NULL, IRQF_DISABLED, NULL)) < 0) {
+ printk("can't reqeust DMA nand channel.\n");
+ return 0;
+ }
+ dprintk("nand dma channel:%d----\n", nand_dma_chan);
+#endif
+
+ __dmac_channel_enable_clk(nand_dma_chan);
+ __dmac_channel_enable_clk(bch_dma_chan);
+
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ if (pagesize < 4096) {
+ read_buf = prog_buf = (u8 *) __get_free_page(GFP_KERNEL);
+ } else {
+ read_buf = prog_buf = (u8 *) __get_free_pages(GFP_KERNEL, 1);
+ }
+ if (!read_buf)
+ return -ENOMEM;
+#endif
+ /* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes), and the space for the value
+ * of ddr and dcs of channel 0 and channel nand_dma_chan (4 * (2 + 2) bytes) */
+ errs = (u32 *)kmalloc(4 * (2 + 2 + 5 * eccsteps), GFP_KERNEL);
+ if (!errs)
+ return -ENOMEM;
+
+ pval_nand_ddr = errs + 5 * eccsteps;
+ pval_nand_dcs = pval_nand_ddr + 1;
+ pval_bch_ddr = pval_nand_dcs + 1;
+ pval_bch_dcs = pval_bch_ddr + 1;
+ /* space for nand prog waiting target, the content is useless */
+ dummy = pval_bch_dcs + 1;
+ /* space to store CMD_PGPROG(0x10) or 0x11 */
+ pval_nand_cmd_pgprog = (u8 *)(dummy + 1);
+
+ /* desc can't across 4KB boundary, as desc base address is fixed */
+ /* space of descriptors for nand reading data and oob blocks */
+ dma_desc_nand_read = (jz_dma_desc_8word *) __get_free_page(GFP_KERNEL);
+ if (!dma_desc_nand_read)
+ return -ENOMEM;
+
+ /* space of descriptors for bch decoding */
+ dma_desc_dec = dma_desc_nand_read + 2;
+ dma_desc_dec1 = dma_desc_dec + eccsteps;
+ dma_desc_dec2 = dma_desc_dec + eccsteps * 2;
+
+ /* space of descriptors for notifying bch channel */
+ dma_desc_bch_ddr = dma_desc_dec2 + eccsteps;
+
+ /* space of descriptors for bch encoding */
+ dma_desc_enc = dma_desc_bch_ddr + 2;
+ dma_desc_enc1 = dma_desc_enc + eccsteps;
+
+ /* space of descriptors for nand programing data and oob blocks */
+ dma_desc_nand_prog = dma_desc_enc1 + eccsteps;
+
+ /* space of descriptors for nand prog waiting, including pgprog and sync */
+ dma_desc_nand_cmd_pgprog = dma_desc_nand_prog + 2;
+
+ /* space of descriptors for notifying nand channel, including ddr and dcsr */
+ dma_desc_nand_ddr = dma_desc_nand_cmd_pgprog + 2;
+
+/*************************************
+ * Setup of nand programing descriptors
+ *************************************/
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ oobbuf = prog_buf + pagesize;
+#endif
+ /* set descriptor for encoding data blocks */
+ desc = dma_desc_enc;
+ for (i = 0; i < eccsteps; i++) {
+ next = (CPHYSADDR((u32)dma_desc_enc1) + i * (sizeof(jz_dma_desc_8word))) >> 4;
+
+ desc->dcmd =
+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 |
+ DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK;
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ desc->dsadr = CPHYSADDR((u32)prog_buf) + i * eccsize; /* DMA source address */
+ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */
+#endif
+ desc->ddadr = (next << 24) + eccsize / DIV_DS_BCH; /* size: eccsize bytes */
+ desc->dreqt = DMAC_DRSR_RS_BCH_ENC;
+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr);
+ desc++;
+ }
+
+ /* set descriptor for encoding oob blocks */
+ desc = dma_desc_enc1;
+ for (i = 0; i < eccsteps; i++) {
+ next = (CPHYSADDR((u32)dma_desc_enc) + (i + 1) * (sizeof(jz_dma_desc_8word))) >> 4;
+
+ desc->dcmd =
+ DMAC_DCMD_BLAST | DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 |
+ DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK;
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address, 28/4 = 7bytes */
+ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */
+#endif
+ desc->ddadr = (next << 24) + (oob_per_eccsize + 3) / 4; /* size: 7 bytes -> 2 words */
+ desc->dreqt = DMAC_DRSR_RS_BCH_ENC;
+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr);
+ desc++;
+ }
+
+ next = (CPHYSADDR((u32)dma_desc_nand_ddr)) >> 4;
+ desc--;
+ desc->ddadr = (next << 24) + (oob_per_eccsize + 3) / 4;
+
+ /* set the descriptor to set door bell of nand_dma_chan for programing nand */
+ desc = dma_desc_nand_ddr;
+ *pval_nand_ddr = 1 << (nand_dma_chan - nand_dma_chan / HALF_DMA_NUM * HALF_DMA_NUM);
+ next = (CPHYSADDR((u32)dma_desc_nand_ddr) + sizeof(jz_dma_desc_8word)) >> 4;
+ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK;
+ desc->dsadr = CPHYSADDR((u32)pval_nand_ddr); /* DMA source address */
+ desc->dtadr = CPHYSADDR(DMAC_DMADBSR(nand_dma_chan / HALF_DMA_NUM)); /* nand_dma_chan's descriptor addres register */
+ desc->ddadr = (next << 24) + 1; /* size: 1 word */
+ desc->dreqt = DMAC_DRSR_RS_AUTO;
+ dprintk("*pval_nand_ddr=0x%x\n", *pval_nand_ddr);
+
+ /* set the descriptor to write dccsr of nand_dma_chan for programing nand, dccsr should be set at last */
+ desc++;
+ *pval_nand_dcs = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; /* set value for writing ddr to enable channel nand_dma_chan */
+ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT;
+ desc->dsadr = CPHYSADDR((u32)pval_nand_dcs); /* DMA source address */
+ desc->dtadr = CPHYSADDR(DMAC_DCCSR(nand_dma_chan)); /* address of dma door bell set register */
+ desc->ddadr = (0 << 24) + 1; /* size: 1 word */
+ desc->dreqt = DMAC_DRSR_RS_AUTO;
+ dprintk("*pval_nand_dcs=0x%x\n", *pval_nand_dcs);
+
+ /* set descriptor for nand programing data block */
+ desc = dma_desc_nand_prog;
+ next = (CPHYSADDR((u32)dma_desc_nand_prog) + sizeof(jz_dma_desc_8word)) >> 4;
+ desc->dcmd =
+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 |
+ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK;
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ desc->dsadr = CPHYSADDR((u32)prog_buf); /* DMA source address */
+#endif
+ desc->dtadr = CPHYSADDR((u32)(chip->IO_ADDR_W)); /* DMA target address */
+ desc->ddadr = (next << 24) + pagesize / DIV_DS_NAND; /* size: eccsize bytes */
+ desc->dreqt = DMAC_DRSR_RS_AUTO;
+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr);
+
+ /* set descriptor for nand programing oob block */
+ desc++;
+ next = (CPHYSADDR((u32)dma_desc_nand_cmd_pgprog)) >> 4;
+ desc->dcmd =
+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 |
+ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK;
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ desc->dsadr = CPHYSADDR((u32)oobbuf); /* DMA source address */
+#endif
+ desc->dtadr = CPHYSADDR((u32)(chip->IO_ADDR_W)); /* DMA target address: dataport */
+ desc->ddadr = (next << 24) + oobsize / DIV_DS_NAND; /* size: eccsize bytes */
+ desc->dreqt = DMAC_DRSR_RS_AUTO;
+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr);
+
+ /* set descriptor for __nand_cmd(CMD_PGPROG) */
+ desc = dma_desc_nand_cmd_pgprog;
+ *pval_nand_cmd_pgprog = NAND_CMD_PAGEPROG;
+ next = (CPHYSADDR((u32)dma_desc_nand_cmd_pgprog) + sizeof(jz_dma_desc_8word)) >> 4;
+ desc->dcmd =
+ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_8BIT | DMAC_DCMD_LINK;
+ desc->dsadr = CPHYSADDR((u32)pval_nand_cmd_pgprog); /* DMA source address */
+ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_R | cmd_offset); /* DMA target address: cmdport */
+ desc->ddadr = (next << 24) + 1; /* size: 1 byte */
+ desc->dreqt = DMAC_DRSR_RS_AUTO;
+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr);
+
+ /* set descriptor for __nand_sync() */
+ desc++;
+#if USE_IRQ
+ desc->dcmd =
+ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_TIE;
+#else
+ desc->dcmd =
+ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT;
+#endif
+ desc->dsadr = CPHYSADDR((u32)pval_nand_ddr); /* DMA source address */
+ desc->dtadr = CPHYSADDR((u32)dummy); /* DMA target address, the content is useless */
+ desc->ddadr = (0 << 24) + 1; /* size: 1 word */
+ desc->dreqt = DMAC_DRSR_RS_NAND;
+ dprintk("1cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr);
+
+ /* eccsteps*2 + 2 + 2 + 2:
+ dma_desc_enc + dma_desc_enc1 + dma_desc_nand_prog(oob) + dma_desc_nand_ddr(csr)
+ + dma_desc_nand_cmd_pgprog(sync) */
+ dma_cache_wback_inv((u32)dma_desc_enc, (eccsteps * 2 + 2 + 2 + 2) * (sizeof(jz_dma_desc_8word)));
+ /* 4*6: pval_nand_ddr, pval_nand_dcs, pval_bch_ddr, pval_bch_dcs, dummy, pval_nand_cmd_pgprog */
+ dma_cache_wback_inv((u32)pval_nand_ddr, 4 * 8); /* 8 words, a cache line */
+
+/*************************************
+ * Setup of nand reading descriptors
+ *************************************/
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ oobbuf = read_buf + pagesize;
+#endif
+ /* set descriptor for nand reading data block */
+ desc = dma_desc_nand_read;
+ next = (CPHYSADDR((u32)dma_desc_nand_read) + sizeof(jz_dma_desc_8word)) >> 4;
+ desc->dcmd =
+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 |
+ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK;
+ desc->dsadr = CPHYSADDR((u32)(chip->IO_ADDR_R)); /* DMA source address */
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ desc->dtadr = CPHYSADDR((u32)read_buf); /* DMA target address */
+#endif
+ desc->ddadr = (next << 24) + pagesize / DIV_DS_NAND; /* size: eccsize bytes */
+ desc->dreqt = DMAC_DRSR_RS_NAND;
+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr);
+
+ /* set descriptor for nand reading oob block */
+ desc++;
+ next = (CPHYSADDR((u32)dma_desc_bch_ddr)) >> 4;
+ desc->dcmd =
+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 |
+ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK;
+ desc->dsadr = CPHYSADDR((u32)(chip->IO_ADDR_R)); /* DMA source address */
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ desc->dtadr = CPHYSADDR((u32)oobbuf); /* DMA target address */
+#endif
+ desc->ddadr = (next << 24) + oobsize / DIV_DS_NAND; /* size: eccsize bytes */
+ desc->dreqt = DMAC_DRSR_RS_AUTO;
+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr);
+
+ /* set the descriptor to set door bell for bch */
+ desc = dma_desc_bch_ddr;
+ *pval_bch_ddr = DMAC_DMADBSR_DBS0; // set value for writing ddr to enable channel 0
+ next = (CPHYSADDR((u32)dma_desc_bch_ddr) + sizeof(jz_dma_desc_8word)) >> 4;
+ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK;
+ desc->dsadr = CPHYSADDR((u32)pval_bch_ddr); /* DMA source address */
+ desc->dtadr = CPHYSADDR(DMAC_DMADBSR(0)); /* channel 1's descriptor addres register */
+ desc->ddadr = (next << 24) + 1; /* size: 1 word */
+ desc->dreqt = DMAC_DRSR_RS_AUTO;
+
+ /* set descriptor for writing dcsr */
+ desc++;
+ *pval_bch_dcs = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; // set value for writing ddr to enable channel 1
+ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT;
+ desc->dsadr = CPHYSADDR((u32)pval_bch_dcs); /* DMA source address */
+ desc->dtadr = CPHYSADDR(DMAC_DCCSR(bch_dma_chan)); /* address of dma door bell set register */
+ desc->ddadr = (0 << 24) + 1; /* size: 1 word */
+ desc->dreqt = DMAC_DRSR_RS_AUTO;
+
+ /* descriptors for data to be written to bch */
+ desc = dma_desc_dec;
+ for (i = 0; i < eccsteps; i++) {
+ next = CPHYSADDR((u32)dma_desc_dec1 + i * (sizeof(jz_dma_desc_8word))) >> 4;
+
+ desc->dcmd =
+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 |
+ DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK;
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ desc->dsadr = CPHYSADDR((u32)read_buf) + i * eccsize; /* DMA source address */
+#endif
+ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */
+ desc->ddadr = (next << 24) + eccsize / DIV_DS_BCH; /* size: eccsize bytes */
+ desc->dreqt = DMAC_DRSR_RS_BCH_DEC;
+ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr,
+ desc->ddadr);
+ desc++;
+ }
+
+ /* descriptors for oob to be written to bch */
+ desc = dma_desc_dec1;
+ for (i = 0; i < eccsteps; i++) {
+ next = CPHYSADDR((u32)dma_desc_dec2 + i * (sizeof(jz_dma_desc_8word))) >> 4;
+
+ desc->dcmd =
+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 |
+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_LINK;
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address */
+#endif
+ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */
+ desc->ddadr = (next << 24) + oob_per_eccsize; /* size: 7 bytes */
+ desc->dreqt = DMAC_DRSR_RS_BCH_DEC;
+ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr,
+ desc->ddadr);
+ desc++;
+ }
+
+ /* descriptors for parities to be written to bch */
+ desc = dma_desc_dec2;
+ for (i = 0; i < eccsteps; i++) {
+ next = (CPHYSADDR((u32)dma_desc_dec) + (i + 1) * (sizeof(jz_dma_desc_8word))) >> 4;
+
+ desc->dcmd =
+ DMAC_DCMD_BLAST | DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 |
+ DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK;
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ desc->dsadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA source address */
+#endif
+ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */
+ desc->ddadr = (next << 24) + (eccbytes + DIV_DS_BCH - 1) / DIV_DS_BCH; /* size: eccbytes bytes */
+ desc->dreqt = DMAC_DRSR_RS_BCH_DEC;
+ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr,
+ desc->ddadr);
+ desc++;
+ }
+ desc--;
+ desc->dcmd &= ~DMAC_DCMD_LINK;
+#if USE_IRQ
+ desc->dcmd |= DMAC_DCMD_TIE;
+#endif
+
+ dma_cache_wback_inv((u32)dma_desc_nand_read, (2 + 2 + eccsteps * 3) * (sizeof(jz_dma_desc_8word)));
+ dma_cache_wback_inv((u32)pval_bch_ddr, 4 * 2); /* two words */
+
+ return 0;
+}
+
+#endif /* CONFIG_MTD_NAND_DMA */
+
+void copy_to_cpu_mode(struct mtd_info *mtd_cpu, struct mtd_info *mtd_dma, char use_planes)
+{
+ struct nand_chip *chip_cpu = (struct nand_chip *)(&mtd_cpu[1]);
+ struct nand_chip *chip_dma = (struct nand_chip *)(&mtd_dma[1]);
+
+#ifdef CONFIG_MTD_HW_BCH_ECC
+ memcpy(mtd_cpu, mtd_dma, sizeof(struct mtd_info));
+ mtd_cpu->priv = chip_cpu;
+ memcpy(chip_cpu, chip_dma, sizeof(struct nand_chip));
+
+ chip_cpu->ecc.correct = jzsoc_nand_bch_correct_data_cpu;
+
+ if (use_planes) {
+ chip_cpu->ecc.read_page = nand_read_page_hwecc_bch_planes_cpu;
+ chip_cpu->ecc.write_page = nand_write_page_hwecc_bch_planes_cpu;
+ } else {
+ chip_cpu->ecc.read_page = nand_read_page_hwecc_bch_cpu;
+ chip_cpu->ecc.write_page = nand_write_page_hwecc_bch_cpu;
+ }
+#else
+ memcpy(mtd_cpu, mtd_dma, sizeof(struct mtd_info));
+ mtd_cpu->priv = chip_cpu;
+ memcpy(chip_cpu, chip_dma, sizeof(struct nand_chip));
+
+#endif
+ mtd_cpu->flags |= MTD_NAND_CPU_MODE;
+}
+
+/*
+ * Main initialization routine
+ */
+int __init jznand_init(void)
+{
+ struct nand_chip *this;
+ struct mtd_info *jz_mtd_cpu, *jz_mtd_cpu1; /* jz_mtd_cpu for 2 planes, jz_mtd_cpu1 for 1 plane */
+ int ret, i;
+
+ printk("JZ NAND init:");
+#if defined(CONFIG_MTD_NAND_DMA)
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ printk(" DMA mode, using DMA buffer in NAND driver, ");
+#else
+ printk(" DMA mode, using DMA buffer in upper layer, ");
+#endif
+#else
+ printk(KERN_INFO " CPU mode, ");
+#endif
+#if defined(CONFIG_MTD_HW_BCH_8BIT)
+ printk(" 8bit BCH.\n");
+#else
+ printk(" 4bit BCH.\n");
+#endif
+
+ /* Allocate memory for MTD device structure and private data */
+ jz_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
+ if (!jz_mtd) {
+ printk("Unable to allocate JzSOC NAND MTD device structure for dma mode using multi-planes.\n");
+ return -ENOMEM;
+ }
+
+ jz_mtd1 = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL);
+ if (!jz_mtd1) {
+ printk ("Unable to allocate JzSOC NAND MTD device structure for dma mode using 1 plane.\n");
+ kfree(jz_mtd);
+ return -ENOMEM;
+ }
+
+ jz_mtd_cpu = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL);
+ if (!jz_mtd_cpu) {
+ printk ("Unable to allocate JzSOC NAND MTD device structure for cpu mode using multi-planes.\n");
+ kfree(jz_mtd);
+ kfree(jz_mtd1);
+ return -ENOMEM;
+ }
+
+ jz_mtd_cpu1 = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL);
+ if (!jz_mtd_cpu) {
+ printk ("Unable to allocate JzSOC NAND MTD device structure for cpu mode using 1 plane.\n");
+ kfree(jz_mtd);
+ kfree(jz_mtd1);
+ kfree(jz_mtd_cpu);
+ return -ENOMEM;
+ }
+
+ /* Get pointer to private data */
+ this = (struct nand_chip *)(&jz_mtd[1]);
+
+ /* Initialize structures */
+ memset((char *)jz_mtd, 0, sizeof(struct mtd_info));
+ memset((char *)this, 0, sizeof(struct nand_chip));
+
+ /* Link the private data with the MTD structure */
+ jz_mtd->priv = this;
+
+ if (is_share_mode()) {
+ addr_offset = NAND_ADDR_OFFSET0;
+ cmd_offset = NAND_CMD_OFFSET0;
+ } else {
+ addr_offset = NAND_ADDR_OFFSET1;
+ cmd_offset = NAND_CMD_OFFSET1;
+ }
+
+ /* Set & initialize NAND Flash controller */
+ jz_device_setup();
+
+ /* Set address of NAND IO lines to static bank1 by default */
+ this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1;
+ this->IO_ADDR_W = (void __iomem *)NAND_DATA_PORT1;
+ this->cmd_ctrl = jz_hwcontrol;
+ this->dev_ready = jz_device_ready;
+
+#ifdef CONFIG_MTD_HW_BCH_ECC
+ this->ecc.calculate = jzsoc_nand_calculate_bch_ecc;
+ this->ecc.hwctl = jzsoc_nand_enable_bch_hwecc;
+ this->ecc.mode = NAND_ECC_HW;
+ this->ecc.size = 512;
+#if defined(CONFIG_MTD_NAND_DMA)
+ this->ecc.correct = jzsoc_nand_bch_correct_data;
+ this->ecc.read_page = nand_read_page_hwecc_bch;
+ this->ecc.write_page = nand_write_page_hwecc_bch;
+#else
+ this->ecc.correct = jzsoc_nand_bch_correct_data_cpu;
+ this->ecc.read_page = nand_read_page_hwecc_bch_cpu;
+ this->ecc.write_page = nand_write_page_hwecc_bch_cpu;
+#endif
+#if defined(CONFIG_MTD_HW_BCH_8BIT)
+ this->ecc.bytes = 13;
+#else
+ this->ecc.bytes = 7;
+#endif
+#endif
+
+#ifdef CONFIG_MTD_SW_HM_ECC
+ this->ecc.mode = NAND_ECC_SOFT;
+#endif
+ /* 20 us command delay time */
+ this->chip_delay = 20;
+ /* Scan to find existance of the device */
+ ret = nand_scan_ident(jz_mtd, nand_chips);
+
+#ifdef CONFIG_MTD_HW_BCH_ECC
+ if (!ret) {
+ if (this->planenum == 2) {
+ /* reset nand functions */
+ this->erase_cmd = single_erase_cmd_planes;
+#if defined(CONFIG_MTD_NAND_DMA)
+ this->ecc.read_page = nand_read_page_hwecc_bch_planes;
+ this->ecc.write_page = nand_write_page_hwecc_bch_planes;
+#else
+ this->ecc.read_page = nand_read_page_hwecc_bch_planes_cpu;
+ this->ecc.write_page = nand_write_page_hwecc_bch_planes_cpu;
+#endif
+ this->ecc.read_oob = nand_read_oob_std_planes;
+ this->ecc.write_oob = nand_write_oob_std_planes;
+
+ printk(KERN_INFO "Nand using two-plane mode, "
+ "and resized to writesize:%d oobsize:%d blocksize:0x%x \n",
+ jz_mtd->writesize, jz_mtd->oobsize, jz_mtd->erasesize);
+ }
+ }
+#endif
+
+ /* Determine whether all the partitions will use multiple planes if supported */
+ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition);
+ all_use_planes = 1;
+ for (i = 0; i < nr_partitions; i++) {
+ all_use_planes &= partition_info[i].use_planes;
+ }
+
+#if !defined(CONFIG_MTD_NAND_DMA)
+ for (i = 0; i < nr_partitions; i++) {
+ partition_info[i].cpu_mode = 1;
+ }
+#endif
+
+ if (!ret)
+ ret = nand_scan_tail(jz_mtd);
+
+ if (ret){
+ kfree (jz_mtd1);
+ kfree (jz_mtd);
+ return -ENXIO;
+ }
+
+#ifdef CONFIG_MTD_HW_BCH_ECC
+#if defined(CONFIG_MTD_NAND_DMA)
+ jz4750_nand_dma_init(jz_mtd);
+
+ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.read_page = nand_read_page_hwecc_bch;
+ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.write_page = nand_write_page_hwecc_bch;
+#else
+ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.read_page = nand_read_page_hwecc_bch_cpu;
+ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.write_page = nand_write_page_hwecc_bch_cpu;
+#endif
+#endif
+
+ /* Register the partitions */
+ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name);
+
+ if ((this->planenum == 2) && !all_use_planes) {
+ copy_to_cpu_mode(jz_mtd_cpu, jz_mtd, 1);
+ copy_to_cpu_mode(jz_mtd_cpu1, jz_mtd1, 0);
+
+ for (i = 0; i < nr_partitions; i++) {
+ if (partition_info[i].use_planes) {
+ if (partition_info[i].cpu_mode)
+ add_mtd_partitions(jz_mtd_cpu, &partition_info[i], 1);
+ else
+ add_mtd_partitions(jz_mtd, &partition_info[i], 1);
+ } else {
+ if (partition_info[i].cpu_mode)
+ add_mtd_partitions(jz_mtd_cpu1, &partition_info[i], 1);
+ else
+ add_mtd_partitions(jz_mtd1, &partition_info[i], 1);
+ }
+ }
+ } else {
+ kfree(jz_mtd1);
+ kfree(jz_mtd_cpu1);
+ copy_to_cpu_mode(jz_mtd_cpu, jz_mtd, 0);
+
+ for (i = 0; i < nr_partitions; i++) {
+ if (partition_info[i].cpu_mode)
+ add_mtd_partitions(jz_mtd_cpu, &partition_info[i], 1);
+ else
+ add_mtd_partitions(jz_mtd, &partition_info[i], 1);
+ }
+ }
+ return 0;
+}
+
+module_init(jznand_init);
+
+/*
+ * Clean up routine
+ */
+#ifdef MODULE
+
+#if defined(CONFIG_MTD_NAND_DMA)
+static int jz4750_nand_dma_exit(struct mtd_info *mtd)
+{
+ int pagesize = mtd->writesize / chip->planenum;
+
+#if USE_IRQ
+ free_irq(IRQ_DMA_0 + nand_dma_chan, NULL);
+ free_irq(IRQ_DMA_0 + bch_dma_chan, NULL);
+#endif
+
+ /* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes),
+ * and the space for the value of ddr and dcs of channel 0 and channel
+ * nand_dma_chan (4 * (2 + 2) bytes) */
+ kfree(errs);
+
+ /* space for dma_desc_nand_read contains dma_desc_nand_prog,
+ * dma_desc_enc and dma_desc_dec */
+ free_page((u32)dma_desc_nand_read);
+
+#if defined(CONFIG_MTD_NAND_DMABUF)
+ if (pagesize < 4096) {
+ free_page((u32)prog_buf);
+ } else {
+ free_pages((u32)prog_buf, 1);
+ }
+#endif
+
+ return 0;
+}
+#endif
+
+static void __exit jznand_cleanup(void)
+{
+#if defined(CONFIG_MTD_NAND_DMA)
+ jz4750_nand_dma_exit(jz_mtd);
+#endif
+
+ /* Unregister partitions */
+ del_mtd_partitions(jz_mtd);
+
+ /* Unregister the device */
+ del_mtd_device(jz_mtd);
+
+ /* Free the MTD device structure */
+ if ((this->planenum == 2) && !all_use_planes)
+ kfree (jz_mtd1);
+ kfree(jz_mtd);
+}
+
+module_exit(jznand_cleanup);
+#endif
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 8c21b89d2d0..acd69924c9b 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -52,6 +52,22 @@
#include <linux/mtd/partitions.h>
#endif
+#include <asm/jzsoc.h>
+
+u8 nand_nce; /* indicates which chip select on JZSOC is used for current nand chip */
+int global_page; /* page index of large page used for nand with multiple planes */
+int global_mafid; /* ID of manufacture */
+struct mtd_info *jz_mtd1 = NULL; /* for 1 plane operation */
+
+/* indicates whether multiple planes operation is used by all partitions
+ if multiple planes is supported by NAND */
+char all_use_planes = 1;
+
+/* The pointer to the address of block cache for partitions which work
+ over mtdblock-jz */
+extern struct mtd_partition partition_info[]; /* defined in jz47xx_nand.c */
+unsigned char **jz_mtdblock_cache = NULL; /* used by mtdblock-jz.c */
+
/* Define default oob placement schemes for large and small page devices */
static struct nand_ecclayout nand_oob_8 = {
.eccbytes = 3,
@@ -68,10 +84,35 @@ static struct nand_ecclayout nand_oob_16 = {
.eccpos = {0, 1, 2, 3, 6, 7},
.oobfree = {
{.offset = 8,
- . length = 8}}
+ .length = 8}}
};
static struct nand_ecclayout nand_oob_64 = {
+#if defined(CONFIG_MTD_HW_RS_ECC)
+/* Reed-Solomon ECC */
+ .eccbytes = 36,
+ .eccpos = {
+ 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63},
+ .oobfree = {
+ {.offset = 2,
+ .length = 26}}
+#elif defined(CONFIG_MTD_HW_BCH_ECC)
+/* BCH ECC */
+ .eccbytes = 28,
+ .eccpos = {
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51},
+ .oobfree = {
+ {.offset = 2,
+ .length = 22}}
+#else
+/* HW&SW Hamming ECC */
.eccbytes = 24,
.eccpos = {
40, 41, 42, 43, 44, 45, 46, 47,
@@ -80,9 +121,69 @@ static struct nand_ecclayout nand_oob_64 = {
.oobfree = {
{.offset = 2,
.length = 38}}
+#endif
};
static struct nand_ecclayout nand_oob_128 = {
+#if defined(CONFIG_MTD_HW_RS_ECC)
+/* Reed-Solomon ECC */
+ .eccbytes = 72,
+ .eccpos = {
+ 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 94, 95, 96, 97, 98, 99},
+ .oobfree = {
+ {.offset = 2,
+ .length = 26},
+ {.offset = 100,
+ .length = 28}}
+#elif defined(CONFIG_MTD_HW_BCH_ECC)
+#if !defined(CONFIG_MTD_HW_BCH_8BIT)
+/* 4-bit BCH ECC */
+ .eccbytes = 56,
+ .eccpos = {
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79},
+ .oobfree = {
+ {.offset = 2,
+ .length = 22},
+ {.offset = 80,
+ .length = 48}}
+#else
+/* 8-bit BCH ECC */
+ .eccbytes = 104,
+ .eccpos = {
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127,},
+ .oobfree = {
+ {.offset = 2,
+ .length = 22}}
+
+#endif
+#else
+/* HW&SW Hamming ECC */
.eccbytes = 48,
.eccpos = {
80, 81, 82, 83, 84, 85, 86, 87,
@@ -94,12 +195,13 @@ static struct nand_ecclayout nand_oob_128 = {
.oobfree = {
{.offset = 2,
.length = 78}}
+#endif
};
static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
int new_state);
-static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
+static int nand_do_write_oob(struct mtd_info *mtd, loff_mtd_t to,
struct mtd_oob_ops *ops);
/*
@@ -109,6 +211,35 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
DEFINE_LED_TRIGGER(nand_led_trigger);
/**
+ * ffs_ll - find first bit set in a 64bit word.
+ * @word: The word to search
+ */
+static inline int ffs_ll(u64 word)
+{
+ u32 low = word & 0xffffffff;
+ u32 high = word >> 32;
+ int i;
+
+ for(i = 0; i < 32; i++) {
+ if (low & 0x1)
+ break;
+ low >>= 1;
+ }
+ if (i == 32) {
+ for(i = 0; i < 32; i++) {
+ if (high & 0x1)
+ break;
+ high >>= 1;
+ }
+ i += 32;
+ }
+ if (i == 64)
+ return 0;
+ else
+ return (i+1);
+}
+
+/**
* nand_release_device - [GENERIC] release chip
* @mtd: MTD device structure
*
@@ -183,6 +314,20 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
break;
case 0:
+ nand_nce = NAND_NCE1;
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+ break;
+ case 1:
+ nand_nce = NAND_NCE2;
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+ break;
+ case 2:
+ nand_nce = NAND_NCE3;
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+ break;
+ case 3:
+ nand_nce = NAND_NCE4;
+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
break;
default:
@@ -312,13 +457,19 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
*
* Check, if the block is bad.
*/
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int nand_block_bad(struct mtd_info *mtd, loff_mtd_t ofs, int getchip)
{
- int page, chipnr, res = 0;
+ int page, page1 = 0, chipnr, res = 0;
struct nand_chip *chip = mtd->priv;
u16 bad;
- page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+ if (chip->planenum > 1) {
+ page = ((int)(ofs >> chip->page_shift) * chip->planenum + CONFIG_MTD_BADBLOCK_FLAG_PAGE);
+ page1 = page + mtd->erasesize / mtd->writesize;
+ page &= chip->pagemask;
+ page1 &= chip->pagemask;
+ } else
+ page = ((int)(ofs >> chip->page_shift) + CONFIG_MTD_BADBLOCK_FLAG_PAGE) & chip->pagemask;
if (getchip) {
chipnr = (int)(ofs >> chip->chip_shift);
@@ -341,6 +492,11 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
if (chip->read_byte(mtd) != 0xff)
res = 1;
+ if (chip->planenum > 1) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page1);
+ if (chip->read_byte(mtd) != 0xff)
+ res = 1;
+ }
}
if (getchip)
@@ -357,7 +513,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
* This is the default implementation, which can be overridden by
* a hardware specific driver.
*/
-static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int nand_default_block_markbad(struct mtd_info *mtd, loff_mtd_t ofs)
{
struct nand_chip *chip = mtd->priv;
uint8_t buf[2] = { 0, 0 };
@@ -377,6 +533,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
*/
nand_get_device(chip, mtd, FL_WRITING);
ofs += mtd->oobsize;
+ ofs += (CONFIG_MTD_BADBLOCK_FLAG_PAGE << chip->page_shift);
chip->ops.len = chip->ops.ooblen = 2;
chip->ops.datbuf = NULL;
chip->ops.oobbuf = buf;
@@ -416,7 +573,7 @@ static int nand_check_wp(struct mtd_info *mtd)
* Check, if the block is bad. Either by reading the bad block table or
* calling of the scan function.
*/
-static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
+static int nand_block_checkbad(struct mtd_info *mtd, loff_mtd_t ofs, int getchip,
int allowbbt)
{
struct nand_chip *chip = mtd->priv;
@@ -568,7 +725,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
/* Emulate NAND_CMD_READOOB */
if (command == NAND_CMD_READOOB) {
- column += mtd->writesize;
+ if (chip->planenum > 1)
+ column += (mtd->writesize / chip->planenum);
+ else
+ column += mtd->writesize;
command = NAND_CMD_READ0;
}
@@ -614,6 +774,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
case NAND_CMD_RNDIN:
case NAND_CMD_STATUS:
case NAND_CMD_DEPLETE1:
+ case 0x81: /* for two-plane page program */
+ case 0x11: /* for two-plane page program */
return;
/*
@@ -689,10 +851,11 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
spin_lock(lock);
/* Hardware controller shared among independend devices */
- /* Hardware controller shared among independend devices */
if (!chip->controller->active)
chip->controller->active = chip;
-
+
+ if (new_state == FL_PM_SUSPENDED)
+ printk("%s(): chip->controller->active: 0x%p, chip: 0x%p, chip->state: 0x%d.\n", __func__, chip->controller->active, chip, chip->state);
if (chip->controller->active == chip && chip->state == FL_READY) {
chip->state = new_state;
spin_unlock(lock);
@@ -979,6 +1142,63 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
return 0;
}
+#ifdef CONFIG_MTD_HW_RS_ECC /* HW&SW Hamming ECC */
+
+/**
+ * nand_read_page_hwecc_rs - [REPLACABLE] hardware rs ecc based page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ *
+ * Not for syndrome calculating ecc controllers which need a special oob layout
+ */
+static int nand_read_page_hwecc_rs(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ uint32_t page;
+ uint8_t flag = 0;
+
+ page = (buf[3]<<24) + (buf[2]<<16) + (buf[1]<<8) + buf[0];
+
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ for (i = 0; i < chip->ecc.total; i++) {
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+ if (ecc_code[i] != 0xff) flag = 1;
+ }
+
+ eccsteps = chip->ecc.steps;
+ p = buf;
+
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1);
+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ int stat;
+ if (flag) {
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+ }
+ else {
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+ }
+ }
+ return 0;
+}
+
+#endif /* CONFIG_MTD_HW_RS_ECC */
+
/**
* nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read
* @mtd: mtd info structure
@@ -1041,7 +1261,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
* @len: size of oob to transfer
*/
static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
- struct mtd_oob_ops *ops, size_t len)
+ struct mtd_oob_ops *ops, size_mtd_t len)
{
switch(ops->mode) {
@@ -1053,7 +1273,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
case MTD_OOB_AUTO: {
struct nand_oobfree *free = chip->ecc.layout->oobfree;
uint32_t boffs = 0, roffs = ops->ooboffs;
- size_t bytes = 0;
+ size_mtd_t bytes = 0;
for(; free->length && len; free++, len -= bytes) {
/* Read request not from offset 0 ? */
@@ -1063,11 +1283,11 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
continue;
}
boffs = free->offset + roffs;
- bytes = min_t(size_t, len,
+ bytes = min_t(size_mtd_t, len,
(free->length - roffs));
roffs = 0;
} else {
- bytes = min_t(size_t, len, free->length);
+ bytes = min_t(size_mtd_t, len, free->length);
boffs = free->offset;
}
memcpy(oob, chip->oob_poi + boffs, bytes);
@@ -1090,7 +1310,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
*
* Internal function. Called with chip held.
*/
-static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
+static int nand_do_read_ops(struct mtd_info *mtd, loff_mtd_t from,
struct mtd_oob_ops *ops)
{
int chipnr, page, realpage, col, bytes, aligned;
@@ -1124,10 +1344,25 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
if (realpage != chip->pagebuf || oob) {
bufpoi = aligned ? buf : chip->buffers->databuf;
+ global_page = page;
+#if defined(CONFIG_MTD_HW_RS_ECC)
+ bufpoi[0] = (uint8_t)page;
+ bufpoi[1] = (uint8_t)(page >> 8);
+ bufpoi[2] = (uint8_t)(page >> 16);
+ bufpoi[3] = (uint8_t)(page >> 24);
+#elif defined(CONFIG_SOC_JZ4730)
if (likely(sndcmd)) {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
sndcmd = 0;
}
+#else /* for jz4750 and later chip */
+ if (mtd->flags & MTD_NAND_CPU_MODE) {
+ if (likely(sndcmd)) {
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+ sndcmd = 0;
+ }
+ }
+#endif
/* Now read the page into the buffer */
if (unlikely(ops->mode == MTD_OOB_RAW))
@@ -1160,7 +1395,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
}
} else
buf = nand_transfer_oob(chip,
- buf, ops, mtd->oobsize);
+ oob, ops, mtd->oobsize);
}
if (!(chip->options & NAND_NO_READRDY)) {
@@ -1206,7 +1441,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
sndcmd = 1;
}
- ops->retlen = ops->len - (size_t) readlen;
+ ops->retlen = ops->len - (size_mtd_t) readlen;
if (oob)
ops->oobretlen = ops->ooblen - oobreadlen;
@@ -1229,8 +1464,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
*
* Get hold of the chip and call nand_do_read
*/
-static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, uint8_t *buf)
+static int nand_read(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len,
+ size_mtd_t *retlen, uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
int ret;
@@ -1240,7 +1475,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
return -EINVAL;
if (!len)
return 0;
-
+
nand_get_device(chip, mtd, FL_READING);
chip->ops.len = len;
@@ -1403,7 +1638,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
*
* NAND read out-of-band data from the spare area
*/
-static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
+static int nand_do_read_oob(struct mtd_info *mtd, loff_mtd_t from,
struct mtd_oob_ops *ops)
{
int page, realpage, chipnr, sndcmd = 1;
@@ -1496,7 +1731,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
*
* NAND read data and/or out-of-band data
*/
-static int nand_read_oob(struct mtd_info *mtd, loff_t from,
+static int nand_read_oob(struct mtd_info *mtd, loff_mtd_t from,
struct mtd_oob_ops *ops)
{
struct nand_chip *chip = mtd->priv;
@@ -1701,10 +1936,15 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
- if (unlikely(raw))
- chip->ecc.write_page_raw(mtd, chip, buf);
- else
+ global_page = page;
+ if (chip->planenum > 1)
chip->ecc.write_page(mtd, chip, buf);
+ else {
+ if (unlikely(raw))
+ chip->ecc.write_page_raw(mtd, chip, buf);
+ else
+ chip->ecc.write_page(mtd, chip, buf);
+ }
/*
* Cached progamming disabled for now, Not sure if its worth the
@@ -1713,8 +1953,17 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
cached = 0;
if (!cached || !(chip->options & NAND_CACHEPRG)) {
-
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+/*
+* __nand_cmd(CMD_PAGEPROG) and __nand_sync() have been done by DMA for jz4750 and
+* later chip, status should still be read by "status = chip->waitfunc(mtd, chip)"
+*/
+#if defined(CONFIG_SOC_JZ4730) || defined(CONFIG_SOC_JZ4740)
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+#else
+ if (mtd->flags & MTD_NAND_CPU_MODE) {
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ }
+#endif
status = chip->waitfunc(mtd, chip);
/*
* See if operation failed and additional status checks are
@@ -1750,7 +1999,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
struct mtd_oob_ops *ops)
{
- size_t len = ops->ooblen;
+ size_mtd_t len = ops->ooblen;
switch(ops->mode) {
@@ -1762,7 +2011,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
case MTD_OOB_AUTO: {
struct nand_oobfree *free = chip->ecc.layout->oobfree;
uint32_t boffs = 0, woffs = ops->ooboffs;
- size_t bytes = 0;
+ size_mtd_t bytes = 0;
for(; free->length && len; free++, len -= bytes) {
/* Write request not from offset 0 ? */
@@ -1772,11 +2021,11 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
continue;
}
boffs = free->offset + woffs;
- bytes = min_t(size_t, len,
+ bytes = min_t(size_mtd_t, len,
(free->length - woffs));
woffs = 0;
} else {
- bytes = min_t(size_t, len, free->length);
+ bytes = min_t(size_mtd_t, len, free->length);
boffs = free->offset;
}
memcpy(chip->oob_poi + boffs, oob, bytes);
@@ -1800,7 +2049,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
*
* NAND write with ECC
*/
-static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
+static int nand_do_write_ops(struct mtd_info *mtd, loff_mtd_t to,
struct mtd_oob_ops *ops)
{
int chipnr, realpage, page, blockmask, column;
@@ -1903,8 +2152,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
*
* NAND write with ECC
*/
-static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const uint8_t *buf)
+static int nand_write(struct mtd_info *mtd, loff_mtd_t to, size_mtd_t len,
+ size_mtd_t *retlen, const uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
int ret;
@@ -1938,7 +2187,7 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
*
* NAND write out-of-band
*/
-static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
+static int nand_do_write_oob(struct mtd_info *mtd, loff_mtd_t to,
struct mtd_oob_ops *ops)
{
int chipnr, page, status, len;
@@ -2016,7 +2265,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
* @to: offset to write to
* @ops: oob operation description structure
*/
-static int nand_write_oob(struct mtd_info *mtd, loff_t to,
+static int nand_write_oob(struct mtd_info *mtd, loff_mtd_t to,
struct mtd_oob_ops *ops)
{
struct nand_chip *chip = mtd->priv;
@@ -2113,9 +2362,9 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
{
int page, status, pages_per_block, ret, chipnr;
struct nand_chip *chip = mtd->priv;
- loff_t rewrite_bbt[NAND_MAX_CHIPS]={0};
+ loff_mtd_t rewrite_bbt[NAND_MAX_CHIPS]={0};
unsigned int bbt_masked_page = 0xffffffff;
- loff_t len;
+ loff_mtd_t len;
DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%012llx, len = %llu\n",
(unsigned long long)instr->addr, (unsigned long long)instr->len);
@@ -2181,7 +2430,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
/*
* heck if we have a bad block, we do not erase bad blocks !
*/
- if (nand_block_checkbad(mtd, ((loff_t) page) <<
+ if (nand_block_checkbad(mtd, ((loff_mtd_t) page) <<
chip->page_shift, 0, allowbbt)) {
printk(KERN_WARNING "nand_erase: attempt to erase a "
"bad block at page 0x%08x\n", page);
@@ -2215,7 +2464,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
"Failed erase, page 0x%08x\n", page);
instr->state = MTD_ERASE_FAILED;
instr->fail_addr =
- ((loff_t)page << chip->page_shift);
+ ((loff_mtd_t)page << chip->page_shift);
goto erase_exit;
}
@@ -2226,7 +2475,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
if (bbt_masked_page != 0xffffffff &&
(page & BBT_PAGE_MASK) == bbt_masked_page)
rewrite_bbt[chipnr] =
- ((loff_t)page << chip->page_shift);
+ ((loff_mtd_t)page << chip->page_shift);
/* Increment page address and decrement length */
len -= (1 << chip->phys_erase_shift);
@@ -2305,7 +2554,7 @@ static void nand_sync(struct mtd_info *mtd)
* @mtd: MTD device structure
* @offs: offset relative to mtd start
*/
-static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
+static int nand_block_isbad(struct mtd_info *mtd, loff_mtd_t offs)
{
/* Check for invalid offset */
if (offs > mtd->size)
@@ -2319,7 +2568,7 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
* @mtd: MTD device structure
* @ofs: offset relative to mtd start
*/
-static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int nand_block_markbad(struct mtd_info *mtd, loff_mtd_t ofs)
{
struct nand_chip *chip = mtd->priv;
int ret;
@@ -2485,11 +2734,26 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
extid >>= 2;
/* Get buswidth information */
busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+ /* The 5th id byte */
+#if defined(CONFIG_MTD_NAND_MULTI_PLANE)
+ extid = chip->read_byte(mtd);
+ chip->realplanenum = 1 << ((extid & 0x0c) >> 2);
+#else
+ chip->realplanenum = 1;
+#endif
+ if (chip->realplanenum > 1) { /* use muti planes mode */
+ chip->planenum = 2;
+ mtd->writesize *= 2; /* two pages as one page */
+ mtd->oobsize *= 2;
+ mtd->erasesize *= 2; /* two blocks as one block */
+ } else
+ chip->planenum = 1;
} else {
/*
* Old devices have chip data hardcoded in the device id table
*/
+ chip->realplanenum = 1;
mtd->erasesize = type->erasesize;
mtd->writesize = type->pagesize;
mtd->oobsize = mtd->writesize / 32;
@@ -2523,10 +2787,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip->bbt_erase_shift = chip->phys_erase_shift =
ffs(mtd->erasesize) - 1;
- if (chip->chipsize & 0xffffffff)
- chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
- else
- chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1;
+ chip->chip_shift = ffs_ll(chip->chipsize) - 1;
/* Set the bad block position */
chip->badblockpos = mtd->writesize > 512 ?
@@ -2558,8 +2819,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip->cmdfunc = nand_command_lp;
printk(KERN_INFO "NAND device: Manufacturer ID:"
- " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
- nand_manuf_ids[maf_idx].name, type->name);
+ " 0x%02x, Chip ID: 0x%02x (%s %s) planenum:%d\n", *maf_id, dev_id,
+ nand_manuf_ids[maf_idx].name, type->name, chip->realplanenum);
return type;
}
@@ -2588,6 +2849,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
/* Read the flash type */
type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
+ global_mafid = nand_maf_id;
if (IS_ERR(type)) {
printk(KERN_WARNING "No NAND device found!!!\n");
chip->select_chip(mtd, -1);
@@ -2627,7 +2889,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
*/
int nand_scan_tail(struct mtd_info *mtd)
{
- int i;
+ int i, res;
struct nand_chip *chip = mtd->priv;
if (!(chip->options & NAND_OWN_BUFFERS))
@@ -2653,7 +2915,14 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.layout = &nand_oob_64;
break;
case 128:
- chip->ecc.layout = &nand_oob_128;
+ if (chip->planenum > 1)
+ chip->ecc.layout = &nand_oob_64;
+ else
+ chip->ecc.layout = &nand_oob_128;
+ break;
+ case 256:
+ if (chip->planenum > 1)
+ chip->ecc.layout = &nand_oob_128;
break;
default:
printk(KERN_WARNING "No oob scheme defined for "
@@ -2673,8 +2942,13 @@ int nand_scan_tail(struct mtd_info *mtd)
switch (chip->ecc.mode) {
case NAND_ECC_HW:
/* Use standard hwecc read page function ? */
- if (!chip->ecc.read_page)
+ if (!chip->ecc.read_page) {
+#ifndef CONFIG_MTD_HW_RS_ECC
chip->ecc.read_page = nand_read_page_hwecc;
+#else
+ chip->ecc.read_page = nand_read_page_hwecc_rs;
+#endif
+ }
if (!chip->ecc.write_page)
chip->ecc.write_page = nand_write_page_hwecc;
if (!chip->ecc.read_page_raw)
@@ -2814,8 +3088,10 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd->sync = nand_sync;
mtd->lock = NULL;
mtd->unlock = NULL;
- mtd->suspend = nand_suspend;
- mtd->resume = nand_resume;
+ mtd->suspend = NULL;
+ mtd->resume = NULL;
+// mtd->suspend = nand_suspend;
+// mtd->resume = nand_resume;
mtd->block_isbad = nand_block_isbad;
mtd->block_markbad = nand_block_markbad;
@@ -2826,8 +3102,80 @@ int nand_scan_tail(struct mtd_info *mtd)
if (chip->options & NAND_SKIP_BBTSCAN)
return 0;
- /* Build bad block table */
- return chip->scan_bbt(mtd);
+ /* Create jz_mtd1 for one plane operation if the NAND support multiple
+ planes operation, because some partitions will only use one plane. */
+ if ((chip->planenum == 2) && !all_use_planes) {
+ int i, len, numblocks;
+ struct nand_chip *this = (struct nand_chip *) (&jz_mtd1[1]);
+
+ memcpy(jz_mtd1, mtd, sizeof(*mtd));
+ jz_mtd1->priv = this;
+ memcpy(this, chip, sizeof(*chip));
+
+ this->planenum = 1;
+ jz_mtd1->writesize >>= 1;
+ jz_mtd1->oobsize >>= 1;
+ jz_mtd1->erasesize >>= 1;
+ this->page_shift = chip->page_shift - 1;
+ this->pagemask = (this->chipsize >> this->page_shift) - 1;
+ this->bbt_erase_shift = this->phys_erase_shift =
+ chip->phys_erase_shift - 1;
+ this->ecc.steps >>= 1;
+ this->ecc.total = this->ecc.steps * this->ecc.bytes;
+ this->subpagesize = jz_mtd1->writesize;
+
+ this->erase_cmd = single_erase_cmd;
+#if defined(CONFIG_MTD_HW_RS_ECC)
+ this->ecc.read_page = nand_read_page_hwecc_rs;
+ this->ecc.write_page = nand_write_page_hwecc;
+#endif
+ this->ecc.read_oob = nand_read_oob_std;
+ this->ecc.write_oob = nand_write_oob_std;
+ this->write_buf = nand_write_buf;
+ this->read_buf = nand_read_buf;
+
+ /* Firstly, build bad block table as one plane */
+ res = this->scan_bbt(jz_mtd1);
+
+ /* Secondly, build bad block table as 2 plane based on bbt of jz_mtd1 */
+ numblocks = chip->chipsize >> (chip->bbt_erase_shift - 1); /* = (real numblocks * 2) */
+ len = mtd->size >> (chip->bbt_erase_shift + 2);
+ chip->bbt = kzalloc(len, GFP_KERNEL);
+
+#define isbad_2plane(block) (((this->bbt[(block) >> 3] >> ((block) & 0x06)) \
+ | (this->bbt[((block)+2) >> 3] >> (((block)+2) & 0x06))) & 0x03)
+
+ for (i = 0; i < numblocks; i += 2) {
+ if (isbad_2plane(2*i))
+ chip->bbt[i >> 3] |= 0x03 << (i & 0x6);
+ }
+ } else {
+ res = chip->scan_bbt(mtd);
+ }
+
+#if defined(CONFIG_ALLOCATE_MTDBLOCK_JZ_EARLY) && !defined(CONFIG_SOC_JZ4730)
+ /* Allocate a block cache for every partitions which works over mtdblock-jz */
+ {
+ extern int nr_partitions;
+
+ jz_mtdblock_cache = kzalloc(nr_partitions * sizeof(unsigned char *), GFP_KERNEL);
+
+ for (i = 0; i < nr_partitions; i++) {
+ if (!(partition_info[i].mtdblock_jz_invalid) && !(partition_info[i].cpu_mode)) {
+ if (partition_info[i].use_planes) {
+ jz_mtdblock_cache[i] = kmalloc(mtd->erasesize, GFP_KERNEL);
+ printk("Allocate 0x%x bytes for jz_mtdblock%d at address:0x%p.\n", mtd->erasesize, i, jz_mtdblock_cache[i]);
+ } else {
+ jz_mtdblock_cache[i] = kmalloc(jz_mtd1->erasesize, GFP_KERNEL);
+ printk("Allocate 0x%x bytes for jz_mtdblock%d at address:0x%p.\n", jz_mtd1->erasesize, i, jz_mtdblock_cache[i]);
+ }
+ if (!jz_mtdblock_cache[i])
+ printk("Cannot allocate memory for jz_mtdblock%d!\n", i);
+ }
+ }
+ }
+#endif
+ return res;
}
/* is_module_text_address() isn't exported, and it's mostly a pointless
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 55c23e5cd21..1185b12393c 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -145,15 +145,15 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
{
int res, i, j, act = 0;
struct nand_chip *this = mtd->priv;
- size_t retlen, len, totlen;
- loff_t from;
+ size_mtd_t retlen, len, totlen;
+ loff_mtd_t from;
uint8_t msk = (uint8_t) ((1 << bits) - 1);
totlen = (num * bits) >> 3;
- from = ((loff_t) page) << this->page_shift;
+ from = ((loff_mtd_t) page) << this->page_shift;
while (totlen) {
- len = min(totlen, (size_t) (1 << this->bbt_erase_shift));
+ len = min(totlen, (size_mtd_t) (1 << this->bbt_erase_shift));
res = mtd->read(mtd, from, len, &retlen, buf);
if (res < 0) {
if (retlen != len) {
@@ -172,7 +172,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
continue;
if (reserved_block_code && (tmp == reserved_block_code)) {
printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n",
- (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+ (loff_mtd_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
mtd->ecc_stats.bbtblocks++;
continue;
@@ -180,7 +180,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
/* Leave it for now, if its matured we can move this
* message to MTD_DEBUG_LEVEL0 */
printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n",
- (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+ (loff_mtd_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
/* Factory marked bad or worn out ? */
if (tmp == 0)
this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
@@ -233,8 +233,8 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
/*
* Scan read raw data from flash
*/
-static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
- size_t len)
+static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_mtd_t offs,
+ size_mtd_t len)
{
struct mtd_oob_ops ops;
@@ -251,7 +251,7 @@ static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
/*
* Scan write data with oob to flash
*/
-static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
+static int scan_write_bbt(struct mtd_info *mtd, loff_mtd_t offs, size_mtd_t len,
uint8_t *buf, uint8_t *oob)
{
struct mtd_oob_ops ops;
@@ -284,7 +284,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
/* Read the primary version, if available */
if (td->options & NAND_BBT_VERSION) {
- scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
+ scan_read_raw(mtd, buf, (loff_mtd_t)td->pages[0] << this->page_shift,
mtd->writesize);
td->version[0] = buf[mtd->writesize + td->veroffs];
printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
@@ -293,7 +293,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
/* Read the mirror version, if available */
if (md && (md->options & NAND_BBT_VERSION)) {
- scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
+ scan_read_raw(mtd, buf, (loff_mtd_t)md->pages[0] << this->page_shift,
mtd->writesize);
md->version[0] = buf[mtd->writesize + md->veroffs];
printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
@@ -306,7 +306,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
* Scan a given block full
*/
static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
- loff_t offs, uint8_t *buf, size_t readlen,
+ loff_mtd_t offs, uint8_t *buf, size_mtd_t readlen,
int scanlen, int len)
{
int ret, j;
@@ -326,7 +326,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
* Scan a given block partially
*/
static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
- loff_t offs, uint8_t *buf, int len)
+ loff_mtd_t offs, uint8_t *buf, int len)
{
struct mtd_oob_ops ops;
int j, ret;
@@ -372,8 +372,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_chip *this = mtd->priv;
int i, numblocks, len, scanlen;
int startblock;
- loff_t from;
- size_t readlen;
+ loff_mtd_t from;
+ size_mtd_t readlen;
printk(KERN_INFO "Scanning device for bad blocks\n");
@@ -401,7 +401,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
* below as it makes shifting and masking less painful */
numblocks = mtd->size >> (this->bbt_erase_shift - 1);
startblock = 0;
- from = 0;
+ from = (CONFIG_MTD_BADBLOCK_FLAG_PAGE << this->page_shift); //from = 0;
} else {
if (chip >= this->numchips) {
printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
@@ -411,7 +411,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
startblock = chip * numblocks;
numblocks += startblock;
- from = (loff_t)startblock << (this->bbt_erase_shift - 1);
+ from = ((loff_mtd_t)startblock << (this->bbt_erase_shift - 1)) + (CONFIG_MTD_BADBLOCK_FLAG_PAGE << this->page_shift); //from = startblock << (this->bbt_erase_shift - 1);
}
for (i = startblock; i < numblocks;) {
@@ -495,7 +495,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
for (block = 0; block < td->maxblocks; block++) {
int actblock = startblock + dir * block;
- loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
+ loff_mtd_t offs = (loff_mtd_t)actblock << this->bbt_erase_shift;
/* Read first page */
scan_read_raw(mtd, buf, offs, mtd->writesize);
@@ -565,8 +565,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
int nrchips, bbtoffs, pageoffs, ooboffs;
uint8_t msk[4];
uint8_t rcode = td->reserved_block_code;
- size_t retlen, len = 0;
- loff_t to;
+ size_mtd_t retlen, len = 0;
+ loff_mtd_t to;
struct mtd_oob_ops ops;
ops.ooblen = mtd->oobsize;
@@ -653,12 +653,12 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
bbtoffs = chip * (numblocks >> 2);
- to = ((loff_t) page) << this->page_shift;
+ to = ((loff_mtd_t) page) << this->page_shift;
/* Must we save the block contents ? */
if (td->options & NAND_BBT_SAVECONTENT) {
/* Make it block aligned */
- to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));
+ to &= ~((loff_mtd_t) ((1 << this->bbt_erase_shift) - 1));
len = 1 << this->bbt_erase_shift;
res = mtd->read(mtd, to, len, &retlen, buf);
if (res < 0) {
@@ -683,12 +683,12 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
pageoffs = page - (int)(to >> this->page_shift);
offs = pageoffs << this->page_shift;
/* Preset the bbt area with 0xff */
- memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));
+ memset(&buf[offs], 0xff, (size_mtd_t) (numblocks >> sft));
ooboffs = len + (pageoffs * mtd->oobsize);
} else {
/* Calc length */
- len = (size_t) (numblocks >> sft);
+ len = (size_mtd_t) (numblocks >> sft);
/* Make it page aligned ! */
len = (len + (mtd->writesize - 1)) &
~(mtd->writesize - 1);
@@ -910,7 +910,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
newval = oldval | (0x2 << (block & 0x06));
this->bbt[(block >> 3)] = newval;
if ((oldval != newval) && td->reserved_block_code)
- nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));
+ nand_update_bbt(mtd, (loff_mtd_t)block << (this->bbt_erase_shift - 1));
continue;
}
update = 0;
@@ -931,7 +931,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
new ones have been marked, then we need to update the stored
bbts. This should only happen once. */
if (update && td->reserved_block_code)
- nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
+ nand_update_bbt(mtd, (loff_mtd_t)(block - 2) << (this->bbt_erase_shift - 1));
}
}
@@ -1015,7 +1015,7 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
*
* The function updates the bad block table(s)
*/
-int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
+int nand_update_bbt(struct mtd_info *mtd, loff_mtd_t offs)
{
struct nand_chip *this = mtd->priv;
int len, res = 0, writeops = 0;
@@ -1190,7 +1190,7 @@ int nand_default_bbt(struct mtd_info *mtd)
* @allowbbt: allow access to bad block table region
*
*/
-int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
+int nand_isbad_bbt(struct mtd_info *mtd, loff_mtd_t offs, int allowbbt)
{
struct nand_chip *this = mtd->priv;
int block;
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 69ee2c90eb0..f1738212d75 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -109,6 +109,10 @@ struct nand_flash_dev nand_flash_ids[] = {
{"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},
{"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
+ /* 32 Gigabit */
+ {"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS},
+
+
/*
* Renesas AND 1 Gigabit. Those chips do not support extended id and
* have a strange page/block layout ! The chosen minimum erasesize is
diff --git a/drivers/mtd/ubi/bdev.c b/drivers/mtd/ubi/bdev.c
new file mode 100644
index 00000000000..cde4e4d4029
--- /dev/null
+++ b/drivers/mtd/ubi/bdev.c
@@ -0,0 +1,432 @@
+/*
+ *
+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Interface to Linux 2.5 block layer for UBI 'translation layers'.
+ *
+ * 2008 Yurong Tan <nancydreaming@gmail.com>:
+ * borrow from mtd_blkdevs.c for building block device layer on top of UBI
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/freezer.h>
+#include <linux/spinlock.h>
+#include <linux/hdreg.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <asm/uaccess.h>
+#include "ubi.h"
+#include "ubiblk.h"
+
+static LIST_HEAD(blktrans_majors);
+extern struct mutex vol_table_mutex;
+extern struct ubi_volume *vol_table[];
+
+extern void register_vol_user (struct vol_notifier *new);
+extern int unregister_vol_user (struct vol_notifier *old);
+extern int ubi_major2num(int major);
+
+struct ubi_blkcore_priv {
+ struct task_struct *thread;
+ struct request_queue *rq;
+ spinlock_t queue_lock;
+};
+
+static int do_blktrans_request(struct ubi_blktrans_ops *tr,
+ struct ubi_blktrans_dev *dev,
+ struct request *req)
+{
+ unsigned long block, nsect;
+ char *buf;
+
+ block = req->sector << 9 >> tr->blkshift;
+ nsect = req->current_nr_sectors << 9 >> tr->blkshift;
+ buf = req->buffer;
+
+ if (!blk_fs_request(req))
+ return 0;
+
+ if (req->sector + req->current_nr_sectors > get_capacity(req->rq_disk))
+ return 0;
+
+ switch(rq_data_dir(req)) {
+ case READ:
+ for (; nsect > 0; nsect--, block++, buf += tr->blksize)
+ if (tr->readsect(dev, block, buf))
+ return 0;
+ return 1;
+
+ case WRITE:
+ if (!tr->writesect)
+ return 0;
+
+ for (; nsect > 0; nsect--, block++, buf += tr->blksize)
+ if (tr->writesect(dev, block, buf))
+ return 0;
+ return 1;
+
+ default:
+ printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req));
+ return 0;
+ }
+}
+
+static int ubi_blktrans_thread(void *arg)
+{
+ struct ubi_blktrans_ops *tr = arg;
+ struct request_queue *rq = tr->blkcore_priv->rq;
+
+ /* we might get involved when memory gets low, so use PF_MEMALLOC */
+ current->flags |= PF_MEMALLOC;
+
+ spin_lock_irq(rq->queue_lock);
+ while (!kthread_should_stop()) {
+ struct request *req;
+ struct ubi_blktrans_dev *dev;
+ int res = 0;
+
+ req = elv_next_request(rq);
+
+ if (!req) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irq(rq->queue_lock);
+ schedule();
+ spin_lock_irq(rq->queue_lock);
+ continue;
+ }
+ dev = req->rq_disk->private_data;
+ tr = dev->tr;
+
+ spin_unlock_irq(rq->queue_lock);
+ mutex_lock(&dev->lock);
+ res = do_blktrans_request(tr, dev, req);
+ mutex_unlock(&dev->lock);
+ spin_lock_irq(rq->queue_lock);
+
+ end_request(req, res);
+ }
+ spin_unlock_irq(rq->queue_lock);
+
+ return 0;
+}
+
+static void ubi_blktrans_request(struct request_queue *rq)
+{
+ struct ubi_blktrans_ops *tr = rq->queuedata;
+ wake_up_process(tr->blkcore_priv->thread);
+}
+
+static int blktrans_open(struct inode *i, struct file *f)
+{
+ struct ubi_blktrans_dev *dev;
+ struct ubi_blktrans_ops *tr;
+ int ret =0;
+
+ dev = i->i_bdev->bd_disk->private_data;
+ tr = dev->tr;
+
+ if (!try_module_get(tr->owner))
+ goto out_tr;
+
+ if(!tr->open)
+ return -1;
+ else
+ ret = tr->open(i,f);
+
+ return ret;
+out_tr:
+ module_put(tr->owner);
+ return -1;
+}
+
+static int blktrans_release(struct inode *i, struct file *f)
+{
+ struct ubi_blktrans_dev *dev;
+ struct ubi_blktrans_ops *tr;
+ struct ubi_volume_desc *desc;
+ int ret = 0;
+
+ dev = i->i_bdev->bd_disk->private_data;
+ tr = dev->tr;
+ desc = dev->uv;
+
+ if (tr->release)
+ ret = tr->release(dev);
+
+ module_put(tr->owner);
+ return ret;
+}
+
+static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+ struct ubi_blktrans_dev *dev = bdev->bd_disk->private_data;
+
+ if (dev->tr->getgeo)
+ return dev->tr->getgeo(dev, geo);
+ return -ENOTTY;
+}
+
+static int blktrans_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ubi_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data;
+ struct ubi_blktrans_ops *tr = dev->tr;
+
+ switch (cmd) {
+ case BLKFLSBUF:
+ if (tr->flush)
+ return tr->flush(dev);
+ /* The core code did the work, we had nothing to do. */
+ return 0;
+ default:
+ return -ENOTTY;
+ }
+}
+
+struct block_device_operations ubi_blktrans_ops = {
+ .owner = THIS_MODULE,
+ .open = blktrans_open,
+ .release = blktrans_release,
+ .ioctl = blktrans_ioctl,
+ .getgeo = blktrans_getgeo,
+};
+
+int add_ubi_blktrans_dev(struct ubi_blktrans_dev *new)
+{
+ struct ubi_blktrans_ops *tr = new->tr;
+ struct list_head *this;
+ int last_devnum = -1;
+ struct gendisk *gd;
+
+ if (mutex_trylock(&vol_table_mutex)) {
+ mutex_unlock(&vol_table_mutex);
+ BUG();
+ }
+
+ list_for_each(this, &tr->devs) {
+ struct ubi_blktrans_dev *d = list_entry(this, struct ubi_blktrans_dev, list);
+ if (new->devnum == -1) {
+ /* Use first free number */
+ if (d->devnum != last_devnum+1) {
+ /* Found a free devnum. Plug it in here */
+ new->devnum = last_devnum+1;
+ list_add_tail(&new->list, &d->list);
+ goto added;
+ }
+ } else if (d->devnum == new->devnum) {
+ /* Required number taken */
+ return -EBUSY;
+ } else if (d->devnum > new->devnum) {
+ /* Required number was free */
+ list_add_tail(&new->list, &d->list);
+ goto added;
+ }
+ last_devnum = d->devnum;
+ }
+ if (new->devnum == -1)
+ new->devnum = last_devnum+1;
+
+ if ((new->devnum << tr->part_bits) > 256) {
+ return -EBUSY;
+ }
+
+ mutex_init(&new->lock);
+ list_add_tail(&new->list, &tr->devs);
+ added:
+ if (!tr->writesect)
+ new->readonly = 1;
+
+ gd = alloc_disk(1 << tr->part_bits);
+ if (!gd) {
+ list_del(&new->list);
+ return -ENOMEM;
+ }
+ gd->major = tr->major;
+ gd->first_minor = (new->devnum) << tr->part_bits;
+ gd->fops = &ubi_blktrans_ops;
+
+ if (tr->part_bits)
+ if (new->devnum < 26)
+ snprintf(gd->disk_name, sizeof(gd->disk_name),
+ "%s%c", tr->name, 'a' + new->devnum);
+ else
+ snprintf(gd->disk_name, sizeof(gd->disk_name),
+ "%s%c%c", tr->name,
+ 'a' - 1 + new->devnum / 26,
+ 'a' + new->devnum % 26);
+ else
+ snprintf(gd->disk_name, sizeof(gd->disk_name),
+ "%s%d", tr->name, new->devnum);
+
+ /* 2.5 has capacity in units of 512 bytes while still
+ having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */
+ set_capacity(gd, (new->size * tr->blksize) >> 9);
+
+ gd->private_data = new;
+ new->blkcore_priv = gd;
+ gd->queue = tr->blkcore_priv->rq;
+
+ if (new->readonly)
+ set_disk_ro(gd, 1);
+
+ add_disk(gd);
+
+ return 0;
+}
+
+int del_ubi_blktrans_dev(struct ubi_blktrans_dev *old)
+{
+ if (mutex_trylock(&vol_table_mutex)) {
+ mutex_unlock(&vol_table_mutex);
+ BUG();
+ }
+
+ list_del(&old->list);
+
+ del_gendisk(old->blkcore_priv);
+ put_disk(old->blkcore_priv);
+
+ return 0;
+}
+
+static void blktrans_notify_remove(struct ubi_volume *vol)
+{
+ struct list_head *this, *this2, *next;
+
+ list_for_each(this, &blktrans_majors) {
+ struct ubi_blktrans_ops *tr = list_entry(this, struct ubi_blktrans_ops, list);
+
+ list_for_each_safe(this2, next, &tr->devs) {
+ struct ubi_blktrans_dev *dev = list_entry(this2, struct ubi_blktrans_dev, list);
+
+ if (dev->uv->vol == vol)
+ tr->remove_vol(dev);
+ }
+ }
+}
+
+static void blktrans_notify_add(struct ubi_volume *vol)
+{
+ struct list_head *this;
+
+ list_for_each(this, &blktrans_majors) {
+ struct ubi_blktrans_ops *tr = list_entry(this, struct ubi_blktrans_ops, list);
+
+ tr->add_vol(tr,vol);
+ }
+
+}
+
+static struct vol_notifier blktrans_notifier = {
+ .add = blktrans_notify_add,
+ .remove = blktrans_notify_remove,
+};
+
+
+int register_ubi_blktrans(struct ubi_blktrans_ops *tr)
+{
+ int i;
+
+ /* Register the notifier if/when the first device type is
+ registered, to prevent the link/init ordering from fucking
+ us over. */
+ if (!blktrans_notifier.list.next)
+ register_vol_user(&blktrans_notifier);
+
+ tr->blkcore_priv = kzalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
+ if (!tr->blkcore_priv)
+ return -ENOMEM;
+
+ mutex_lock(&vol_table_mutex);
+ tr->major = register_blkdev(0, tr->name);
+ spin_lock_init(&tr->blkcore_priv->queue_lock);
+
+ tr->blkcore_priv->rq = blk_init_queue(ubi_blktrans_request, &tr->blkcore_priv->queue_lock);
+ if (!tr->blkcore_priv->rq) {
+ unregister_blkdev(tr->major, tr->name);
+ kfree(tr->blkcore_priv);
+ mutex_unlock(&vol_table_mutex);
+ return -ENOMEM;
+ }
+
+ tr->blkcore_priv->rq->queuedata = tr;
+ blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize);
+ tr->blkshift = ffs(tr->blksize) - 1;
+
+ tr->blkcore_priv->thread = kthread_run(ubi_blktrans_thread, tr,
+ "%sd", tr->name);
+ if (IS_ERR(tr->blkcore_priv->thread)) {
+ blk_cleanup_queue(tr->blkcore_priv->rq);
+ unregister_blkdev(tr->major, tr->name);
+ kfree(tr->blkcore_priv);
+ mutex_unlock(&vol_table_mutex);
+ return PTR_ERR(tr->blkcore_priv->thread);
+ }
+
+ INIT_LIST_HEAD(&tr->devs);
+ list_add(&tr->list, &blktrans_majors);
+
+ for (i=0; i<UBI_MAX_VOLUMES; i++) {
+ if (vol_table[i] )
+ tr->add_vol(tr, vol_table[i]);
+ }
+
+ mutex_unlock(&vol_table_mutex);
+ return 0;
+}
+
+int deregister_ubi_blktrans(struct ubi_blktrans_ops *tr)
+{
+ struct list_head *this, *next;
+
+ mutex_lock(&vol_table_mutex);
+
+ /* Clean up the kernel thread */
+ kthread_stop(tr->blkcore_priv->thread);
+
+ /* Remove it from the list of active majors */
+ list_del(&tr->list);
+
+ list_for_each_safe(this, next, &tr->devs) {
+ struct ubi_blktrans_dev *dev = list_entry(this, struct ubi_blktrans_dev, list);
+ tr->remove_vol(dev);
+ }
+
+ blk_cleanup_queue(tr->blkcore_priv->rq);
+ unregister_blkdev(tr->major, tr->name);
+
+ mutex_unlock(&vol_table_mutex);
+
+ kfree(tr->blkcore_priv);
+
+ BUG_ON(!list_empty(&tr->devs));
+ return 0;
+}
+
+static void __exit ubi_blktrans_exit(void)
+{
+ /* No race here -- if someone's currently in register_ubi_blktrans
+ we're screwed anyway. */
+ if (blktrans_notifier.list.next)
+ unregister_vol_user(&blktrans_notifier);
+}
+
+
+module_exit(ubi_blktrans_exit);
+
+EXPORT_SYMBOL_GPL(register_ubi_blktrans);
+EXPORT_SYMBOL_GPL(deregister_ubi_blktrans);
+EXPORT_SYMBOL_GPL(add_ubi_blktrans_dev);
+EXPORT_SYMBOL_GPL(del_ubi_blktrans_dev);
+
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Yurong Tan <nancydreaming@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Common interface to block layer for UBI 'translation layers'");
+
diff --git a/drivers/mtd/ubi/ubiblk.c b/drivers/mtd/ubi/ubiblk.c
new file mode 100644
index 00000000000..c9df0f0ae28
--- /dev/null
+++ b/drivers/mtd/ubi/ubiblk.c
@@ -0,0 +1,359 @@
+/*
+ * Direct UBI block device access
+ *
+ * (C) 2000-2003 Nicolas Pitre <nico@cam.org>
+ * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
+ * (C) 2008 Yurong Tan <nancydreaming@gmail.com> :
+ * borrow mtdblock.c to work on top of UBI
+ */
+
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/freezer.h>
+#include <asm/uaccess.h>
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/hdreg.h>
+#include <linux/mutex.h>
+#include "ubi.h"
+#include "ubiblk.h"
+
+#define UBIBLK_UNMAPPED 0
+#define UBIBLK_SECTOR_SIZE 512
+
+extern void ubi_open_blkdev(int ubi_num, int vol_id, int mode);
+extern void ubi_close_blkdev(struct ubi_volume_desc *desc);
+static void ubiblk_setup_writecache(struct ubiblk_dev *ubiblk, int virt_block);
+static int ubiblk_flush_writecache(struct ubiblk_dev *ubiblk);
+extern int ubiblk_leb_change(struct ubiblk_dev *ubiblk);
+
+struct ubiblk_dev *ubiblks[UBI_MAX_VOLUMES];
+static unsigned short subpage_shift;
+
+static int ubiblk_flush_writecache(struct ubiblk_dev *ubiblk)
+{
+ if (STATE_UNUSED == ubiblk->write_cache_state)
+ return 0;
+ ubiblk_leb_change(ubiblk);
+ ubiblk->write_cache_state = STATE_UNUSED;
+
+ return 0;
+}
+
+static void ubiblk_setup_writecache(struct ubiblk_dev *ubiblk, int virt_block)
+{
+ struct ubi_volume_desc *uv = ubiblk->uv;
+ struct ubi_device *ubi = uv->vol->ubi;
+ int ppb = ubi->leb_size / ubi->min_io_size;
+ unsigned short spp = ubi->min_io_size >> subpage_shift;
+
+ ubiblk->vbw = virt_block;
+ ubiblk->write_cache_state = STATE_USED;
+
+ memset(ubiblk->page_sts, 0, ppb);
+ memset(ubiblk->subpage_sts, 0, ppb*spp);
+}
+
+static int do_cached_write (struct ubiblk_dev *ubiblk, unsigned long sector,
+ int len, const char *buf)
+{
+ struct ubi_volume_desc *uv = ubiblk->uv;
+ struct ubi_device *ubi = uv->vol->ubi;
+ int ppb = ubi->leb_size / ubi->min_io_size;
+ unsigned short sectors_per_page = ubi->min_io_size / len;
+ unsigned short sectors_in_page_shift = ffs(sectors_per_page) - 1;
+ unsigned short page_shift = ffs(ubi->min_io_size) - 1;
+ unsigned short virt_block, page, subpage;
+ unsigned long virt_page;
+
+ virt_page = sector / sectors_per_page;
+ subpage = sector % sectors_per_page;
+ virt_block = virt_page / ppb;
+ page = virt_page % ppb;
+
+ if(ubi_is_mapped(uv, virt_block) == UBIBLK_UNMAPPED ){
+ mutex_lock(&ubiblk->cache_mutex);
+ ubiblk_flush_writecache(ubiblk);
+ mutex_unlock(&ubiblk->cache_mutex);
+
+ ubiblk_setup_writecache(ubiblk, virt_block);
+ } else {
+ if ( STATE_USED == ubiblk->write_cache_state ) {
+ if ( ubiblk->vbw != virt_block) {
+ // Commit before we start a new cache.
+ mutex_lock(&ubiblk->cache_mutex);
+ ubiblk_flush_writecache(ubiblk);
+ mutex_unlock(&ubiblk->cache_mutex);
+
+ ubiblk_setup_writecache(ubiblk, virt_block);
+ } else {
+ //printk("cache hit: 0x%x\n", virt_page);
+ }
+ } else {
+// printk("with existing mapping\n");
+ ubiblk_setup_writecache(ubiblk, virt_block);
+ }
+ }
+ ubiblk->page_sts[page] = 1;
+ ubiblk->subpage_sts[(page<<sectors_in_page_shift) + subpage] = 1;
+ memcpy(&ubiblk->write_cache[(page<<page_shift) +(subpage<<subpage_shift)],
+ buf,len);
+ return 0;
+}
+
+static int do_cached_read (struct ubiblk_dev *ubiblk, unsigned long sector,
+ int len, char *buf)
+{
+ struct ubi_volume_desc *uv = ubiblk->uv;
+ int ppb = uv->vol->ubi->leb_size / uv->vol->ubi->min_io_size;
+ unsigned short sectors_per_page = uv->vol->ubi->min_io_size >> 9;
+ unsigned short page_shift = ffs(uv->vol->ubi->min_io_size) - 1;
+ unsigned short virt_block, page, page_offset;
+ unsigned long virt_page;
+
+ virt_page = sector / sectors_per_page;
+ page_offset = sector % sectors_per_page;
+ virt_block = virt_page / ppb;
+ page = virt_page % ppb;
+
+ if(ubiblk->vbw == virt_block){
+ mutex_lock(&ubiblk->cache_mutex);
+ ubiblk_flush_writecache(ubiblk);
+ mutex_unlock(&ubiblk->cache_mutex);
+ }
+
+ if ( ubi_is_mapped( uv, virt_block) == UBIBLK_UNMAPPED){
+ /* In a Flash Memory device, there might be a logical block that is
+ * not allcated to a physical block due to the block not being used.
+ * All data returned should be set to 0xFF when accessing this logical
+ * block.
+ */
+
+ //printk("address translate fail\n");
+ memset(buf, 0xFF, UBIBLK_SECTOR_SIZE);
+ } else {
+
+ if( ubiblk->vbr != virt_block ||ubiblk->read_cache_state == STATE_UNUSED ){
+ ubiblk->vbr = virt_block;
+ ubi_leb_read(uv, virt_block, ubiblk->read_cache, 0, uv->vol->usable_leb_size, 0);
+ ubiblk->read_cache_state = STATE_USED;
+ }
+ memcpy(buf, &ubiblk->read_cache[(page<<page_shift)+(page_offset<<9)], len);
+ }
+ return 0;
+}
+
+static int ubiblk_readsect(struct ubi_blktrans_dev *dev,
+ unsigned long block, char *buf)
+{
+ struct ubiblk_dev *ubiblk = ubiblks[dev->devnum];
+ return do_cached_read(ubiblk, block, UBIBLK_SECTOR_SIZE, buf);
+}
+
+static int ubiblk_writesect(struct ubi_blktrans_dev *dev,
+ unsigned long block, char *buf)
+{
+ struct ubiblk_dev *ubiblk = ubiblks[dev->devnum];
+ return do_cached_write(ubiblk, block, UBIBLK_SECTOR_SIZE, buf);
+}
+
+static int ubiblk_init_vol(int dev, struct ubi_volume_desc *uv)
+{
+ struct ubiblk_dev *ubiblk;
+ struct ubi_device *ubi = uv->vol->ubi;
+ int ppb = ubi->leb_size / ubi->min_io_size;
+ unsigned short spp = ubi->min_io_size >> subpage_shift;
+
+ ubiblk = kmalloc(sizeof(struct ubiblk_dev), GFP_KERNEL);
+ if (!ubiblk)
+ return -ENOMEM;
+
+ memset(ubiblk, 0, sizeof(*ubiblk));
+
+ ubiblk->count = 1;
+ ubiblk->uv = uv;
+ mutex_init (&ubiblk->cache_mutex);
+
+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF)
+ ubiblk->write_cache = kmalloc(ubiblk->uv->vol->usable_leb_size, GFP_KERNEL);
+ ubiblk->read_cache = kmalloc(ubiblk->uv->vol->usable_leb_size, GFP_KERNEL);
+ ubiblk->page_sts = kmalloc(ppb, GFP_KERNEL);
+ ubiblk->subpage_sts = kmalloc(ppb*spp, GFP_KERNEL);
+#else
+ ubiblk->write_cache = vmalloc(ubiblk->uv->vol->usable_leb_size);
+ ubiblk->read_cache = vmalloc(ubiblk->uv->vol->usable_leb_size);
+ ubiblk->page_sts = vmalloc(ppb);
+ ubiblk->subpage_sts = vmalloc(ppb*spp);
+#endif
+
+ if(!ubiblk->write_cache ||
+ !ubiblk->read_cache ||
+ !ubiblk->page_sts ||
+ !ubiblk->subpage_sts)
+ return -ENOMEM;
+
+ ubiblk->write_cache_state = STATE_UNUSED;
+ ubiblk->read_cache_state = STATE_UNUSED;
+
+ ubiblks[dev] = ubiblk;
+ DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
+ return 0;
+}
+
+static int ubiblk_open(struct inode *i, struct file *f )
+{
+ struct ubi_volume_desc *desc;
+ struct ubi_blktrans_dev *dev;
+ int ubi_num = ubi_major2num(imajor(i));
+ int vol_id = iminor(i);
+ int mode;
+ int ret = 0;
+
+ if (f->f_mode & FMODE_WRITE)
+ mode = UBI_READWRITE;
+ else
+ mode = UBI_READONLY;
+
+ dev = i->i_bdev->bd_disk->private_data;
+ if (ubiblks[dev->devnum]) {
+ ubiblks[dev->devnum]->count++;
+ ubi_open_blkdev(ubi_num, vol_id, mode);
+ printk("%s: increase use count\n",__FUNCTION__);
+ return 0;
+ }
+
+ desc = ubi_open_volume(ubi_num, vol_id, mode);
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+
+ desc->vol->bdev_mode = mode;
+ dev->uv = desc;
+
+ subpage_shift = ffs(UBIBLK_SECTOR_SIZE)-1;
+ ret = ubiblk_init_vol(dev->devnum, desc);
+ return ret;
+}
+
+static int ubiblk_release(struct ubi_blktrans_dev *ubd)
+{
+ int dev = ubd->devnum;
+ struct ubiblk_dev *ubiblk = ubiblks[dev];
+ struct ubi_device *ubi = ubiblk->uv->vol->ubi;
+
+ mutex_lock(&ubiblk->cache_mutex);
+ ubiblk_flush_writecache(ubiblk);
+ mutex_unlock(&ubiblk->cache_mutex);
+
+ ubiblk->count --;
+ if (!ubiblk->count) {
+ /* It was the last usage. Free the device */
+ ubiblks[dev] = NULL;
+
+ if (ubi->mtd->sync)
+ ubi->mtd->sync(ubi->mtd);
+
+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF)
+ kfree(ubiblk->write_cache);
+ kfree(ubiblk->read_cache);
+#else
+ vfree(ubiblk->write_cache);
+ vfree(ubiblk->read_cache);
+#endif
+ kfree(ubiblk);
+
+ ubi_close_volume(ubiblk->uv);
+ return 0;
+ }
+ else{
+ printk("%s: decrease use count\n",__FUNCTION__);
+ ubi_close_blkdev(ubiblk->uv);
+ return 0;
+ }
+ return 1;
+}
+static int ubiblk_flush(struct ubi_blktrans_dev *dev)
+{
+ struct ubiblk_dev *ubiblk = ubiblks[dev->devnum];
+ struct ubi_device *ubi = ubiblk->uv->vol->ubi;
+
+ mutex_lock(&ubiblk->cache_mutex);
+ ubiblk_flush_writecache(ubiblk);
+ mutex_unlock(&ubiblk->cache_mutex);
+
+ if (ubi->mtd->sync)
+ ubi->mtd->sync(ubi->mtd);
+ return 0;
+}
+
+void ubiblk_add_vol_dev(struct ubi_blktrans_ops *tr, struct ubi_volume *vol)
+{
+ struct ubi_blktrans_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return;
+
+ dev->devnum = vol->vol_id;
+ dev->size = vol->used_bytes >> 9;
+ dev->tr = tr;
+
+ if (vol->bdev_mode == UBI_READONLY)
+ dev->readonly = 1;
+
+ vol->ubi->bdev_major = tr->major;
+
+ add_ubi_blktrans_dev(dev);
+}
+
+void ubiblk_remove_vol_dev(struct ubi_blktrans_dev *dev)
+{
+ del_ubi_blktrans_dev(dev);
+ kfree(dev);
+}
+
+static int ubiblk_getgeo(struct ubi_blktrans_dev *dev, struct hd_geometry *geo)
+{
+ memset(geo, 0, sizeof(*geo));
+ geo->heads = 4;
+ geo->sectors = 16;
+ geo->cylinders = dev->size/(4*16);
+ return 0;
+}
+
+static struct ubi_blktrans_ops ubiblk_tr = {
+ .name = "ubiblock",
+ .major = 0,
+ .part_bits = 0,
+ .blksize = UBIBLK_SECTOR_SIZE,
+ .open = ubiblk_open,
+ .release = ubiblk_release,
+ .readsect = ubiblk_readsect,
+ .writesect = ubiblk_writesect,
+ .getgeo = ubiblk_getgeo,
+ .flush = ubiblk_flush,
+ .add_vol = ubiblk_add_vol_dev,
+ .remove_vol = ubiblk_remove_vol_dev,
+ .owner = THIS_MODULE,
+};
+
+static int __init init_ubiblock(void)
+{
+ return register_ubi_blktrans(&ubiblk_tr);
+}
+
+static void __exit cleanup_ubiblock(void)
+{
+ deregister_ubi_blktrans(&ubiblk_tr);
+}
+
+module_init(init_ubiblock);
+module_exit(cleanup_ubiblock);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nicolas Pitre <nico@cam.org> , Yurong Tan <nancydreaming@gmail.com>");
+MODULE_DESCRIPTION("Caching read/erase/writeback block device emulation access to UBI volumes");
diff --git a/drivers/mtd/ubi/ubiblk.h b/drivers/mtd/ubi/ubiblk.h
new file mode 100644
index 00000000000..5bf4f99a15b
--- /dev/null
+++ b/drivers/mtd/ubi/ubiblk.h
@@ -0,0 +1,85 @@
+/*
+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
+ * (C) 2008 Yurong Tan <nancydreaming@gmail.com> : borrow from MTD blktrans.h for UBI used
+ * Interface to Linux block layer for UBI 'translation layers'.
+ */
+
+#ifndef __UBI_TRANS_H__
+#define __UBI_TRANS_H__
+
+#include <linux/mutex.h>
+#include <linux/fs.h>
+#include "ubi.h"
+
+struct hd_geometry;
+struct ubi_volume_desc;
+struct ubi_blktrans_ops;
+struct file;
+struct inode;
+
+struct ubiblk_dev {
+ struct ubi_volume_desc *uv;
+ int count;
+ struct mutex cache_mutex;
+ unsigned short vbw; //virt block number of write cache
+ unsigned short vbr; //virt block number of read cache
+
+ unsigned char *write_cache;
+ unsigned char *page_sts;
+ unsigned char *subpage_sts;
+
+ unsigned char *read_cache;
+ enum { STATE_UNUSED, STATE_USED } read_cache_state, write_cache_state;
+};
+
+struct ubi_blktrans_dev {
+ struct ubi_blktrans_ops *tr;
+ struct list_head list;
+ struct ubi_volume_desc *uv;
+ struct mutex lock;
+ int devnum;
+ unsigned long size;
+ int readonly;
+ void *blkcore_priv; /* gendisk in 2.5, devfs_handle in 2.4 */
+};
+
+struct blkcore_priv; /* Differs for 2.4 and 2.5 kernels; private */
+
+struct ubi_blktrans_ops {
+ char *name;
+ int major;
+ int part_bits;
+ int blksize;
+ int blkshift;
+
+ /* Access functions */
+ int (*readsect)(struct ubi_blktrans_dev *dev,
+ unsigned long block, char *buffer);
+ int (*writesect)(struct ubi_blktrans_dev *dev,
+ unsigned long block, char *buffer);
+
+ /* Block layer ioctls */
+ int (*getgeo)(struct ubi_blktrans_dev *dev, struct hd_geometry *geo);
+ int (*flush)(struct ubi_blktrans_dev *dev);
+
+ /* Called with mtd_table_mutex held; no race with add/remove */
+ int (*open)(struct inode *i, struct file *f);
+ int (*release)(struct ubi_blktrans_dev *dev);
+
+ /* Called on {de,}registration and on subsequent addition/removal
+ of devices, with mtd_table_mutex held. */
+ void (*add_vol)(struct ubi_blktrans_ops *tr, struct ubi_volume *vol);
+ void (*remove_vol)(struct ubi_blktrans_dev *dev);
+
+ struct list_head devs;
+ struct list_head list;
+ struct module *owner;
+
+ struct ubi_blkcore_priv *blkcore_priv;
+};
+
+extern int add_ubi_blktrans_dev(struct ubi_blktrans_dev *new);
+extern int del_ubi_blktrans_dev(struct ubi_blktrans_dev *old);
+extern int register_ubi_blktrans(struct ubi_blktrans_ops *tr);
+extern int deregister_ubi_blktrans(struct ubi_blktrans_ops *tr);
+#endif /* __UBI_TRANS_H__ */
diff --git a/drivers/mtd/udc_cache.c b/drivers/mtd/udc_cache.c
new file mode 100644
index 00000000000..d83c0f1dc2a
--- /dev/null
+++ b/drivers/mtd/udc_cache.c
@@ -0,0 +1,531 @@
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/hdreg.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/blktrans.h>
+#include <linux/mutex.h>
+#include <asm/jzsoc.h>
+
+#define CACHE_MAX_NUM 256
+#define SECTOR_SIZE 512
+
+//#define UDC_CACHE_DEBUG
+
+#ifdef UDC_CACHE_DEBUG
+#define dprintk(a...) printk(a)
+#else
+#define dprintk(a...) while(0){}
+#endif
+
+typedef struct {
+ unsigned short CacheState;
+ unsigned short UseCount;
+ unsigned short CacheChange;
+ unsigned short CacheReserve;
+ unsigned int BlockId;
+ unsigned char *aBlockData;
+} SSFDC__LB_CACHE;
+
+#define FREE_CACHE 0
+#define PREWRITE_CACHE 2
+#define OFTEN_USE_CACHE 3
+#define SECTOR_SHIFT 9
+
+#define CACHE_TO_UNCATCH(x) ((unsigned int)x | 0xa0000000)
+static unsigned int __aBlockData[SECTOR_SIZE * CACHE_MAX_NUM / 4] __attribute__ ((aligned (32)));
+static SSFDC__LB_CACHE ssfdc_cache[CACHE_MAX_NUM];
+static unsigned short Cur_CacheCount = 0;
+int FlushDataState = 0;
+static struct mtdblk_dev *g_udc_mtdblk;
+static struct mtd_info *g_udc_mtd;
+
+extern int udc_mtdblock_readsect(struct mtdblk_dev *, unsigned long, char *, int);
+extern int udc_mtdblock_writesect(struct mtdblk_dev *, unsigned long, char *);
+extern struct mtdblk_dev *udc_get_mtdblk(void);
+extern struct mtd_info *udc_get_mtd(void);
+extern void udc_flush_cache(struct mtdblk_dev *mtdblk);
+
+#define _NAND_LB_Write(pCache) udc_mtdblock_writesect(g_udc_mtdblk, pCache->BlockId,pCache->aBlockData)
+#define _NAND_LB_Read(Sector,pBuffer) udc_mtdblock_readsect(g_udc_mtdblk, Sector, pBuffer, SECTOR_SIZE);
+
+#define DMA_ENABLE 0
+
+#if DMA_ENABLE
+#define DMA_CHANNEL 5
+#define PHYSADDR(x) virt_to_phys((void *)x)
+#else
+#define lb_memcpy memcpy
+#endif
+
+#if DMA_ENABLE
+static void lb_memcpy(void *target,void* source,unsigned int len)
+{
+ int ch = DMA_CHANNEL;
+ if(((unsigned int)source < 0xa0000000) && len)
+ dma_cache_wback_inv((unsigned long)source, len);
+ if(((unsigned int)target < 0xa0000000) && len)
+ dma_cache_wback_inv((unsigned long)target, len);
+
+ REG_DMAC_DSAR(ch) = PHYSADDR((unsigned long)source);
+ REG_DMAC_DTAR(ch) = PHYSADDR((unsigned long)target);
+ REG_DMAC_DTCR(ch) = len / 32;
+ REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_AUTO;
+ REG_DMAC_DCMD(ch) = DMAC_DCMD_SAI| DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32|DMAC_DCMD_DS_32BYTE;
+ REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES;
+ while ( REG_DMAC_DTCR(ch) );
+}
+#endif
+
+static void _NAND_LB_InitCache(void)
+{
+ int i;
+ SSFDC__LB_CACHE *pCache = ssfdc_cache;
+#if DMA_ENABLE
+ unsigned char * ptr = (unsigned char *)CACHE_TO_UNCATCH(__aBlockData);
+#else
+ unsigned char * ptr = (unsigned char *)(__aBlockData);
+#endif
+ for(i = 0;i < CACHE_MAX_NUM;i++)
+ {
+ pCache->CacheState = FREE_CACHE;
+ pCache->UseCount = 0;
+ pCache->CacheChange = 0;
+ pCache->aBlockData = ptr;
+ ptr+=SECTOR_SIZE;
+ pCache++;
+ }
+ Cur_CacheCount = 0;
+}
+
+static SSFDC__LB_CACHE * _NAND_LB_GetFreeCache(void)
+{
+ int ret = 0;
+ SSFDC__LB_CACHE *pCacheInfo = &ssfdc_cache[Cur_CacheCount];
+ while(1)
+ {
+ if(ret >= CACHE_MAX_NUM)
+ return 0;
+ if(pCacheInfo >= &ssfdc_cache[CACHE_MAX_NUM])
+ {
+ pCacheInfo = ssfdc_cache;
+ Cur_CacheCount = 0;
+ }
+
+ if(pCacheInfo->CacheState == FREE_CACHE)
+ {
+ return pCacheInfo;
+ }
+ pCacheInfo++;
+ Cur_CacheCount++;
+ ret++;
+ }
+ return 0;
+}
+
+static void _NAND_LB_CloseCACHES(unsigned int sectorstart,unsigned int sectorend)
+{
+ unsigned int i;
+ SSFDC__LB_CACHE *pCache = ssfdc_cache;
+ for( i = 0;i < CACHE_MAX_NUM;i++){
+ if((pCache->CacheState != FREE_CACHE) && (pCache->BlockId >= sectorstart) && (pCache->BlockId < sectorend)){
+ pCache->CacheChange = 0;
+ pCache->CacheState = FREE_CACHE;
+ pCache->UseCount = 0;
+ }
+ pCache++;
+ }
+}
+
+static void _NAND_LB_FLUSHCACHES(unsigned int sectorstart,unsigned int sectorend)
+{
+ unsigned int i;
+ SSFDC__LB_CACHE *pCache = ssfdc_cache;
+ for( i = 0;i < CACHE_MAX_NUM;i++){
+ if((pCache->CacheState != FREE_CACHE) && (pCache->BlockId >= sectorstart) && (pCache->BlockId < sectorend)){
+ if(pCache->CacheChange)
+ _NAND_LB_Write(pCache);
+ pCache->CacheChange = 0;
+ pCache->CacheState = FREE_CACHE;
+ pCache->UseCount = 0;
+ }
+ pCache++;
+
+ }
+}
+
+inline static int Get_NAND_CacheFreeCount(void)
+{
+ SSFDC__LB_CACHE *pCache = ssfdc_cache;
+ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM];
+ unsigned int count = 0;
+ while(pCache < pEndCache)
+ {
+ if(pCache->CacheState == FREE_CACHE)
+ count++;
+ pCache++;
+ }
+ return count;
+
+}
+
+static unsigned int _NAND_LB_PreWiteToNand(SSFDC__LB_CACHE *pCache,unsigned short *count,unsigned int update)
+{
+ SSFDC__LB_CACHE *pWriteCache;
+ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM];
+ unsigned int sector = -1;
+ unsigned int flag;
+ while(1)
+ {
+ sector = -1;
+ flag = 0;
+ pWriteCache = ssfdc_cache;
+ while(pWriteCache < pEndCache)
+ {
+ if(pWriteCache->CacheState == update) //PREWRITE_CACHE
+ {
+ if(pWriteCache->BlockId < sector)
+ {
+ sector = pWriteCache->BlockId;
+ pCache = pWriteCache;
+ }
+ }else
+ flag++;
+ pWriteCache++;
+ }
+
+ if(flag < CACHE_MAX_NUM)
+ {
+ if(pCache->CacheChange)
+ {
+ _NAND_LB_Write(pCache);
+ pCache->CacheChange = 0;
+ }
+ pCache->CacheState = FREE_CACHE;
+ pCache->UseCount = 0;
+ (*count)++;
+ }else
+ break;
+ }
+ return 0;
+}
+
+static void _NAND_LB_OftenToNand(SSFDC__LB_CACHE *pCache,unsigned short *count,unsigned int update)
+{
+ SSFDC__LB_CACHE *pWriteCache = pCache;
+ SSFDC__LB_CACHE *pOldCache = pCache;
+ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM];
+
+ dprintk("%s!\n",__FUNCTION__);
+ while(pCache)
+ {
+ if(pCache->CacheState == OFTEN_USE_CACHE)
+ {
+ if(pWriteCache->CacheState != OFTEN_USE_CACHE)
+ pWriteCache = pCache;
+ else if(pWriteCache->UseCount > pCache->UseCount)
+ {
+ pWriteCache = pCache;
+ }
+ }
+ pCache++;
+ if(pCache >= pEndCache)
+ break;
+ }
+ if(pWriteCache->CacheState == OFTEN_USE_CACHE)
+ {
+ (*count)++;
+ if(pWriteCache->CacheChange)
+ _NAND_LB_Write(pWriteCache);
+ pWriteCache->CacheState = FREE_CACHE;
+
+ pWriteCache->UseCount = 0;
+ pWriteCache->CacheChange = 0;
+ if(update != -1)
+ update--;
+ if(update != 0)
+ _NAND_LB_OftenToNand(pOldCache,count,update);
+ }
+}
+
+static int _NAND_LB_FreeCache(unsigned int update)
+{
+ unsigned short freecount = 0,totalfree = 0;
+
+ freecount = 0;
+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,PREWRITE_CACHE);
+
+ totalfree += freecount;
+ dprintk("free count = %d\n",freecount);
+ if(freecount == 0)
+ {
+ freecount = 0;
+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE);
+ totalfree += freecount;
+ update = 0;
+ }
+ if(update)
+ {
+ if(Get_NAND_CacheFreeCount() < CACHE_MAX_NUM * 1 / 4) // because fat is 4 sector
+ {
+ freecount = 0;
+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE);
+ totalfree += freecount;
+ }
+ }
+
+ dprintk("Free = %d\r\n",totalfree);
+ return totalfree;
+}
+
+static int _NAND_LB_GetFromCache(unsigned int Sector, void *pBuffer) {
+
+ SSFDC__LB_CACHE *pCache = &ssfdc_cache[Cur_CacheCount];
+ SSFDC__LB_CACHE *pUseCache = 0;
+ unsigned short i;
+ dprintk("sector = %x pBuffer = %x\n",Sector,pBuffer);
+ if(pCache >= &ssfdc_cache[CACHE_MAX_NUM])
+ pCache = ssfdc_cache;
+
+ i = 0;
+ while (1) {
+ if(pCache->CacheState != FREE_CACHE)
+ {
+ if (Sector == pCache->BlockId) {
+ dprintk("Cache is use = %d\r\n",pCache->BlockId);
+ pUseCache = pCache;
+ pCache->UseCount++;
+ if(pCache->UseCount == 0)
+ pCache->UseCount = -1;
+ pCache->CacheState = OFTEN_USE_CACHE;
+ }
+ }
+ pCache--;
+ if(pCache < ssfdc_cache)
+ pCache = &ssfdc_cache[CACHE_MAX_NUM - 1];
+
+ i++;
+ if (i >= CACHE_MAX_NUM) {
+ break; /* Sector not in cache */
+ }
+ }
+ if (pUseCache) {
+ dprintk("From Cache %d\r\n",Sector);
+ lb_memcpy(pBuffer, pUseCache->aBlockData, SECTOR_SIZE);
+ return 0;
+ }
+ return -1;
+}
+
+static void _NAND_LB_ClearCache(void) {
+
+ unsigned short freecount = 0;
+ dprintk("Clear Cache\r\n");
+
+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,PREWRITE_CACHE);
+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE);
+}
+
+static void _NAND_LB_CopyToCache(unsigned int Sector, void *pBuffer,unsigned short rw)
+{
+ SSFDC__LB_CACHE *pCache = _NAND_LB_GetFreeCache();
+ dprintk("Copy to Cache = 0x%08x 0x%08x\r\n",pCache,ssfdc_cache);
+
+ if(!pCache)
+ {
+ _NAND_LB_FreeCache(rw);
+
+ pCache = _NAND_LB_GetFreeCache();
+ }
+ pCache->BlockId = Sector;
+ pCache->CacheState = PREWRITE_CACHE;
+ pCache->UseCount = 0;
+ pCache->CacheChange = rw;
+
+ lb_memcpy(pCache->aBlockData,pBuffer,SECTOR_SIZE);
+}
+
+
+static int _NAND_LB_UpdateInCache(unsigned int Sector, void *pBuffer) {
+ short i,ret = 0;
+ i = Cur_CacheCount;
+ if(Cur_CacheCount > CACHE_MAX_NUM)
+ i = 0;
+ while(1)
+ {
+ if(ret >= CACHE_MAX_NUM)
+ return -1;
+ if(ssfdc_cache[i].CacheState != FREE_CACHE)
+ {
+
+ if(ssfdc_cache[i].BlockId == Sector)
+ {
+ dprintk("UpdateInCache = %d\r\n",Sector);
+ ssfdc_cache[i].CacheState = OFTEN_USE_CACHE;
+ ssfdc_cache[i].UseCount++;
+ ssfdc_cache[i].CacheChange = 1;
+ lb_memcpy(ssfdc_cache[i].aBlockData,pBuffer,SECTOR_SIZE);
+ return 0;
+ }
+ }
+ i--;
+ if(i < 0)
+ i = CACHE_MAX_NUM - 1;
+ ret++;
+ }
+ return -1;
+}
+
+static int NAND_LB_MultiRead(unsigned int Sector, void *pBuffer,unsigned int SectorCount)
+{
+ int i,ret,end;
+ void *p;
+
+ dprintk("NAND_LB_MultiRead = %d %d \n",Sector,SectorCount);
+ end = Sector + SectorCount;
+ _NAND_LB_FLUSHCACHES(Sector,end);
+
+ p = pBuffer;
+ for (i = Sector; i < end; i ++)
+ {
+ ret = udc_mtdblock_readsect(g_udc_mtdblk, i, p, SECTOR_SIZE);
+ p += SECTOR_SIZE;
+ }
+ return ret;
+}
+
+static int NAND_LB_Read(unsigned int Sector, void *pBuffer)
+{
+ int x;
+#if DMA_ENABLE
+ unsigned char *ptr = (unsigned char *)CACHE_TO_UNCATCH(pBuffer);
+ dma_cache_wback_inv(pBuffer,SECTOR_SIZE);
+#else
+ unsigned char *ptr = (unsigned char *)pBuffer;
+#endif
+ dprintk("LB_Read = %d \n",Sector);
+ if(_NAND_LB_GetFromCache(Sector,ptr))
+ {
+ x = _NAND_LB_Read(Sector,ptr);
+ _NAND_LB_CopyToCache(Sector,ptr,0);
+ }
+ return 512;
+}
+
+static int NAND_LB_MultiWrite(unsigned int Sector, void *pBuffer,unsigned int SectorCount)
+{
+ int i,ret;
+ unsigned char *p;
+
+ _NAND_LB_CloseCACHES(Sector,Sector + SectorCount);
+ p = (unsigned char *)pBuffer;
+ for (i = Sector; i < Sector + SectorCount; i ++)
+ {
+ ret = udc_mtdblock_writesect(g_udc_mtdblk, i, p);
+ p += 512;
+ }
+ return ret;
+}
+
+static int NAND_LB_Write(unsigned int Sector, void *pBuffer)
+{
+#if DMA_ENABLE
+ unsigned char *ptr = (unsigned char *)CACHE_TO_UNCATCH(pBuffer);
+ dma_cache_wback_inv(pBuffer,SECTOR_SIZE);
+#else
+ unsigned char *ptr = (unsigned char *)pBuffer;
+#endif
+ dprintk("LB_Write = %x %x\r\n",Sector,pBuffer);
+ if(_NAND_LB_UpdateInCache(Sector,ptr))
+ {
+ _NAND_LB_CopyToCache(Sector,ptr,1);
+ }
+ return 512;
+}
+/*********************************************************************
+*
+* Global functions
+*
+***********************************************************************/
+
+int NAND_LB_Init(void)
+{
+ dprintk("UDC CACHE Init \n");
+ _NAND_LB_InitCache();
+ g_udc_mtdblk = udc_get_mtdblk();
+ g_udc_mtd = udc_get_mtd();
+ return 0;
+}
+
+int NAND_LB_FLASHCACHE(void)
+{
+ dprintk("Flush lb cache !\n");
+ _NAND_LB_ClearCache();
+// dprintk("Flush mtd cache !\n");
+// udc_flush_cache(g_udc_mtdblk);
+ return 0;
+}
+
+int NAND_MTD_FLASHCACHE(void)
+{
+ dprintk("Flush mtd cache !\n");
+ udc_flush_cache(g_udc_mtdblk);
+ return 0;
+}
+
+int udc_read(unsigned long long offset, unsigned int len, unsigned char *buf)
+{
+ unsigned long block,sector,i;
+
+ block = offset >> SECTOR_SHIFT;
+ sector = len >> SECTOR_SHIFT;
+ dprintk("read dev = ia:%x, s:%d c:%d\r\n",buf,block,sector);
+
+ if (sector <= 8)
+ {
+ for(i = 0;i < sector; i++)
+ {
+ NAND_LB_Read(block + i,(void *)(buf));
+ buf += 512;
+ }
+ }
+ else
+ NAND_LB_MultiRead(block, buf, sector);
+
+ return len;
+}
+
+int udc_write(unsigned long long offset, unsigned int len, unsigned char *buf)
+{
+ unsigned long block,sector,i;
+
+ block = offset >> SECTOR_SHIFT;
+ sector = len >> SECTOR_SHIFT;
+ dprintk("write dev s:%d c:%d\r\n",block,sector);
+
+ if(sector <= 8)
+ {
+ for(i = 0;i < sector; i++)
+ {
+ NAND_LB_Write(block + i,(void *)(buf));
+ buf += 512;
+ FlushDataState = 1;
+ }
+ }else
+ NAND_LB_MultiWrite(block,(void *)(buf),sector);
+
+ return len;
+}
+
+EXPORT_SYMBOL_GPL(udc_write);
+EXPORT_SYMBOL_GPL(udc_read);
+EXPORT_SYMBOL_GPL(NAND_LB_Init);
+EXPORT_SYMBOL_GPL(NAND_LB_FLASHCACHE);
+EXPORT_SYMBOL_GPL(FlushDataState);
+EXPORT_SYMBOL_GPL(NAND_MTD_FLASHCACHE);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 5ce7cbabd7a..39f21d5f321 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -207,6 +207,24 @@ config MII
or internal device. It is safe to say Y or M here even if your
ethernet card lack MII.
+config JZ_ETH
+ tristate "JZ4730/JZ5730 On-Chip Ethernet support"
+ depends on NET_ETHERNET && (SOC_JZ4730 || SOC_JZ5730 || JZ_FPGA)
+ help
+ Say Y for support of JZ4730/JZ5730 On-Chip Ethernet interface.
+
+ To compile this driver as a module, choose M here: the module
+ will be called jz_eth.
+
+config JZCS8900
+ tristate "JZ CS8900A Ethernet support"
+ depends on NET_ETHERNET && (SOC_JZ4740 || SOC_JZ4750)
+ help
+ Say Y for support of JZ CS8900A Ethernet interface.
+
+ To compile this driver as a module, choose M here: the module
+ will be called jzcs8900a.
+
config MACB
tristate "Atmel MACB support"
depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91SAM9G20 || ARCH_AT91CAP9
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index ead8cab3cfe..b90ef6b65f8 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -103,6 +103,9 @@ obj-$(CONFIG_MII) += mii.o
obj-$(CONFIG_MDIO) += mdio.o
obj-$(CONFIG_PHYLIB) += phy/
+obj-$(CONFIG_JZ_ETH) += jz_eth.o
+obj-$(CONFIG_JZCS8900) += jzcs8900a.o
+
obj-$(CONFIG_SUNDANCE) += sundance.o
obj-$(CONFIG_HAMACHI) += hamachi.o
obj-$(CONFIG_NET) += Space.o loopback.o
diff --git a/drivers/net/jz_eth.c b/drivers/net/jz_eth.c
new file mode 100644
index 00000000000..b3c2ffa99f9
--- /dev/null
+++ b/drivers/net/jz_eth.c
@@ -0,0 +1,1299 @@
+/*
+ * linux/drivers/net/jz_eth.c
+ *
+ * Jz4730/Jz5730 On-Chip ethernet driver.
+ *
+ * Copyright (C) 2005 - 2007 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/uaccess.h>
+#include <asm/cacheflush.h>
+#include <asm/cacheops.h>
+#include <asm/jzsoc.h>
+
+#include "jz_eth.h"
+
+#define P2ADDR(a) (((unsigned long)(a) & 0x1fffffff) | 0xa0000000)
+#define P1ADDR(a) (((unsigned long)(a) & 0x1fffffff) | 0x80000000)
+
+//#define DEBUG
+#ifdef DEBUG
+# define DBPRINTK(fmt,args...) printk(KERN_DEBUG fmt,##args)
+#else
+# define DBPRINTK(fmt,args...) do {} while(0)
+#endif
+
+#define errprintk(fmt,args...) printk(KERN_ERR fmt,##args);
+#define infoprintk(fmt,args...) printk(KERN_INFO fmt,##args);
+
+#define DRV_NAME "jz_eth"
+#define DRV_VERSION "1.2"
+#define DRV_AUTHOR "Peter Wei <jlwei@ingenic.cn>"
+#define DRV_DESC "JzSOC On-chip Ethernet driver"
+
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables
+ */
+static struct net_device *netdev;
+static char * hwaddr = NULL;
+static int debug = -1;
+static struct mii_if_info mii_info;
+
+MODULE_PARM_DESC(debug, "i");
+MODULE_PARM_DESC(hwaddr,"s");
+
+/*
+ * Local routines
+ */
+static irqreturn_t jz_eth_interrupt(int irq, void *dev_id);
+
+static int link_check_thread (void *data);
+
+/*
+ * Get MAC address
+ */
+
+#define I2C_DEVICE 0x57
+#define MAC_OFFSET 64
+
+extern void i2c_open(void);
+extern void i2c_close(void);
+extern int i2c_read(unsigned char device, unsigned char *buf,
+ unsigned char address, int count);
+
+static inline unsigned char str2hexnum(unsigned char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return 0; /* foo */
+}
+
+static inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ unsigned char num;
+
+ if((*str == '.') || (*str == ':'))
+ str++;
+ num = str2hexnum(*str++) << 4;
+ num |= (str2hexnum(*str++));
+ ea[i] = num;
+ }
+}
+
+static int ethaddr_cmd = 0;
+static unsigned char ethaddr_hex[6];
+
+static int __init ethernet_addr_setup(char *str)
+{
+ if (!str) {
+ printk("ethaddr not set in command line\n");
+ return -1;
+ }
+ ethaddr_cmd = 1;
+ str2eaddr(ethaddr_hex, str);
+
+ return 0;
+}
+
+__setup("ethaddr=", ethernet_addr_setup);
+
+static int get_mac_address(struct net_device *dev)
+{
+ int i;
+ unsigned char flag0=0;
+ unsigned char flag1=0xff;
+
+ dev->dev_addr[0] = 0xff;
+ if (hwaddr != NULL) {
+ /* insmod jz-ethc.o hwaddr=00:ef:a3:c1:00:10 */
+ str2eaddr(dev->dev_addr, hwaddr);
+ } else if (ethaddr_cmd) {
+ /* linux command line: ethaddr=00:ef:a3:c1:00:10 */
+ for (i=0; i<6; i++)
+ dev->dev_addr[i] = ethaddr_hex[i];
+ } else {
+#if 0
+ /* mac address in eeprom: byte 0x40-0x45 */
+ i2c_open();
+ i2c_read(I2C_DEVICE, dev->dev_addr, MAC_OFFSET, 6);
+ i2c_close();
+#endif
+ }
+
+ /* check whether valid MAC address */
+ for (i=0; i<6; i++) {
+ flag0 |= dev->dev_addr[i];
+ flag1 &= dev->dev_addr[i];
+ }
+ if ((dev->dev_addr[0] & 0xC0) || (flag0 == 0) || (flag1 == 0xff)) {
+ printk("WARNING: There is not MAC address, use default ..\n");
+ dev->dev_addr[0] = 0x00;
+ dev->dev_addr[1] = 0xef;
+ dev->dev_addr[2] = 0xa3;
+ dev->dev_addr[3] = 0xc1;
+ dev->dev_addr[4] = 0x00;
+ dev->dev_addr[5] = 0x10;
+ dev->dev_addr[5] = 0x03;
+ }
+ return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+static u32 jz_eth_curr_mode(struct net_device *dev);
+
+/*
+ * Ethernet START/STOP routines
+ */
+#define START_ETH { \
+ s32 val; \
+ val = readl(DMA_OMR); \
+ val |= OMR_ST | OMR_SR; \
+ writel(val, DMA_OMR); \
+}
+
+#define STOP_ETH { \
+ s32 val; \
+ val = readl(DMA_OMR); \
+ val &= ~(OMR_ST|OMR_SR); \
+ writel(val, DMA_OMR); \
+}
+
+/*
+ * Link check routines
+ */
+static void start_check(struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+
+ np->thread_die = 0;
+ init_waitqueue_head(&np->thr_wait);
+ init_completion (&np->thr_exited);
+ np->thr_pid = kernel_thread (link_check_thread,(void *)dev,
+ CLONE_FS | CLONE_FILES);
+ if (np->thr_pid < 0)
+ errprintk("%s: unable to start kernel thread\n",dev->name);
+}
+
+static int close_check(struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+
+ int ret = 0;
+
+ if (np->thr_pid >= 0) {
+ np->thread_die = 1;
+ wmb();
+ ret = kill_proc (np->thr_pid, SIGTERM, 1);
+ if (ret) {
+ errprintk("%s: unable to signal thread\n", dev->name);
+ return 1;
+ }
+ wait_for_completion (&np->thr_exited);
+ }
+ return 0;
+}
+
+static int link_check_thread(void *data)
+{
+ struct net_device *dev=(struct net_device *)data;
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(netdev);
+
+ unsigned char current_link;
+ unsigned long timeout;
+
+ daemonize("%s", dev->name);
+ spin_lock_irq(&current->sighand->siglock);
+ sigemptyset(&current->blocked);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ strncpy (current->comm, dev->name, sizeof(current->comm) - 1);
+ current->comm[sizeof(current->comm) - 1] = '\0';
+
+ while (1) {
+ timeout = 3*HZ;
+ do {
+ timeout = interruptible_sleep_on_timeout (&np->thr_wait, timeout);
+ /* make swsusp happy with our thread */
+// if (current->flags & PF_FREEZE)
+// refrigerator(PF_FREEZE);
+ } while (!signal_pending (current) && (timeout > 0));
+
+ if (signal_pending (current)) {
+ spin_lock_irq(&current->sighand->siglock);
+ flush_signals(current);
+ spin_unlock_irq(&current->sighand->siglock);
+ }
+
+ if (np->thread_die)
+ break;
+
+ current_link=mii_link_ok(&mii_info);
+ if (np->link_state!=current_link) {
+ if (current_link) {
+ infoprintk("%s: Ethernet Link OK!\n",dev->name);
+ jz_eth_curr_mode(dev);
+ netif_carrier_on(dev);
+ }
+ else {
+ errprintk("%s: Ethernet Link offline!\n",dev->name);
+ netif_carrier_off(dev);
+ }
+ }
+ np->link_state=current_link;
+
+ }
+ complete_and_exit (&np->thr_exited, 0);
+}
+
+#ifdef DEBUG
+/*
+ * Display ethernet packet header
+ * This routine is used for test function
+ */
+static void eth_dbg_rx(struct sk_buff *skb, int len)
+{
+
+ int i, j;
+
+ printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
+ (u8)skb->data[0],
+ (u8)skb->data[1],
+ (u8)skb->data[2],
+ (u8)skb->data[3],
+ (u8)skb->data[4],
+ (u8)skb->data[5],
+ (u8)skb->data[6],
+ (u8)skb->data[7],
+ (u8)skb->data[8],
+ (u8)skb->data[9],
+ (u8)skb->data[10],
+ (u8)skb->data[11],
+ (u8)skb->data[12],
+ (u8)skb->data[13],
+ len);
+ for (j=0; len>0; j+=16, len-=16) {
+ printk(" %03x: ",j);
+ for (i=0; i<16 && i<len; i++) {
+ printk("%02x ",(u8)skb->data[i+j]);
+ }
+ printk("\n");
+ }
+ return;
+ }
+#endif
+
+/*
+ * Reset ethernet device
+ */
+static inline void jz_eth_reset(void)
+{
+ u32 i;
+ i = readl(DMA_BMR);
+ writel(i | BMR_SWR, DMA_BMR);
+ for(i = 0; i < 1000; i++) {
+ if(!(readl(DMA_BMR) & BMR_SWR)) break;
+ mdelay(1);
+ }
+}
+
+/*
+ * MII operation routines
+ */
+static inline void mii_wait(void)
+{
+ int i;
+ for(i = 0; i < 10000; i++) {
+ if(!(readl(MAC_MIIA) & 0x1))
+ break;
+ mdelay(1);
+ }
+ if (i >= 10000)
+ printk("MII wait timeout : %d.\n", i);
+}
+
+static int mdio_read(struct net_device *dev,int phy_id, int location)
+{
+ u32 mii_cmd = (phy_id << 11) | (location << 6) | 1;
+ int retval = 0;
+
+ writel(mii_cmd, MAC_MIIA);
+ mii_wait();
+ retval = readl(MAC_MIID) & 0x0000ffff;
+
+ return retval;
+
+}
+
+static void mdio_write(struct net_device *dev,int phy_id, int location, int data)
+{
+ u32 mii_cmd = (phy_id << 11) | (location << 6) | 0x2 | 1;
+
+ writel(mii_cmd, MAC_MIIA);
+ writel(data & 0x0000ffff, MAC_MIID);
+ mii_wait();
+}
+
+
+/*
+ * Search MII phy
+ */
+static int jz_search_mii_phy(struct net_device *dev)
+{
+
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+
+ int phy, phy_idx = 0;
+
+ np->valid_phy = 0xff;
+ for (phy = 0; phy < 32; phy++) {
+ int mii_status = mdio_read(dev,phy, 1);
+ if (mii_status != 0xffff && mii_status != 0x0000) {
+ np->phys[phy_idx] = phy;
+ np->ecmds[phy_idx].speed=SPEED_100;
+ np->ecmds[phy_idx].duplex=DUPLEX_FULL;
+ np->ecmds[phy_idx].port=PORT_MII;
+ np->ecmds[phy_idx].transceiver=XCVR_INTERNAL;
+ np->ecmds[phy_idx].phy_address=np->phys[phy_idx];
+ np->ecmds[phy_idx].autoneg=AUTONEG_ENABLE;
+ np->ecmds[phy_idx].advertising=(ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full);
+ phy_idx++;
+ }
+ }
+ if (phy_idx == 1) {
+ np->valid_phy = np->phys[0];
+ np->phy_type = 0;
+ }
+ if (phy_idx != 0) {
+ phy = np->valid_phy;
+ np->advertising = mdio_read(dev,phy, 4);
+ }
+ return phy_idx;
+}
+
+/*
+ * CRC calc for Destination Address for gets hashtable index
+ */
+
+#define POLYNOMIAL 0x04c11db7UL
+static u16 jz_hashtable_index(u8 *addr)
+{
+#if 1
+ u32 crc = 0xffffffff, msb;
+ int i, j;
+ u32 byte;
+ for (i = 0; i < 6; i++) {
+ byte = *addr++;
+ for (j = 0; j < 8; j++) {
+ msb = crc >> 31;
+ crc <<= 1;
+ if (msb ^ (byte & 1)) crc ^= POLYNOMIAL;
+ byte >>= 1;
+ }
+ }
+ return ((int)(crc >> 26));
+#endif
+#if 0
+ int crc = -1;
+ int length=6;
+ int bit;
+ unsigned char current_octet;
+ while (--length >= 0) {
+ current_octet = *addr++;
+ for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+ crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
+ POLYNOMIAL : 0);
+ }
+ return ((int)(crc >> 26));
+#endif
+}
+
+/*
+ * Multicast filter and config multicast hash table
+ */
+#define MULTICAST_FILTER_LIMIT 64
+
+static void jz_set_multicast_list(struct net_device *dev)
+{
+ int i, hash_index;
+ u32 mcr, hash_h, hash_l, hash_bit;
+
+ mcr = readl(MAC_MCR);
+ mcr &= ~(MCR_PR | MCR_PM | MCR_HP);
+
+ if (dev->flags & IFF_PROMISC) {
+ /* Accept any kinds of packets */
+ mcr |= MCR_PR;
+ hash_h = 0xffffffff;
+ hash_l = 0xffffffff;
+ DBPRINTK("%s: enter promisc mode!\n",dev->name);
+ }
+ else if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > MULTICAST_FILTER_LIMIT)){
+ /* Accept all multicast packets */
+ mcr |= MCR_PM;
+ hash_h = 0xffffffff;
+ hash_l = 0xffffffff;
+ DBPRINTK("%s: enter allmulticast mode! %d \n",dev->name,dev->mc_count);
+ }
+ else if (dev->flags & IFF_MULTICAST)
+ {
+ /* Update multicast hash table */
+ struct dev_mc_list *mclist;
+ hash_h = readl(MAC_HTH);
+ hash_l = readl(MAC_HTL);
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next)
+ {
+ hash_index = jz_hashtable_index(mclist->dmi_addr);
+ hash_bit=0x00000001;
+ hash_bit <<= (hash_index & 0x1f);
+ if (hash_index > 0x1f)
+ hash_h |= hash_bit;
+ else
+ hash_l |= hash_bit;
+ DBPRINTK("----------------------------\n");
+#ifdef DEBUG
+ int j;
+ for (j=0;j<mclist->dmi_addrlen;j++)
+ printk("%2.2x:",mclist->dmi_addr[j]);
+ printk("\n");
+#endif
+ DBPRINTK("dmi.addrlen => %d\n",mclist->dmi_addrlen);
+ DBPRINTK("dmi.users => %d\n",mclist->dmi_users);
+ DBPRINTK("dmi.gusers => %d\n",mclist->dmi_users);
+ }
+ writel(hash_h,MAC_HTH);
+ writel(hash_l,MAC_HTL);
+ mcr |= MCR_HP;
+ DBPRINTK("This is multicast hash table high bits [%4.4x]\n",readl(MAC_HTH));
+ DBPRINTK("This is multicast hash table low bits [%4.4x]\n",readl(MAC_HTL));
+ DBPRINTK("%s: enter multicast mode!\n",dev->name);
+ }
+ writel(mcr,MAC_MCR);
+}
+
+static inline int jz_phy_reset(struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+
+ unsigned int mii_reg0;
+ unsigned int count;
+
+ mii_reg0 = mdio_read(dev,np->valid_phy,MII_BMCR);
+ mii_reg0 |=MII_CR_RST;
+ mdio_write(dev,np->valid_phy,MII_BMCR,mii_reg0); //reset phy
+ for ( count = 0; count < 1000; count++) {
+ mdelay(1);
+ mii_reg0 = mdio_read(dev,np->valid_phy,MII_BMCR);
+ if (!(mii_reg0 & MII_CR_RST)) break; //reset completed
+ }
+ if (count>=100)
+ return 1; //phy error
+ else
+ return 0;
+}
+
+/*
+ * Show all mii registers - this routine is used for test
+ */
+#ifdef DEBUG
+static void mii_db_out(struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+
+ unsigned int mii_test;
+
+ mii_test = mdio_read(dev,np->valid_phy,MII_BMCR);
+ DBPRINTK("BMCR ====> 0x%4.4x \n",mii_test);
+
+ mii_test = mdio_read(dev,np->valid_phy,MII_BMSR);
+ DBPRINTK("BMSR ====> 0x%4.4x \n",mii_test);
+
+ mii_test = mdio_read(dev,np->valid_phy,MII_ANAR);
+ DBPRINTK("ANAR ====> 0x%4.4x \n",mii_test);
+
+ mii_test = mdio_read(dev,np->valid_phy,MII_ANLPAR);
+ DBPRINTK("ANLPAR ====> 0x%4.4x \n",mii_test);
+
+ mii_test = mdio_read(dev,np->valid_phy,16);
+ DBPRINTK("REG16 ====> 0x%4.4x \n",mii_test);
+
+ mii_test = mdio_read(dev,np->valid_phy,17);
+ DBPRINTK("REG17 ====> 0x%4.4x \n",mii_test);
+}
+#endif
+
+/*
+ * Start Auto-Negotiation function for PHY
+ */
+static int jz_autonet_complete(struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+ int count;
+ u32 mii_reg1, timeout = 3000;
+
+ for (count = 0; count < timeout; count++) {
+ mdelay(1);
+ mii_reg1 = mdio_read(dev,np->valid_phy,MII_BMSR);
+ if (mii_reg1 & 0x0020) break;
+ }
+ //mii_db_out(dev); //for debug to display all register of MII
+ if (count >= timeout)
+ return 1; //auto negotiation error
+ else
+ return 0;
+}
+
+/*
+ * Get current mode of eth phy
+ */
+static u32 jz_eth_curr_mode(struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+ unsigned int mii_reg17;
+ u32 flag = 0;
+
+ mii_reg17 = mdio_read(dev,np->valid_phy,MII_DSCSR);
+ np->media = mii_reg17>>12;
+ if (np->media==8) {
+ infoprintk("%s: Current Operation Mode is [100M Full Duplex]",dev->name);
+ flag = 0;
+ np->full_duplex=1;
+ }
+ if (np->media==4) {
+ infoprintk("%s: Current Operation Mode is [100M Half Duplex]",dev->name);
+ flag = 0;
+ np->full_duplex=0;
+ }
+ if (np->media==2) {
+ infoprintk("%s: Current Operation Mode is [10M Full Duplex]",dev->name);
+ flag = OMR_TTM;
+ np->full_duplex=1;
+ }
+ if (np->media==1) {
+ infoprintk("%s: Current Operation Mode is [10M Half Duplex]",dev->name);
+ flag = OMR_TTM;
+ np->full_duplex=0;
+ }
+ printk("\n");
+ return flag;
+}
+
+/*
+ * Ethernet device hardware init
+ * This routine initializes the ethernet device hardware and PHY
+ */
+static int jz_init_hw(struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+ struct ethtool_cmd ecmd;
+ u32 mcr, omr;
+ u32 sts, flag = 0;
+ int i;
+
+ jz_eth_reset();
+ STOP_ETH;
+#if 0
+ /* mii operation */
+ if (jz_phy_reset(dev)) {
+ errprintk("PHY device do not reset!\n");
+ return -EPERM; // return operation not permitted
+ }
+#endif
+ /* Set MAC address */
+ writel(le32_to_cpu(*(unsigned long *)&dev->dev_addr[0]), MAC_MAL);
+ writel(le32_to_cpu(*(unsigned long *)&dev->dev_addr[4]), MAC_MAH);
+ printk("%s: JZ On-Chip ethernet (MAC ", dev->name);
+ for (i = 0; i < 5; i++) {
+ printk("%2.2x:", dev->dev_addr[i]);
+ }
+ printk("%2.2x, IRQ %d)\n", dev->dev_addr[i], dev->irq);
+
+ np->mii_phy_cnt = jz_search_mii_phy(dev);
+ printk("%s: Found %d PHY on JZ MAC\n", dev->name, np->mii_phy_cnt);
+
+ mii_info.phy_id = np->valid_phy;
+ mii_info.dev = dev;
+ mii_info.mdio_read = &mdio_read;
+ mii_info.mdio_write = &mdio_write;
+
+ ecmd.speed = SPEED_100;
+ ecmd.duplex = DUPLEX_FULL;
+ ecmd.port = PORT_MII;
+ ecmd.transceiver = XCVR_INTERNAL;
+ ecmd.phy_address = np->valid_phy;
+ ecmd.autoneg = AUTONEG_ENABLE;
+
+ mii_ethtool_sset(&mii_info,&ecmd);
+ if (jz_autonet_complete(dev))
+ errprintk("%s: Ethernet Module AutoNegotiation failed\n",dev->name);
+ mii_ethtool_gset(&mii_info,&ecmd);
+
+ infoprintk("%s: Provide Modes: ",dev->name);
+ for (i = 0; i < 5;i++)
+ if (ecmd.advertising & (1<<i))
+ printk("(%d)%s", i+1, media_types[i]);
+ printk("\n");
+
+ flag = jz_eth_curr_mode(dev);
+
+ /* Config OMR register */
+ omr = readl(DMA_OMR) & ~OMR_TTM;
+ omr |= flag;
+ //omr |= OMR_OSF;
+ omr |= OMR_SF;
+ writel(omr, DMA_OMR);
+
+ readl(DMA_MFC); //through read operation to clear the register for 0x0000000
+ /* Set the programmable burst length (value 1 or 4 is validate)*/
+#if 0 /* __BIG_ENDIAN__ */
+ writel(PBL_4 | DSL_0 | 0x100080, DMA_BMR); /* DSL_0: see DESC_SKIP_LEN and DESC_ALIGN */
+#else /* __LITTLE_ENDIAN__ */
+ writel(PBL_4 | DSL_0, DMA_BMR); /* DSL_0: see DESC_SKIP_LEN and DESC_ALIGN */
+#endif
+ /* Config MCR register*/
+ mcr = (readl(MAC_MCR) & ~(MCR_PS | MCR_HBD | MCR_FDX));
+ if(np->full_duplex)
+ mcr |= MCR_FDX;
+ mcr |= MCR_BFD | MCR_TE | MCR_RE | MCR_OWD|MCR_HBD;
+ writel(mcr, MAC_MCR);
+// mcr &= (readl(MAC_MCR) & ~(MCR_PM | MCR_PR | MCR_IF | MCR_HO | MCR_HP));
+// mcr &= 0xffdf;
+// mcr |= 0x0020;
+// writel(mcr, MAC_MCR);
+
+ /* Set base address of TX and RX descriptors */
+ writel(np->dma_rx_ring, DMA_RRBA);
+ writel(np->dma_tx_ring, DMA_TRBA);
+
+ START_ETH;
+
+ /* set interrupt mask */
+ writel(IMR_DEFAULT | IMR_ENABLE, DMA_IMR);
+
+ /* Reset any pending (stale) interrupts */
+ sts = readl(DMA_STS);
+ writel(sts, DMA_STS);
+
+ return 0;
+}
+
+static int jz_eth_open(struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+ int retval, i;
+
+ retval = request_irq(dev->irq, jz_eth_interrupt, 0, dev->name, dev);
+ if (retval) {
+ errprintk("%s: unable to get IRQ %d .\n", dev->name, dev->irq);
+ return -EAGAIN;
+ }
+
+ for (i = 0; i < NUM_RX_DESCS; i++) {
+ np->rx_ring[i].status = cpu_to_le32(R_OWN);
+ np->rx_ring[i].desc1 = cpu_to_le32(RX_BUF_SIZE | RD_RCH);
+ np->rx_ring[i].buf1_addr = cpu_to_le32(np->dma_rx_buf + i*RX_BUF_SIZE);
+ np->rx_ring[i].next_addr = cpu_to_le32(np->dma_rx_ring + (i+1) * sizeof (jz_desc_t));
+ }
+ np->rx_ring[NUM_RX_DESCS - 1].next_addr = cpu_to_le32(np->dma_rx_ring);
+
+ for (i = 0; i < NUM_TX_DESCS; i++) {
+ np->tx_ring[i].status = cpu_to_le32(0);
+ np->tx_ring[i].desc1 = cpu_to_le32(TD_TCH);
+ np->tx_ring[i].buf1_addr = 0;
+ np->tx_ring[i].next_addr = cpu_to_le32(np->dma_tx_ring + (i+1) * sizeof (jz_desc_t));
+ }
+ np->tx_ring[NUM_TX_DESCS - 1].next_addr = cpu_to_le32(np->dma_tx_ring);
+
+ np->rx_head = 0;
+ np->tx_head = np->tx_tail = 0;
+
+ jz_init_hw(dev);
+
+ dev->trans_start = jiffies;
+ netif_start_queue(dev);
+ start_check(dev);
+
+ return 0;
+}
+
+static int jz_eth_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ close_check(dev);
+ STOP_ETH;
+ free_irq(dev->irq, dev);
+ return 0;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the device open or closed.
+ */
+static struct net_device_stats * jz_eth_get_stats(struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+ int tmp;
+
+ tmp = readl(DMA_MFC); // After read clear to zero
+ np->stats.rx_missed_errors += (tmp & MFC_CNT2) + ((tmp & MFC_CNT1) >> 16);
+
+ return &np->stats;
+}
+
+/*
+ * ethtool routines
+ */
+static int jz_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+ u32 ethcmd;
+
+ /* dev_ioctl() in ../../net/core/dev.c has already checked
+ capable(CAP_NET_ADMIN), so don't bother with that here. */
+
+ if (get_user(ethcmd, (u32 *)useraddr))
+ return -EFAULT;
+
+ switch (ethcmd) {
+
+ case ETHTOOL_GDRVINFO: {
+ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+ strcpy (info.driver, DRV_NAME);
+ strcpy (info.version, DRV_VERSION);
+ strcpy (info.bus_info, "OCS");
+ if (copy_to_user (useraddr, &info, sizeof (info)))
+ return -EFAULT;
+ return 0;
+ }
+
+ /* get settings */
+ case ETHTOOL_GSET: {
+ struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+ spin_lock_irq(&np->lock);
+ mii_ethtool_gset(&mii_info, &ecmd);
+ spin_unlock_irq(&np->lock);
+ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+ return 0;
+ }
+ /* set settings */
+ case ETHTOOL_SSET: {
+ int r;
+ struct ethtool_cmd ecmd;
+ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+ return -EFAULT;
+ spin_lock_irq(&np->lock);
+ r = mii_ethtool_sset(&mii_info, &ecmd);
+ spin_unlock_irq(&np->lock);
+ return r;
+ }
+ /* restart autonegotiation */
+ case ETHTOOL_NWAY_RST: {
+ return mii_nway_restart(&mii_info);
+ }
+ /* get link status */
+ case ETHTOOL_GLINK: {
+ struct ethtool_value edata = {ETHTOOL_GLINK};
+ edata.data = mii_link_ok(&mii_info);
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+
+ /* get message-level */
+ case ETHTOOL_GMSGLVL: {
+ struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+ edata.data = debug;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+ /* set message-level */
+ case ETHTOOL_SMSGLVL: {
+ struct ethtool_value edata;
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ debug = edata.data;
+ return 0;
+ }
+
+
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+
+}
+
+/*
+ * Config device
+ */
+static int jz_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct jz_eth_private *np =(struct jz_eth_private *)netdev_priv(dev);
+ struct mii_ioctl_data *data, rdata;
+
+ switch (cmd) {
+ case SIOCETHTOOL:
+ return jz_ethtool_ioctl(dev, (void *) rq->ifr_data);
+ case SIOCGMIIPHY:
+ case SIOCDEVPRIVATE:
+ data = (struct mii_ioctl_data *)&rq->ifr_data;
+ data->phy_id = np->valid_phy;
+ case SIOCGMIIREG:
+ case SIOCDEVPRIVATE+1:
+ data = (struct mii_ioctl_data *)&rq->ifr_data;
+ data->val_out = mdio_read(dev,np->valid_phy, data->reg_num & 0x1f);
+ return 0;
+ case SIOCSMIIREG:
+ case SIOCDEVPRIVATE+2:
+ data = (struct mii_ioctl_data *)&rq->ifr_data;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ mdio_write(dev,np->valid_phy, data->reg_num & 0x1f, data->val_in);
+ return 0;
+ case READ_COMMAND:
+ data = (struct mii_ioctl_data *)rq->ifr_data;
+ if (copy_from_user(&rdata,data,sizeof(rdata)))
+ return -EFAULT;
+ rdata.val_out = mdio_read(dev,rdata.phy_id, rdata.reg_num & 0x1f);
+ if (copy_to_user(data,&rdata,sizeof(rdata)))
+ return -EFAULT;
+ return 0;
+ case WRITE_COMMAND:
+ if (np->phy_type==1) {
+ data = (struct mii_ioctl_data *)rq->ifr_data;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&rdata,data,sizeof(rdata)))
+ return -EFAULT;
+ mdio_write(dev,rdata.phy_id, rdata.reg_num & 0x1f, rdata.val_in);
+ }
+ return 0;
+ case GETDRIVERINFO:
+ if (np->phy_type==1) {
+ data = (struct mii_ioctl_data *)rq->ifr_data;
+ if (copy_from_user(&rdata,data,sizeof(rdata)))
+ return -EFAULT;
+ rdata.val_in = 0x1;
+ rdata.val_out = 0x00d0;
+ if (copy_to_user(data,&rdata,sizeof(rdata)))
+ return -EFAULT;
+ }
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+/*
+ * Received one packet
+ */
+static void eth_rxready(struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private*)netdev_priv(dev);
+ struct sk_buff *skb;
+ unsigned char *pkt_ptr;
+ u32 pkt_len;
+ u32 status;
+
+ status = le32_to_cpu(np->rx_ring[np->rx_head].status);
+ while (!(status & R_OWN)) { /* owner bit = 0 */
+ if (status & RD_ES) { /* error summary */
+ np->stats.rx_errors++; /* Update the error stats. */
+ if (status & (RD_RF | RD_TL))
+ np->stats.rx_frame_errors++;
+ if (status & RD_CE)
+ np->stats.rx_crc_errors++;
+ if (status & RD_TL)
+ np->stats.rx_length_errors++;
+ } else {
+ pkt_ptr = bus_to_virt(le32_to_cpu(np->rx_ring[np->rx_head].buf1_addr));
+ pkt_len = ((status & RD_FL) >> 16) - 4;
+
+ skb = dev_alloc_skb(pkt_len + 2);
+ if (skb == NULL) {
+ printk("%s: Memory squeeze, dropping.\n",
+ dev->name);
+ np->stats.rx_dropped++;
+ break;
+ }
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* 16 byte align */
+
+ //pkt_ptr = P1ADDR(pkt_ptr);
+ //dma_cache_inv(pkt_ptr, pkt_len);
+ memcpy(skb->data, pkt_ptr, pkt_len);
+ skb_put(skb, pkt_len);
+
+ //eth_dbg_rx(skb, pkt_len);
+ skb->protocol = eth_type_trans(skb,dev);
+ netif_rx(skb); /* pass the packet to upper layers */
+ dev->last_rx = jiffies;
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += pkt_len;
+ }
+ np->rx_ring[np->rx_head].status = cpu_to_le32(R_OWN);
+
+ np->rx_head ++;
+ if (np->rx_head >= NUM_RX_DESCS)
+ np->rx_head = 0;
+ status = le32_to_cpu(np->rx_ring[np->rx_head].status);
+ }
+}
+
+/*
+ * Tx timeout routine
+ */
+static void jz_eth_tx_timeout(struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+
+ jz_init_hw(dev);
+ np->stats.tx_errors ++;
+ netif_wake_queue(dev);
+}
+
+/*
+ * One packet was transmitted
+ */
+static void eth_txdone(struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private*)netdev_priv(dev);
+ int tx_tail = np->tx_tail;
+
+ while (tx_tail != np->tx_head) {
+ int entry = tx_tail % NUM_TX_DESCS;
+ s32 status = le32_to_cpu(np->tx_ring[entry].status);
+ if(status < 0) break;
+ if (status & TD_ES ) { /* Error summary */
+ np->stats.tx_errors++;
+ if (status & TD_NC) np->stats.tx_carrier_errors++;
+ if (status & TD_LC) np->stats.tx_window_errors++;
+ if (status & TD_UF) np->stats.tx_fifo_errors++;
+ if (status & TD_DE) np->stats.tx_aborted_errors++;
+ if (np->tx_head != np->tx_tail)
+ writel(1, DMA_TPD); /* Restart a stalled TX */
+ } else
+ np->stats.tx_packets++;
+ /* Update the collision counter */
+ np->stats.collisions += ((status & TD_EC) ? 16 : ((status & TD_CC) >> 3));
+ /* Free the original skb */
+ if (np->tx_skb[entry]) {
+ dev_kfree_skb_irq(np->tx_skb[entry]);
+ np->tx_skb[entry] = 0;
+ }
+ tx_tail++;
+ }
+ if (np->tx_full && (tx_tail + NUM_TX_DESCS > np->tx_head + 1)) {
+ /* The ring is no longer full */
+ np->tx_full = 0;
+ netif_start_queue(dev);
+ }
+ np->tx_tail = tx_tail;
+}
+
+/*
+ * Update the tx descriptor
+ */
+static void load_tx_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+ int entry = np->tx_head % NUM_TX_DESCS;
+
+ np->tx_ring[entry].buf1_addr = cpu_to_le32(virt_to_bus(buf));
+ np->tx_ring[entry].desc1 &= cpu_to_le32((TD_TER | TD_TCH));
+ np->tx_ring[entry].desc1 |= cpu_to_le32(flags);
+ np->tx_ring[entry].status = cpu_to_le32(T_OWN);
+ np->tx_skb[entry] = skb;
+}
+
+/*
+ * Transmit one packet
+ */
+static int jz_eth_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct jz_eth_private *np = (struct jz_eth_private *)netdev_priv(dev);
+ u32 length;
+
+ if (np->tx_full) {
+ return 0;
+ }
+#ifdef CONFIG_FPGA
+ mdelay(10);
+#else
+ udelay(500); /* FIXME: can we remove this delay ? */
+#endif
+ length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+ dma_cache_wback((unsigned long)skb->data, length);
+ load_tx_packet(dev, (char *)skb->data, TD_IC | TD_LS | TD_FS | length, skb);
+ spin_lock_irq(&np->lock);
+ np->tx_head ++;
+ np->stats.tx_bytes += length;
+ writel(1, DMA_TPD); /* Start the TX */
+ dev->trans_start = jiffies; /* for timeout */
+ if (np->tx_tail + NUM_TX_DESCS > np->tx_head + 1) {
+ np->tx_full = 0;
+ }
+ else {
+ np->tx_full = 1;
+ netif_stop_queue(dev);
+ }
+ spin_unlock_irq(&np->lock);
+
+ return 0;
+}
+
+/*
+ * Interrupt service routine
+ */
+static irqreturn_t jz_eth_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct jz_eth_private *np = netdev_priv(dev);
+ u32 sts;
+ int i;
+
+ spin_lock(&np->lock);
+
+ writel((readl(DMA_IMR) & ~IMR_ENABLE), DMA_IMR); /* Disable interrupt */
+
+ for (i = 0; i < 100; i++) {
+ sts = readl(DMA_STS);
+ writel(sts, DMA_STS); /* clear status */
+
+ if (!(sts & IMR_DEFAULT)) break;
+
+ if (sts & (DMA_INT_RI | DMA_INT_RU)) /* Rx IRQ */
+ eth_rxready(dev);
+ if (sts & (DMA_INT_TI | DMA_INT_TU)) /* Tx IRQ */
+ eth_txdone(dev);
+
+ /* check error conditions */
+ if (sts & DMA_INT_FB){ /* fatal bus error */
+ STOP_ETH;
+ errprintk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",dev->name, sts);
+ break;
+ }
+
+ if (sts & DMA_INT_UN) { /* Transmit underrun */
+ u32 omr;
+ omr = readl(DMA_OMR);
+ if (!(omr & OMR_SF)) {
+ omr &= ~(OMR_ST | OMR_SR);
+ writel(omr, DMA_OMR);
+ while (readl(DMA_STS) & STS_TS); /* wait for stop */
+ if ((omr & OMR_TR) < OMR_TR) { /* ? */
+ omr += TR_24;
+ } else {
+ omr |= OMR_SF;
+ }
+ writel(omr | OMR_ST | OMR_SR, DMA_OMR);
+ }
+ }
+ }
+
+ writel(readl(DMA_IMR) | IMR_ENABLE, DMA_IMR); /* enable interrupt */
+
+ spin_unlock(&np->lock);
+
+ return IRQ_HANDLED;
+}
+
+#if 0 //def CONFIG_PM
+/*
+ * Suspend the ETH interface.
+ */
+static int jz_eth_suspend(struct net_device *dev, int state)
+{
+ struct jz_eth_private *jep = (struct jz_eth_private *)netdev_priv(dev);
+ unsigned long flags, tmp;
+
+ printk("ETH suspend.\n");
+
+ if (!netif_running(dev)) {
+ return 0;
+ }
+
+ netif_device_detach(dev);
+
+ spin_lock_irqsave(&jep->lock, flags);
+
+ /* Disable interrupts, stop Tx and Rx. */
+ REG32(DMA_IMR) = 0;
+ STOP_ETH;
+
+ /* Update the error counts. */
+ tmp = REG32(DMA_MFC);
+ jep->stats.rx_missed_errors += (tmp & 0x1ffff);
+ jep->stats.rx_fifo_errors += ((tmp >> 17) & 0x7ff);
+
+ spin_unlock_irqrestore(&jep->lock, flags);
+
+ return 0;
+}
+
+/*
+ * Resume the ETH interface.
+ */
+static int jz_eth_resume(struct net_device *dev)
+{
+ printk("ETH resume.\n");
+
+ if (!netif_running(dev))
+ return 0;
+
+ jz_init_hw(dev);
+
+ netif_device_attach(dev);
+ jz_eth_tx_timeout(dev);
+ netif_wake_queue(dev);
+
+ return 0;
+}
+
+static int jz_eth_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+ int ret;
+
+ if (!dev->data)
+ return -EINVAL;
+
+ switch (rqst) {
+ case PM_SUSPEND:
+ ret = jz_eth_suspend((struct net_device *)dev->data,
+ (int)data);
+ break;
+
+ case PM_RESUME:
+ ret = jz_eth_resume((struct net_device *)dev->data);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_PM */
+
+static const struct net_device_ops jz_eth_netdev_ops = {
+ .ndo_open = jz_eth_open,
+ .ndo_stop = jz_eth_close,
+ .ndo_get_stats = jz_eth_get_stats,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = jz_eth_do_ioctl,
+ .ndo_start_xmit = jz_eth_send_packet,
+ .ndo_set_multicast_list = jz_set_multicast_list,
+ .ndo_tx_timeout = jz_eth_tx_timeout,
+};
+
+static int __init jz_eth_init(void)
+{
+ struct net_device *dev;
+ struct jz_eth_private *np;
+ int err;
+
+ dev = alloc_etherdev(sizeof(struct jz_eth_private));
+ if (!dev) {
+ printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME);
+ return -ENOMEM;
+ }
+
+ netdev = dev;
+ np = netdev_priv(dev);
+ memset(np, 0, sizeof(struct jz_eth_private));
+
+ np->vaddr_rx_buf = (u32)dma_alloc_noncoherent(NULL, NUM_RX_DESCS*RX_BUF_SIZE,
+ &np->dma_rx_buf, 0);
+
+ if (!np->vaddr_rx_buf) {
+ printk(KERN_ERR "%s: Cannot alloc dma buffers\n", DRV_NAME);
+ unregister_netdev(dev);
+ free_netdev(dev);
+ return -ENOMEM;
+ }
+
+ np->dma_rx_ring = virt_to_bus(np->rx_ring);
+ np->dma_tx_ring = virt_to_bus(np->tx_ring);
+ np->full_duplex = 1;
+ np->link_state = 1;
+
+ spin_lock_init(&np->lock);
+
+ dev->irq = IRQ_ETH;
+ dev->watchdog_timeo = ETH_TX_TIMEOUT;
+ dev->netdev_ops = &jz_eth_netdev_ops;
+
+ /* configure MAC address */
+ get_mac_address(dev);
+
+ if ((err = register_netdev(dev)) != 0) {
+ printk(KERN_ERR "%s: Cannot register net device, error %d\n",
+ DRV_NAME, err);
+ free_netdev(dev);
+ return -ENOMEM;
+ }
+
+//#ifdef 0 //CONFIG_PM
+// np->pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, jz_eth_pm_callback);
+// if (np->pmdev)
+// np->pmdev->data = dev;
+//#endif
+
+ return 0;
+}
+
+static void __exit jz_eth_exit(void)
+{
+ struct net_device *dev = netdev;
+ struct jz_eth_private *np = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ dma_free_noncoherent(NULL, NUM_RX_DESCS * RX_BUF_SIZE,
+ (void *)np->vaddr_rx_buf, np->dma_rx_buf);
+ free_netdev(dev);
+}
+
+module_init(jz_eth_init);
+module_exit(jz_eth_exit);
diff --git a/drivers/net/jz_eth.h b/drivers/net/jz_eth.h
new file mode 100644
index 00000000000..cb8486ead95
--- /dev/null
+++ b/drivers/net/jz_eth.h
@@ -0,0 +1,403 @@
+/*
+ * linux/drivers/net/jz_eth.h
+ *
+ * Jz4730/Jz5730 On-Chip ethernet driver.
+ *
+ * Copyright (C) 2005 - 2007 Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __JZ_ETH_H__
+#define __JZ_ETH_H__
+
+/* DMA control and status registers */
+#define DMA_BMR (ETH_BASE + 0x1000) // Bus mode
+#define DMA_TPD (ETH_BASE + 0x1004) // Transmit poll demand register
+#define DMA_RPD (ETH_BASE + 0x1008) // Receieve poll demand register
+#define DMA_RRBA (ETH_BASE + 0x100C) // Receieve descriptor base address
+#define DMA_TRBA (ETH_BASE + 0x1010) // Transmit descriptor base address
+#define DMA_STS (ETH_BASE + 0x1014) // Status register
+#define DMA_OMR (ETH_BASE + 0x1018) // Command register
+#define DMA_IMR (ETH_BASE + 0x101C)
+#define DMA_MFC (ETH_BASE + 0x1020)
+
+/* DMA CSR8-CSR19 reserved */
+#define DMA_CTA (ETH_BASE + 0x1050)
+#define DMA_CRA (ETH_BASE + 0x1054)
+
+/* Mac control and status registers */
+#define MAC_MCR (ETH_BASE + 0x0000)
+#define MAC_MAH (ETH_BASE + 0x0004)
+#define MAC_MAL (ETH_BASE + 0x0008)
+#define MAC_HTH (ETH_BASE + 0x000C)
+#define MAC_HTL (ETH_BASE + 0x0010)
+#define MAC_MIIA (ETH_BASE + 0x0014)
+#define MAC_MIID (ETH_BASE + 0x0018)
+#define MAC_FCR (ETH_BASE + 0x001C)
+#define MAC_VTR1 (ETH_BASE + 0x0020)
+#define MAC_VTR2 (ETH_BASE + 0x0024)
+
+/*
+ * Bus Mode Register (DMA_BMR)
+ */
+#define BMR_PBL 0x00003f00 /* Programmable Burst Length */
+#define BMR_DSL 0x0000007c /* Descriptor Skip Length */
+#define BMR_BAR 0x00000002 /* Bus ARbitration */
+#define BMR_SWR 0x00000001 /* Software Reset */
+
+#define PBL_0 0x00000000 /* DMA burst length = amount in RX FIFO */
+#define PBL_1 0x00000100 /* 1 longword DMA burst length */
+#define PBL_2 0x00000200 /* 2 longwords DMA burst length */
+#define PBL_4 0x00000400 /* 4 longwords DMA burst length */
+#define PBL_8 0x00000800 /* 8 longwords DMA burst length */
+#define PBL_16 0x00001000 /* 16 longwords DMA burst length */
+#define PBL_32 0x00002000 /* 32 longwords DMA burst length */
+
+#define DSL_0 0x00000000 /* 0 longword / descriptor */
+#define DSL_1 0x00000004 /* 1 longword / descriptor */
+#define DSL_2 0x00000008 /* 2 longwords / descriptor */
+#define DSL_4 0x00000010 /* 4 longwords / descriptor */
+#define DSL_8 0x00000020 /* 8 longwords / descriptor */
+#define DSL_16 0x00000040 /* 16 longwords / descriptor */
+#define DSL_32 0x00000080 /* 32 longwords / descriptor */
+
+/*
+ * Status Register (DMA_STS)
+ */
+#define STS_BE 0x03800000 /* Bus Error Bits */
+#define STS_TS 0x00700000 /* Transmit Process State */
+#define STS_RS 0x000e0000 /* Receive Process State */
+
+#define TS_STOP 0x00000000 /* Stopped */
+#define TS_FTD 0x00100000 /* Running Fetch Transmit Descriptor */
+#define TS_WEOT 0x00200000 /* Running Wait for End Of Transmission */
+#define TS_QDAT 0x00300000 /* Running Queue skb data into TX FIFO */
+#define TS_RES 0x00400000 /* Reserved */
+#define TS_SPKT 0x00500000 /* Reserved */
+#define TS_SUSP 0x00600000 /* Suspended */
+#define TS_CLTD 0x00700000 /* Running Close Transmit Descriptor */
+
+#define RS_STOP 0x00000000 /* Stopped */
+#define RS_FRD 0x00020000 /* Running Fetch Receive Descriptor */
+#define RS_CEOR 0x00040000 /* Running Check for End of Receive Packet */
+#define RS_WFRP 0x00060000 /* Running Wait for Receive Packet */
+#define RS_SUSP 0x00080000 /* Suspended */
+#define RS_CLRD 0x000a0000 /* Running Close Receive Descriptor */
+#define RS_FLUSH 0x000c0000 /* Running Flush RX FIFO */
+#define RS_QRFS 0x000e0000 /* Running Queue RX FIFO into RX Skb */
+
+/*
+ * Operation Mode Register (DMA_OMR)
+ */
+#define OMR_TTM 0x00400000 /* Transmit Threshold Mode */
+#define OMR_SF 0x00200000 /* Store and Forward */
+#define OMR_TR 0x0000c000 /* Threshold Control Bits */
+#define OMR_ST 0x00002000 /* Start/Stop Transmission Command */
+#define OMR_OSF 0x00000004 /* Operate on Second Frame */
+#define OMR_SR 0x00000002 /* Start/Stop Receive */
+
+#define TR_18 0x00000000 /* Threshold set to 18 (32) bytes */
+#define TR_24 0x00004000 /* Threshold set to 24 (64) bytes */
+#define TR_32 0x00008000 /* Threshold set to 32 (128) bytes */
+#define TR_40 0x0000c000 /* Threshold set to 40 (256) bytes */
+
+/*
+ * Missed Frames Counters (DMA_MFC)
+ */
+//#define MFC_CNT1 0xffff0000 /* Missed Frames Counter Bits by application */
+#define MFC_CNT1 0x0ffe0000 /* Missed Frames Counter Bits by application */
+#define MFC_CNT2 0x0000ffff /* Missed Frames Counter Bits by controller */
+
+/*
+ * Mac control Register (MAC_MCR)
+ */
+#define MCR_RA 0x80000000 /* Receive All */
+#define MCR_HBD 0x10000000 /* HeartBeat Disable */
+#define MCR_PS 0x08000000 /* Port Select */
+#define MCR_OWD 0x00800000 /* Receive own Disable */
+#define MCR_OM 0x00600000 /* Operating(loopback) Mode */
+#define MCR_FDX 0x00100000 /* Full Duplex Mode */
+#define MCR_PM 0x00080000 /* Pass All Multicast */
+#define MCR_PR 0x00040000 /* Promiscuous Mode */
+#define MCR_IF 0x00020000 /* Inverse Filtering */
+#define MCR_PB 0x00010000 /* Pass Bad Frames */
+#define MCR_HO 0x00008000 /* Hash Only Filtering Mode */
+#define MCR_HP 0x00002000 /* Hash/Perfect Receive Filtering Mode */
+#define MCR_FC 0x00001000 /* Late Collision control */
+#define MCR_BFD 0x00000800 /* Boardcast frame Disable */
+#define MCR_RED 0x00000400 /* Retry Disable */
+#define MCR_APS 0x00000100 /* Automatic pad stripping */
+#define MCR_BL 0x000000c0 /* Back off Limit */
+#define MCR_DC 0x00000020 /* Deferral check */
+#define MCR_TE 0x00000008 /* Transmitter enable */
+#define MCR_RE 0x00000004 /* Receiver enable */
+
+#define MCR_MII_10 ( OMR_TTM | MCR_PS)
+#define MCR_MII_100 ( MCR_HBD | MCR_PS)
+
+/* Flow control Register (MAC_FCR) */
+#define FCR_PT 0xffff0000 /* Pause time */
+#define FCR_PCF 0x00000004 /* Pass control frames */
+#define FCR_FCE 0x00000002 /* Flow control enable */
+#define FCR_FCB 0x00000001 /* Flow control busy */
+
+
+/* Constants for the interrupt mask and
+ * interrupt status registers. (DMA_SIS and DMA_IMR)
+ */
+#define DMA_INT_NI 0x00010000 // Normal interrupt summary
+#define DMA_INT_AI 0x00008000 // Abnormal interrupt summary
+#define DMA_INT_ER 0x00004000 // Early receive interrupt
+#define DMA_INT_FB 0x00002000 // Fatal bus error
+#define DMA_INT_ET 0x00000400 // Early transmit interrupt
+#define DMA_INT_RW 0x00000200 // Receive watchdog timeout
+#define DMA_INT_RS 0x00000100 // Receive stop
+#define DMA_INT_RU 0x00000080 // Receive buffer unavailble
+#define DMA_INT_RI 0x00000040 // Receive interrupt
+#define DMA_INT_UN 0x00000020 // Underflow
+#define DMA_INT_TJ 0x00000008 // Transmit jabber timeout
+#define DMA_INT_TU 0x00000004 // Transmit buffer unavailble
+#define DMA_INT_TS 0x00000002 // Transmit stop
+#define DMA_INT_TI 0x00000001 // Transmit interrupt
+
+/*
+ * Receive Descriptor Bit Summary
+ */
+#define R_OWN 0x80000000 /* Own Bit */
+#define RD_FF 0x40000000 /* Filtering Fail */
+#define RD_FL 0x3fff0000 /* Frame Length */
+#define RD_ES 0x00008000 /* Error Summary */
+#define RD_DE 0x00004000 /* Descriptor Error */
+#define RD_LE 0x00001000 /* Length Error */
+#define RD_RF 0x00000800 /* Runt Frame */
+#define RD_MF 0x00000400 /* Multicast Frame */
+#define RD_FS 0x00000200 /* First Descriptor */
+#define RD_LS 0x00000100 /* Last Descriptor */
+#define RD_TL 0x00000080 /* Frame Too Long */
+#define RD_CS 0x00000040 /* Collision Seen */
+#define RD_FT 0x00000020 /* Frame Type */
+#define RD_RJ 0x00000010 /* Receive Watchdog timeout*/
+#define RD_RE 0x00000008 /* Report on MII Error */
+#define RD_DB 0x00000004 /* Dribbling Bit */
+#define RD_CE 0x00000002 /* CRC Error */
+
+#define RD_RER 0x02000000 /* Receive End Of Ring */
+#define RD_RCH 0x01000000 /* Second Address Chained */
+#define RD_RBS2 0x003ff800 /* Buffer 2 Size */
+#define RD_RBS1 0x000007ff /* Buffer 1 Size */
+
+/*
+ * Transmit Descriptor Bit Summary
+ */
+#define T_OWN 0x80000000 /* Own Bit */
+#define TD_ES 0x00008000 /* Frame Aborted (error summary)*/
+#define TD_LO 0x00000800 /* Loss Of Carrier */
+#define TD_NC 0x00000400 /* No Carrier */
+#define TD_LC 0x00000200 /* Late Collision */
+#define TD_EC 0x00000100 /* Excessive Collisions */
+#define TD_HF 0x00000080 /* Heartbeat Fail */
+#define TD_CC 0x0000003c /* Collision Counter */
+#define TD_UF 0x00000002 /* Underflow Error */
+#define TD_DE 0x00000001 /* Deferred */
+
+#define TD_IC 0x80000000 /* Interrupt On Completion */
+#define TD_LS 0x40000000 /* Last Segment */
+#define TD_FS 0x20000000 /* First Segment */
+#define TD_FT1 0x10000000 /* Filtering Type */
+#define TD_SET 0x08000000 /* Setup Packet */
+#define TD_AC 0x04000000 /* Add CRC Disable */
+#define TD_TER 0x02000000 /* Transmit End Of Ring */
+#define TD_TCH 0x01000000 /* Second Address Chained */
+#define TD_DPD 0x00800000 /* Disabled Padding */
+#define TD_FT0 0x00400000 /* Filtering Type */
+#define TD_TBS2 0x003ff800 /* Buffer 2 Size */
+#define TD_TBS1 0x000007ff /* Buffer 1 Size */
+
+#define PERFECT_F 0x00000000
+#define HASH_F TD_FT0
+#define INVERSE_F TD_FT1
+#define HASH_O_F (TD_FT1 | TD_F0)
+
+/*
+ * Constant setting
+ */
+
+#define IMR_DEFAULT ( DMA_INT_TI | DMA_INT_RI | \
+ DMA_INT_TS | DMA_INT_RS | \
+ DMA_INT_TU | DMA_INT_RU | \
+ DMA_INT_FB )
+
+#define IMR_ENABLE (DMA_INT_NI | DMA_INT_AI)
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
+
+#define HASH_TABLE_LEN 512 /* Bits */
+#define HASH_BITS 0x01ff /* 9 LS bits */
+
+#define SETUP_FRAME_LEN 192 /* Bytes */
+#define IMPERF_PA_OFFSET 156 /* Bytes */
+
+/*
+ * Address Filtering Modes
+ */
+#define PERFECT 0 /* 16 perfect physical addresses */
+#define HASH_PERF 1 /* 1 perfect, 512 multicast addresses */
+#define PERFECT_REJ 2 /* Reject 16 perfect physical addresses */
+#define ALL_HASH 3 /* Hashes all physical & multicast addrs */
+
+#define ALL 0 /* Clear out all the setup frame */
+#define PHYS_ADDR_ONLY 1 /* Update the physical address only */
+
+/* MII register */
+#define MII_BMCR 0x00 /* MII Basic Mode Control Register */
+#define MII_BMSR 0x01 /* MII Basic Mode Status Register */
+#define MII_ID1 0x02 /* PHY Identifier Register 1 */
+#define MII_ID2 0x03 /* PHY Identifier Register 2 */
+#define MII_ANAR 0x04 /* Auto Negotiation Advertisement Register */
+#define MII_ANLPAR 0x05 /* Auto Negotiation Link Partner Ability */
+#define MII_ANER 0x06 /* Auto Negotiation Expansion */
+#define MII_DSCR 0x10 /* Davicom Specified Configration Register */
+#define MII_DSCSR 0x11 /* Davicom Specified Configration/Status Register */
+#define MII_10BTCSR 0x12 /* 10base-T Specified Configration/Status Register */
+
+
+#define MII_PREAMBLE 0xffffffff /* MII Management Preamble */
+#define MII_TEST 0xaaaaaaaa /* MII Test Signal */
+#define MII_STRD 0x06 /* Start of Frame+Op Code: use low nibble */
+#define MII_STWR 0x0a /* Start of Frame+Op Code: use low nibble */
+
+/*
+ * MII Management Control Register
+ */
+#define MII_CR_RST 0x8000 /* RESET the PHY chip */
+#define MII_CR_LPBK 0x4000 /* Loopback enable */
+#define MII_CR_SPD 0x2000 /* 0: 10Mb/s; 1: 100Mb/s */
+#define MII_CR_ASSE 0x1000 /* Auto Speed Select Enable */
+#define MII_CR_PD 0x0800 /* Power Down */
+#define MII_CR_ISOL 0x0400 /* Isolate Mode */
+#define MII_CR_RAN 0x0200 /* Restart Auto Negotiation */
+#define MII_CR_FDM 0x0100 /* Full Duplex Mode */
+#define MII_CR_CTE 0x0080 /* Collision Test Enable */
+
+/*
+ * MII Management Status Register
+ */
+#define MII_SR_T4C 0x8000 /* 100BASE-T4 capable */
+#define MII_SR_TXFD 0x4000 /* 100BASE-TX Full Duplex capable */
+#define MII_SR_TXHD 0x2000 /* 100BASE-TX Half Duplex capable */
+#define MII_SR_TFD 0x1000 /* 10BASE-T Full Duplex capable */
+#define MII_SR_THD 0x0800 /* 10BASE-T Half Duplex capable */
+#define MII_SR_ASSC 0x0020 /* Auto Speed Selection Complete*/
+#define MII_SR_RFD 0x0010 /* Remote Fault Detected */
+#define MII_SR_ANC 0x0008 /* Auto Negotiation capable */
+#define MII_SR_LKS 0x0004 /* Link Status */
+#define MII_SR_JABD 0x0002 /* Jabber Detect */
+#define MII_SR_XC 0x0001 /* Extended Capabilities */
+
+/*
+ * MII Management Auto Negotiation Advertisement Register
+ */
+#define MII_ANA_TAF 0x03e0 /* Technology Ability Field */
+#define MII_ANA_T4AM 0x0200 /* T4 Technology Ability Mask */
+#define MII_ANA_TXAM 0x0180 /* TX Technology Ability Mask */
+#define MII_ANA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */
+#define MII_ANA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */
+#define MII_ANA_100M 0x0380 /* 100Mb Technology Ability Mask */
+#define MII_ANA_10M 0x0060 /* 10Mb Technology Ability Mask */
+#define MII_ANA_CSMA 0x0001 /* CSMA-CD Capable */
+
+/*
+ * MII Management Auto Negotiation Remote End Register
+ */
+#define MII_ANLPA_NP 0x8000 /* Next Page (Enable) */
+#define MII_ANLPA_ACK 0x4000 /* Remote Acknowledge */
+#define MII_ANLPA_RF 0x2000 /* Remote Fault */
+#define MII_ANLPA_TAF 0x03e0 /* Technology Ability Field */
+#define MII_ANLPA_T4AM 0x0200 /* T4 Technology Ability Mask */
+#define MII_ANLPA_TXAM 0x0180 /* TX Technology Ability Mask */
+#define MII_ANLPA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */
+#define MII_ANLPA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */
+#define MII_ANLPA_100M 0x0380 /* 100Mb Technology Ability Mask */
+#define MII_ANLPA_10M 0x0060 /* 10Mb Technology Ability Mask */
+#define MII_ANLPA_CSMA 0x0001 /* CSMA-CD Capable */
+
+/*
+ * MII Management DAVICOM Specified Configuration And Status Register
+ */
+#define MII_DSCSR_100FDX 0x8000 /* 100M Full Duplex Operation Mode */
+#define MII_DSCSR_100HDX 0x4000 /* 100M Half Duplex Operation Mode */
+#define MII_DSCSR_10FDX 0x2000 /* 10M Full Duplex Operation Mode */
+#define MII_DSCSR_10HDX 0x1000 /* 10M Half Duplex Operation Mode */
+#define MII_DSCSR_ANMB 0x000f /* Auto-Negotiation Monitor Bits */
+
+
+/*
+ * Used by IOCTL
+ */
+#define READ_COMMAND (SIOCDEVPRIVATE+4)
+#define WRITE_COMMAND (SIOCDEVPRIVATE+5)
+#define GETDRIVERINFO (SIOCDEVPRIVATE+6)
+
+/*
+ * Device data and structure
+ */
+
+#define ETH_TX_TIMEOUT (6*HZ)
+
+#define RX_BUF_SIZE 1536
+
+#define NUM_RX_DESCS 32
+#define NUM_TX_DESCS 16
+
+static const char *media_types[] = {
+ "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ",
+ "100baseTx-FD", "100baseT4", 0
+};
+
+typedef struct {
+ unsigned int status;
+ unsigned int desc1;
+ unsigned int buf1_addr;
+ unsigned int next_addr;
+} jz_desc_t;
+
+struct jz_eth_private {
+ jz_desc_t tx_ring[NUM_TX_DESCS]; /* transmit descriptors */
+ jz_desc_t rx_ring[NUM_RX_DESCS]; /* receive descriptors */
+ dma_addr_t dma_tx_ring; /* bus address of tx ring */
+ dma_addr_t dma_rx_ring; /* bus address of rx ring */
+ dma_addr_t dma_rx_buf; /* DMA address of rx buffer */
+ unsigned int vaddr_rx_buf; /* virtual address of rx buffer */
+
+ unsigned int rx_head; /* first rx descriptor */
+ unsigned int tx_head; /* first tx descriptor */
+ unsigned int tx_tail; /* last unacked transmit packet */
+ unsigned int tx_full; /* transmit buffers are full */
+ struct sk_buff *tx_skb[NUM_TX_DESCS]; /* skbuffs for packets to transmit */
+
+ struct net_device_stats stats;
+ spinlock_t lock;
+
+ int media; /* Media (eg TP), mode (eg 100B)*/
+ int full_duplex; /* Current duplex setting. */
+ int link_state;
+ char phys[32]; /* List of attached PHY devices */
+ char valid_phy; /* Current linked phy-id with MAC */
+ int mii_phy_cnt;
+ int phy_type; /* 1-RTL8309,0-DVCOM */
+ struct ethtool_cmd ecmds[32];
+ u16 advertising; /* NWay media advertisement */
+
+ pid_t thr_pid; /* Link cheak thread ID */
+ int thread_die;
+ struct completion thr_exited;
+ wait_queue_head_t thr_wait;
+
+ struct pm_dev *pmdev;
+};
+
+#endif /* __JZ_ETH_H__ */
diff --git a/drivers/net/jzcs8900a.c b/drivers/net/jzcs8900a.c
new file mode 100644
index 00000000000..03aa8bce17e
--- /dev/null
+++ b/drivers/net/jzcs8900a.c
@@ -0,0 +1,646 @@
+
+/*
+ * linux/drivers/net/jzcs8900a.c
+ *
+ * Author: Lucifer <yliu@ingenic>
+ *
+ * A Cirrus Logic CS8900A driver for Linux
+ * based on the cs89x0 driver written by Russell Nelson,
+ * Donald Becker, and others.
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+/*
+ * At the moment the driver does not support memory mode operation.
+ * It is trivial to implement this, but not worth the effort.
+ */
+
+/*
+ * TODO:
+ *
+ * 1. If !ready in send_start(), queue buffer and send it in interrupt handler
+ * when we receive a BufEvent with Rdy4Tx, send it again. dangerous!
+ * 2. how do we prevent interrupt handler destroying integrity of get_stats()?
+ * 3. Change reset code to check status.
+ * 4. Implement set_mac_address and remove fake mac address
+ * 5. Link status detection stuff
+ * 6. Write utility to write EEPROM, do self testing, etc.
+ * 7. Implement DMA routines (I need a board w/ DMA support for that)
+ * 8. Power management
+ * 9. Add support for multiple ethernet chips
+ * 10. Add support for other cs89xx chips (need hardware for that)
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/jzsoc.h>
+
+#include "jzcs8900a.h"
+
+#define FULL_DUPLEX
+#define INT_PIN 0
+#ifdef CONFIG_SOC_JZ4740
+#define CIRRUS_DEFAULT_IO 0xa8000000
+#define CIRRUS_DEFAULT_IRQ 107
+
+#elif CONFIG_SOC_JZ4750
+#define CIRRUS_DEFAULT_IO 0xac000000
+
+#ifdef CONFIG_JZ4750_FUWA
+#define CIRRUS_DEFAULT_IRQ (32*4+20+48)
+#else
+#define CIRRUS_DEFAULT_IRQ (32*2 +6+48)
+#endif
+
+
+#endif
+
+typedef struct {
+ struct net_device_stats stats;
+ u16 txlen;
+} cirrus_t;
+
+static int ethaddr_cmd = 0;
+static unsigned char ethaddr_hex[6];
+static struct net_device *dev;
+
+/*
+ * I/O routines
+ */
+static void gpio_init_cs8900(void)
+{
+#ifdef CONFIG_SOC_JZ4740
+ __gpio_as_func0(60); //CS4#
+ __gpio_as_func0(61); //RD#
+ __gpio_as_func0(62); //WR#
+ __gpio_as_irq_high_level(59); //irq
+ __gpio_disable_pull(59); //disable pull
+ REG_EMC_SMCR4 |= (1 << 6); //16bit
+#elif CONFIG_SOC_JZ4750
+ __gpio_as_func0(32*2+23); //CS3#
+ __gpio_as_func0(32*2+25); //RD#
+ __gpio_as_func0(32*2+26); //WR#
+
+#ifdef CONFIG_JZ4750_FUWA
+ __gpio_as_irq_high_level(32*4+20); //irq
+ __gpio_disable_pull(32*4+20); //disable pull
+#else
+ __gpio_as_irq_high_level(32*2 +6); //irq
+ __gpio_disable_pull(32*2 +6); //disable pull
+#endif
+
+ REG_EMC_SMCR3 |= (1 << 6); //16bit
+#endif
+ udelay(1);
+}
+
+static inline u16 cirrus_read (struct net_device *dev,u16 reg)
+{
+ outw (reg,dev->base_addr + PP_Address);
+ return (inw (dev->base_addr + PP_Data));
+}
+
+static inline void cirrus_write (struct net_device *dev,u16 reg,u16 value)
+{
+ outw (reg,dev->base_addr + PP_Address);
+ outw (value,dev->base_addr + PP_Data);
+}
+
+static inline void cirrus_set (struct net_device *dev,u16 reg,u16 value)
+{
+ cirrus_write (dev,reg,cirrus_read (dev,reg) | value);
+}
+
+static inline void cirrus_clear (struct net_device *dev,u16 reg,u16 value)
+{
+ cirrus_write (dev,reg,cirrus_read (dev,reg) & ~value);
+}
+
+static inline void cirrus_frame_read (struct net_device *dev,struct sk_buff *skb,u16 length)
+{
+ insw (dev->base_addr,skb_put (skb,length),(length + 1) / 2);
+}
+
+static inline void cirrus_frame_write (struct net_device *dev,struct sk_buff *skb)
+{
+ outsw (dev->base_addr,skb->data,(skb->len + 1) / 2);
+}
+
+/*
+ * Debugging functions
+ */
+
+#ifdef DEBUG
+static inline int printable (int c)
+{
+ return ((c >= 32 && c <= 126) ||
+ (c >= 174 && c <= 223) ||
+ (c >= 242 && c <= 243) ||
+ (c >= 252 && c <= 253));
+}
+
+static void dump16 (struct net_device *dev,const u8 *s,size_t len)
+{
+ int i;
+ char str[128];
+
+ if (!len) return;
+
+ *str = '\0';
+
+ for (i = 0; i < len; i++) {
+ if (i && !(i % 4)) strcat (str," ");
+ sprintf (str,"%s%.2x ",str,s[i]);
+ }
+
+ for ( ; i < 16; i++) {
+ if (i && !(i % 4)) strcat (str," ");
+ strcat (str," ");
+ }
+
+ strcat (str," ");
+ for (i = 0; i < len; i++) sprintf (str,"%s%c",str,printable (s[i]) ? s[i] : '.');
+
+ printk (KERN_DEBUG "%s: %s\n",dev->name,str);
+}
+
+static void hexdump (struct net_device *dev,const void *ptr,size_t size)
+{
+ const u8 *s = (u8 *) ptr;
+ int i;
+ for (i = 0; i < size / 16; i++, s += 16) dump16 (dev,s,16);
+ dump16 (dev,s,size % 16);
+}
+
+static void dump_packet (struct net_device *dev,struct sk_buff *skb,const char *type)
+{
+ printk (KERN_INFO "%s: %s %d byte frame %.2x:%.2x:%.2x:%.2x:%.2x:%.2x to %.2x:%.2x:%.2x:%.2x:%.2x:%.2x type %.4x\n",
+ dev->name,
+ type,
+ skb->len,
+ skb->data[0],skb->data[1],skb->data[2],skb->data[3],skb->data[4],skb->data[5],
+ skb->data[6],skb->data[7],skb->data[8],skb->data[9],skb->data[10],skb->data[11],
+ (skb->data[12] << 8) | skb->data[13]);
+ if (skb->len < 0x100) hexdump (dev,skb->data,skb->len);
+}
+#endif /* #ifdef DEBUG */
+
+/*
+ * Driver functions
+ */
+
+static void cirrus_receive (struct net_device *dev)
+{
+ cirrus_t *priv = netdev_priv(dev);
+ struct sk_buff *skb;
+ u16 status,length;
+
+ status = cirrus_read (dev,PP_RxStatus);
+ length = cirrus_read (dev,PP_RxLength);
+
+ if (!(status & RxOK)) {
+ priv->stats.rx_errors++;
+ if ((status & (Runt | Extradata))) priv->stats.rx_length_errors++;
+ if ((status & CRCerror)) priv->stats.rx_crc_errors++;
+ return;
+ }
+
+ if ((skb = dev_alloc_skb (length + 4)) == NULL) {
+ priv->stats.rx_dropped++;
+ return;
+ }
+
+ skb->dev = dev;
+ skb_reserve (skb,2);
+
+ cirrus_frame_read (dev,skb,length);
+ skb->protocol = eth_type_trans (skb,dev);
+
+ netif_rx (skb);
+ dev->last_rx = jiffies;
+
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += length;
+}
+
+static int cirrus_send_start (struct sk_buff *skb,struct net_device *dev)
+{
+ cirrus_t *priv = netdev_priv(dev);
+ u16 status;
+
+ mdelay(10);
+ netif_stop_queue (dev);
+
+ cirrus_write (dev,PP_TxCMD,TxStart (After5));
+ cirrus_write (dev,PP_TxLength,skb->len);
+
+ status = cirrus_read (dev,PP_BusST);
+
+ if ((status & TxBidErr)) {
+ printk (KERN_WARNING "%s: Invalid frame size %d!\n",dev->name,skb->len);
+ priv->stats.tx_errors++;
+ priv->stats.tx_aborted_errors++;
+ priv->txlen = 0;
+ return (1);
+ }
+
+ if (!(status & Rdy4TxNOW)) {
+ //printk (KERN_WARNING "%s: Transmit buffer not free!\n",dev->name);
+ priv->stats.tx_errors++;
+ priv->txlen = 0;
+ /* FIXME: store skb and send it in interrupt handler */
+ return (1);
+ }
+
+ cirrus_frame_write (dev,skb);
+ dev->trans_start = jiffies;
+
+ dev_kfree_skb (skb);
+
+ priv->txlen = skb->len;
+
+ return (0);
+}
+
+static irqreturn_t cirrus_interrupt(int irq, void *id)
+{
+ struct net_device *dev = (struct net_device *) id;
+ cirrus_t *priv;
+ u16 status;
+
+ priv = (cirrus_t *) netdev_priv(dev);
+
+ while ((status = cirrus_read (dev,PP_ISQ))) {
+ switch (RegNum (status)) {
+ case RxEvent:
+ cirrus_receive (dev);
+ break;
+
+ case TxEvent:
+ priv->stats.collisions += ColCount (cirrus_read (dev,PP_TxCOL));
+ if (!(RegContent (status) & TxOK)) {
+ priv->stats.tx_errors++;
+ if ((RegContent (status) & Out_of_window)) priv->stats.tx_window_errors++;
+ if ((RegContent (status) & Jabber)) priv->stats.tx_aborted_errors++;
+ break;
+ } else if (priv->txlen) {
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += priv->txlen;
+ }
+ priv->txlen = 0;
+ netif_wake_queue (dev);
+ break;
+
+ case BufEvent:
+ if ((RegContent (status) & RxMiss)) {
+ u16 missed = MissCount (cirrus_read (dev,PP_RxMISS));
+ priv->stats.rx_errors += missed;
+ priv->stats.rx_missed_errors += missed;
+ }
+ if ((RegContent (status) & TxUnderrun)) {
+ priv->stats.tx_errors++;
+ priv->stats.tx_fifo_errors++;
+ }
+ /* FIXME: if Rdy4Tx, transmit last sent packet (if any) */
+ priv->txlen = 0;
+ netif_wake_queue (dev);
+ break;
+
+ case TxCOL:
+ priv->stats.collisions += ColCount (cirrus_read (dev,PP_TxCOL));
+ break;
+
+ case RxMISS:
+ status = MissCount (cirrus_read (dev,PP_RxMISS));
+ priv->stats.rx_errors += status;
+ priv->stats.rx_missed_errors += status;
+ break;
+ default:
+ return IRQ_HANDLED;
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void cirrus_transmit_timeout (struct net_device *dev)
+{
+ cirrus_t *priv = netdev_priv(dev);
+ priv->stats.tx_errors++;
+ priv->stats.tx_heartbeat_errors++;
+ priv->txlen = 0;
+ netif_wake_queue (dev);
+}
+
+static int cirrus_start (struct net_device *dev)
+{
+ int result;
+
+ /* valid ethernet address? */
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ printk(KERN_ERR "%s: invalid ethernet MAC address\n",dev->name);
+ return (-EINVAL);
+ }
+
+ /* install interrupt handler */
+ if ((result = request_irq (dev->irq, &cirrus_interrupt, IRQF_DISABLED, dev->name, dev)) < 0) {
+ printk (KERN_ERR "%s: could not register interrupt %d\n",dev->name,dev->irq);
+ return (result);
+ }
+
+ /* enable the ethernet controller */
+ cirrus_set (dev,PP_RxCFG,RxOKiE | BufferCRC | CRCerroriE | RuntiE | ExtradataiE);
+ cirrus_set (dev,PP_RxCTL,RxOKA | IndividualA | BroadcastA);
+ cirrus_set (dev,PP_TxCFG,TxOKiE | Out_of_windowiE | JabberiE);
+ cirrus_set (dev,PP_BufCFG,Rdy4TxiE | RxMissiE | TxUnderruniE | TxColOvfiE | MissOvfloiE);
+ cirrus_set (dev,PP_LineCTL,SerRxON | SerTxON);
+ cirrus_set (dev,PP_BusCTL,EnableRQ);
+
+#ifdef FULL_DUPLEX
+ cirrus_set (dev,PP_TestCTL,FDX);
+#endif /* #ifdef FULL_DUPLEX */
+
+ /* start the queue */
+ netif_start_queue (dev);
+ __gpio_unmask_irq(59);
+
+ //MOD_INC_USE_COUNT;
+ return (0);
+}
+
+static int cirrus_stop (struct net_device *dev)
+{
+ /* disable ethernet controller */
+ cirrus_write (dev,PP_BusCTL,0);
+ cirrus_write (dev,PP_TestCTL,0);
+ cirrus_write (dev,PP_SelfCTL,0);
+ cirrus_write (dev,PP_LineCTL,0);
+ cirrus_write (dev,PP_BufCFG,0);
+ cirrus_write (dev,PP_TxCFG,0);
+ cirrus_write (dev,PP_RxCTL,0);
+ cirrus_write (dev,PP_RxCFG,0);
+
+ /* uninstall interrupt handler */
+ free_irq (dev->irq,dev);
+
+ /* stop the queue */
+ netif_stop_queue (dev);
+
+ //MOD_DEC_USE_COUNT;
+
+ return (0);
+}
+
+static int cirrus_set_mac_address (struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = (struct sockaddr *)p;
+ int i;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ /* configure MAC address */
+ for (i = 0; i < ETH_ALEN; i += 2)
+ cirrus_write (dev,PP_IA + i,dev->dev_addr[i] | (dev->dev_addr[i + 1] << 8));
+
+ return 0;
+}
+
+static struct net_device_stats *cirrus_get_stats (struct net_device *dev)
+{
+ cirrus_t *priv = netdev_priv(dev);
+ return (&priv->stats);
+}
+
+static void cirrus_set_receive_mode (struct net_device *dev)
+{
+ if ((dev->flags & IFF_PROMISC))
+ cirrus_set (dev,PP_RxCTL,PromiscuousA);
+ else
+ cirrus_clear (dev,PP_RxCTL,PromiscuousA);
+
+ if ((dev->flags & IFF_ALLMULTI) && dev->mc_list)
+ cirrus_set (dev,PP_RxCTL,MulticastA);
+ else
+ cirrus_clear (dev,PP_RxCTL,MulticastA);
+}
+
+/*
+ * Architecture dependant code
+ */
+
+static const struct net_device_ops cirrus_netdev_ops = {
+ .ndo_open = cirrus_start,
+ .ndo_stop = cirrus_stop,
+ .ndo_get_stats = cirrus_get_stats,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = cirrus_set_mac_address,
+ .ndo_start_xmit = cirrus_send_start,
+ .ndo_set_multicast_list = cirrus_set_receive_mode,
+ .ndo_tx_timeout = cirrus_transmit_timeout,
+};
+
+/*
+ * Driver initialization routines
+ */
+
+int __init cirrus_probe(void)
+{
+ int i;
+ u16 value;
+
+ printk (JZ_SOC_NAME": CS8900A driver for Linux (V0.02)\n");
+
+ /* Init hardware for PAVO board */
+ gpio_init_cs8900();
+
+ /* Allocate ethernet device */
+ dev = alloc_etherdev(sizeof(cirrus_t));
+ if (dev == NULL) {
+ printk("Unable to alloc new net device.\n");
+ return -ENOMEM;
+ }
+
+ dev->if_port = IF_PORT_10BASET;
+ dev->base_addr = CIRRUS_DEFAULT_IO;
+ dev->irq = CIRRUS_DEFAULT_IRQ;
+ dev->watchdog_timeo = HZ;
+ dev->netdev_ops = &cirrus_netdev_ops;
+
+ if (ethaddr_cmd==1)
+ {
+ dev->dev_addr[0] = ethaddr_hex[0];
+ dev->dev_addr[1] = ethaddr_hex[1];
+ dev->dev_addr[2] = ethaddr_hex[2];
+ dev->dev_addr[3] = ethaddr_hex[3];
+ dev->dev_addr[4] = ethaddr_hex[4];
+ dev->dev_addr[5] = ethaddr_hex[5];
+ }
+ else //default mac address 00:2a:cc:2a:af:fe
+ {
+ dev->dev_addr[0] = 0x00;
+ dev->dev_addr[1] = 0x62;
+ dev->dev_addr[2] = 0xde;
+ dev->dev_addr[3] = 0xad;
+ dev->dev_addr[4] = 0xbe;
+ dev->dev_addr[5] = 0xef;
+ }
+ /* module parameters override everything */
+ if (!dev->base_addr) {
+ printk (KERN_ERR
+ "%s: No default I/O base address defined. Use io=... or\n"
+ "%s: define CIRRUS_DEFAULT_IO for your platform\n",
+ dev->name,dev->name);
+ return (-EINVAL);
+ }
+
+ if (!dev->irq) {
+ printk (KERN_ERR
+ "%s: No default IRQ number defined. Use irq=... or\n"
+ "%s: define CIRRUS_DEFAULT_IRQ for your platform\n",
+ dev->name,dev->name);
+ return (-EINVAL);
+ }
+#if 0
+ if ((result = check_region (dev->base_addr,16))) {
+ printk (KERN_ERR "%s: can't get I/O port address 0x%lx\n",dev->name,dev->base_addr);
+ return (result);
+ }
+#endif
+ if (!request_region (dev->base_addr,16,dev->name))
+ return -EBUSY;
+#if 0
+ /* verify EISA registration number for Cirrus Logic */
+ if ((value = cirrus_read (dev,PP_ProductID)) != EISA_REG_CODE) {
+ printk (KERN_ERR "%s: incorrect signature 0x%.4x\n",dev->name,value);
+ return (-ENXIO);
+ }
+#endif
+
+ /* verify chip version */
+ value = cirrus_read (dev,PP_ProductID + 2);
+ if (VERSION (value) != CS8900A) {
+ printk (KERN_ERR "%s: unknown chip version 0x%.8x\n",dev->name,VERSION (value));
+ return (-ENXIO);
+ }
+ printk (KERN_INFO "%s: CS8900A rev %c detected\n",dev->name,'B' + REVISION (value) - REV_B);
+
+ /* setup interrupt number */
+ cirrus_write (dev,PP_IntNum,INT_PIN);
+
+ /* configure MAC address */
+ for (i = 0; i < ETH_ALEN; i += 2)
+ {
+ //printk(" %x",dev->dev_addr[i] | (dev->dev_addr[i + 1] << 8));
+ cirrus_write (dev,PP_IA + i,dev->dev_addr[i] | (dev->dev_addr[i + 1] << 8));
+ }
+
+ if (register_netdev(dev) != 0) {
+ printk(KERN_ERR " Cannot register net device\n");
+ free_netdev(dev);
+ return -ENOMEM;
+ }
+
+ return (0);
+}
+
+static inline unsigned char str2hexnum(unsigned char c)
+{
+ if(c >= '0' && c <= '9')
+ return c - '0';
+ if(c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if(c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return 0; /* foo */
+}
+
+static inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+ int i;
+
+ for(i = 0; i < 6; i++) {
+ unsigned char num;
+
+ if((*str == '.') || (*str == ':'))
+ str++;
+ num = str2hexnum(*str++) << 4;
+ num |= (str2hexnum(*str++));
+ ea[i] = num;
+ }
+}
+
+static int __init ethernet_addr_setup(char *str)
+{
+ if (!str) {
+ printk("ethaddr not set in command line\n");
+ return -1;
+ }
+ ethaddr_cmd = 1;
+ str2eaddr(ethaddr_hex, str);
+ return 0;
+}
+
+__setup("ethaddr=", ethernet_addr_setup);
+
+//EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR ("Lucifer <yliu@ingenic.com>");
+MODULE_DESCRIPTION ("Jz CS8900A driver for Linux (V0.02)");
+MODULE_LICENSE ("GPL");
+
+//#ifdef MODULE
+
+
+#if 0
+static int io = 0;
+static int irq = 0;
+
+module_param(io, int, 0);
+MODULE_PARM_DESC (io,"I/O Base Address");
+//MODULE_PARM (io,"i");
+
+module_param(irq, int, 0);
+MODULE_PARM_DESC (irq,"IRQ Number");
+//MODULE_PARM (irq,"i");
+#endif
+
+static int __init jzcs8900_init(void)
+{
+ if (cirrus_probe()) {
+ printk(KERN_WARNING "jzcs8900: No cs8900a found\n");
+ }
+
+ return 0;
+}
+
+static void __exit jzcs8900_exit(void)
+{
+ release_region(dev->base_addr,16);
+ unregister_netdev(dev);
+ free_netdev(dev);
+}
+
+module_init(jzcs8900_init);
+module_exit(jzcs8900_exit);
diff --git a/drivers/net/jzcs8900a.h b/drivers/net/jzcs8900a.h
new file mode 100644
index 00000000000..68d76bb0b2e
--- /dev/null
+++ b/drivers/net/jzcs8900a.h
@@ -0,0 +1,235 @@
+#ifndef JZCS8900A_H
+#define JZCS8900A_H
+
+/*
+ * linux/drivers/net/jzcs8900a.h
+ *
+ * Author: Lucifer <yliu@ingenic>
+ *
+ * A Cirrus Logic CS8900A driver for Linux
+ * based on the cs89x0 driver written by Russell Nelson,
+ * Donald Becker, and others.
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+/*
+ * Ports
+ */
+
+#define PP_Address 0x0a /* PacketPage Pointer Port (Section 4.10.10) */
+#define PP_Data 0x0c /* PacketPage Data Port (Section 4.10.10) */
+
+/*
+ * Registers
+ */
+
+#define PP_ProductID 0x0000 /* Section 4.3.1 Product Identification Code */
+#define PP_MemBase 0x002c /* Section 4.9.2 Memory Base Address Register */
+#define PP_IntNum 0x0022 /* Section 3.2.3 Interrupt Number */
+#define PP_EEPROMCommand 0x0040 /* Section 4.3.11 EEPROM Command */
+#define PP_EEPROMData 0x0042 /* Section 4.3.12 EEPROM Data */
+#define PP_RxCFG 0x0102 /* Section 4.4.6 Receiver Configuration */
+#define PP_RxCTL 0x0104 /* Section 4.4.8 Receiver Control */
+#define PP_TxCFG 0x0106 /* Section 4.4.9 Transmit Configuration */
+#define PP_BufCFG 0x010a /* Section 4.4.12 Buffer Configuration */
+#define PP_LineCTL 0x0112 /* Section 4.4.16 Line Control */
+#define PP_SelfCTL 0x0114 /* Section 4.4.18 Self Control */
+#define PP_BusCTL 0x0116 /* Section 4.4.20 Bus Control */
+#define PP_TestCTL 0x0118 /* Section 4.4.22 Test Control */
+#define PP_ISQ 0x0120 /* Section 4.4.5 Interrupt Status Queue */
+#define PP_TxEvent 0x0128 /* Section 4.4.10 Transmitter Event */
+#define PP_BufEvent 0x012c /* Section 4.4.13 Buffer Event */
+#define PP_RxMISS 0x0130 /* Section 4.4.14 Receiver Miss Counter */
+#define PP_TxCOL 0x0132 /* Section 4.4.15 Transmit Collision Counter */
+#define PP_SelfST 0x0136 /* Section 4.4.19 Self Status */
+#define PP_BusST 0x0138 /* Section 4.4.21 Bus Status */
+#define PP_TxCMD 0x0144 /* Section 4.4.11 Transmit Command */
+#define PP_TxLength 0x0146 /* Section 4.5.2 Transmit Length */
+#define PP_IA 0x0158 /* Section 4.6.2 Individual Address (IEEE Address) */
+#define PP_RxStatus 0x0400 /* Section 4.7.1 Receive Status */
+#define PP_RxLength 0x0402 /* Section 4.7.1 Receive Length (in bytes) */
+#define PP_RxFrame 0x0404 /* Section 4.7.2 Receive Frame Location */
+#define PP_TxFrame 0x0a00 /* Section 4.7.2 Transmit Frame Location */
+
+/*
+ * Values
+ */
+
+/* PP_IntNum */
+#define INTRQ0 0x0000
+#define INTRQ1 0x0001
+#define INTRQ2 0x0002
+#define INTRQ3 0x0003
+
+/* PP_ProductID */
+#define EISA_REG_CODE 0x630e
+#define REVISION(x) (((x) & 0x1f00) >> 8)
+#define VERSION(x) ((x) & ~0x1f00)
+
+#define CS8900A 0x0000
+#define REV_B 7
+#define REV_C 8
+#define REV_D 9
+
+/* PP_RxCFG */
+#define Skip_1 0x0040
+#define StreamE 0x0080
+#define RxOKiE 0x0100
+#define RxDMAonly 0x0200
+#define AutoRxDMAE 0x0400
+#define BufferCRC 0x0800
+#define CRCerroriE 0x1000
+#define RuntiE 0x2000
+#define ExtradataiE 0x4000
+
+/* PP_RxCTL */
+#define IAHashA 0x0040
+#define PromiscuousA 0x0080
+#define RxOKA 0x0100
+#define MulticastA 0x0200
+#define IndividualA 0x0400
+#define BroadcastA 0x0800
+#define CRCerrorA 0x1000
+#define RuntA 0x2000
+#define ExtradataA 0x4000
+
+/* PP_TxCFG */
+#define Loss_of_CRSiE 0x0040
+#define SQErroriE 0x0080
+#define TxOKiE 0x0100
+#define Out_of_windowiE 0x0200
+#define JabberiE 0x0400
+#define AnycolliE 0x0800
+#define T16colliE 0x8000
+
+/* PP_BufCFG */
+#define SWint_X 0x0040
+#define RxDMAiE 0x0080
+#define Rdy4TxiE 0x0100
+#define TxUnderruniE 0x0200
+#define RxMissiE 0x0400
+#define Rx128iE 0x0800
+#define TxColOvfiE 0x1000
+#define MissOvfloiE 0x2000
+#define RxDestiE 0x8000
+
+/* PP_LineCTL */
+#define SerRxON 0x0040
+#define SerTxON 0x0080
+#define AUIonly 0x0100
+#define AutoAUI_10BT 0x0200
+#define ModBackoffE 0x0800
+#define PolarityDis 0x1000
+#define L2_partDefDis 0x2000
+#define LoRxSquelch 0x4000
+
+/* PP_SelfCTL */
+#define RESET 0x0040
+#define SWSuspend 0x0100
+#define HWSleepE 0x0200
+#define HWStandbyE 0x0400
+#define HC0E 0x1000
+#define HC1E 0x2000
+#define HCB0 0x4000
+#define HCB1 0x8000
+
+/* PP_BusCTL */
+#define ResetRxDMA 0x0040
+#define DMAextend 0x0100
+#define UseSA 0x0200
+#define MemoryE 0x0400
+#define DMABurst 0x0800
+#define IOCHRDYE 0x1000
+#define RxDMAsize 0x2000
+#define EnableRQ 0x8000
+
+/* PP_TestCTL */
+#define DisableLT 0x0080
+#define ENDECloop 0x0200
+#define AUIloop 0x0400
+#define DisableBackoff 0x0800
+#define FDX 0x4000
+
+/* PP_ISQ */
+#define RegNum(x) ((x) & 0x3f)
+#define RegContent(x) ((x) & ~0x3d)
+
+#define RxEvent 0x0004
+#define TxEvent 0x0008
+#define BufEvent 0x000c
+#define RxMISS 0x0010
+#define TxCOL 0x0012
+
+/* PP_RxStatus */
+#define IAHash 0x0040
+#define Dribblebits 0x0080
+#define RxOK 0x0100
+#define Hashed 0x0200
+#define IndividualAdr 0x0400
+#define Broadcast 0x0800
+#define CRCerror 0x1000
+#define Runt 0x2000
+#define Extradata 0x4000
+
+#define HashTableIndex(x) ((x) >> 0xa)
+
+/* PP_TxCMD */
+#define After5 0
+#define After381 1
+#define After1021 2
+#define AfterAll 3
+#define TxStart(x) ((x) << 6)
+
+#define Force 0x0100
+#define Onecoll 0x0200
+#define InhibitCRC 0x1000
+#define TxPadDis 0x2000
+
+/* PP_BusST */
+#define TxBidErr 0x0080
+#define Rdy4TxNOW 0x0100
+
+/* PP_TxEvent */
+#define Loss_of_CRS 0x0040
+#define SQEerror 0x0080
+#define TxOK 0x0100
+#define Out_of_window 0x0200
+#define Jabber 0x0400
+#define T16coll 0x8000
+
+#define TX_collisions(x) (((x) >> 0xb) & ~0x8000)
+
+/* PP_BufEvent */
+#define SWint 0x0040
+#define RxDMAFrame 0x0080
+#define Rdy4Tx 0x0100
+#define TxUnderrun 0x0200
+#define RxMiss 0x0400
+#define Rx128 0x0800
+#define RxDest 0x8000
+
+/* PP_RxMISS */
+#define MissCount(x) ((x) >> 6)
+
+/* PP_TxCOL */
+#define ColCount(x) ((x) >> 6)
+
+/* PP_SelfST */
+#define T3VActive 0x0040
+#define INITD 0x0080
+#define SIBUSY 0x0100
+#define EEPROMpresent 0x0200
+#define EEPROMOK 0x0400
+#define ELpresent 0x0800
+#define EEsize 0x1000
+
+/* PP_EEPROMCommand */
+#define EEWriteRegister 0x0100
+#define EEReadRegister 0x0200
+#define EEEraseRegister 0x0300
+#define ELSEL 0x0400
+
+#endif /* #ifndef CIRRUS_H */
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index fb867a9f55e..c1c381384c1 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -194,7 +194,7 @@ static const struct serial8250_config uart_config[] = {
[PORT_16550A] = {
.name = "16550A",
.fifo_size = 16,
- .tx_loadsz = 16,
+ .tx_loadsz = 8,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO,
},
@@ -401,6 +401,10 @@ static unsigned int mem_serial_in(struct uart_port *p, int offset)
static void mem_serial_out(struct uart_port *p, int offset, int value)
{
offset = map_8250_out_reg(p, offset) << p->regshift;
+#if defined(CONFIG_JZSOC)
+ if (offset == (UART_FCR << p->regshift))
+ value |= 0x10; /* set FCR.UUE */
+#endif
writeb(value, p->membase + offset);
}
@@ -2213,6 +2217,83 @@ static void serial8250_shutdown(struct uart_port *port)
serial_unlink_irq_chain(up);
}
+#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
+static unsigned short quot1[3] = {0}; /* quot[0]:baud_div, quot[1]:umr, quot[2]:uacr */
+static unsigned short * serial8250_get_divisor(struct uart_port *port, unsigned int baud)
+{
+ int err, sum, i, j;
+ int a[12], b[12];
+ unsigned short div, umr, uacr;
+ unsigned short umr_best, div_best, uacr_best;
+ long long t0, t1, t2, t3;
+
+ sum = 0;
+ umr_best = div_best = uacr_best = 0;
+ div = 1;
+
+ if ((port->uartclk % (16 * baud)) == 0) {
+ quot1[0] = port->uartclk / (16 * baud);
+ quot1[1] = 16;
+ quot1[2] = 0;
+ return quot1;
+ }
+
+ while (1) {
+ umr = port->uartclk / (baud * div);
+ if (umr > 32) {
+ div++;
+ continue;
+ }
+ if (umr < 4) {
+ break;
+ }
+ for (i = 0; i < 12; i++) {
+ a[i] = umr;
+ b[i] = 0;
+ sum = 0;
+ for (j = 0; j <= i; j++) {
+ sum += a[j];
+ }
+
+ /* the precision could be 1/2^(36) due to the value of t0 */
+ t0 = 0x1000000000LL;
+ t1 = (i + 1) * t0;
+ t2 = (sum * div) * t0;
+ t3 = div * t0;
+ do_div(t1, baud);
+ do_div(t2, port->uartclk);
+ do_div(t3, (2 * port->uartclk));
+ err = t1 - t2 - t3;
+
+ if (err > 0) {
+ a[i] += 1;
+ b[i] = 1;
+ }
+ }
+
+ uacr = 0;
+ for (i = 0; i < 12; i++) {
+ if (b[i] == 1) {
+ uacr |= 1 << i;
+ }
+ }
+
+ /* the best value of umr should be near 16, and the value of uacr should better be smaller */
+ if (abs(umr - 16) < abs(umr_best - 16) || (abs(umr - 16) == abs(umr_best - 16) && uacr_best > uacr)) {
+ div_best = div;
+ umr_best = umr;
+ uacr_best = uacr;
+ }
+ div++;
+ }
+
+ quot1[0] = div_best;
+ quot1[1] = umr_best;
+ quot1[2] = uacr_best;
+
+ return quot1;
+}
+#else
static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
{
unsigned int quot;
@@ -2232,6 +2313,7 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int
return quot;
}
+#endif
static void
serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
@@ -2241,6 +2323,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int baud, quot;
+#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
+ unsigned short *quot1;
+#endif
switch (termios->c_cflag & CSIZE) {
case CS5:
@@ -2273,7 +2358,12 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
+ quot1 = serial8250_get_divisor(port, baud);
+ quot = quot1[0]; /* not usefull, just let gcc happy */
+#else
quot = serial8250_get_divisor(port, baud);
+#endif
/*
* Oxford Semi 952 rev B workaround
@@ -2351,6 +2441,10 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
if (up->capabilities & UART_CAP_UUE)
up->ier |= UART_IER_UUE | UART_IER_RTOIE;
+#ifdef CONFIG_JZSOC
+ up->ier |= UART_IER_RTOIE; /* Set this flag, or very slow */
+#endif
+
serial_out(up, UART_IER, up->ier);
if (up->capabilities & UART_CAP_EFR) {
@@ -2385,7 +2479,15 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
}
+#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
+#define UART_UMR 9
+#define UART_UACR 10
+ serial_dl_write(up, quot1[0]);
+ serial_outp(up, UART_UMR, quot1[1]);
+ serial_outp(up, UART_UACR, quot1[2]);
+#else
serial_dl_write(up, quot);
+#endif
/*
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
@@ -2819,6 +2921,7 @@ static int __init serial8250_console_init(void)
nr_uarts = UART_NR;
serial8250_isa_init_ports();
+
register_console(&serial8250_console);
return 0;
}
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index dcd49f1e96d..a520bed1f4b 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -44,6 +44,7 @@ config USB_ARCH_HAS_OHCI
default y if PPC_MPC52xx
# MIPS:
default y if SOC_AU1X00
+ default y if JZSOC
# SH:
default y if CPU_SUBTYPE_SH7720
default y if CPU_SUBTYPE_SH7721
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 71f86c60d83..01e5f04a422 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -80,6 +80,41 @@ struct usb_hub {
struct delayed_work init_work;
};
+#if defined (CONFIG_USB_OHCI_HCD) && (CONFIG_JZSOC)
+/* JZ USB Root Hub Workaround - River. */
+static inline int is_root_hub(struct usb_device *udev)
+{
+ return (udev->parent == NULL);
+}
+
+static inline int jz_usb_hub_workaround(struct usb_hub *hub, int port1)
+{
+ if (!is_root_hub(hub->hdev))
+ return 0;
+
+#ifdef CONFIG_SOC_JZ4730
+ /*
+ * On Jz4730, we assume that the first USB port was used as device.
+ * If not, please comment next lines.
+ */
+ if ((port1 == 1)) {
+ return 1;
+ }
+#endif
+
+#if defined(CONFIG_SOC_JZ4740) || defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D)
+ /*
+ * On Jz4740 and Jz4750, the second USB port was used as device.
+ */
+ if ((port1 == 2)) {
+ return 1;
+ }
+#endif
+ return 0;
+}
+#else
+#define jz_usb_hub_workaround(hub, port1) 0
+#endif
/* Protect struct usb_device->state and ->children members
* Note: Both are also protected by ->dev.sem, except that ->state can
@@ -1857,6 +1892,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
{
int i, status;
+ if (jz_usb_hub_workaround(hub, port1))
+ return 0;
+
/* Block EHCI CF initialization during the port reset.
* Some companion controllers don't like it when they mix.
*/
@@ -2724,7 +2762,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = -ENOMSG;
goto fail;
}
-
+
retval = 0;
fail:
@@ -2819,10 +2857,13 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
struct usb_device *udev;
int status, i;
+ if (jz_usb_hub_workaround(hub, port1))
+ return;
+
dev_dbg (hub_dev,
"port %d, status %04x, change %04x, %s\n",
port1, portstatus, portchange, portspeed (portstatus));
-
+
if (hub->has_indicators) {
set_port_led(hub, port1, HUB_LED_AUTO);
hub->indicator[port1-1] = INDICATOR_AUTO;
@@ -3133,7 +3174,7 @@ static void hub_events(void)
hub->nerrors = 0;
hub->error = 0;
}
-
+
/* deal with port status changes */
for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
if (test_bit(i, hub->busy_bits))
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 7f8e83a954a..a116704166f 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -121,6 +121,74 @@ choice
#
# Integrated controllers
#
+config USB_GADGET_JZ4740
+ boolean "JZ4740 UDC"
+ depends on SOC_JZ4740
+ select USB_GADGET_DUALSPEED
+ help
+ Select this to support the Ingenic JZ4740 processor
+ high speed USB device controller.
+
+config USB_JZ4740
+ tristate
+ depends on USB_GADGET_JZ4740
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+config USB_GADGET_JZ4750
+ boolean "JZ4750 UDC"
+ depends on SOC_JZ4750
+ select USB_GADGET_DUALSPEED
+ help
+ Select this to support the Ingenic JZ4750 processor
+ high speed USB device controller.
+
+config USB_JZ4750
+ tristate
+ depends on USB_GADGET_JZ4750
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+config USB_GADGET_JZ4750D
+ boolean "JZ4750D UDC"
+ depends on SOC_JZ4750D
+ select USB_GADGET_DUALSPEED
+ help
+ Select this to support the Ingenic JZ4750D processor
+ high speed USB device controller.
+
+config USB_JZ4750D
+ tristate
+ depends on USB_GADGET_JZ4750D
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+config USB_GADGET_JZ4750L
+ boolean "JZ4750L UDC"
+ depends on SOC_JZ4750L
+ select USB_GADGET_DUALSPEED
+ help
+ Select this to support the Ingenic JZ4750D processor
+ high speed USB device controller.
+
+config USB_JZ4750L
+ tristate
+ depends on USB_GADGET_JZ4750L
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+config USB_GADGET_JZ4730
+ boolean "JZ4730 UDC"
+ depends on SOC_JZ4730
+ help
+ Select this to support the Ingenic JZ4730 processor
+ full speed USB device controller.
+
+config USB_JZ4730
+ tristate
+ depends on USB_GADGET_JZ4730
+ default USB_GADGET
+ select USB_GADGET_SELECTED
config USB_GADGET_AT91
boolean "Atmel AT91 USB Device Port"
@@ -542,6 +610,10 @@ config USB_GADGET_DUALSPEED
Means that gadget drivers should include extra descriptors
and code to handle dual-speed controllers.
+config JZ_UDC_HOTPLUG
+ bool "Support Ingenic USB Device Controller Hotplug"
+ depends on JZSOC
+
#
# USB Gadget Drivers
#
@@ -702,6 +774,14 @@ config USB_FILE_STORAGE_TEST
behavior of USB Mass Storage hosts. Not needed for
normal operation.
+config UDC_USE_LB_CACHE
+ bool "enable lb cache"
+ depends on USB_FILE_STORAGE && (SOC_JZ4740 || SOC_JZ4750 || SOC_JZ4750D)
+ default y
+ help
+ say "y" to enable lb cache and UDC work in faster speed.
+ say "n" to disable lb cache and UDC work in normal speed.
+
config USB_G_SERIAL
tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
help
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e6017e6bf6d..5bf1ccf3fe7 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -27,6 +27,11 @@ obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o
obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
+obj-$(CONFIG_USB_JZ4730) += jz4730_udc.o
+obj-$(CONFIG_USB_JZ4740) += jz4740_udc.o
+obj-$(CONFIG_USB_JZ4750) += jz4740_udc.o
+obj-$(CONFIG_USB_JZ4750D) += jz4740_udc.o
+obj-$(CONFIG_USB_JZ4750L) += jz4740_udc.o
#
# USB gadget drivers
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 1e6aa504d58..243695aab67 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -297,7 +297,18 @@ MODULE_LICENSE("Dual BSD/GPL");
/*-------------------------------------------------------------------------*/
+#if defined(CONFIG_UDC_USE_LB_CACHE)
+#define GHOST
+#endif
+#ifdef GHOST
+extern unsigned long udc_read(unsigned long long offset, unsigned int len, unsigned char *);
+extern unsigned long udc_write(unsigned long long offset, unsigned int len, unsigned char *);
+extern int NAND_LB_Init(void);
+extern int NAND_LB_FLASHCACHE(void);
+extern int NAND_MTD_FLASHCACHE(void);
+extern int FlushDataState;
+#endif
#define LDBG(lun,fmt,args...) \
dev_dbg(&(lun)->dev , fmt , ## args)
#define MDBG(fmt,args...) \
@@ -369,8 +380,8 @@ static struct {
} mod_data = { // Default values
.transport_parm = "BBB",
.protocol_parm = "SCSI",
- .removable = 0,
- .can_stall = 1,
+ .removable = 1,
+ .can_stall = 0,
.cdrom = 0,
.vendor = DRIVER_VENDOR_ID,
.product = DRIVER_PRODUCT_ID,
@@ -580,6 +591,9 @@ struct lun {
u32 sense_data_info;
u32 unit_attention_data;
+#ifdef GHOST
+ unsigned int is_nand;
+#endif
struct device dev;
};
@@ -714,6 +728,11 @@ struct fsg_dev {
unsigned int nluns;
struct lun *luns;
struct lun *curlun;
+
+#ifdef GHOST
+ unsigned int nand_lb_active;
+#endif
+
};
typedef void (*fsg_routine_t)(struct fsg_dev *);
@@ -1627,9 +1646,19 @@ static int do_read(struct fsg_dev *fsg)
/* Perform the read */
file_offset_tmp = file_offset;
+#ifdef GHOST
+ if (curlun->is_nand)
+ nread = udc_read(file_offset_tmp, amount, bh->buf);
+ else
+ nread = vfs_read(curlun->filp,
+ (char __user *) bh->buf,
+ amount, &file_offset_tmp);
+#else
nread = vfs_read(curlun->filp,
(char __user *) bh->buf,
amount, &file_offset_tmp);
+#endif
+
VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset,
(int) nread);
@@ -1813,9 +1842,18 @@ static int do_write(struct fsg_dev *fsg)
/* Perform the write */
file_offset_tmp = file_offset;
+#ifdef GHOST
+ if (curlun->is_nand)
+ nwritten = udc_write(file_offset_tmp, amount, bh->buf);
+ else
+ nwritten = vfs_write(curlun->filp,
+ (char __user *) bh->buf,
+ amount, &file_offset_tmp);
+#else
nwritten = vfs_write(curlun->filp,
(char __user *) bh->buf,
amount, &file_offset_tmp);
+#endif
VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset,
(int) nwritten);
@@ -1974,9 +2012,18 @@ static int do_verify(struct fsg_dev *fsg)
/* Perform the read */
file_offset_tmp = file_offset;
+#ifdef GHOST
+ if (curlun->is_nand)
+ nread = udc_read(file_offset_tmp, amount, bh->buf);
+ else
+ nread = vfs_read(curlun->filp,
+ (char __user *) bh->buf,
+ amount, &file_offset_tmp);
+#else
nread = vfs_read(curlun->filp,
(char __user *) bh->buf,
amount, &file_offset_tmp);
+#endif
VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset,
(int) nread);
@@ -2011,7 +2058,7 @@ static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
u8 *buf = (u8 *) bh->buf;
- static char vendor_id[] = "Linux ";
+ static char vendor_id[] = "Ingenic ";
static char product_disk_id[] = "File-Stor Gadget";
static char product_cdrom_id[] = "File-CD Gadget ";
@@ -2992,6 +3039,15 @@ static int do_scsi_command(struct fsg_dev *fsg)
reply = check_command(fsg, 6, DATA_DIR_NONE,
0, 1,
"TEST UNIT READY");
+#ifdef GHOST
+ if( FlushDataState >= 1)
+ FlushDataState++;
+ if(FlushDataState > 6)
+ {
+ NAND_LB_FLASHCACHE();
+ FlushDataState = 0;
+ }
+#endif
break;
/* Although optional, this command is used by MS-Windows. We
@@ -3544,6 +3600,15 @@ static int fsg_main_thread(void *fsg_)
/* The main loop */
while (fsg->state != FSG_STATE_TERMINATED) {
+#ifdef GHOST
+ if (fsg->nand_lb_active && (test_bit(SUSPENDED, &fsg->atomic_bitflags)))
+ {
+ NAND_LB_FLASHCACHE();
+
+ /* Don't use resume() to clear this flag - It seems inaccurate. We clear it ourself. */
+ clear_bit(SUSPENDED, &fsg->atomic_bitflags);
+ }
+#endif
if (exception_in_progress(fsg) || signal_pending(current)) {
handle_exception(fsg);
continue;
@@ -3676,6 +3741,17 @@ static int open_backing_file(struct lun *curlun, const char *filename)
LDBG(curlun, "open backing file: %s\n", filename);
rc = 0;
+#ifdef GHOST
+ if (strstr(filename,"mtdblock")) {
+ if (!the_fsg->nand_lb_active) {
+ NAND_LB_Init();
+ }
+
+ the_fsg->nand_lb_active++;
+ curlun->is_nand = 1;
+ }
+#endif
+
out:
filp_close(filp, current->files);
return rc;
@@ -3684,6 +3760,16 @@ out:
static void close_backing_file(struct lun *curlun)
{
+
+#ifdef GHOST
+ if (curlun->is_nand) {
+ the_fsg->nand_lb_active--;
+ curlun->is_nand = 0;
+
+ NAND_LB_FLASHCACHE();
+ }
+#endif
+
if (curlun->filp) {
LDBG(curlun, "close backing file\n");
fput(curlun->filp);
@@ -4141,8 +4227,13 @@ static int __init fsg_bind(struct usb_gadget *gadget)
if (IS_ERR(p))
p = NULL;
}
+#ifdef GHOST
+ LINFO(curlun, "ro=%d, is_nand=%d, file: %s\n",
+ curlun->ro, curlun->is_nand, (p ? p : "(error)"));
+#else
LINFO(curlun, "ro=%d, file: %s\n",
curlun->ro, (p ? p : "(error)"));
+#endif
}
}
kfree(pathbuf);
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 8e0e9a0b736..677f012b2ce 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -15,6 +15,30 @@
#ifndef __GADGET_CHIPS_H
#define __GADGET_CHIPS_H
+#ifdef CONFIG_USB_GADGET_JZ4750D
+#define gadget_is_jz4750d(g) !strcmp("jz4740_udc", (g)->name)
+#else
+#define gadget_is_jz4750d(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_JZ4750
+#define gadget_is_jz4750(g) !strcmp("jz4740_udc", (g)->name)
+#else
+#define gadget_is_jz4750(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_JZ4740
+#define gadget_is_jz4740(g) !strcmp("jz4740_udc", (g)->name)
+#else
+#define gadget_is_jz4740(g) 0
+#endif
+
+#ifdef CONFIG_USB_GADGET_JZ4730
+#define gadget_is_jz4730(g) !strcmp("jz4730_udc", (g)->name)
+#else
+#define gadget_is_jz4730(g) 0
+#endif
+
#ifdef CONFIG_USB_GADGET_NET2280
#define gadget_is_net2280(g) !strcmp("net2280", (g)->name)
#else
@@ -239,6 +263,15 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x23;
else if (gadget_is_langwell(gadget))
return 0x24;
+ else if (gadget_is_jz4730(gadget))
+ return 0x25;
+ else if (gadget_is_jz4740(gadget))
+ return 0x26;
+ else if (gadget_is_jz4750(gadget))
+ return 0x27;
+ else if (gadget_is_jz4750d(gadget))
+ return 0x28;
+
return -ENOENT;
}
diff --git a/drivers/usb/gadget/jz4730_udc.c b/drivers/usb/gadget/jz4730_udc.c
new file mode 100644
index 00000000000..fb182a66800
--- /dev/null
+++ b/drivers/usb/gadget/jz4730_udc.c
@@ -0,0 +1,1403 @@
+/*
+ * JZ4730 USB Device Controller driver
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/*
+ * This device has ep0 and six bulk/interrupt/iso endpoints.
+ *
+ * - Endpoint numbering is fixed: ep0, ep1in-int, ep2in-bulk, ep3in-bulk,
+ * ep4in-iso, ep5out-bulk, ep6out-bulk, ep7out-iso.
+ * - Gadget drivers can choose ep maxpacket (8/16/32/64).
+ * - Just PIO mode currently.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/usb.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include <asm-mips/mach-jz4730/regs.h>
+#include <asm-mips/mach-jz4730/ops.h>
+
+#include "jz4730_udc.h"
+
+//#define DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args)
+//#define DEBUG_EP0(fmt,args...) printk(KERN_DEBUG fmt , ## args)
+
+#ifndef DEBUG
+# define DEBUG(fmt,args...) do {} while(0)
+#endif
+#ifndef DEBUG_EP0
+# define DEBUG_EP0(fmt,args...) do {} while(0)
+#endif
+
+#define DRIVER_DESC "JZ4730 USB Device Controller"
+#define DRIVER_VERSION "20 Sep 2007"
+
+static const char driver_name [] = "jz4730_udc";
+static const char driver_desc [] = DRIVER_DESC;
+
+static unsigned int udc_debug = 0; /* 0: normal mode, 1: test udc cable type mode */
+
+module_param(udc_debug, int, 0);
+MODULE_PARM_DESC(udc_debug, "test udc cable type");
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+extern int jz_udc_active; /* 0: No actions; 1: Have actions */
+#endif
+
+/*
+ * Local declarations.
+ */
+static void nuke(struct jz4730_ep *, int status);
+static inline void pio_irq_enable(struct jz4730_ep *ep);
+static inline void pio_irq_disable(struct jz4730_ep *ep);
+static void jz4730_udc_release (struct device *dev) {}
+/*-------------------------------------------------------------------------*/
+
+static int jz4730_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct jz4730_udc *dev;
+ struct jz4730_ep *ep;
+ unsigned long flags;
+ u32 max;
+
+ ep = container_of(_ep, struct jz4730_ep, ep);
+ if (!_ep || !desc || ep->desc
+ || desc->bDescriptorType != USB_DT_ENDPOINT)
+ return -EINVAL;
+ dev = ep->dev;
+ if (ep == &dev->ep[0])
+ return -EINVAL;
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+ if (ep->index != (desc->bEndpointAddress & 0x0f))
+ return -EINVAL;
+
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+// max = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
+ max = 64;
+ ep->is_in = (USB_DIR_IN & desc->bEndpointAddress) != 0;
+
+ spin_lock_irqsave(&ep->dev->lock, flags);
+
+ ep->stopped = 0;
+ ep->desc = desc;
+ ep->ep.maxpacket = max;
+
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+ DEBUG("enable %s %s maxpacket %u\n", ep->ep.name,
+ ep->is_in ? "IN" : "OUT", max);
+
+ return 0;
+}
+
+static int jz4730_ep_disable(struct usb_ep *_ep)
+{
+ struct jz4730_ep *ep;
+ struct jz4730_udc *dev;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct jz4730_ep, ep);
+ if (!_ep || !ep->desc)
+ return -ENODEV;
+ dev = ep->dev;
+ if (dev->ep0state == EP0_SUSPEND)
+ return -EBUSY;
+
+ DEBUG("disable %s\n", _ep->name);
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* Nuke all pending requests */
+ nuke(ep, -ESHUTDOWN);
+
+ /* Disable ep IRQ */
+ pio_irq_disable(ep);
+
+ ep->desc = 0;
+ ep->stopped = 1;
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return 0;
+}
+
+static struct usb_request *jz4730_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+ struct jz4730_request *req;
+
+ req = kzalloc(sizeof *req, gfp_flags);
+ if (!req)
+ return 0;
+
+ INIT_LIST_HEAD(&req->queue);
+ return &req->req;
+}
+
+static void jz4730_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct jz4730_request *req;
+
+ req = container_of(_req, struct jz4730_request, req);
+ WARN_ON(!list_empty(&req->queue));
+ kfree(req);
+}
+
+static void *jz4730_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
+ dma_addr_t *dma, gfp_t gfp_flags)
+{
+ void *retval;
+
+ retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA | __GFP_HIGHMEM));
+ if (retval)
+ *dma = virt_to_phys(retval);
+ return retval;
+}
+
+static void jz4730_free_buffer(struct usb_ep *_ep, void *buf,
+ dma_addr_t dma, unsigned bytes)
+{
+ kfree(buf);
+}
+
+/*
+ * done - retire a request; caller blocked irqs
+ */
+static void done(struct jz4730_ep *ep, struct jz4730_request *req, int status)
+{
+ struct jz4730_udc *dev;
+ unsigned stopped = ep->stopped;
+
+ list_del_init(&req->queue);
+
+ if (likely(req->req.status == -EINPROGRESS))
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ if (status && status != -ESHUTDOWN)
+ DEBUG("complete %s req %p stat %d len %u/%u\n",
+ ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+
+ dev = ep->dev;
+
+ /* don't modify queue heads during completion callback */
+ ep->stopped = 1;
+ spin_unlock(&dev->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&dev->lock);
+ ep->stopped = stopped;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static __inline__ int write_packet(struct jz4730_ep *ep,
+ struct jz4730_request *req, int max)
+{
+ u8 *buf;
+ int length, nlong, nbyte;
+ volatile u32 *fifo = (volatile u32 *)ep->fifo;
+
+ buf = req->req.buf + req->req.actual;
+ prefetch(buf);
+
+ length = req->req.length - req->req.actual;
+ length = min(length, max);
+ req->req.actual += length;
+
+ DEBUG("Write %d (max %d), fifo %p\n", length, max, fifo);
+
+ if (!length) {
+ /* Send ZLP */
+ writel(0, (unsigned int *)UDC_TXZLP);
+ writel(0x12345678, (unsigned int *)fifo);
+ }
+ else {
+ nlong = length >> 2;
+ nbyte = length & 0x3;
+ while (nlong--) {
+ *fifo = *((u32 *)buf);
+ buf += 4;
+ }
+ while (nbyte--) {
+ *((volatile u8 *)fifo) = *buf++;
+ }
+ }
+
+ writel(0, (unsigned int *)UDC_TXCONFIRM);
+
+ return length;
+}
+
+static __inline__ int read_packet(struct jz4730_ep *ep,
+ struct jz4730_request *req, int count)
+{
+ u8 *buf;
+ int length, nlong, nbyte;
+ volatile u32 *fifo = (volatile u32 *)ep->fifo;
+
+ buf = req->req.buf + req->req.actual;
+ prefetchw(buf);
+
+ length = req->req.length - req->req.actual;
+ length = min(length, count);
+ req->req.actual += length;
+
+ DEBUG("Read %d, fifo %p\n", length, fifo);
+
+ nlong = length >> 2;
+ nbyte = length & 0x3;
+ while (nlong--) {
+ *((u32 *)buf) = *fifo;
+ buf += 4;
+ }
+ if (nbyte) {
+ u32 data = *fifo;
+ while (nbyte--) {
+ *buf++ = data & 0x0ff;
+ data >>= 8;
+ }
+ }
+
+ REG32(UDC_RXCONFIRM);
+
+ return length;
+}
+
+/** Write request to FIFO (max write == maxp size)
+ * Return: 0 = still running, 1 = completed, negative = errno
+ */
+static int write_fifo(struct jz4730_ep *ep, struct jz4730_request *req)
+{
+ u32 max, count;
+ int is_last;
+
+ max = ep->ep.maxpacket;
+
+ count = write_packet(ep, req, max);
+
+ /* last packet often short (sometimes a zlp, especially on ep0) */
+ if (unlikely(count != max)) {
+ is_last = 1;
+ } else {
+ if (likely(req->req.length != req->req.actual)
+ || req->req.zero)
+ is_last = 0;
+ else
+ is_last = 1;
+ }
+
+ DEBUG("write %s (%d)(IN) %d bytes%s req %p %d/%d is_last %d\n",
+ ep->ep.name, ep->index, count,
+ (count != ep->ep.maxpacket) ? " (short)" : "",
+ req, req->req.actual, req->req.length, is_last);
+
+ /* requests complete when all IN data is in the FIFO,
+ * or sometimes later, if a zlp was needed.
+ */
+ if (is_last) {
+ done(ep, req, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Read to request from FIFO (max read == bytes in fifo)
+ * Return: 0 = still running, 1 = completed, negative = errno
+ */
+static int read_fifo(struct jz4730_ep *ep, struct jz4730_request *req, u32 count)
+{
+ int is_short;
+
+ is_short = (count < ep->ep.maxpacket);
+
+ count = read_packet(ep, req, count);
+
+ DEBUG("read %s %u bytes%s OUT req %p %u/%u is_short %d\n",
+ ep->ep.name, count, (count < ep->ep.maxpacket) ? "(short)" : "",
+ req, req->req.actual, req->req.length, is_short);
+
+ /* completion */
+ if (is_short || req->req.actual == req->req.length) {
+ done(ep, req, 0);
+ return 1;
+ }
+
+ /* finished that packet. the next one may be waiting... */
+ return 0;
+}
+
+static inline void pio_irq_enable(struct jz4730_ep *ep)
+{
+ switch (ep->index) {
+ case 0:
+ REG_UDC_EPIntMR &= ~0x1;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ REG_UDC_EPIntMR &= ~(1 << ep->index);
+ break;
+ case 5:
+ case 6:
+ case 7:
+ REG_UDC_EPIntMR &= ~(1 << (ep->index + 16));
+ break;
+ }
+}
+
+static inline void pio_irq_disable(struct jz4730_ep *ep)
+{
+ switch (ep->index) {
+ case 0:
+ REG_UDC_EPIntMR |= 0x1;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ REG_UDC_EPIntMR |= (1 << ep->index);
+ break;
+ case 5:
+ case 6:
+ case 7:
+ REG_UDC_EPIntMR |= (1 << (ep->index + 16));
+ break;
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+jz4730_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct jz4730_request *req;
+ struct jz4730_ep *ep;
+ struct jz4730_udc *dev;
+ unsigned long flags;
+ int status;
+
+ /* always require a cpu-view buffer so pio works */
+ req = container_of(_req, struct jz4730_request, req);
+ if (unlikely(!_req || !_req->complete
+ || !_req->buf || !list_empty(&req->queue)))
+ return -EINVAL;
+ ep = container_of(_ep, struct jz4730_ep, ep);
+ if (unlikely(!_ep || (!ep->desc && ep->index != 0)))
+ return -EINVAL;
+ dev = ep->dev;
+ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
+ return -ESHUTDOWN;
+
+ DEBUG("%s queue req %p, len %u buf %p\n",
+ _ep->name, _req, _req->length, _req->buf);
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ /* for ep0 IN without premature status, zlp is required and
+ * writing EOP starts the status stage (OUT).
+ */
+ if (unlikely(ep->index == 0 && ep->is_in))
+ _req->zero = 1;
+
+ /* kickstart this i/o queue? */
+ status = 0;
+ if (list_empty(&ep->queue) && likely(!ep->stopped)) {
+ if (unlikely(ep->index == 0)) {
+ pio_irq_enable(ep);
+ if (ep->irq_pending ||
+ (REG_UDC_EPIntR & UDC_EPIntR_OUTEP0)) {
+ u32 stats, count;
+
+ stats = REG_UDC_EP0OutSR;
+ if (stats & UDC_EPSR_OUT_RCVDATA) {
+ ep->irq_pending = 0;
+ REG_UDC_EP0OutSR &= ~UDC_EPSR_OUT_MASK;
+ if (REG_UDC_EPIntR & UDC_EPIntR_OUTEP0)
+ REG_UDC_EPIntR = UDC_EPIntR_OUTEP0;
+
+ count = OUT_COUNT(stats);
+ if (read_fifo(ep, req, count) == 1)
+ req = 0;
+ }
+ }
+
+ } else if (ep->is_in) {
+ /* EP1 ~ EP4 */
+ if (ep->irq_pending ||
+ (REG_UDC_EPIntR & UDC_EPIntR_INEP2)) {
+ if (REG_UDC_EP2InSR & UDC_EPSR_IN) {
+ ep->irq_pending = 0;
+ REG_UDC_EP2InSR &= ~UDC_EPSR_IN;
+ if (REG_UDC_EPIntR & UDC_EPIntR_INEP2)
+ REG_UDC_EPIntR = UDC_EPIntR_INEP2;
+
+ if (write_fifo(ep, req) == 1)
+ req = 0;
+ }
+ }
+ pio_irq_enable(ep);
+ } else {
+ /* EP5 ~ EP7 */
+ pio_irq_enable(ep);
+
+ if (ep->irq_pending ||
+ (REG_UDC_EPIntR & UDC_EPIntR_OUTEP5)) {
+ u32 stats, count;
+
+ stats = REG_UDC_EP5OutSR;
+ if (stats & UDC_EPSR_OUT_RCVDATA) {
+ ep->irq_pending = 0;
+ REG_UDC_EP5OutSR &= ~UDC_EPSR_OUT_MASK;
+ if (REG_UDC_EPIntR & UDC_EPIntR_OUTEP5)
+ REG_UDC_EPIntR = UDC_EPIntR_OUTEP5;
+
+ count = OUT_COUNT(stats);
+ if (read_fifo(ep, req, count) == 1)
+ req = 0;
+ }
+ }
+ }
+ }
+
+ /* pio or dma irq handler advances the queue. */
+ if (likely(req != 0)) {
+ list_add_tail(&req->queue, &ep->queue);
+ }
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return status;
+}
+
+/* dequeue ALL requests */
+static void nuke(struct jz4730_ep *ep, int status)
+{
+ struct jz4730_request *req;
+
+ if (list_empty(&ep->queue))
+ return;
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct jz4730_request, queue);
+ done(ep, req, status);
+ }
+}
+
+/* dequeue JUST ONE request */
+static int jz4730_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct jz4730_request *req;
+ struct jz4730_ep *ep;
+ struct jz4730_udc *dev;
+ unsigned long flags;
+ int stopped;
+
+ ep = container_of(_ep, struct jz4730_ep, ep);
+ if (!_ep || !_req || (!ep->desc && ep->index != 0))
+ return -EINVAL;
+ dev = ep->dev;
+ if (!dev->driver)
+ return -ESHUTDOWN;
+
+ DEBUG("%s %s %p\n", __FUNCTION__, _ep->name,_req);
+
+ spin_lock_irqsave(&dev->lock, flags);
+ stopped = ep->stopped;
+ ep->stopped = 1;
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry (req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+ if (&req->req != _req) {
+ spin_unlock_irqrestore (&dev->lock, flags);
+ return -EINVAL;
+ }
+
+ /* queue head may be partially complete. */
+ if (ep->queue.next == &req->queue) {
+ done (ep, req, -ECONNRESET);
+ req = 0;
+ }
+
+ if (req)
+ done (ep, req, -ECONNRESET);
+ ep->stopped = stopped;
+
+ spin_unlock_irqrestore (&ep->dev->lock, flags);
+ return req ? 0 : -EOPNOTSUPP;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void jz4730_clear_halt(struct jz4730_ep *ep)
+{
+ if (ep->stopped) {
+ ep->stopped = 0;
+ }
+}
+
+static int jz4730_set_halt(struct usb_ep *_ep, int value)
+{
+ struct jz4730_ep *ep;
+ unsigned long flags;
+ int retval = 0;
+
+ if (!_ep)
+ return -ENODEV;
+ ep = container_of (_ep, struct jz4730_ep, ep);
+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+ if (ep->desc /* not ep0 */ && (ep->desc->bmAttributes & 0x03)
+ == USB_ENDPOINT_XFER_ISOC)
+ return -EINVAL;
+
+ if (ep->index == 0) {
+ if (value) {
+ ep->dev->ep0state = EP0_STALL;
+ ep->dev->ep[0].stopped = 1;
+ } else
+ return -EINVAL;
+
+ /* don't change EPxSTATUS_EP_INVALID to READY */
+ } else if (!ep->desc) {
+ DEBUG("%s %s inactive?\n", __FUNCTION__, ep->ep.name);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ep->dev->lock, flags);
+
+ if (!list_empty(&ep->queue))
+ retval = -EAGAIN;
+ else if (!value)
+ jz4730_clear_halt(ep);
+ else {
+ ep->stopped = 1;
+ }
+
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+ return retval;
+}
+
+static int jz4730_fifo_status(struct usb_ep *_ep)
+{
+ struct jz4730_ep *ep;
+ u32 size = 0;
+
+ if (!_ep)
+ return -ENODEV;
+ ep = container_of(_ep, struct jz4730_ep, ep);
+
+ /* size is only reported sanely for OUT */
+ if (ep->is_in)
+ return -EOPNOTSUPP;
+
+ return size;
+}
+
+static void jz4730_fifo_flush(struct usb_ep *_ep)
+{
+ struct jz4730_ep *ep;
+
+ if (!_ep)
+ return;
+ ep = container_of(_ep, struct jz4730_ep, ep);
+
+ /* don't change EPxSTATUS_EP_INVALID to READY */
+ if (!ep->desc && ep->index != 0) {
+ return;
+ }
+}
+
+static struct usb_ep_ops jz4730_ep_ops = {
+ .enable = jz4730_ep_enable,
+ .disable = jz4730_ep_disable,
+
+ .alloc_request = jz4730_alloc_request,
+ .free_request = jz4730_free_request,
+#if 0
+ .alloc_buffer = jz4730_alloc_buffer,
+ .free_buffer = jz4730_free_buffer,
+#endif
+ .queue = jz4730_queue,
+ .dequeue = jz4730_dequeue,
+
+ .set_halt = jz4730_set_halt,
+ .fifo_status = jz4730_fifo_status,
+ .fifo_flush = jz4730_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int jz4730_get_frame(struct usb_gadget *_gadget)
+{
+ return -EOPNOTSUPP;
+}
+
+static const struct usb_gadget_ops jz4730_ops = {
+ .get_frame = jz4730_get_frame,
+ // no remote wakeup
+ // not selfpowered
+};
+
+/*-------------------------------------------------------------------------*/
+
+static void udc_reinit(struct jz4730_udc *dev)
+{
+ static char *names [] = { "ep0", "ep1in-int", "ep2in-bulk", "ep3in-bulk",
+ "ep4in-iso", "ep5out-bulk", "ep6out-bulk",
+ "ep7out-iso" };
+ int i;
+
+ INIT_LIST_HEAD (&dev->gadget.ep_list);
+ dev->gadget.ep0 = &dev->ep[0].ep;
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+ dev->ep0state = EP0_DISCONNECT;
+
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ struct jz4730_ep *ep = &dev->ep[i];
+
+ ep->index = i;
+ ep->ep.name = names[i];
+ ep->fifo = ep_fifo[i];
+ ep->ep.maxpacket = 64;
+
+ ep->ep.ops = &jz4730_ep_ops;
+ list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
+ ep->dev = dev;
+ INIT_LIST_HEAD(&ep->queue);
+
+ ep->desc = 0;
+ ep->stopped = 1;
+ ep->irq_pending = 0;
+ }
+
+ dev->ep[0].ep.maxpacket = MAX_EP0_SIZE;
+ list_del_init(&dev->ep[0].ep.ep_list);
+}
+
+/* Reset udc registers */
+static void udc_reset(struct jz4730_udc *dev)
+{
+ REG_UDC_DevIntMR = 0x32; /* Enable RESET and SC interrupts */
+ REG_UDC_EPIntMR = 0x0; /* Enable all EP interrupts */
+ REG_UDC_DevCFGR = 0x17;
+ REG_UDC_DevCR = 0x0;
+
+ REG_UDC_EP0InCR = (0 << 4) | (1 << 1);
+ REG_UDC_EP0InCR = (0 << 4);
+ REG_UDC_EP1InCR = (3 << 4) | (1 << 1);
+ REG_UDC_EP1InCR = (3 << 4);
+ REG_UDC_EP2InCR = (2 << 4) | (1 << 1);
+ REG_UDC_EP2InCR = (2 << 4);
+ REG_UDC_EP3InCR = (2 << 4) | (1 << 1);
+ REG_UDC_EP3InCR = (2 << 4);
+ REG_UDC_EP4InCR = (1 << 4) | (1 << 1);
+ REG_UDC_EP4InCR = (1 << 4);
+
+ REG_UDC_EP0OutCR = (0 << 4);
+ REG_UDC_EP5OutCR = (2 << 4);
+ REG_UDC_EP6OutCR = (2 << 4);
+ REG_UDC_EP7OutCR = (1 << 4);
+
+ REG_UDC_EP0InSR = 0;
+ REG_UDC_EP1InSR = 0;
+ REG_UDC_EP2InSR = 0;
+ REG_UDC_EP3InSR = 0;
+ REG_UDC_EP4InSR = 0;
+ REG_UDC_EP5OutSR = 0;
+ REG_UDC_EP6OutSR = 0;
+ REG_UDC_EP7OutSR = 0;
+
+ REG_UDC_EP0InBSR = MAX_EP0_SIZE/4;
+ REG_UDC_EP1InBSR = MAX_EP1_SIZE/4;
+ REG_UDC_EP2InBSR = MAX_EP2_SIZE/4;
+ REG_UDC_EP3InBSR = MAX_EP3_SIZE/4;
+ REG_UDC_EP4InBSR = MAX_EP4_SIZE/4;
+
+ REG_UDC_EP0InMPSR = MAX_EP0_SIZE;
+ REG_UDC_EP1InMPSR = MAX_EP1_SIZE;
+ REG_UDC_EP2InMPSR = MAX_EP2_SIZE;
+ REG_UDC_EP3InMPSR = MAX_EP3_SIZE;
+ REG_UDC_EP4InMPSR = MAX_EP4_SIZE;
+
+ REG_UDC_EP0OutMPSR = MAX_EP0_SIZE;
+ REG_UDC_EP5OutMPSR = MAX_EP5_SIZE;
+ REG_UDC_EP6OutMPSR = MAX_EP6_SIZE;
+ REG_UDC_EP7OutMPSR = MAX_EP7_SIZE;
+
+ REG_UDC_EP0InfR = (MAX_EP0_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (0 << 5) | (0 << 4) | (0 << 0);
+ REG_UDC_EP1InfR = (MAX_EP1_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (3 << 5) | (1 << 4) | (1 << 0);
+ REG_UDC_EP2InfR = (MAX_EP2_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (1 << 4) | (2 << 0);
+ REG_UDC_EP3InfR = (MAX_EP3_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (1 << 4) | (3 << 0);
+ REG_UDC_EP4InfR = (MAX_EP4_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (1 << 4) | (4 << 0);
+ REG_UDC_EP5InfR = (MAX_EP5_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (0 << 4) | (5 << 0);
+ REG_UDC_EP6InfR = (MAX_EP6_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (0 << 4) | (6 << 0);
+ REG_UDC_EP7InfR = (MAX_EP7_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (0 << 4) | (7 << 0);
+
+ REG_UDC_STCMAR = 0xffff;
+}
+
+static void ep0_start(struct jz4730_udc *dev)
+{
+ udc_reset(dev);
+ udc_reinit(dev);
+
+ /* expect ep0 requests when the host drops reset */
+ dev->gadget.speed = USB_SPEED_FULL;
+ dev->ep0state = EP0_IDLE;
+}
+
+static void udc_enable(struct jz4730_udc *dev)
+{
+ /* Enable udc and enable all interrupts */
+ __intc_unmask_irq(IRQ_UDC);
+ __harb_usb0_udc();
+
+ /* start enumeration now, or after power detect irq */
+ ep0_start(dev);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* keeping it simple:
+ * - one bus driver, initted first;
+ * - one function driver, initted second
+ */
+
+static struct jz4730_udc *the_controller;
+
+/* when a driver is successfully registered, it will receive
+ * control requests including set_configuration(), which enables
+ * non-control requests. then usb traffic follows until a
+ * disconnect is reported. then a host may connect again, or
+ * the driver might get unbound.
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct jz4730_udc *dev = the_controller;
+ int retval;
+
+ if (!driver
+// || driver->speed != USB_SPEED_FULL
+ || !driver->bind
+ || !driver->unbind
+ || !driver->disconnect
+ || !driver->setup)
+ {
+ printk("\n -EINVAL");
+ return -EINVAL;
+ }
+ if (!dev)
+ return -ENODEV;
+
+ if (dev->driver)
+ return -EBUSY;
+
+ /* hook up the driver */
+ dev->driver = driver;
+ retval = driver->bind(&dev->gadget);
+ if (retval) {
+ DEBUG("bind to driver %s --> error %d\n",
+ driver->driver.name, retval);
+ dev->driver = 0;
+ return retval;
+ }
+ /* then enable host detection and ep0; and we're ready
+ * for set_configuration as well as eventual disconnect.
+ */
+ udc_enable(dev);
+
+ DEBUG("registered gadget driver '%s'\n", driver->driver.name);
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+static void
+stop_activity(struct jz4730_udc *dev, struct usb_gadget_driver *driver)
+{
+ unsigned i;
+
+ DEBUG("%s\n", __FUNCTION__);
+
+ if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = 0;
+
+ /* disconnect gadget driver after quiesceing hw and the driver */
+ udc_reset (dev);
+ for (i = 0; i < MAX_EP_NUM; i++)
+ nuke(&dev->ep [i], -ESHUTDOWN);
+ if (driver) {
+ spin_unlock(&dev->lock);
+ driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+
+ if (dev->driver)
+ udc_enable(dev);
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct jz4730_udc *dev = the_controller;
+ unsigned long flags;
+
+ /* disable UDC irq */
+ __intc_mask_irq(IRQ_UDC);
+ __harb_usb0_uhc();
+
+ if (!dev)
+ return -ENODEV;
+ if (!driver || driver != dev->driver)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ dev->driver = 0;
+ stop_activity(dev, driver);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ driver->unbind(&dev->gadget);
+
+ DEBUG("unregistered driver '%s'\n", driver->driver.name);
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static void jz4730_epn_out(struct jz4730_udc *dev, int ep_idx, u32 count)
+{
+ struct jz4730_request *req;
+ struct jz4730_ep *ep = &dev->ep[ep_idx];
+
+ req = list_entry(ep->queue.next, struct jz4730_request, queue);
+ read_fifo(ep, req, count);
+}
+
+static void jz4730_epn_in(struct jz4730_udc *dev, int ep_idx)
+{
+ struct jz4730_request *req;
+ struct jz4730_ep *ep = &dev->ep[ep_idx];
+
+ req = list_entry(ep->queue.next, struct jz4730_request, queue);
+ write_fifo(ep, req);
+}
+
+/****************************************************************/
+/* End Point 0 related functions */
+/****************************************************************/
+
+/* return: 0 = still running, 1 = completed, negative = errno */
+static int write_fifo_ep0(struct jz4730_ep *ep, struct jz4730_request *req)
+{
+ u32 max, count;
+ int is_last;
+
+ max = ep->ep.maxpacket;
+
+ count = write_packet(ep, req, max);
+
+ /* last packet is usually short (or a zlp) */
+ if (unlikely(count != max))
+ is_last = 1;
+ else {
+ if (likely(req->req.length != req->req.actual) || req->req.zero)
+ is_last = 0;
+ else
+ is_last = 1;
+ }
+
+ DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__,
+ ep->ep.name, count,
+ is_last ? "/L" : "", req->req.length - req->req.actual, req);
+
+ /* requests complete when all IN data is in the FIFO */
+ if (is_last) {
+ done(ep, req, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Simulate a USB_REQ_SET_CONFIGURATION to the function driver,
+ * this is required to enable the endpoints of the function driver.
+ * UDC should let software have the chance to handle this standard
+ * request, unfortunately UDC can't do that.
+ */
+static void psudo_set_config(void)
+{
+ struct jz4730_udc *dev = (struct jz4730_udc *) the_controller;
+ struct usb_ctrlrequest ctrl;
+ int tmp;
+
+ /* SETUP packet */
+ ctrl.bRequestType = 0x00;
+ ctrl.bRequest = USB_REQ_SET_CONFIGURATION;
+ ctrl.wValue = 1;
+ ctrl.wIndex = 0;
+ ctrl.wLength = 0;
+
+ nuke(&dev->ep[0], 0);
+ dev->ep[0].stopped = 0;
+
+ if (likely(ctrl.bRequestType & USB_DIR_IN)) {
+ dev->ep[0].is_in = 1;
+ dev->ep0state = EP0_IN;
+ } else {
+ dev->ep[0].is_in = 0;
+ dev->ep0state = EP0_OUT;
+ }
+
+ /* delegate everything to the gadget driver.
+ * it may respond after this irq handler returns.
+ */
+ spin_unlock (&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &ctrl);
+ spin_lock (&dev->lock);
+ if (unlikely(tmp < 0)) {
+ DEBUG_EP0("req %02x.%02x protocol STALL; err %d\n",
+ ctrl.bRequestType, ctrl.bRequest, tmp);
+ dev->ep[0].stopped = 1;
+ dev->ep0state = EP0_STALL;
+ }
+}
+
+/*
+ * Read 8 bytes setup packet from EP0 RX buffer
+ */
+static void read_setup_packet(u8 *buf)
+{
+ u32 *tmp = (u32 *)buf;
+
+ *tmp++ = readl((unsigned int *)RXFIFO);
+ *tmp++ = readl((unsigned int *)RXFIFO);
+
+ REG32(UDC_RXCONFIRM);
+}
+
+static void jz4730_ep0_setup(struct jz4730_udc *dev)
+{
+ struct jz4730_ep *ep = &dev->ep[0];
+ struct usb_ctrlrequest ctrl;
+ int tmp;
+
+ /* read control req from fifo (8 bytes) */
+ read_setup_packet((unsigned char *) &ctrl);
+
+ DEBUG_EP0("SETUP %02x.%02x v%04x i%04x l%04x\n",
+ ctrl.bRequestType, ctrl.bRequest,
+ ctrl.wValue, ctrl.wIndex, ctrl.wLength);
+
+ /* Set direction of EP0 */
+ if (likely(ctrl.bRequestType & USB_DIR_IN)) {
+ ep->is_in = 1;
+ dev->ep0state = EP0_IN;
+ } else {
+ ep->is_in = 0;
+ dev->ep0state = EP0_OUT;
+ }
+
+ /* Nuke all previous transfers */
+ nuke(ep, 0);
+ ep->stopped = 0;
+
+ /* delegate everything to the gadget driver.
+ * it may respond after this irq handler returns.
+ */
+ if (likely((u32)dev->driver)) {
+ /* device-2-host (IN) or no data setup command, process immediately */
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &ctrl);
+ spin_lock(&dev->lock);
+
+ if (unlikely(tmp < 0)) {
+ /* setup processing failed, force stall */
+ DEBUG_EP0("req %02x.%02x protocol STALL; err %d\n",
+ ctrl.bRequestType, ctrl.bRequest, tmp);
+ dev->ep0state = EP0_STALL;
+ }
+ }
+}
+
+static int jz4730_ep0_in(struct jz4730_udc *dev)
+{
+ struct jz4730_request *req;
+ struct jz4730_ep *ep = &dev->ep[0];
+ int ret;
+
+ if (list_empty(&ep->queue))
+ req = 0;
+ else
+ req = list_entry(ep->queue.next, struct jz4730_request, queue);
+
+ if (!req) {
+ DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__);
+ return 0;
+ }
+
+ ret = write_fifo_ep0(ep, req);
+
+ return ret;
+}
+
+static void jz4730_ep0_out(struct jz4730_udc *dev)
+{
+ u32 epsr;
+ struct jz4730_ep *ep = &dev->ep[0];
+
+ epsr = REG_UDC_EP0OutSR;
+ REG_UDC_EP0OutSR &= ~UDC_EPSR_OUT_MASK;
+
+ if (epsr & UDC_EPSR_OUT_RCVSETUP) {
+ jz4730_ep0_setup(dev);
+ }
+ else if (epsr & UDC_EPSR_OUT_RCVDATA) {
+ u32 count = __udc_ep0out_packet_size();
+ if (count == 0) {
+ readl((unsigned int *)UDC_RXCONFIRM); // ack zero packet
+ }
+ else {
+ /* EP0 OUT Data */
+ if (list_empty(&ep->queue)) {
+ ep->irq_pending = 1;
+ pio_irq_disable(ep);
+ }
+ else
+ jz4730_epn_out(dev, 0, count);
+
+ }
+ }
+}
+
+static void handle_reset_irq(struct jz4730_udc *dev)
+{
+ int i;
+
+ /* clear any status */
+ REG_UDC_EPIntR = 0xffffffff;
+ REG_UDC_DevIntR = 0xffffffff;
+
+ /* reset udc */
+ udc_reset(dev);
+
+ /* reset driver status */
+ for (i = 0; i < MAX_EP_NUM; i++) {
+ struct jz4730_ep *ep = &dev->ep[i];
+
+ ep->irq_pending = 0;
+// nuke(ep, 0);
+ nuke(ep, -ESHUTDOWN);
+ }
+}
+
+static irqreturn_t jz4730_udc_irq(int irq, void *_dev)
+{
+ struct jz4730_udc *dev = _dev;
+ struct jz4730_ep *ep;
+
+ u32 intr_dev, intr_ep, stats, count;
+
+ spin_lock(&dev->lock);
+
+ intr_dev = REG_UDC_DevIntR;
+ intr_ep = REG_UDC_EPIntR;
+
+ DEBUG("*** udc irq intr_dev=0x%x intr_ep=0x%x\n", intr_dev, intr_ep);
+
+ if (!intr_dev && !intr_ep) {
+ spin_unlock(&dev->lock);
+ return IRQ_HANDLED;
+ }
+
+ if (udc_debug) {
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+ jz_udc_active = 1;
+#endif
+ REG_UDC_DevIntR = intr_dev;
+ REG_UDC_EPIntR = intr_ep;
+ __harb_usb0_uhc();
+ __intc_mask_irq(IRQ_UDC);
+ spin_unlock(&dev->lock);
+ return IRQ_HANDLED;
+ }
+
+ if (intr_dev) {
+ if (intr_dev & UDC_DevIntR_SC) {
+ psudo_set_config();
+ udelay(100);
+ }
+
+ if (intr_dev & UDC_DevIntR_UR) {
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+ jz_udc_active = 1;
+#endif
+ handle_reset_irq(dev);
+ }
+
+ REG_UDC_DevIntR = intr_dev;
+ }
+
+ if (intr_ep & UDC_EPIntR_OUTEP0) {
+ REG_UDC_EPIntR = UDC_EPIntR_OUTEP0;
+ jz4730_ep0_out(dev);
+ }
+
+ if (intr_ep & UDC_EPIntR_INEP0) {
+ ep = &dev->ep[0];
+ if (list_empty(&ep->queue)) {
+ pio_irq_disable(ep);
+ }
+ else {
+ stats = REG_UDC_EP0InSR;
+ if (stats & UDC_EPSR_IN) {
+ REG_UDC_EPIntR = UDC_EPIntR_INEP0;
+ REG_UDC_EP0InSR &= ~UDC_EPSR_IN;
+
+ jz4730_ep0_in(dev);
+ }
+ }
+ }
+
+ if (intr_ep & UDC_EPIntR_OUTEP5) {
+ REG_UDC_EPIntR = UDC_EPIntR_OUTEP5;
+ ep = &dev->ep[5];
+ if (list_empty(&ep->queue)) {
+ ep->irq_pending = 1;
+ pio_irq_disable(ep);
+ }
+ else {
+ stats = REG_UDC_EP5OutSR;
+ if (stats & UDC_EPSR_OUT_RCVDATA) {
+ REG_UDC_EP5OutSR &= ~UDC_EPSR_OUT_MASK;
+
+ count = OUT_COUNT(stats);
+ jz4730_epn_out(dev, 5, count);
+ }
+ }
+ }
+
+ if (intr_ep & UDC_EPIntR_INEP2) {
+ ep = &dev->ep[2];
+ if (list_empty(&ep->queue)) {
+ ep->irq_pending = 1;
+ pio_irq_disable(ep);
+ }
+ else {
+ stats = REG_UDC_EP2InSR;
+ if (stats & UDC_EPSR_IN) {
+ REG_UDC_EP2InSR &= ~UDC_EPSR_IN;
+ jz4730_epn_in(dev, 2);
+ }
+ }
+
+ REG_UDC_EPIntR = UDC_EPIntR_INEP2;
+ }
+
+ if (intr_ep & UDC_EPIntR_INEP1) {
+ ep = &dev->ep[1];
+ if (list_empty(&ep->queue)) {
+ ep->irq_pending = 1;
+ pio_irq_disable(ep);
+ }
+ else {
+ stats = REG_UDC_EP1InSR;
+ if (stats & UDC_EPSR_IN) {
+ REG_UDC_EP1InSR &= ~UDC_EPSR_IN;
+ jz4730_epn_in(dev, 1);
+ }
+ }
+
+ REG_UDC_EPIntR = UDC_EPIntR_INEP1;
+ }
+
+ spin_unlock(&dev->lock);
+ return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct jz4730_udc udc_dev = {
+ .usb_address = 0,
+
+ .gadget = {
+ .ops = &jz4730_ops,
+ .ep0 = &udc_dev.ep[0].ep,
+ .name = driver_name,
+ .dev = {
+ .bus_id = "gadget",
+ },
+ },
+ /* control endpoint no need to init here!*/
+ /* control endpoint */
+};
+
+
+/* tear down the binding between this driver and the pci device */
+static int jz4730_udc_remove(struct platform_device *pdev)
+{
+ struct jz4730_udc *dev = platform_get_drvdata(pdev);
+
+ if (dev->driver)
+ return -EBUSY;
+
+ /* USB port0 as UHC */
+ __harb_usb0_uhc();
+
+ /* reset udc */
+ udc_reset(dev);
+
+ /* clear any status */
+ REG_UDC_EPIntR = 0xffffffff;
+ REG_UDC_DevIntR = 0xffffffff;
+
+ /* disable all UDC interrupts */
+ REG_UDC_DevIntMR = 0xffffffff;
+ REG_UDC_EPIntMR = 0xffffffff;
+
+ free_irq(IRQ_UDC, dev);
+ platform_set_drvdata(pdev, 0);
+ device_unregister(&dev->gadget.dev);
+ the_controller = 0;
+
+ return 0;
+}
+
+static int jz4730_udc_probe(struct platform_device *pdev)
+{
+ struct jz4730_udc *dev = &udc_dev;
+ int retval,rc;
+
+ /* if you want to support more than one controller in a system,
+ * usb_gadget_driver_{register,unregister}() must change.
+ */
+ if (the_controller) {
+ printk("Check the_controller: %s\n", driver_name);
+ return -EBUSY;
+ }
+
+ spin_lock_init(&dev->lock);
+ device_initialize(&dev->gadget.dev);
+ dev->gadget.dev.parent = &pdev->dev; //if no,can only insmod once!!
+ dev->gadget.dev.release = jz4730_udc_release;
+ rc = device_register (&dev->gadget.dev);
+ if (rc < 0)
+ return rc;
+ platform_set_drvdata(pdev, dev);
+
+ /*
+ * Note: we just mask INTC irq but allow UDC irq.
+ * This avoid that we miss any UDC irqs.
+ */
+
+ /* To avoid any UDC irqs here, we call cli() first */
+// cli();
+
+ /* disable INTC irq */
+ __intc_mask_irq(IRQ_UDC);
+
+ /* init to known state, then setup irqs */
+ udc_reset(dev);
+ udc_reinit(dev);
+
+ /* request UDC irq */
+ if (request_irq(IRQ_UDC, jz4730_udc_irq, IRQF_DISABLED, // SA_INTERRUPT,
+ driver_name, dev) != 0) {
+ printk(KERN_INFO "request UDC interrupt %d failed\n", IRQ_UDC);
+ retval = -EBUSY;
+ goto done;
+ }
+
+ /* disable INTC irq again since request_irq has enabled it */
+ __intc_mask_irq(IRQ_UDC);
+ __intc_ack_irq(IRQ_UDC);
+
+ /* Re-enable irqs */
+// sti();
+
+ printk(KERN_INFO "%s\n", driver_desc);
+ printk(KERN_INFO "version: " DRIVER_VERSION "\n");
+
+ /* done */
+ the_controller = dev;
+
+ return 0;
+
+done:
+ if (dev)
+ jz4730_udc_remove (pdev);
+ return retval;
+}
+
+static struct platform_driver udc_driver = {
+ .probe = jz4730_udc_probe,
+ .remove = jz4730_udc_remove,
+ .suspend = NULL,
+ .resume = NULL,
+ .driver = {
+ .name = (char *) driver_name,
+ .owner = THIS_MODULE,
+ },
+};
+static struct platform_device the_udc_pdev = {
+ .name = (char *) driver_name,
+ .id = -1,
+ .dev = {
+ .release = jz4730_udc_release,
+ },
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init udc_init (void)
+{
+ platform_driver_register(&udc_driver);
+ return platform_device_register (&the_udc_pdev);
+}
+
+static void __exit udc_exit (void)
+{
+ platform_driver_unregister(&udc_driver);
+ platform_device_unregister(&the_udc_pdev);
+}
+
+module_init(udc_init);
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Wei Jianli <jlwei@ingenic.cn>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/jz4730_udc.h b/drivers/usb/gadget/jz4730_udc.h
new file mode 100644
index 00000000000..6ea368b32dd
--- /dev/null
+++ b/drivers/usb/gadget/jz4730_udc.h
@@ -0,0 +1,107 @@
+/*
+ * JZ4730 USB Device Controller driver
+ *
+ * Copyright (C) 2005 by Wei Jianli
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __JZ4730_UDC_H__
+#define __JZ4730_UDC_H__
+
+/* DRIVER DATA STRUCTURES and UTILITIES */
+#define MAX_EP_NUM 8 /* Number of endpoints on this UDC */
+
+#define MAX_EP0_SIZE 32
+#define MAX_EP1_SIZE 64
+#define MAX_EP2_SIZE 64
+#define MAX_EP3_SIZE 64
+#define MAX_EP4_SIZE 64
+#define MAX_EP5_SIZE 64
+#define MAX_EP6_SIZE 64
+#define MAX_EP7_SIZE 64
+
+// UDC FIFO
+#define RXFIFO (UDC_RXFIFO) /* EP0 OUT, EP5-7 OUT */
+#define TXFIFOEP0 (UDC_TXFIFOEP0) /* EP0 IN */
+#define TXFIFOEP1 (TXFIFOEP0 + MAX_EP0_SIZE) /* EP1 IN */
+#define TXFIFOEP2 (TXFIFOEP1 + MAX_EP1_SIZE) /* EP2 IN */
+#define TXFIFOEP3 (TXFIFOEP2 + MAX_EP2_SIZE) /* EP3 IN */
+#define TXFIFOEP4 (TXFIFOEP3 + MAX_EP3_SIZE) /* EP4 IN */
+
+static u32 ep_fifo[MAX_EP_NUM] = {TXFIFOEP0, TXFIFOEP1, TXFIFOEP2,
+ TXFIFOEP3, TXFIFOEP4, RXFIFO, RXFIFO,
+ RXFIFO};
+
+#define OUT_COUNT(stats) \
+ ((stats&UDC_EPSR_RXPKTSIZE_MASK)>>UDC_EPSR_RXPKTSIZE_BIT)
+
+struct jz4730_ep {
+ struct usb_ep ep;
+ struct jz4730_udc *dev;
+
+ u8 index;
+ u8 is_in;
+ u8 stopped;
+ u8 irq_pending;
+ u32 fifo;
+
+ struct list_head queue;
+ const struct usb_endpoint_descriptor *desc;
+};
+
+struct jz4730_request {
+ struct usb_request req;
+ struct list_head queue;
+};
+
+enum ep0state {
+ EP0_DISCONNECT, /* no host */
+ EP0_IDLE, /* between STATUS ack and SETUP report */
+ EP0_IN, EP0_OUT, /* data stage */
+ EP0_STATUS, /* status stage */
+ EP0_STALL, /* data or status stages */
+ EP0_SUSPEND, /* usb suspend */
+};
+
+struct jz4730_udc {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ spinlock_t lock;
+
+ struct jz4730_ep ep[MAX_EP_NUM];
+ enum ep0state ep0state;
+ unsigned char usb_address;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* 2.5 stuff that's sometimes missing in 2.4 */
+
+#ifndef container_of
+#define container_of list_entry
+#endif
+
+#ifndef likely
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+#ifndef BUG_ON
+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
+#endif
+
+#ifndef WARN_ON
+#define WARN_ON(x) do { } while (0)
+#endif
+
+#ifndef IRQ_NONE
+typedef void irqreturn_t;
+#define IRQ_NONE
+#define IRQ_HANDLED
+#define IRQ_RETVAL(x)
+#endif
+
+#endif /* __JZ4730_UDC_H__ */
diff --git a/drivers/usb/gadget/jz4740_udc.c b/drivers/usb/gadget/jz4740_udc.c
new file mode 100644
index 00000000000..ccc989a6e90
--- /dev/null
+++ b/drivers/usb/gadget/jz4740_udc.c
@@ -0,0 +1,2326 @@
+/*
+ * linux/drivers/usb/gadget/jz4740_udc.c
+ *
+ * Ingenic JZ4740 on-chip high speed USB device controller
+ *
+ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * This device has ep0, two bulk-in/interrupt-in endpoints, and one bulk-out endpoint.
+ *
+ * - Endpoint numbering is fixed: ep0, ep1in-int, ep2in-bulk, ep1out-bulk.
+ * - DMA works with bulk-in (channel 1) and bulk-out (channel 2) endpoints.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/usb.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/jzsoc.h>
+
+#include "jz4740_udc.h"
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+#include "udc_hotplug.c"
+#endif
+
+//#define DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args)
+//#define DEBUG(fmt,args...) printk(fmt , ## args)
+//#define DEBUG_EP0(fmt,args...) printk(fmt , ## args)
+//#define DEBUG_SETUP(fmt,args...) printk(fmt , ## args)
+
+#ifndef DEBUG
+# define DEBUG(fmt,args...) do {} while(0)
+#endif
+#ifndef DEBUG_EP0
+# define NO_STATES
+# define DEBUG_EP0(fmt,args...) do {} while(0)
+#endif
+#ifndef DEBUG_SETUP
+# define DEBUG_SETUP(fmt,args...) do {} while(0)
+#endif
+
+static unsigned int use_dma = 1; /* 1: use DMA, 0: use PIO */
+
+module_param(use_dma, int, 0);
+MODULE_PARM_DESC(use_dma, "DMA mode enable flag");
+
+/*
+ * Local definintions.
+ */
+
+#define DRIVER_VERSION "13-Mar-2008"
+#define DRIVER_DESC "JZ4740 USB Device Controller"
+
+static const char gadget_name [] = "jz4740_udc";
+
+struct jz4740_udc *the_controller;
+
+static const char driver_name [] = "jz4740_udc";
+static const char driver_desc [] = DRIVER_DESC;
+static const char ep0name[] = "ep0";
+
+#ifndef NO_STATES
+static char *state_names[] = {
+ "WAIT_FOR_SETUP",
+ "DATA_STATE_XMIT",
+ "DATA_STATE_NEED_ZLP",
+ "WAIT_FOR_OUT_STATUS",
+ "DATA_STATE_RECV"
+};
+#endif
+
+/*
+ * Local declarations.
+ */
+static int jz4740_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc);
+static int jz4740_ep_disable(struct usb_ep *_ep);
+static struct usb_request *jz4740_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags);
+static void jz4740_free_request(struct usb_ep *_ep, struct usb_request *_req);
+
+static int jz4740_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags);
+static int jz4740_dequeue(struct usb_ep *_ep, struct usb_request *_req);
+static int jz4740_set_halt(struct usb_ep *_ep, int value);
+static int jz4740_fifo_status(struct usb_ep *_ep);
+static void jz4740_fifo_flush(struct usb_ep *_ep);
+
+static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep, struct usb_request *req);
+static void jz4740_handle_ep0(struct jz4740_udc *dev, u32 intr);
+
+static void done(struct jz4740_ep *ep, struct jz4740_request *req,
+ int status);
+static void pio_irq_enable(struct jz4740_ep *ep);
+static void pio_irq_disable(struct jz4740_ep *ep);
+static void stop_activity(struct jz4740_udc *dev,
+ struct usb_gadget_driver *driver);
+static void nuke(struct jz4740_ep *ep, int status);
+static void flush(struct jz4740_ep *ep);
+static void udc_enable(struct jz4740_udc *dev);
+static void udc_set_address(struct jz4740_udc *dev, unsigned char address);
+static void jz4740_udc_release (struct device *dev) {}
+
+extern void *dma_alloc_noncoherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag);
+extern void dma_free_noncoherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
+
+static struct usb_ep_ops jz4740_ep_ops = {
+ .enable = jz4740_ep_enable,
+ .disable = jz4740_ep_disable,
+
+ .alloc_request = jz4740_alloc_request,
+ .free_request = jz4740_free_request,
+
+ .queue = jz4740_queue,
+ .dequeue = jz4740_dequeue,
+
+ .set_halt = jz4740_set_halt,
+ .fifo_status = jz4740_fifo_status,
+ .fifo_flush = jz4740_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* inline functions of register read/write/set/clear */
+
+static __inline__ u8 usb_readb(u32 port)
+{
+ return *(volatile u8 *)port;
+}
+
+static __inline__ u16 usb_readw(u32 port)
+{
+ return *(volatile u16 *)port;
+}
+
+static __inline__ u32 usb_readl(u32 port)
+{
+ return *(volatile u32 *)port;
+}
+
+static __inline__ void usb_writeb(u32 port, u8 val)
+{
+ *(volatile u8 *)port = val;
+}
+
+static __inline__ void usb_writew(u32 port, u16 val)
+{
+ *(volatile u16 *)port = val;
+}
+
+static __inline__ void usb_writel(u32 port, u32 val)
+{
+ *(volatile u32 *)port = val;
+}
+
+static __inline__ void usb_setb(u32 port, u8 val)
+{
+ volatile u8 *ioport = (volatile u8 *)(port);
+ *ioport = (*ioport) | val;
+}
+
+static __inline__ void usb_setw(u32 port, u16 val)
+{
+ volatile u16 *ioport = (volatile u16 *)(port);
+ *ioport = (*ioport) | val;
+}
+
+static __inline__ void usb_setl(u32 port, u32 val)
+{
+ volatile u32 *ioport = (volatile u32 *)(port);
+ *ioport = (*ioport) | val;
+}
+
+static __inline__ void usb_clearb(u32 port, u8 val)
+{
+ volatile u8 *ioport = (volatile u8 *)(port);
+ *ioport = (*ioport) & ~val;
+}
+
+static __inline__ void usb_clearw(u32 port, u16 val)
+{
+ volatile u16 *ioport = (volatile u16 *)(port);
+ *ioport = (*ioport) & ~val;
+}
+
+static __inline__ void usb_clearl(u32 port, u32 val)
+{
+ volatile u32 *ioport = (volatile u32 *)(port);
+ *ioport = (*ioport) & ~val;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static __inline__ int write_packet(struct jz4740_ep *ep,
+ struct jz4740_request *req, int max)
+{
+ u8 *buf;
+ int length, nlong, nbyte;
+ volatile u32 *fifo = (volatile u32 *)ep->fifo;
+
+ buf = req->req.buf + req->req.actual;
+ prefetch(buf);
+
+ length = req->req.length - req->req.actual;
+ length = min(length, max);
+ req->req.actual += length;
+
+ DEBUG("Write %d (max %d), fifo %p\n", length, max, fifo);
+
+ nlong = length >> 2;
+ nbyte = length & 0x3;
+ while (nlong--) {
+ *fifo = *((u32 *)buf);
+ buf += 4;
+ }
+ while (nbyte--) {
+ *((volatile u8 *)fifo) = *buf++;
+ }
+
+ return length;
+}
+
+static __inline__ int read_packet(struct jz4740_ep *ep,
+ struct jz4740_request *req, int count)
+{
+ u8 *buf;
+ int length, nlong, nbyte;
+ volatile u32 *fifo = (volatile u32 *)ep->fifo;
+
+ buf = req->req.buf + req->req.actual;
+ prefetchw(buf);
+
+ length = req->req.length - req->req.actual;
+ length = min(length, count);
+ req->req.actual += length;
+
+ DEBUG("Read %d, fifo %p\n", length, fifo);
+
+ nlong = length >> 2;
+ nbyte = length & 0x3;
+ while (nlong--) {
+ *((u32 *)buf) = *fifo;
+ buf += 4;
+ }
+ while (nbyte--) {
+ *buf++ = *((volatile u8 *)fifo);
+ }
+
+ return length;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * udc_disable - disable USB device controller
+ */
+static void udc_disable(struct jz4740_udc *dev)
+{
+ DEBUG("%s, %p\n", __FUNCTION__, dev);
+
+ udc_set_address(dev, 0);
+
+ /* Disable interrupts */
+ usb_writew(USB_REG_INTRINE, 0);
+ usb_writew(USB_REG_INTROUTE, 0);
+ usb_writeb(USB_REG_INTRUSBE, 0);
+
+ /* Disable DMA */
+ usb_writel(USB_REG_CNTL1, 0);
+ usb_writel(USB_REG_CNTL2, 0);
+
+ /* Disconnect from usb */
+ usb_clearb(USB_REG_POWER, USB_POWER_SOFTCONN);
+
+ /* Disable the USB PHY */
+#ifdef CONFIG_SOC_JZ4740
+ REG_CPM_SCR &= ~CPM_SCR_USBPHY_ENABLE;
+#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) || defined(CONFIG_SOC_JZ4750L)
+ REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE;
+#endif
+
+ dev->ep0state = WAIT_FOR_SETUP;
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+/*
+ * udc_reinit - initialize software state
+ */
+static void udc_reinit(struct jz4740_udc *dev)
+{
+ u32 i;
+
+ DEBUG("%s, %p\n", __FUNCTION__, dev);
+
+ /* device/ep0 records init */
+ INIT_LIST_HEAD(&dev->gadget.ep_list);
+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+ dev->ep0state = WAIT_FOR_SETUP;
+
+ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) {
+ struct jz4740_ep *ep = &dev->ep[i];
+
+ if (i != 0)
+ list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
+
+ INIT_LIST_HEAD(&ep->queue);
+ ep->desc = 0;
+ ep->stopped = 0;
+ ep->pio_irqs = 0;
+ }
+}
+
+/* until it's enabled, this UDC should be completely invisible
+ * to any USB host.
+ */
+static void udc_enable(struct jz4740_udc *dev)
+{
+ int i;
+
+ DEBUG("%s, %p\n", __FUNCTION__, dev);
+
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+ /* Flush FIFO for each */
+ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) {
+ struct jz4740_ep *ep = &dev->ep[i];
+
+ usb_set_index(ep_index(ep));
+ flush(ep);
+ }
+
+ /* Set this bit to allow the UDC entering low-power mode when
+ * there are no actions on the USB bus.
+ * UDC still works during this bit was set.
+ */
+ __cpm_stop_udc();
+
+ /* Enable the USB PHY */
+#ifdef CONFIG_SOC_JZ4740
+ REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE;
+#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) || defined(CONFIG_SOC_JZ4750L)
+ REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE;
+#endif
+
+ /* Disable interrupts */
+ usb_writew(USB_REG_INTRINE, 0);
+ usb_writew(USB_REG_INTROUTE, 0);
+ usb_writeb(USB_REG_INTRUSBE, 0);
+
+ /* Enable interrupts */
+ usb_setw(USB_REG_INTRINE, USB_INTR_EP0);
+ usb_setb(USB_REG_INTRUSBE, USB_INTR_RESET);
+ /* Don't enable rest of the interrupts */
+ /* usb_setw(USB_REG_INTRINE, USB_INTR_INEP1 | USB_INTR_INEP2);
+ usb_setw(USB_REG_INTROUTE, USB_INTR_OUTEP1); */
+
+ /* Enable SUSPEND */
+ /* usb_setb(USB_REG_POWER, USB_POWER_SUSPENDM); */
+
+ /* Enable HS Mode */
+ usb_setb(USB_REG_POWER, USB_POWER_HSENAB);
+
+ /* Let host detect UDC:
+ * Software must write a 1 to the PMR:USB_POWER_SOFTCONN bit to turn this
+ * transistor on and pull the USBDP pin HIGH.
+ */
+ usb_setb(USB_REG_POWER, USB_POWER_SOFTCONN);
+}
+
+/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+static int jz4740_udc_uh_event(struct notifier_block *n, unsigned long val, void *data)
+{
+ struct jz4740_udc *dev = the_controller;
+ unsigned long flags;
+
+ int state = *((int *)data);
+
+ if (!dev || !dev->driver)
+ return 0;
+
+ switch (val) {
+ case UH_NOTIFY_CABLE_STATE:
+ switch (state) {
+ case UH_CABLE_STATE_OFFLINE:
+ case UH_CABLE_STATE_POWER:
+ spin_lock_irqsave(&dev->lock, flags);
+ stop_activity(dev, dev->driver);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ udc_disable(dev);
+
+ break;
+
+ case UH_CABLE_STATE_USB:
+ udc_enable(dev);
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static struct notifier_block jz4740_udc_nb = {
+ .notifier_call = jz4740_udc_uh_event,
+};
+#endif
+
+/* keeping it simple:
+ * - one bus driver, initted first;
+ * - one function driver, initted second
+ */
+
+/*
+ * Register entry point for the peripheral controller driver.
+ */
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct jz4740_udc *dev = the_controller;
+ int retval;
+
+ if (!driver
+ || !driver->bind
+ || !driver->unbind || !driver->disconnect || !driver->setup)
+ {
+ printk("\n-EINVAL");
+ return -EINVAL;
+ }
+ if (!dev)
+ {
+ printk("\n-ENODEV");
+ return -ENODEV;
+ }
+ if (dev->driver)
+ {
+ printk("\n-ENODEV");
+ return -EBUSY;
+ }
+
+ /* hook up the driver */
+ dev->driver = driver;
+ retval = driver->bind(&dev->gadget);
+ if (retval) {
+ DEBUG("%s: bind to driver %s --> error %d\n", dev->gadget.name,
+ driver->driver.name, retval);
+ dev->driver = 0;
+ return retval;
+ }
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+ uh_register_notifier(&jz4740_udc_nb);
+#else
+ /* then enable host detection and ep0; and we're ready
+ * for set_configuration as well as eventual disconnect.
+ */
+ udc_enable(dev);
+#endif
+
+ DEBUG("%s: registered gadget driver '%s'\n", dev->gadget.name,
+ driver->driver.name);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+static void stop_activity(struct jz4740_udc *dev,
+ struct usb_gadget_driver *driver)
+{
+ int i;
+
+ DEBUG("%s\n", __FUNCTION__);
+
+ /* don't disconnect drivers more than once */
+ if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = 0;
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+ /* prevent new request submissions, kill any outstanding requests */
+ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) {
+ struct jz4740_ep *ep = &dev->ep[i];
+
+ ep->stopped = 1;
+
+ usb_set_index(ep_index(ep));
+ nuke(ep, -ESHUTDOWN);
+ }
+
+ /* report disconnect; the driver is already quiesced */
+ if (driver) {
+ spin_unlock(&dev->lock);
+ driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+
+ /* re-init driver-visible data structures */
+ udc_reinit(dev);
+}
+
+/*
+ * Unregister entry point for the peripheral controller driver.
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct jz4740_udc *dev = the_controller;
+ unsigned long flags;
+
+ if (!dev)
+ return -ENODEV;
+ if (!driver || driver != dev->driver)
+ return -EINVAL;
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+ uh_unregister_notifier(&jz4740_udc_nb);
+#endif
+
+ spin_lock_irqsave(&dev->lock, flags);
+ dev->driver = 0;
+ stop_activity(dev, driver);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ driver->unbind(&dev->gadget);
+
+ udc_disable(dev);
+
+ DEBUG("unregistered driver '%s'\n", driver->driver.name);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Starting DMA using mode 1
+ */
+static void kick_dma(struct jz4740_ep *ep, struct jz4740_request *req)
+{
+ u32 count = req->req.length;
+ u32 physaddr = virt_to_phys((void *)req->req.buf);
+
+ usb_set_index(ep_index(ep));
+ if (ep_is_in(ep)) { /* Bulk-IN transfer using DMA channel 1 */
+ ep->reg_addr = USB_REG_ADDR1;
+
+ dma_cache_wback_inv((unsigned long)req->req.buf, count);
+
+ pio_irq_enable(ep);
+
+ usb_writeb(USB_REG_INCSRH,
+ USB_INCSRH_DMAREQENAB | USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQMODE);
+
+ usb_writel(USB_REG_ADDR1, physaddr);
+ usb_writel(USB_REG_COUNT1, count);
+ usb_writel(USB_REG_CNTL1, USB_CNTL_ENA | USB_CNTL_DIR_IN | USB_CNTL_MODE_1 |
+ USB_CNTL_INTR_EN | USB_CNTL_BURST_16 | USB_CNTL_EP(ep_index(ep)));
+ }
+ else { /* Bulk-OUT transfer using DMA channel 2 */
+ ep->reg_addr = USB_REG_ADDR2;
+
+ dma_cache_wback_inv((unsigned long)req->req.buf, count);
+
+ pio_irq_enable(ep);
+
+ usb_setb(USB_REG_OUTCSRH,
+ USB_OUTCSRH_DMAREQENAB | USB_OUTCSRH_AUTOCLR | USB_OUTCSRH_DMAREQMODE);
+
+ usb_writel(USB_REG_ADDR2, physaddr);
+ usb_writel(USB_REG_COUNT2, count);
+ usb_writel(USB_REG_CNTL2, USB_CNTL_ENA | USB_CNTL_MODE_1 |
+ USB_CNTL_INTR_EN | USB_CNTL_BURST_16 | USB_CNTL_EP(ep_index(ep)));
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/** Write request to FIFO (max write == maxp size)
+ * Return: 0 = still running, 1 = completed, negative = errno
+ * NOTE: INDEX register must be set for EP
+ */
+static int write_fifo(struct jz4740_ep *ep, struct jz4740_request *req)
+{
+ u32 max, csr;
+ u32 physaddr = virt_to_phys((void *)req->req.buf);
+
+ max = le16_to_cpu(ep->desc->wMaxPacketSize);
+
+ if (use_dma) {
+ u32 dma_count;
+
+ /* DMA interrupt generated due to the last packet loaded into the FIFO */
+
+ dma_count = usb_readl(ep->reg_addr) - physaddr;
+ req->req.actual += dma_count;
+
+ if (dma_count % max) {
+ /* If the last packet is less than MAXP, set INPKTRDY manually */
+ usb_setb(ep->csr, USB_INCSR_INPKTRDY);
+ }
+
+ done(ep, req, 0);
+ if (list_empty(&ep->queue)) {
+ pio_irq_disable(ep);
+ return 1;
+ }
+ else {
+ /* advance the request queue */
+ req = list_entry(ep->queue.next, struct jz4740_request, queue);
+ kick_dma(ep, req);
+ return 0;
+ }
+ }
+
+ /*
+ * PIO mode handling starts here ...
+ */
+
+ csr = usb_readb(ep->csr);
+
+ if (!(csr & USB_INCSR_FFNOTEMPT)) {
+ unsigned count;
+ int is_last, is_short;
+
+ count = write_packet(ep, req, max);
+ usb_setb(ep->csr, USB_INCSR_INPKTRDY);
+
+ /* last packet is usually short (or a zlp) */
+ if (unlikely(count != max))
+ is_last = is_short = 1;
+ else {
+ if (likely(req->req.length != req->req.actual)
+ || req->req.zero)
+ is_last = 0;
+ else
+ is_last = 1;
+ /* interrupt/iso maxpacket may not fill the fifo */
+ is_short = unlikely(max < ep_maxpacket(ep));
+ }
+
+ DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__,
+ ep->ep.name, count,
+ is_last ? "/L" : "", is_short ? "/S" : "",
+ req->req.length - req->req.actual, req);
+
+ /* requests complete when all IN data is in the FIFO */
+ if (is_last) {
+ done(ep, req, 0);
+ if (list_empty(&ep->queue)) {
+ pio_irq_disable(ep);
+ }
+ return 1;
+ }
+ } else {
+ DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep));
+ }
+
+ return 0;
+}
+
+/** Read to request from FIFO (max read == bytes in fifo)
+ * Return: 0 = still running, 1 = completed, negative = errno
+ * NOTE: INDEX register must be set for EP
+ */
+static int read_fifo(struct jz4740_ep *ep, struct jz4740_request *req)
+{
+ u32 csr;
+ unsigned count, is_short;
+ u32 physaddr = virt_to_phys((void *)req->req.buf);
+
+ if (use_dma) {
+ u32 dma_count;
+
+ /* DMA interrupt generated due to a packet less than MAXP loaded into the FIFO */
+ dma_count = usb_readl(ep->reg_addr) - physaddr;
+ req->req.actual += dma_count;
+
+ /* Disable interrupt and DMA */
+ pio_irq_disable(ep);
+ usb_writel(USB_REG_CNTL2, 0);
+
+ /* Read all bytes from this packet */
+ count = usb_readw(USB_REG_OUTCOUNT);
+ count = read_packet(ep, req, count);
+
+ if (count) {
+ /* If the last packet is greater than zero, clear OUTPKTRDY manually */
+ usb_clearb(ep->csr, USB_OUTCSR_OUTPKTRDY);
+ }
+
+ done(ep, req, 0);
+
+ if (!list_empty(&ep->queue)) {
+ /* advance the request queue */
+ req = list_entry(ep->queue.next, struct jz4740_request, queue);
+ kick_dma(ep, req);
+ }
+
+ return 1;
+ }
+
+ /*
+ * PIO mode handling starts here ...
+ */
+
+ /* make sure there's a packet in the FIFO. */
+ csr = usb_readb(ep->csr);
+ if (!(csr & USB_OUTCSR_OUTPKTRDY)) {
+ DEBUG("%s: Packet NOT ready!\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* read all bytes from this packet */
+ count = usb_readw(USB_REG_OUTCOUNT);
+
+ is_short = (count < ep->ep.maxpacket);
+
+ count = read_packet(ep, req, count);
+
+ DEBUG("read %s %02x, %d bytes%s req %p %d/%d\n",
+ ep->ep.name, csr, count,
+ is_short ? "/S" : "", req, req->req.actual, req->req.length);
+
+ /* Clear OutPktRdy */
+ usb_clearb(ep->csr, USB_OUTCSR_OUTPKTRDY);
+
+ /* completion */
+ if (is_short || req->req.actual == req->req.length) {
+ done(ep, req, 0);
+
+ if (list_empty(&ep->queue))
+ pio_irq_disable(ep);
+ return 1;
+ }
+
+ /* finished that packet. the next one may be waiting... */
+ return 0;
+}
+
+/*
+ * done - retire a request; caller blocked irqs
+ * INDEX register is preserved to keep same
+ */
+static void done(struct jz4740_ep *ep, struct jz4740_request *req, int status)
+{
+ unsigned int stopped = ep->stopped;
+ u32 index;
+
+ DEBUG("%s, %p\n", __FUNCTION__, ep);
+ list_del_init(&req->queue);
+
+ if (likely(req->req.status == -EINPROGRESS))
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ if (status && status != -ESHUTDOWN)
+ DEBUG("complete %s req %p stat %d len %u/%u\n",
+ ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+
+ /* don't modify queue heads during completion callback */
+ ep->stopped = 1;
+ /* Read current index (completion may modify it) */
+ index = usb_readb(USB_REG_INDEX);
+
+ spin_unlock(&ep->dev->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&ep->dev->lock);
+
+ /* Restore index */
+ usb_set_index(index);
+ ep->stopped = stopped;
+}
+
+/** Enable EP interrupt */
+static void pio_irq_enable(struct jz4740_ep *ep)
+{
+ DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT");
+
+ if (ep_is_in(ep)) {
+ switch (ep_index(ep)) {
+ case 1:
+ usb_setw(USB_REG_INTRINE, USB_INTR_INEP1);
+ break;
+ case 2:
+ usb_setw(USB_REG_INTRINE, USB_INTR_INEP2);
+ break;
+ default:
+ DEBUG("Unknown endpoint: %d\n", ep_index(ep));
+ break;
+ }
+ }
+ else {
+ switch (ep_index(ep)) {
+ case 1:
+ usb_setw(USB_REG_INTROUTE, USB_INTR_OUTEP1);
+ break;
+ default:
+ DEBUG("Unknown endpoint: %d\n", ep_index(ep));
+ break;
+ }
+ }
+}
+
+/** Disable EP interrupt */
+static void pio_irq_disable(struct jz4740_ep *ep)
+{
+ DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT");
+
+ if (ep_is_in(ep)) {
+ switch (ep_index(ep)) {
+ case 1:
+ usb_clearw(USB_REG_INTRINE, USB_INTR_INEP1);
+ break;
+ case 2:
+ usb_clearw(USB_REG_INTRINE, USB_INTR_INEP2);
+ break;
+ default:
+ DEBUG("Unknown endpoint: %d\n", ep_index(ep));
+ break;
+ }
+ }
+ else {
+ switch (ep_index(ep)) {
+ case 1:
+ usb_clearw(USB_REG_INTROUTE, USB_INTR_OUTEP1);
+ break;
+ default:
+ DEBUG("Unknown endpoint: %d\n", ep_index(ep));
+ break;
+ }
+ }
+}
+
+/*
+ * nuke - dequeue ALL requests
+ */
+static void nuke(struct jz4740_ep *ep, int status)
+{
+ struct jz4740_request *req;
+
+ DEBUG("%s, %p\n", __FUNCTION__, ep);
+
+ /* Flush FIFO */
+ flush(ep);
+
+ /* called with irqs blocked */
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct jz4740_request, queue);
+ done(ep, req, status);
+ }
+
+ /* Disable IRQ if EP is enabled (has descriptor) */
+ if (ep->desc)
+ pio_irq_disable(ep);
+}
+
+/** Flush EP FIFO
+ * NOTE: INDEX register must be set before this call
+ */
+static void flush(struct jz4740_ep *ep)
+{
+ DEBUG("%s, %p\n", __FUNCTION__, ep);
+
+ switch (ep->ep_type) {
+ case ep_control:
+ break;
+
+ case ep_bulk_in:
+ case ep_interrupt:
+ usb_setb(ep->csr, USB_INCSR_FF);
+ break;
+
+ case ep_bulk_out:
+ usb_setb(ep->csr, USB_OUTCSR_FF);
+ break;
+ }
+}
+
+/**
+ * jz4740_in_epn - handle IN interrupt
+ */
+static void jz4740_in_epn(struct jz4740_udc *dev, u32 ep_idx, u32 intr)
+{
+ u32 csr;
+ struct jz4740_ep *ep = &dev->ep[ep_idx + 1];
+ struct jz4740_request *req;
+
+ usb_set_index(ep_index(ep));
+
+ csr = usb_readb(ep->csr);
+ DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr);
+
+ if (csr & USB_INCSR_SENTSTALL) {
+ DEBUG("USB_INCSR_SENTSTALL\n");
+ usb_clearb(ep->csr, USB_INCSR_SENTSTALL);
+ return;
+ }
+
+ if (!ep->desc) {
+ DEBUG("%s: NO EP DESC\n", __FUNCTION__);
+ return;
+ }
+
+ if (list_empty(&ep->queue))
+ req = 0;
+ else
+ req = list_entry(ep->queue.next, struct jz4740_request, queue);
+
+ DEBUG("req: %p\n", req);
+
+ if (!req)
+ return;
+
+ write_fifo(ep, req);
+}
+
+/*
+ * Bulk OUT (recv)
+ */
+static void jz4740_out_epn(struct jz4740_udc *dev, u32 ep_idx, u32 intr)
+{
+ struct jz4740_ep *ep = &dev->ep[ep_idx];
+ struct jz4740_request *req;
+
+ DEBUG("%s: %d\n", __FUNCTION__, ep_idx);
+
+ usb_set_index(ep_index(ep));
+ if (ep->desc) {
+ u32 csr;
+
+ if (use_dma) {
+ /* DMA starts here ... */
+ if (list_empty(&ep->queue))
+ req = 0;
+ else
+ req = list_entry(ep->queue.next, struct jz4740_request, queue);
+
+ if (req)
+ read_fifo(ep, req);
+ return;
+ }
+
+ /*
+ * PIO mode starts here ...
+ */
+
+ while ((csr = usb_readb(ep->csr)) &
+ (USB_OUTCSR_OUTPKTRDY | USB_OUTCSR_SENTSTALL)) {
+ DEBUG("%s: %x\n", __FUNCTION__, csr);
+
+ if (csr & USB_OUTCSR_SENTSTALL) {
+ DEBUG("%s: stall sent, flush fifo\n",
+ __FUNCTION__);
+ /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */
+ flush(ep);
+ } else if (csr & USB_OUTCSR_OUTPKTRDY) {
+ if (list_empty(&ep->queue))
+ req = 0;
+ else
+ req =
+ list_entry(ep->queue.next,
+ struct jz4740_request,
+ queue);
+
+ if (!req) {
+ DEBUG("%s: NULL REQ %d\n",
+ __FUNCTION__, ep_idx);
+ break;
+ } else {
+ read_fifo(ep, req);
+ }
+ }
+ }
+ } else {
+ /* Throw packet away.. */
+ printk("%s: ep %p ep_indx %d No descriptor?!?\n", __FUNCTION__, ep, ep_idx);
+ flush(ep);
+ }
+}
+
+static int jz4740_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct jz4740_ep *ep;
+ struct jz4740_udc *dev;
+ unsigned long flags;
+ u32 max, csrh = 0;
+
+ ep = container_of(_ep, struct jz4740_ep, ep);
+ if (!_ep || !desc || ep->desc || _ep->name == ep0name
+ || desc->bDescriptorType != USB_DT_ENDPOINT
+ || ep->bEndpointAddress != desc->bEndpointAddress) {
+ DEBUG("%s, bad ep or descriptor\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* xfer types must match, except that interrupt ~= bulk */
+ if (ep->bmAttributes != desc->bmAttributes
+ && ep->bmAttributes != USB_ENDPOINT_XFER_BULK
+ && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
+ DEBUG("%s, %s type mismatch\n", __FUNCTION__, _ep->name);
+ return -EINVAL;
+ }
+
+ dev = ep->dev;
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+ DEBUG("%s, bogus device state\n", __FUNCTION__);
+ return -ESHUTDOWN;
+ }
+
+ max = le16_to_cpu(desc->wMaxPacketSize);
+
+ /* Configure the endpoint */
+ usb_set_index(desc->bEndpointAddress & 0x0F);
+ if (ep_is_in(ep)) {
+ usb_writew(USB_REG_INMAXP, max);
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ csrh &= ~USB_INCSRH_ISO;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ csrh |= USB_INCSRH_ISO;
+ break;
+ }
+ usb_writeb(USB_REG_INCSRH, csrh);
+ }
+ else {
+ usb_writew(USB_REG_OUTMAXP, max);
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK:
+ csrh &= ~USB_OUTCSRH_ISO;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ csrh &= ~USB_OUTCSRH_ISO;
+ csrh |= USB_OUTCSRH_DNYT;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ csrh |= USB_OUTCSRH_ISO;
+ break;
+ }
+ usb_writeb(USB_REG_OUTCSRH, csrh);
+ }
+
+ spin_lock_irqsave(&ep->dev->lock, flags);
+
+ ep->stopped = 0;
+ ep->desc = desc;
+ ep->pio_irqs = 0;
+ ep->ep.maxpacket = max;
+
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+ /* Reset halt state (does flush) */
+ jz4740_set_halt(_ep, 0);
+
+ DEBUG("%s: enabled %s\n", __FUNCTION__, _ep->name);
+
+ return 0;
+}
+
+/** Disable EP
+ * NOTE: Sets INDEX register
+ */
+static int jz4740_ep_disable(struct usb_ep *_ep)
+{
+ struct jz4740_ep *ep;
+ unsigned long flags;
+
+ DEBUG("%s, %p\n", __FUNCTION__, _ep);
+
+ ep = container_of(_ep, struct jz4740_ep, ep);
+ if (!_ep || !ep->desc) {
+ DEBUG("%s, %s not enabled\n", __FUNCTION__,
+ _ep ? ep->ep.name : NULL);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ep->dev->lock, flags);
+
+ usb_set_index(ep_index(ep));
+
+ /* Nuke all pending requests (does flush) */
+ nuke(ep, -ESHUTDOWN);
+
+ /* Disable ep IRQ */
+ pio_irq_disable(ep);
+
+ ep->desc = 0;
+ ep->stopped = 1;
+
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+ DEBUG("%s: disabled %s\n", __FUNCTION__, _ep->name);
+ return 0;
+}
+
+static struct usb_request *jz4740_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+ struct jz4740_request *req;
+
+ DEBUG("%s, %p\n", __FUNCTION__, ep);
+
+ req = kzalloc(sizeof(*req), gfp_flags);
+ if (!req)
+ return 0;
+
+ INIT_LIST_HEAD(&req->queue);
+
+ return &req->req;
+}
+
+static void jz4740_free_request(struct usb_ep *ep, struct usb_request *_req)
+{
+ struct jz4740_request *req;
+
+ DEBUG("%s, %p\n", __FUNCTION__, ep);
+
+ req = container_of(_req, struct jz4740_request, req);
+ WARN_ON(!list_empty(&req->queue));
+ kfree(req);
+}
+
+/*--------------------------------------------------------------------*/
+
+/** Queue one request
+ * Kickstart transfer if needed
+ * NOTE: Sets INDEX register
+ */
+static int jz4740_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct jz4740_request *req;
+ struct jz4740_ep *ep;
+ struct jz4740_udc *dev;
+ unsigned long flags;
+
+ DEBUG("%s, %p\n", __FUNCTION__, _ep);
+
+ req = container_of(_req, struct jz4740_request, req);
+ if (unlikely
+ (!_req || !_req->complete || !_req->buf
+ || !list_empty(&req->queue))) {
+ DEBUG("%s, bad params\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ ep = container_of(_ep, struct jz4740_ep, ep);
+ if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ DEBUG("%s, bad ep\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ dev = ep->dev;
+ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+ DEBUG("%s, bogus device state %p\n", __FUNCTION__, dev->driver);
+ return -ESHUTDOWN;
+ }
+
+ DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length,
+ _req->buf);
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ /* kickstart this i/o queue? */
+ DEBUG("Add to %d Q %d %d\n", ep_index(ep), list_empty(&ep->queue),
+ ep->stopped);
+ if (list_empty(&ep->queue) && likely(!ep->stopped)) {
+ u32 csr;
+
+ if (unlikely(ep_index(ep) == 0)) {
+ /* EP0 */
+ usb_set_index(0);
+ list_add_tail(&req->queue, &ep->queue);
+ jz4740_ep0_kick(dev, ep, _req);
+ goto done;
+ } else if (use_dma) {
+ /* DMA */
+ kick_dma(ep, req);
+ }
+ /* PIO */
+ else if (ep_is_in(ep)) {
+ /* EP1 & EP2 */
+ usb_set_index(ep_index(ep));
+ csr = usb_readb(ep->csr);
+ pio_irq_enable(ep);
+ if (!(csr & USB_INCSR_FFNOTEMPT)) {
+ if (write_fifo(ep, req) == 1)
+ req = 0;
+ }
+ } else {
+ /* EP1 */
+ usb_set_index(ep_index(ep));
+ csr = usb_readb(ep->csr);
+ pio_irq_enable(ep);
+ if (csr & USB_OUTCSR_OUTPKTRDY) {
+ if (read_fifo(ep, req) == 1)
+ req = 0;
+ }
+ }
+ }
+
+ /* pio or dma irq handler advances the queue. */
+ if (likely(req != 0))
+ list_add_tail(&req->queue, &ep->queue);
+done:
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return 0;
+}
+
+/* dequeue JUST ONE request */
+static int jz4740_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct jz4740_ep *ep;
+ struct jz4740_request *req;
+ unsigned long flags;
+
+ DEBUG("%s, %p\n", __FUNCTION__, _ep);
+
+ ep = container_of(_ep, struct jz4740_ep, ep);
+ if (!_ep || ep->ep.name == ep0name)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->dev->lock, flags);
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+ if (&req->req != _req) {
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+ return -EINVAL;
+ }
+
+ done(ep, req, -ECONNRESET);
+
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+ return 0;
+}
+
+/** Halt specific EP
+ * Return 0 if success
+ * NOTE: Sets INDEX register to EP !
+ */
+static int jz4740_set_halt(struct usb_ep *_ep, int value)
+{
+ struct jz4740_ep *ep;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct jz4740_ep, ep);
+ if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ DEBUG("%s, bad ep\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ usb_set_index(ep_index(ep));
+
+ DEBUG("%s, ep %d, val %d\n", __FUNCTION__, ep_index(ep), value);
+
+ spin_lock_irqsave(&ep->dev->lock, flags);
+
+ if (ep_index(ep) == 0) {
+ /* EP0 */
+ usb_setb(USB_REG_CSR0, USB_CSR0_SENDSTALL);
+ } else if (ep_is_in(ep)) {
+ u32 csr = usb_readb(ep->csr);
+ if (value && ((csr & USB_INCSR_FFNOTEMPT)
+ || !list_empty(&ep->queue))) {
+ /*
+ * Attempts to halt IN endpoints will fail (returning -EAGAIN)
+ * if any transfer requests are still queued, or if the controller
+ * FIFO still holds bytes that the host hasnÂ’t collected.
+ */
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+ DEBUG
+ ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n",
+ (csr & USB_INCSR_FFNOTEMPT),
+ !list_empty(&ep->queue));
+ return -EAGAIN;
+ }
+ flush(ep);
+ if (value) {
+ usb_setb(ep->csr, USB_INCSR_SENDSTALL);
+ }
+ else {
+ usb_clearb(ep->csr, USB_INCSR_SENDSTALL);
+ usb_setb(ep->csr, USB_INCSR_CDT);
+ }
+ } else {
+
+ flush(ep);
+ if (value) {
+ usb_setb(ep->csr, USB_OUTCSR_SENDSTALL);
+ }
+ else {
+ usb_clearb(ep->csr, USB_OUTCSR_SENDSTALL);
+ usb_setb(ep->csr, USB_OUTCSR_CDT);
+ }
+ }
+
+ if (value) {
+ ep->stopped = 1;
+ } else {
+ ep->stopped = 0;
+ }
+
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+ DEBUG("%s %s halted\n", _ep->name, value == 0 ? "NOT" : "IS");
+
+ return 0;
+}
+
+/** Return bytes in EP FIFO
+ * NOTE: Sets INDEX register to EP
+ */
+static int jz4740_fifo_status(struct usb_ep *_ep)
+{
+ u32 csr;
+ int count = 0;
+ struct jz4740_ep *ep;
+
+ ep = container_of(_ep, struct jz4740_ep, ep);
+ if (!_ep) {
+ DEBUG("%s, bad ep\n", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ DEBUG("%s, %d\n", __FUNCTION__, ep_index(ep));
+
+ /* LPD can't report unclaimed bytes from IN fifos */
+ if (ep_is_in(ep))
+ return -EOPNOTSUPP;
+
+ usb_set_index(ep_index(ep));
+
+ csr = usb_readb(ep->csr);
+ if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN ||
+ csr & 0x1) {
+ count = usb_readw(USB_REG_OUTCOUNT);
+ }
+
+ return count;
+}
+
+/** Flush EP FIFO
+ * NOTE: Sets INDEX register to EP
+ */
+static void jz4740_fifo_flush(struct usb_ep *_ep)
+{
+ struct jz4740_ep *ep;
+
+ ep = container_of(_ep, struct jz4740_ep, ep);
+ if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ DEBUG("%s, bad ep\n", __FUNCTION__);
+ return;
+ }
+
+ usb_set_index(ep_index(ep));
+ flush(ep);
+}
+
+/****************************************************************/
+/* End Point 0 related functions */
+/****************************************************************/
+
+/* return: 0 = still running, 1 = completed, negative = errno */
+static int write_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req)
+{
+ u32 max;
+ unsigned count;
+ int is_last;
+
+ max = ep_maxpacket(ep);
+
+ if (req->req.length == 0) {
+ is_last = 1;
+ goto done;
+ }
+ count = write_packet(ep, req, max);
+
+ /* last packet is usually short (or a zlp) */
+ if (unlikely(count != max))
+ is_last = 1;
+ else {
+ if (likely(req->req.length != req->req.actual) || req->req.zero)
+ is_last = 0;
+ else
+ is_last = 1;
+ }
+
+ DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__,
+ ep->ep.name, count,
+ is_last ? "/L" : "", req->req.length - req->req.actual, req);
+
+done:
+ /* requests complete when all IN data is in the FIFO */
+ if (is_last) {
+ done(ep, req, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+static __inline__ int jz4740_fifo_read(struct jz4740_ep *ep,
+ unsigned char *cp, int max)
+{
+ int bytes;
+ int count = usb_readw(USB_REG_OUTCOUNT);
+ volatile u8 *fifo = (volatile u8 *)ep->fifo;
+
+ if (count > max)
+ count = max;
+ bytes = count;
+ while (count--)
+ *cp++ = *fifo;
+ return bytes;
+}
+
+static __inline__ void jz4740_fifo_write(struct jz4740_ep *ep,
+ unsigned char *cp, int count)
+{
+ volatile u8 *fifo = (volatile u8 *)ep->fifo;
+ DEBUG_EP0("fifo_write: %d %d\n", ep_index(ep), count);
+ while (count--)
+ *fifo = *cp++;
+}
+
+static int read_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req)
+{
+ u32 csr;
+ u8 *buf;
+ unsigned bufferspace, count, is_short = 0;
+ volatile u8 *fifo = (volatile u8 *)ep->fifo;
+
+ DEBUG_EP0("%s\n", __FUNCTION__);
+
+ csr = usb_readb(USB_REG_CSR0);
+ if (!(csr & USB_CSR0_OUTPKTRDY))
+ return 0;
+
+ if (req->req.length == 0)
+ goto done;
+ buf = req->req.buf + req->req.actual;
+ prefetchw(buf);
+ bufferspace = req->req.length - req->req.actual;
+
+ /* read all bytes from this packet */
+ if (likely(csr & USB_CSR0_OUTPKTRDY)) {
+ count = usb_readw(USB_REG_OUTCOUNT);
+ req->req.actual += min(count, bufferspace);
+ } else /* zlp */
+ count = 0;
+
+ is_short = (count < ep->ep.maxpacket);
+ DEBUG_EP0("read %s %02x, %d bytes%s req %p %d/%d\n",
+ ep->ep.name, csr, count,
+ is_short ? "/S" : "", req, req->req.actual, req->req.length);
+
+ while (likely(count-- != 0)) {
+ u8 byte = (u8) (*fifo & 0xff);
+
+ if (unlikely(bufferspace == 0)) {
+ /* this happens when the driver's buffer
+ * is smaller than what the host sent.
+ * discard the extra data.
+ */
+ if (req->req.status != -EOVERFLOW)
+ DEBUG_EP0("%s overflow %d\n", ep->ep.name,
+ count);
+ req->req.status = -EOVERFLOW;
+ } else {
+ *buf++ = byte;
+ bufferspace--;
+ }
+ }
+done:
+
+ /* completion */
+ if (is_short || req->req.actual == req->req.length) {
+ done(ep, req, 0);
+ return 1;
+ }
+
+ /* finished that packet. the next one may be waiting... */
+ return 0;
+}
+
+/**
+ * udc_set_address - set the USB address for this device
+ * @address:
+ *
+ * Called from control endpoint function after it decodes a set address setup packet.
+ */
+static void udc_set_address(struct jz4740_udc *dev, unsigned char address)
+{
+ DEBUG_EP0("%s: %d\n", __FUNCTION__, address);
+
+ dev->usb_address = address;
+ usb_writeb(USB_REG_FADDR, address);
+}
+
+/*
+ * DATA_STATE_RECV (USB_CSR0_OUTPKTRDY)
+ * - if error
+ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits
+ * - else
+ * set USB_CSR0_SVDOUTPKTRDY bit
+ if last set USB_CSR0_DATAEND bit
+ */
+static void jz4740_ep0_out(struct jz4740_udc *dev, u32 csr)
+{
+ struct jz4740_request *req;
+ struct jz4740_ep *ep = &dev->ep[0];
+ int ret;
+
+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
+
+ if (list_empty(&ep->queue))
+ req = 0;
+ else
+ req = list_entry(ep->queue.next, struct jz4740_request, queue);
+
+ if (req) {
+ ret = read_fifo_ep0(ep, req);
+ if (ret) {
+ /* Done! */
+ DEBUG_EP0("%s: finished, waiting for status\n",
+ __FUNCTION__);
+ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));
+ dev->ep0state = WAIT_FOR_SETUP;
+ } else {
+ /* Not done yet.. */
+ DEBUG_EP0("%s: not finished\n", __FUNCTION__);
+ usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY);
+ }
+ } else {
+ DEBUG_EP0("NO REQ??!\n");
+ }
+}
+
+/*
+ * DATA_STATE_XMIT
+ */
+static int jz4740_ep0_in(struct jz4740_udc *dev, u32 csr)
+{
+ struct jz4740_request *req;
+ struct jz4740_ep *ep = &dev->ep[0];
+ int ret, need_zlp = 0;
+
+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
+
+ if (list_empty(&ep->queue))
+ req = 0;
+ else
+ req = list_entry(ep->queue.next, struct jz4740_request, queue);
+
+ if (!req) {
+ DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__);
+ return 0;
+ }
+
+
+ if (req->req.length - req->req.actual == EP0_MAXPACKETSIZE) {
+ /* Next write will end with the packet size, */
+ /* so we need zero-length-packet */
+ need_zlp = 1;
+ }
+
+ ret = write_fifo_ep0(ep, req);
+
+ if (ret == 1 && !need_zlp) {
+ /* Last packet */
+ DEBUG_EP0("%s: finished, waiting for status\n", __FUNCTION__);
+
+ usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND));
+ dev->ep0state = WAIT_FOR_SETUP;
+ } else {
+ DEBUG_EP0("%s: not finished\n", __FUNCTION__);
+ usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY);
+ }
+
+ if (need_zlp) {
+ DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__);
+ usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY);
+ dev->ep0state = DATA_STATE_NEED_ZLP;
+ }
+
+ return 1;
+}
+
+#if 0
+static int jz4740_handle_get_status(struct jz4740_udc *dev,
+ struct usb_ctrlrequest *ctrl)
+{
+ struct jz4740_ep *ep0 = &dev->ep[0];
+ struct jz4740_ep *qep;
+ int reqtype = (ctrl->bRequestType & USB_RECIP_MASK);
+ u16 val = 0;
+
+ if (reqtype == USB_RECIP_INTERFACE) {
+ /* This is not supported.
+ * And according to the USB spec, this one does nothing..
+ * Just return 0
+ */
+ DEBUG_SETUP("GET_STATUS: USB_RECIP_INTERFACE\n");
+ } else if (reqtype == USB_RECIP_DEVICE) {
+ DEBUG_SETUP("GET_STATUS: USB_RECIP_DEVICE\n");
+ val |= (1 << 0); /* Self powered */
+ /*val |= (1<<1); *//* Remote wakeup */
+ } else if (reqtype == USB_RECIP_ENDPOINT) {
+ int ep_num = (ctrl->wIndex & ~USB_DIR_IN);
+
+ DEBUG_SETUP
+ ("GET_STATUS: USB_RECIP_ENDPOINT (%d), ctrl->wLength = %d\n",
+ ep_num, ctrl->wLength);
+
+ if (ctrl->wLength > 2 || ep_num > 3)
+ return -EOPNOTSUPP;
+
+ qep = &dev->ep[ep_num];
+ if (ep_is_in(qep) != ((ctrl->wIndex & USB_DIR_IN) ? 1 : 0)
+ && ep_index(qep) != 0) {
+ return -EOPNOTSUPP;
+ }
+
+ usb_set_index(ep_index(qep));
+
+ /* Return status on next IN token */
+ switch (qep->ep_type) {
+ case ep_control:
+ val =
+ (usb_readb(qep->csr) & USB_CSR0_SENDSTALL) ==
+ USB_CSR0_SENDSTALL;
+ break;
+ case ep_bulk_in:
+ case ep_interrupt:
+ val =
+ (usb_readb(qep->csr) & USB_INCSR_SENDSTALL) ==
+ USB_INCSR_SENDSTALL;
+ break;
+ case ep_bulk_out:
+ val =
+ (usb_readb(qep->csr) & USB_OUTCSR_SENDSTALL) ==
+ USB_OUTCSR_SENDSTALL;
+ break;
+ }
+
+ /* Back to EP0 index */
+ usb_set_index(0);
+
+ DEBUG_SETUP("GET_STATUS, ep: %d (%x), val = %d\n", ep_num,
+ ctrl->wIndex, val);
+ } else {
+ DEBUG_SETUP("Unknown REQ TYPE: %d\n", reqtype);
+ return -EOPNOTSUPP;
+ }
+
+ /* Clear "out packet ready" */
+ usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY);
+ /* Put status to FIFO */
+ jz4740_fifo_write(ep0, (u8 *) & val, sizeof(val));
+ /* Issue "In packet ready" */
+ usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND));
+
+ return 0;
+}
+#endif
+
+/*
+ * WAIT_FOR_SETUP (OUTPKTRDY)
+ * - read data packet from EP0 FIFO
+ * - decode command
+ * - if error
+ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits
+ * - else
+ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND bits
+ */
+static void jz4740_ep0_setup(struct jz4740_udc *dev, u32 csr)
+{
+ struct jz4740_ep *ep = &dev->ep[0];
+ struct usb_ctrlrequest ctrl;
+ int i;
+ int clear = 1;
+
+ DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr);
+
+ /* Nuke all previous transfers */
+ nuke(ep, -EPROTO);
+
+ /* read control req from fifo (8 bytes) */
+ jz4740_fifo_read(ep, (unsigned char *)&ctrl, 8);
+
+ DEBUG_SETUP("SETUP %02x.%02x v%04x i%04x l%04x\n",
+ ctrl.bRequestType, ctrl.bRequest,
+ ctrl.wValue, ctrl.wIndex, ctrl.wLength);
+
+ /* Set direction of EP0 */
+ if (likely(ctrl.bRequestType & USB_DIR_IN)) {
+ ep->bEndpointAddress |= USB_DIR_IN;
+ } else {
+ ep->bEndpointAddress &= ~USB_DIR_IN;
+ }
+
+ /* Handle some SETUP packets ourselves */
+ switch (ctrl.bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+ break;
+
+ DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue);
+ udc_set_address(dev, ctrl.wValue);
+ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));
+ return;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+ break;
+
+ DEBUG_SETUP("USB_REQ_SET_CONFIGURATION (%d)\n", ctrl.wValue);
+ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));
+
+ /* Enable RESUME and SUSPEND interrupts */
+ usb_setb(USB_REG_INTRUSBE, (USB_INTR_RESUME | USB_INTR_SUSPEND));
+ break;
+
+ case USB_REQ_SET_INTERFACE:
+ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+ break;
+
+ DEBUG_SETUP("USB_REQ_SET_INTERFACE (%d)\n", ctrl.wValue);
+ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));
+ break;
+
+// case USB_REQ_GET_STATUS:
+// if (jz4740_handle_get_status(dev, &ctrl) == 0)
+// return;
+
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ if (ctrl.bRequestType == USB_RECIP_ENDPOINT) {
+ struct jz4740_ep *qep;
+ int ep_num = (ctrl.wIndex & 0x0f);
+
+ /* Support only HALT feature */
+ if (ctrl.wValue != 0 || ctrl.wLength != 0
+ || ep_num > 3 || ep_num < 1)
+ break;
+
+ qep = &dev->ep[ep_num];
+ spin_unlock(&dev->lock);
+ if (ctrl.bRequest == USB_REQ_SET_FEATURE) {
+ DEBUG_SETUP("SET_FEATURE (%d)\n",
+ ep_num);
+ jz4740_set_halt(&qep->ep, 1);
+ } else {
+ DEBUG_SETUP("CLR_FEATURE (%d)\n",
+ ep_num);
+ jz4740_set_halt(&qep->ep, 0);
+ }
+ spin_lock(&dev->lock);
+
+ usb_set_index(0);
+
+ /* Reply with a ZLP on next IN token */
+ usb_setb(USB_REG_CSR0,
+ (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (clear) {
+ DEBUG_EP0("Clear OUTPKTRDY.\n");
+ usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY);
+ }
+ /* gadget drivers see class/vendor specific requests,
+ * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION},
+ * and more.
+ */
+ if (likely((u32)dev->driver)) {
+ /* device-2-host (IN) or no data setup command, process immediately */
+ spin_unlock(&dev->lock);
+
+ i = dev->driver->setup(&dev->gadget, &ctrl);
+ spin_lock(&dev->lock);
+
+ if (unlikely(i < 0)) {
+ /* setup processing failed, force stall */
+ DEBUG_SETUP
+ (" --> ERROR: gadget setup FAILED (stalling), setup returned %d\n",
+ i);
+ usb_set_index(0);
+ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL));
+
+ /* ep->stopped = 1; */
+ dev->ep0state = WAIT_FOR_SETUP;
+ }
+ else {
+ DEBUG_SETUP("gadget driver setup ok (%d)\n", ctrl.wLength);
+ }
+ }
+}
+
+/*
+ * DATA_STATE_NEED_ZLP
+ */
+static void jz4740_ep0_in_zlp(struct jz4740_udc *dev, u32 csr)
+{
+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
+
+ usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND));
+ dev->ep0state = WAIT_FOR_SETUP;
+}
+
+/*
+ * handle ep0 interrupt
+ */
+static void jz4740_handle_ep0(struct jz4740_udc *dev, u32 intr)
+{
+ struct jz4740_ep *ep = &dev->ep[0];
+ u32 csr;
+
+ /* Set index 0 */
+ usb_set_index(0);
+ csr = usb_readb(USB_REG_CSR0);
+
+ DEBUG_EP0("%s: csr = %x state = \n", __FUNCTION__, csr);//, state_names[dev->ep0state]);
+
+ /*
+ * if SENT_STALL is set
+ * - clear the SENT_STALL bit
+ */
+ if (csr & USB_CSR0_SENTSTALL) {
+ DEBUG_EP0("%s: USB_CSR0_SENTSTALL is set: %x\n", __FUNCTION__, csr);
+ usb_clearb(USB_REG_CSR0, USB_CSR0_SENDSTALL | USB_CSR0_SENTSTALL);
+ nuke(ep, -ECONNABORTED);
+ dev->ep0state = WAIT_FOR_SETUP;
+ return;
+ }
+
+ /*
+ * if a transfer is in progress && INPKTRDY and OUTPKTRDY are clear
+ * - fill EP0 FIFO
+ * - if last packet
+ * - set IN_PKT_RDY | DATA_END
+ * - else
+ * set IN_PKT_RDY
+ */
+ if (!(csr & (USB_CSR0_INPKTRDY | USB_CSR0_OUTPKTRDY))) {
+ DEBUG_EP0("%s: INPKTRDY and OUTPKTRDY are clear\n",
+ __FUNCTION__);
+
+ switch (dev->ep0state) {
+ case DATA_STATE_XMIT:
+ DEBUG_EP0("continue with DATA_STATE_XMIT\n");
+ jz4740_ep0_in(dev, csr);
+ return;
+ case DATA_STATE_NEED_ZLP:
+ DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n");
+ jz4740_ep0_in_zlp(dev, csr);
+ return;
+ default:
+ /* Stall? */
+// DEBUG_EP0("Odd state!! state = %s\n",
+// state_names[dev->ep0state]);
+ dev->ep0state = WAIT_FOR_SETUP;
+ /* nuke(ep, 0); */
+ /* usb_setb(ep->csr, USB_CSR0_SENDSTALL); */
+// break;
+ return;
+ }
+ }
+
+ /*
+ * if SETUPEND is set
+ * - abort the last transfer
+ * - set SERVICED_SETUP_END_BIT
+ */
+ if (csr & USB_CSR0_SETUPEND) {
+ DEBUG_EP0("%s: USB_CSR0_SETUPEND is set: %x\n", __FUNCTION__, csr);
+
+ usb_setb(USB_REG_CSR0, USB_CSR0_SVDSETUPEND);
+ nuke(ep, 0);
+ dev->ep0state = WAIT_FOR_SETUP;
+ }
+
+ /*
+ * if USB_CSR0_OUTPKTRDY is set
+ * - read data packet from EP0 FIFO
+ * - decode command
+ * - if error
+ * set SVDOUTPKTRDY | DATAEND | SENDSTALL bits
+ * - else
+ * set SVDOUTPKTRDY | DATAEND bits
+ */
+ if (csr & USB_CSR0_OUTPKTRDY) {
+
+ DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__,
+ csr);
+
+ switch (dev->ep0state) {
+ case WAIT_FOR_SETUP:
+ DEBUG_EP0("WAIT_FOR_SETUP\n");
+ jz4740_ep0_setup(dev, csr);
+ break;
+
+ case DATA_STATE_RECV:
+ DEBUG_EP0("DATA_STATE_RECV\n");
+ jz4740_ep0_out(dev, csr);
+ break;
+
+ default:
+ /* send stall? */
+ DEBUG_EP0("strange state!! 2. send stall? state = %d\n",
+ dev->ep0state);
+ break;
+ }
+ }
+}
+
+static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep, struct usb_request *req)
+{
+ u32 csr;
+
+ csr = usb_readb(USB_REG_CSR0);
+
+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
+
+ if (ep_is_in(ep)) {
+ dev->ep0state = DATA_STATE_XMIT;
+ jz4740_ep0_in(dev, csr);
+ } else {
+ dev->ep0state = DATA_STATE_RECV;
+ /* out request will wait for the interrupt except the zero length state */
+ if (!req->length)
+ jz4740_ep0_out(dev, csr);
+ }
+}
+
+static void jz4740_handle_reset(struct jz4740_udc *dev)
+{
+ udc_set_address(dev, 0);
+
+ /* Disable interrupts */
+ usb_writew(USB_REG_INTRINE, 0);
+ usb_writew(USB_REG_INTROUTE, 0);
+ usb_writeb(USB_REG_INTRUSBE, 0);
+
+ /* Disable DMA */
+ usb_writel(USB_REG_CNTL1, 0);
+ usb_writel(USB_REG_CNTL2, 0);
+
+ stop_activity(dev, dev->driver);
+
+ /* Enable interrupts */
+ usb_setw(USB_REG_INTRINE, USB_INTR_EP0);
+ usb_setb(USB_REG_INTRUSBE, USB_INTR_RESET);
+
+ dev->ep0state = WAIT_FOR_SETUP;
+
+ dev->gadget.speed = (usb_readb(USB_REG_POWER) & USB_POWER_HSMODE) ?
+ USB_SPEED_HIGH : USB_SPEED_FULL;
+
+ DEBUG_SETUP("%s: address = %d, speed = %s\n", __FUNCTION__, dev->usb_address,
+ (dev->gadget.speed == USB_SPEED_HIGH) ? "HIGH":"FULL");
+}
+
+static void jz4740_handle_resume(struct jz4740_udc *dev)
+{
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN
+ && dev->driver && dev->driver->resume)
+ dev->driver->resume(&dev->gadget);
+
+ return;
+}
+
+static void jz4740_handle_suspend(struct jz4740_udc *dev)
+{
+ /* Host unloaded from us, can do something, such as flushing
+ the NAND block cache etc. */
+
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN
+ && dev->driver && dev->driver->suspend)
+ dev->driver->suspend(&dev->gadget);
+
+ return;
+}
+
+/*
+ * jz4740 usb device interrupt handler.
+ */
+static irqreturn_t jz4740_udc_irq(int irq, void *_dev)
+{
+ struct jz4740_udc *dev = _dev;
+
+ int do_keep_alive = 1;
+
+ u32 intr_usb = usb_readb(USB_REG_INTRUSB) & 0x7; /* mask SOF */
+ u32 intr_in = usb_readw(USB_REG_INTRIN);
+ u32 intr_out = usb_readw(USB_REG_INTROUT);
+ u32 intr_dma = usb_readb(USB_REG_INTR);
+
+ if (!intr_usb && !intr_in && !intr_out && !intr_dma)
+ return IRQ_HANDLED;
+
+ DEBUG("intr_out = %x intr_in=%x intr_usb=%x\n",
+ intr_out, intr_in, intr_usb);
+
+ spin_lock(&dev->lock);
+
+ /* Check for resume from suspend mode */
+ if ((intr_usb & USB_INTR_RESUME) &&
+ (usb_readb(USB_REG_INTRUSBE) & USB_INTR_RESUME)) {
+ DEBUG("USB resume\n");
+ jz4740_handle_resume(dev);
+
+ do_keep_alive = 0;
+ }
+
+ /* Check for system interrupts */
+ if (intr_usb & USB_INTR_RESET) {
+ DEBUG("USB reset\n");
+ jz4740_handle_reset(dev);
+ }
+
+ /* Check for endpoint 0 interrupt */
+ if (intr_in & USB_INTR_EP0) {
+ DEBUG("USB_INTR_EP0 (control)\n");
+ jz4740_handle_ep0(dev, intr_in);
+ }
+
+ /* Check for Bulk-IN DMA interrupt */
+ if (intr_dma & 0x1) {
+ int ep_num;
+ ep_num = (usb_readl(USB_REG_CNTL1) >> 4) & 0xf;
+ jz4740_in_epn(dev, ep_num, intr_in);
+ }
+
+ /* Check for Bulk-OUT DMA interrupt */
+ if (intr_dma & 0x2) {
+ int ep_num;
+ ep_num = (usb_readl(USB_REG_CNTL2) >> 4) & 0xf;
+ jz4740_out_epn(dev, ep_num, intr_out);
+ }
+
+ /* Check for each configured endpoint interrupt */
+ if (intr_in & USB_INTR_INEP1) {
+ DEBUG("USB_INTR_INEP1\n");
+ jz4740_in_epn(dev, 1, intr_in);
+ }
+
+ if (intr_in & USB_INTR_INEP2) {
+ DEBUG("USB_INTR_INEP2\n");
+ jz4740_in_epn(dev, 2, intr_in);
+ }
+
+ if (intr_out & USB_INTR_OUTEP1) {
+ DEBUG("USB_INTR_OUTEP1\n");
+ jz4740_out_epn(dev, 1, intr_out);
+ }
+
+ /* Check for suspend mode */
+ if ((intr_usb & USB_INTR_SUSPEND) &&
+ (usb_readb(USB_REG_INTRUSBE) & USB_INTR_SUSPEND)) {
+ DEBUG("USB suspend\n");
+ jz4740_handle_suspend(dev);
+
+ do_keep_alive = 0;
+ }
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+ if (do_keep_alive)
+ uh_alive();
+#endif
+
+ spin_unlock(&dev->lock);
+ return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int jz4740_udc_get_frame(struct usb_gadget *_gadget)
+{
+ DEBUG("%s, %p\n", __FUNCTION__, _gadget);
+ return usb_readw(USB_REG_FRAME);
+}
+
+static int jz4740_udc_wakeup(struct usb_gadget *_gadget)
+{
+ /* host may not have enabled remote wakeup */
+ /*if ((UDCCS0 & UDCCS0_DRWF) == 0)
+ return -EHOSTUNREACH;
+ udc_set_mask_UDCCR(UDCCR_RSM); */
+ return -ENOTSUPP;
+}
+
+static const struct usb_gadget_ops jz4740_udc_ops = {
+ .get_frame = jz4740_udc_get_frame,
+ .wakeup = jz4740_udc_wakeup,
+ /* current versions must always be self-powered */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static struct jz4740_udc udc_dev = {
+ .usb_address = 0,
+
+ .gadget = {
+ .ops = &jz4740_udc_ops,
+ .ep0 = &udc_dev.ep[0].ep,
+ .name = driver_name,
+ .dev = {
+ .init_name = "gadget",
+ },
+ },
+
+ /* control endpoint */
+ .ep[0] = {
+ .ep = {
+ .name = ep0name,
+ .ops = &jz4740_ep_ops,
+ .maxpacket = EP0_MAXPACKETSIZE,
+ },
+ .dev = &udc_dev,
+
+ .bEndpointAddress = 0,
+ .bmAttributes = 0,
+
+ .ep_type = ep_control,
+ .fifo = USB_FIFO_EP0,
+ .csr = USB_REG_CSR0,
+ },
+
+ /* bulk out endpoint */
+ .ep[1] = {
+ .ep = {
+ .name = "ep1out-bulk",
+ .ops = &jz4740_ep_ops,
+ .maxpacket = EPBULK_MAXPACKETSIZE,
+ },
+ .dev = &udc_dev,
+
+ .bEndpointAddress = 1,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+ .ep_type = ep_bulk_out,
+ .fifo = USB_FIFO_EP1,
+ .csr = USB_REG_OUTCSR,
+ },
+
+ /* bulk in endpoint */
+ .ep[2] = {
+ .ep = {
+ .name = "ep1in-bulk",
+ .ops = &jz4740_ep_ops,
+ .maxpacket = EPBULK_MAXPACKETSIZE,
+ },
+ .dev = &udc_dev,
+
+ .bEndpointAddress = USB_DIR_IN | 1,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+ .ep_type = ep_bulk_in,
+ .fifo = USB_FIFO_EP1,
+ .csr = USB_REG_INCSR,
+ },
+
+ /* interrupt in endpoint */
+ .ep[3] = {
+ .ep = {
+ .name = "ep2in-int",
+ .ops = &jz4740_ep_ops,
+ .maxpacket = EPINTR_MAXPACKETSIZE,
+ },
+ .dev = &udc_dev,
+
+ .bEndpointAddress = USB_DIR_IN | 2,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+
+ .ep_type = ep_interrupt,
+ .fifo = USB_FIFO_EP2,
+ .csr = USB_REG_INCSR,
+ },
+};
+
+
+
+static int jz4740_udc_probe(struct platform_device *pdev)
+{
+ struct jz4740_udc *dev = &udc_dev;
+ int rc;
+
+ DEBUG("%s\n", __FUNCTION__);
+
+ spin_lock_init(&dev->lock);
+ the_controller = dev;
+
+ dev->dev = &pdev->dev;
+ dev->gadget.dev.parent = &pdev->dev;
+
+// strcpy (dum->gadget.dev.bus_id, "gadget");
+ dev->gadget.dev.release = jz4740_udc_release;
+ if ((rc = device_register (&dev->gadget.dev)) < 0)
+ return rc;
+ platform_set_drvdata(pdev, dev);
+
+ udc_disable(dev);
+ udc_reinit(dev);
+
+ /* irq setup */
+ if (request_irq(IRQ_UDC, jz4740_udc_irq, IRQF_DISABLED,//SA_SHIRQ/*|SA_SAMPLE_RANDOM*/,
+ driver_name, dev) != 0) {
+ printk(KERN_INFO "request UDC interrupt %d failed\n", IRQ_UDC);
+ return -EBUSY;
+ }
+
+ printk(KERN_INFO "%s\n", driver_desc);
+ printk(KERN_INFO "version: " DRIVER_VERSION "\n");
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+ uh_setup(pdev);
+
+ printk(KERN_INFO "Support UDC Hotplug.\n");
+#endif
+
+ return 0;
+}
+
+static int jz4740_udc_remove(struct platform_device *pdev)
+{
+ struct jz4740_udc *dev = platform_get_drvdata(pdev);
+ DEBUG("%s: %p\n", __FUNCTION__, dev);
+
+ if (dev->driver)
+ return -EBUSY;
+
+ udc_disable(dev);
+
+#ifdef CONFIG_JZ_UDC_HOTPLUG
+ uh_cleanup(pdev);
+#endif
+
+ free_irq(IRQ_UDC, dev);
+ platform_set_drvdata(pdev, 0);
+ device_unregister(&dev->gadget.dev);
+ the_controller = 0;
+
+ return 0;
+}
+
+static struct platform_driver udc_driver = {
+ .probe = jz4740_udc_probe,
+ .remove = jz4740_udc_remove,
+ .suspend = NULL,
+ .resume = NULL,
+ .driver = {
+ .name = (char *) driver_name,
+ .owner = THIS_MODULE,
+ },
+};
+
+static struct platform_device the_udc_pdev = {
+ .name = (char *) gadget_name,
+ .id = -1,
+ .dev = {
+ .release = jz4740_udc_release,
+ },
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+static int __init udc_init (void)
+{
+ platform_driver_register(&udc_driver);
+ return platform_device_register (&the_udc_pdev);
+}
+
+static void __exit udc_exit (void)
+{
+ platform_driver_unregister(&udc_driver);
+ platform_device_unregister(&the_udc_pdev);
+}
+
+module_init(udc_init);
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Wei Jianli <jlwei@ingenic.cn>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/jz4740_udc.h b/drivers/usb/gadget/jz4740_udc.h
new file mode 100644
index 00000000000..5d59f72a8d2
--- /dev/null
+++ b/drivers/usb/gadget/jz4740_udc.h
@@ -0,0 +1,105 @@
+/*
+ * linux/drivers/usb/gadget/jz4740_udc.h
+ *
+ * Ingenic JZ4740 on-chip high speed USB device controller
+ *
+ * Copyright (C) 2006 Ingenic Semiconductor Inc.
+ * Author: <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __USB_GADGET_JZ4740_H__
+#define __USB_GADGET_JZ4740_H__
+
+/*-------------------------------------------------------------------------*/
+
+// Max packet size
+#define EP0_MAXPACKETSIZE 64
+#define EPBULK_MAXPACKETSIZE 512
+#define EPINTR_MAXPACKETSIZE 64
+
+#define UDC_MAX_ENDPOINTS 4
+
+/*-------------------------------------------------------------------------*/
+
+typedef enum ep_type {
+ ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt
+} ep_type_t;
+
+struct jz4740_ep {
+ struct usb_ep ep;
+ struct jz4740_udc *dev;
+
+ const struct usb_endpoint_descriptor *desc;
+ struct list_head queue;
+ unsigned long pio_irqs;
+
+ u8 stopped;
+ u8 bEndpointAddress;
+ u8 bmAttributes;
+
+ ep_type_t ep_type;
+ u32 fifo;
+ u32 csr;
+
+ u32 reg_addr;
+};
+
+struct jz4740_request {
+ struct usb_request req;
+ struct list_head queue;
+};
+
+enum ep0state {
+ WAIT_FOR_SETUP, /* between STATUS ack and SETUP report */
+ DATA_STATE_XMIT, /* data tx stage */
+ DATA_STATE_NEED_ZLP, /* data tx zlp stage */
+ WAIT_FOR_OUT_STATUS, /* status stages */
+ DATA_STATE_RECV, /* data rx stage */
+};
+
+struct jz4740_udc {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct device *dev;
+ spinlock_t lock;
+
+ enum ep0state ep0state;
+ struct jz4740_ep ep[UDC_MAX_ENDPOINTS];
+
+ unsigned char usb_address;
+};
+
+extern struct jz4740_udc *the_controller;
+
+#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN)==USB_DIR_IN)
+#define ep_maxpacket(EP) ((EP)->ep.maxpacket)
+#define ep_index(EP) ((EP)->bEndpointAddress&0xF)
+#define usb_set_index(i) (REG8(USB_REG_INDEX) = (i))
+
+/*-------------------------------------------------------------------------*/
+
+/* 2.5 stuff that's sometimes missing in 2.4 */
+
+#ifndef container_of
+#define container_of list_entry
+#endif
+
+#ifndef likely
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+#ifndef BUG_ON
+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
+#endif
+
+#ifndef WARN_ON
+#define WARN_ON(x) do { } while (0)
+#endif
+
+#endif /* __USB_GADGET_JZ4740_H__ */
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index fc6e709f45b..7f235856447 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -105,7 +105,7 @@ struct gs_port {
struct list_head read_pool;
struct list_head read_queue;
unsigned n_read;
- struct tasklet_struct push;
+ struct work_struct push;
struct list_head write_pool;
struct gs_buf port_write_buf;
@@ -464,9 +464,9 @@ __acquires(&port->port_lock)
* So QUEUE_SIZE packets plus however many the FIFO holds (usually two)
* can be buffered before the TTY layer's buffers (currently 64 KB).
*/
-static void gs_rx_push(unsigned long _port)
+static void gs_rx_push(struct work_struct *work)
{
- struct gs_port *port = (void *)_port;
+ struct gs_port *port = container_of(work, struct gs_port, push);
struct tty_struct *tty;
struct list_head *queue = &port->read_queue;
bool disconnect = false;
@@ -560,7 +560,7 @@ recycle:
if (!list_empty(queue) && tty) {
if (!test_bit(TTY_THROTTLED, &tty->flags)) {
if (do_push)
- tasklet_schedule(&port->push);
+ schedule_work(&port->push);
else
pr_warning(PREFIX "%d: RX not scheduled?\n",
port->port_num);
@@ -581,7 +581,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
/* Queue all received data until the tty layer is ready for it. */
spin_lock(&port->port_lock);
list_add_tail(&req->list, &port->read_queue);
- tasklet_schedule(&port->push);
+ schedule_work(&port->push);
spin_unlock(&port->port_lock);
}
@@ -975,7 +975,7 @@ static void gs_unthrottle(struct tty_struct *tty)
* rts/cts, or other handshaking with the host, but if the
* read queue backs up enough we'll be NAKing OUT packets.
*/
- tasklet_schedule(&port->push);
+ schedule_work(&port->push);
pr_vdebug(PREFIX "%d: unthrottle\n", port->port_num);
}
spin_unlock_irqrestore(&port->port_lock, flags);
@@ -1028,7 +1028,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
init_waitqueue_head(&port->close_wait);
init_waitqueue_head(&port->drain_wait);
- tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
+ INIT_WORK(&port->push, gs_rx_push);
INIT_LIST_HEAD(&port->read_pool);
INIT_LIST_HEAD(&port->read_queue);
@@ -1183,7 +1183,7 @@ void gserial_cleanup(void)
ports[i].port = NULL;
mutex_unlock(&ports[i].lock);
- tasklet_kill(&port->push);
+ flush_scheduled_work();
/* wait for old opens to finish */
wait_event(port->close_wait, gs_closed(port));
diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h
deleted file mode 100644
index 300f0ed9475..00000000000
--- a/drivers/usb/gadget/u_serial.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * u_serial.h - interface to USB gadget "serial port"/TTY utilities
- *
- * Copyright (C) 2008 David Brownell
- * Copyright (C) 2008 by Nokia Corporation
- *
- * This software is distributed under the terms of the GNU General
- * Public License ("GPL") as published by the Free Software Foundation,
- * either version 2 of that License or (at your option) any later version.
- */
-
-#ifndef __U_SERIAL_H
-#define __U_SERIAL_H
-
-#include <linux/usb/composite.h>
-#include <linux/usb/cdc.h>
-
-/*
- * One non-multiplexed "serial" I/O port ... there can be several of these
- * on any given USB peripheral device, if it provides enough endpoints.
- *
- * The "u_serial" utility component exists to do one thing: manage TTY
- * style I/O using the USB peripheral endpoints listed here, including
- * hookups to sysfs and /dev for each logical "tty" device.
- *
- * REVISIT at least ACM could support tiocmget() if needed.
- *
- * REVISIT someday, allow multiplexing several TTYs over these endpoints.
- */
-struct gserial {
- struct usb_function func;
-
- /* port is managed by gserial_{connect,disconnect} */
- struct gs_port *ioport;
-
- struct usb_ep *in;
- struct usb_ep *out;
- struct usb_endpoint_descriptor *in_desc;
- struct usb_endpoint_descriptor *out_desc;
-
- /* REVISIT avoid this CDC-ACM support harder ... */
- struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */
-
- /* notification callbacks */
- void (*connect)(struct gserial *p);
- void (*disconnect)(struct gserial *p);
- int (*send_break)(struct gserial *p, int duration);
-};
-
-/* utilities to allocate/free request and buffer */
-struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags);
-void gs_free_req(struct usb_ep *, struct usb_request *req);
-
-/* port setup/teardown is handled by gadget driver */
-int gserial_setup(struct usb_gadget *g, unsigned n_ports);
-void gserial_cleanup(void);
-
-/* connect/disconnect is handled by individual functions */
-int gserial_connect(struct gserial *, u8 port_num);
-void gserial_disconnect(struct gserial *);
-
-/* functions are bound to configurations by a config or gadget driver */
-int acm_bind_config(struct usb_configuration *c, u8 port_num);
-int gser_bind_config(struct usb_configuration *c, u8 port_num);
-int obex_bind_config(struct usb_configuration *c, u8 port_num);
-
-#endif /* __U_SERIAL_H */
diff --git a/drivers/usb/gadget/udc_hotplug.c b/drivers/usb/gadget/udc_hotplug.c
new file mode 100644
index 00000000000..f606404f51b
--- /dev/null
+++ b/drivers/usb/gadget/udc_hotplug.c
@@ -0,0 +1,766 @@
+/*
+ * Ingenic USB Device Controller Hotplug Driver.
+ *
+ * Author: River Wang <zwang@ingenic.cn>
+ */
+
+/*
+How to use
+
+1. Basic usage:
+All controlling interfaces are locacated in /sys/devices/platform/jz4740_udc/.
+[uh_cable]: It indicates the status of the cable: offline/power/usb.
+
+2. Asychronous notification:
+You can use a non-blocking PF_NETLINK socket to receive the uevent sent by udc_houplug. DRIVER & UDC_HOTPLUG_CABLE_STATE varible in uevent can be used to get the status of UDC cable.
+
+3. Notification mode & Gadget loading:
+There are two notification modes can be configured by [uh_notify_mode]: auto/manual.
+Auto: When a USB cable with active signals is plugged in, the udc_hotplug driver will broadcast this event to jz4740_udc & userspace app, and jz4740_udc will try to activate the current gadget.
+
+This mode is used when userspace APP only wants to get the cable status notification.
+
+Manual: The event will only be broadcast to userspace APP. When APP decides to how to handle this event, It can make it with [uh_notify]:
+auto: The udc_hotplug driver broadcast the latest cable status to jz4740_udc.
+offline/power/usb:....
+
+This mode is recommended when multiple gadgets are used. Userspace APP is notified by the uevent, load the specific gadget module by insmod, then set [uh_notify] to broadcat the event at last.
+*/
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/wait.h>
+#include <linux/kthread.h>
+#include <linux/timer.h>
+#include <linux/kobject.h>
+#include <linux/notifier.h>
+
+#include <asm/jzsoc.h>
+
+#define UDC_PFX "jz_hotplug_udc"
+
+#define D(msg, fmt...) \
+ printk(KERN_ERR UDC_PFX": %s(): "msg, __func__, ##fmt)
+
+#define NR_UDC_WAIT_INTR_LOOP (5 * 1000 * 1000)
+
+#define DEFAULT_KEEP_ALIVE_TIMER_INTERVAL (2 * HZ)
+#define DEFAULT_KEEP_ALIVE_COUNTER_LIMIT 2
+
+#define UDC_HOTPLUG_PIN GPIO_UDC_HOTPLUG
+#define UDC_HOTPLUG_IRQ (IRQ_GPIO_0 + UDC_HOTPLUG_PIN)
+
+typedef enum {
+ UH_NOTIFY_CABLE_STATE = 0,
+}uh_notify_type_t;
+
+typedef enum {
+ UH_CABLE_STATE_OFFLINE = 0,
+ UH_CABLE_STATE_POWER,
+ UH_CABLE_STATE_USB,
+}uh_cable_state_t;
+
+typedef enum {
+ UH_THREAD_STATE_IDLE = 0,
+ UH_THREAD_STATE_START,
+ UH_THREAD_STATE_BUSY,
+ UH_THREAD_STATE_DONE,
+}uh_thread_state_t;
+
+/* UDC Flag bits */
+enum {
+ BIT_UH_ENABLE,
+
+ /* State changed ?*/
+ BIT_CABLE_STATE_CHANGE,
+
+ BIT_DO_DETECT,
+ BIT_DO_NOTIFY,
+
+ /* Keep alive */
+ BIT_KEEP_ALIVE,
+ BIT_KEEP_ALIVE_STOP,
+};
+
+#define DO_DETECT (1 << BIT_DO_DETECT)
+#define DO_NOTIFY (1 << BIT_DO_NOTIFY)
+#define DO_ALL ( DO_DETECT | DO_NOTIFY)
+
+struct uh_data {
+ unsigned long flags;
+
+ /* Notifier */
+ struct blocking_notifier_head notifier_head;
+
+ /* Thread */
+ struct task_struct *kthread;
+
+ int b_notify_mode;
+
+ /* Wait queue */
+ wait_queue_head_t kthread_wq; /* Kernel thread sleep here. */
+ wait_queue_head_t timer_wq; /* Wake up when timer is finished. */
+ wait_queue_head_t finish_wq; /* Wake up when thread is finished. */
+
+ uh_thread_state_t thread_state;
+ uh_cable_state_t cable_state;
+ uh_cable_state_t cable_detect_state;
+
+ struct timer_list stable_timer;
+ struct timer_list keep_alive_timer; /* Keep alive */
+
+ unsigned long keep_alive_counter_limit;
+ unsigned long keep_alive_timer_interval;
+ unsigned long keep_alive_counter;
+
+ struct platform_device *pdev;
+};
+
+static struct uh_data *g_puh_data = NULL;
+
+static inline void uh_start_work(struct uh_data *uh, int work)
+{
+ if (work & DO_DETECT) {
+ set_bit(BIT_DO_DETECT, &uh->flags);
+ }
+
+ if (work & DO_NOTIFY) {
+ set_bit(BIT_DO_NOTIFY, &uh->flags);
+ }
+
+ mod_timer(&uh->stable_timer, 1 + jiffies);
+
+ return;
+}
+
+static inline void set_cable_state(struct uh_data *uh, uh_cable_state_t state)
+{
+ if (uh->cable_state != state) {
+ D("Cable state: %d -> %d.\n", uh->cable_state, state);
+
+ uh->cable_state = state;
+ set_bit(BIT_CABLE_STATE_CHANGE, &uh->flags);
+ }
+
+ return;
+}
+
+static void uh_stable_timer_func(unsigned long data)
+{
+ struct uh_data *uh = (struct uh_data *)data;
+
+ D("Called.\n");
+
+ if (!test_bit(BIT_UH_ENABLE, &uh->flags))
+ return;
+
+ uh->thread_state = UH_THREAD_STATE_START;
+
+ /* Start. */
+ wake_up_process(uh->kthread);
+
+ return;
+}
+
+/* Do cable detection */
+static void cable_detect(struct uh_data *uh)
+{
+ if (__gpio_get_pin(UDC_HOTPLUG_PIN)) {
+ D("Cable online.\n");
+
+ uh->cable_detect_state = UH_CABLE_STATE_POWER;
+
+ }else {
+ D("Cable offline.\n");
+
+ clear_bit(BIT_KEEP_ALIVE, &uh->flags);
+
+ uh->cable_detect_state = UH_CABLE_STATE_OFFLINE;
+ }
+
+ return;
+}
+
+/* USB is active ? */
+static int usb_is_active(void)
+{
+ unsigned long timeout = NR_UDC_WAIT_INTR_LOOP;
+ unsigned long frame_no = REG16(USB_REG_FRAME);
+
+ /*
+ Some power charger may cause fake SOF,
+ We must handle this situation.
+ - River.
+ */
+
+ int counter = 7;
+
+ while (timeout && counter) {
+ if (frame_no != REG16(USB_REG_FRAME)) {
+ if (!--counter)
+ break;
+
+ /* Wait next frame. */
+ frame_no = REG16(USB_REG_FRAME);
+ }
+
+ timeout --;
+ }
+
+ D("timout: %d, counter: %d.\n", timeout, counter);
+
+ return timeout ? 1 : 0;
+}
+
+/* Really do USB detection */
+static int do_usb_detect(struct uh_data *uh)
+{
+ int rv;
+
+ D("Called.\n");
+
+ __intc_mask_irq(IRQ_UDC);
+
+ /* Now enable PHY to start detect */
+#ifdef CONFIG_SOC_JZ4740
+ REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE;
+#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D)
+ REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE;
+#endif
+ /* Clear IRQs */
+ REG16(USB_REG_INTRINE) = 0;
+ REG16(USB_REG_INTROUTE) = 0;
+ REG8(USB_REG_INTRUSBE) = 0;
+
+ /* disable UDC IRQs first */
+ REG16(USB_REG_INTRINE) = 0;
+ REG16(USB_REG_INTROUTE) = 0;
+ REG8(USB_REG_INTRUSBE) = 0;
+
+ /* Disable DMA */
+ REG32(USB_REG_CNTL1) = 0;
+ REG32(USB_REG_CNTL2) = 0;
+
+ /* Enable HS Mode */
+ REG8(USB_REG_POWER) |= USB_POWER_HSENAB;
+ /* Enable soft connect */
+ REG8(USB_REG_POWER) |= USB_POWER_SOFTCONN;
+
+ rv = usb_is_active();
+
+ /* Detect finish ,clean every thing */
+ /* Disconnect from usb */
+ REG8(USB_REG_POWER) &= ~USB_POWER_SOFTCONN;
+
+ /* Disable the USB PHY */
+#ifdef CONFIG_SOC_JZ4740
+ REG_CPM_SCR &= ~CPM_SCR_USBPHY_ENABLE;
+#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D)
+ REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE;
+#endif
+
+ /* Clear IRQs */
+ REG16(USB_REG_INTRINE) = 0;
+ REG16(USB_REG_INTROUTE) = 0;
+ REG8(USB_REG_INTRUSBE) = 0;
+
+ __intc_ack_irq(IRQ_UDC);
+ __intc_unmask_irq(IRQ_UDC);
+
+ return rv;
+}
+
+/* Do USB bus protocol detection */
+static void usb_detect(struct uh_data *uh)
+{
+ int rv = 0;
+
+ D("Called.\n");
+
+ /* If the cable has already been offline, we just pass the real USB detection. */
+ if (uh->cable_detect_state != UH_CABLE_STATE_OFFLINE) {
+ D("Do real detection.\n");
+ rv = do_usb_detect(uh);
+ }else{
+ D("No need to do real detection.\n");
+ }
+
+ if (rv) {
+ /* Online. */
+ uh->cable_detect_state = UH_CABLE_STATE_USB;
+ }else{
+ /* No USB Signal. */
+ if (uh->cable_detect_state == UH_CABLE_STATE_POWER) {
+ /* TODO: Wait USB alive again. */
+ }
+ }
+
+ return;
+}
+
+static void do_wait(struct uh_data *uh)
+{
+ D("Called.\n");
+
+ wait_event(uh->kthread_wq, uh->thread_state == UH_THREAD_STATE_START);
+
+ uh->thread_state = UH_THREAD_STATE_BUSY;
+
+ return;
+}
+
+/* Called from kernel thread */
+static void do_detect(struct uh_data *uh)
+{
+ D("Called.\n");
+
+ if (!test_and_clear_bit(BIT_DO_DETECT, &uh->flags))
+ return;
+
+ D("Do detect.\n");
+
+ if(__gpio_get_pin(UDC_HOTPLUG_PIN)) {
+ cable_detect(uh);
+ usb_detect(uh);
+
+ set_cable_state(uh, uh->cable_detect_state);
+ }else{
+ set_cable_state(uh, UH_CABLE_STATE_OFFLINE);
+ }
+
+ return;
+}
+
+static void __do_notify(struct uh_data *uh)
+{
+ D("Called.\n");
+
+ if (test_and_clear_bit(BIT_CABLE_STATE_CHANGE, &uh->flags)) {
+ D("Kick notifier chain.\n");
+
+ blocking_notifier_call_chain(&uh->notifier_head,
+ UH_NOTIFY_CABLE_STATE, &uh->cable_state);
+
+
+ D("Send uevent to userspace.\n");
+
+ switch (uh->cable_state) {
+ case UH_CABLE_STATE_USB:
+ kobject_uevent(&uh->pdev->dev.kobj, KOBJ_ADD);
+ break;
+
+ case UH_CABLE_STATE_POWER:
+ kobject_uevent(&uh->pdev->dev.kobj, KOBJ_CHANGE);
+ break;
+
+ case UH_CABLE_STATE_OFFLINE:
+ kobject_uevent(&uh->pdev->dev.kobj, KOBJ_REMOVE);
+ break;
+ }
+ }
+
+ return;
+}
+
+static inline void do_notify(struct uh_data *uh)
+{
+ if (!uh->b_notify_mode) /* Auto nofity mode. */
+ set_bit(BIT_DO_NOTIFY, &uh->flags);
+
+ if (test_and_clear_bit(BIT_DO_NOTIFY, &uh->flags))
+ __do_notify(uh);
+
+ return;
+}
+
+static inline void do_done(struct uh_data *uh)
+{
+ D("Done.\n");
+
+ uh->thread_state = UH_THREAD_STATE_IDLE;
+
+ wake_up(&uh->finish_wq);
+
+ return;
+}
+
+/* Kernel thread */
+static int uh_thread(void *data)
+{
+ struct uh_data *uh = (struct uh_data *)data;
+
+ while (!kthread_should_stop()) {
+ do_wait(uh);
+
+ if (kthread_should_stop())
+ break;
+
+ do_detect(uh);
+
+ do_notify(uh);
+
+ do_done(uh);
+ }
+
+ D("Exit.\n");
+
+ return 0;
+}
+
+static irqreturn_t uh_irq(int irq, void *dev_id)
+{
+ struct uh_data *uh = (struct uh_data *)dev_id;
+
+ D("Called.\n");
+
+ uh_start_work(uh, DO_DETECT);
+
+ return IRQ_HANDLED;
+}
+
+static void uh_init_gpio(struct uh_data *uh)
+{
+ /* get current pin level */
+ __gpio_disable_pull(UDC_HOTPLUG_PIN);
+ __gpio_as_input(UDC_HOTPLUG_PIN);
+
+ udelay(1);
+
+ /* Because of every plug IN/OUT action will casue more than one interrupt,
+ So whether rising trigger or falling trigger method can both start the detection.
+ */
+
+ __gpio_as_irq_rise_edge(UDC_HOTPLUG_PIN);
+
+ return;
+}
+
+static void uh_keep_alive_timer_func(unsigned long data)
+{
+ struct uh_data *uh = (struct uh_data *)data;
+
+// D("Timer running.\n");
+
+ /* Decrease the counter. */
+ if (test_bit(BIT_KEEP_ALIVE, &uh->flags)
+ && !(--uh->keep_alive_counter)) {
+
+ if (!usb_is_active()) {
+ D("Timeout.\n");
+
+ clear_bit(BIT_KEEP_ALIVE, &uh->flags);
+
+ if (uh->cable_state == UH_CABLE_STATE_USB)
+ set_cable_state(uh, UH_CABLE_STATE_POWER);
+
+ uh_start_work(uh, DO_NOTIFY);
+ }
+ }
+
+ /* Set next active time. */
+ if (test_bit(BIT_KEEP_ALIVE, &uh->flags)) {
+ mod_timer(&uh->keep_alive_timer, uh->keep_alive_timer_interval + jiffies);
+ }else{
+ D("Timer will stop.\n");
+
+ set_bit(BIT_KEEP_ALIVE_STOP, &uh->flags);
+ wake_up(&uh->timer_wq);
+ }
+
+ return;
+}
+
+static void uh_set_counter(unsigned long timer_interval_in_jiffies, unsigned long counter_limit)
+{
+ struct uh_data *uh = g_puh_data;
+
+ uh->keep_alive_timer_interval = timer_interval_in_jiffies;
+ uh->keep_alive_counter_limit = counter_limit;
+
+ uh->keep_alive_counter = uh->keep_alive_counter_limit;
+
+ return;
+}
+
+static void uh_disable(void)
+{
+ struct uh_data *uh = g_puh_data;
+
+ /* Disable the source of input. */
+ clear_bit(BIT_UH_ENABLE, &uh->flags);
+
+ if (test_and_clear_bit(BIT_KEEP_ALIVE, &uh->flags))
+ /* Wait timer stop. */
+ wait_event(uh->timer_wq, test_and_clear_bit(BIT_KEEP_ALIVE_STOP, &uh->flags));
+
+ /* Wait thread idle. */
+ wait_event(uh->finish_wq, uh->thread_state == UH_THREAD_STATE_IDLE);
+
+ return;
+}
+
+static void uh_enable(void)
+{
+ struct uh_data *uh = g_puh_data;
+
+ set_bit(BIT_UH_ENABLE, &uh->flags);
+
+ return;
+}
+
+static void uh_alive(void)
+{
+ struct uh_data *uh = g_puh_data;
+
+ if (!test_bit(BIT_UH_ENABLE, &uh->flags))
+ return;
+
+ /* Reset counter */
+ uh->keep_alive_counter = uh->keep_alive_counter_limit;
+
+ /* We are alive. */
+ if (!test_bit(BIT_KEEP_ALIVE, &uh->flags)) {
+ D("Active timer.\n");
+
+ /* Active timer. */
+ set_bit(BIT_KEEP_ALIVE, &uh->flags);
+ clear_bit(BIT_KEEP_ALIVE_STOP, &uh->flags);
+
+ mod_timer(&uh->keep_alive_timer, 3 + jiffies);
+ }
+
+ return;
+}
+
+int uh_register_notifier(struct notifier_block *n)
+{
+ struct uh_data *uh = g_puh_data;
+
+ D("Register notifier: 0x%p.\n", (void *)n);
+
+ BUG_ON(!n->notifier_call);
+
+ /* Notify in auto mode. */
+ if (!uh->b_notify_mode)
+ n->notifier_call(n, UH_NOTIFY_CABLE_STATE, &uh->cable_state);
+
+ return blocking_notifier_chain_register(&uh->notifier_head, n);
+}EXPORT_SYMBOL(uh_register_notifier);
+
+int uh_unregister_notifier(struct notifier_block *n)
+{
+ struct uh_data *uh = g_puh_data;
+
+ int rv;
+
+ D("Unregister notifier: 0x%p.\n", (void *)n);
+
+ /* Wait all stop. */
+ uh_disable();
+
+ rv = blocking_notifier_chain_unregister(&uh->notifier_head, n);
+
+ uh_enable();
+
+ uh_start_work(uh, DO_DETECT); /* Update status. */
+
+ return rv;
+}EXPORT_SYMBOL(uh_unregister_notifier);
+
+static ssize_t show_cable(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct uh_data *uh = g_puh_data;
+
+ char *s = NULL;
+
+ switch (uh->cable_state) {
+ case UH_CABLE_STATE_OFFLINE:
+ s = "offline";
+ break;
+
+ case UH_CABLE_STATE_POWER:
+ s = "power";
+ break;
+
+ case UH_CABLE_STATE_USB:
+ s = "usb";
+ break;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t show_notify_mode(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct uh_data *uh = g_puh_data;
+
+ char *s = uh->b_notify_mode ? "manual" : "auto";
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t store_notify_mode(struct device *device, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct uh_data *uh = g_puh_data;
+
+ if (!strncmp(buf, "auto", 4)) {
+ uh->b_notify_mode = 0;
+ }else if (!strncmp(buf, "manual", 6)) {
+ uh->b_notify_mode = 1;
+ }
+
+ return count;
+}
+
+
+static ssize_t store_notify(struct device *device, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct uh_data *uh = g_puh_data;
+
+ if (!strncmp(buf, "auto", 4)) {
+ uh_start_work(uh, DO_ALL);
+ }
+
+ return count;
+}
+
+static struct device_attribute uh_sysfs_attrs[] = {
+ __ATTR(uh_cable, S_IRUGO|S_IWUSR, show_cable, NULL),
+ __ATTR(uh_notify_mode, S_IRUGO|S_IWUSR, show_notify_mode, store_notify_mode),
+ __ATTR(uh_notify, S_IRUGO|S_IWUSR, NULL, store_notify),
+};
+
+static int uh_register_attr(struct platform_device *pdev)
+{
+ int i, error = 0;
+
+ for (i = 0; i < ARRAY_SIZE(uh_sysfs_attrs); i++) {
+ error = device_create_file(&pdev->dev, &uh_sysfs_attrs[i]);
+
+ if (error)
+ break;
+ }
+
+ if (error) {
+ while (--i >= 0)
+ device_remove_file(&pdev->dev, &uh_sysfs_attrs[i]);
+ }
+
+ return 0;
+}
+
+static void uh_unregister_attr(struct platform_device *pdev)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(uh_sysfs_attrs); i++)
+ device_remove_file(&pdev->dev, &uh_sysfs_attrs[i]);
+}
+
+static int uh_setup(struct platform_device *pdev)
+{
+ struct uh_data *uh;
+
+ unsigned long status = 0;
+
+ int rv;
+
+ g_puh_data = (struct uh_data *)kzalloc(sizeof(struct uh_data), GFP_KERNEL);
+ if (!g_puh_data) {
+ printk(KERN_ERR UDC_PFX": Failed to allocate memory.\n");
+ return -ENOMEM;
+ }
+
+ uh = g_puh_data;
+ uh->pdev = pdev;
+
+ set_bit(1, &status);
+
+ init_waitqueue_head(&uh->kthread_wq);
+ init_waitqueue_head(&uh->timer_wq);
+ init_waitqueue_head(&uh->finish_wq);
+
+ BLOCKING_INIT_NOTIFIER_HEAD(&uh->notifier_head);
+
+ setup_timer(&uh->keep_alive_timer, uh_keep_alive_timer_func, (unsigned long)uh);
+ setup_timer(&uh->stable_timer, uh_stable_timer_func, (unsigned long)uh);
+
+ uh->kthread = kthread_run(uh_thread, uh, "kuhd");
+ if (IS_ERR(uh->kthread)) {
+ printk(KERN_ERR UDC_PFX": Failed to create UDC hotplug monitor thread.\n");
+ rv = PTR_ERR(uh->kthread);
+ goto err;
+ }
+
+ set_bit(2, &status);
+
+ uh_init_gpio(uh);
+
+ rv = uh_register_attr(pdev);
+ if (rv) {
+ printk(KERN_ERR UDC_PFX": Failed to register UDC sysfs interface.\n");
+ goto err;
+ }
+
+ set_bit(3, &status);
+
+ rv = request_irq(UDC_HOTPLUG_IRQ, uh_irq, IRQF_DISABLED, UDC_PFX, uh);
+ if (rv) {
+ printk(KERN_ERR UDC_PFX": Could not get udc hotplug irq %d\n", UDC_HOTPLUG_IRQ);
+ goto err;
+ }
+
+ uh_enable();
+
+ uh_set_counter(DEFAULT_KEEP_ALIVE_TIMER_INTERVAL, DEFAULT_KEEP_ALIVE_COUNTER_LIMIT);
+
+ uh_start_work(uh, DO_DETECT);
+
+ printk(KERN_ERR UDC_PFX": Registered.\n");
+
+ return 0;
+
+err:
+ if (test_bit(3, &status)) {
+ uh_unregister_attr(pdev);
+ }
+
+ if (test_bit(2, &status)) {
+ uh->thread_state = UH_THREAD_STATE_START;
+ kthread_stop(uh->kthread);
+ }
+
+ if (test_bit(1, &status)) {
+ kfree(g_puh_data);
+ }
+
+ return rv;
+}
+
+static void uh_cleanup(struct platform_device *pdev)
+{
+ struct uh_data *uh = g_puh_data;
+
+ uh_disable();
+
+ free_irq(UDC_HOTPLUG_IRQ, uh);
+
+ /* Let our thread to exit. */
+ uh->thread_state = UH_THREAD_STATE_START;
+ kthread_stop(uh->kthread);
+
+ uh_unregister_attr(pdev);
+ kfree(uh);
+
+ return;
+}
+
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 58151687d35..148ef674b55 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -992,6 +992,11 @@ MODULE_LICENSE ("GPL");
#define PCI_DRIVER ohci_pci_driver
#endif
+#ifdef CONFIG_JZSOC
+#include "ohci-jz.c"
+#define PLATFORM_DRIVER ohci_hcd_jz_driver
+#endif
+
#if defined(CONFIG_ARCH_SA1100) && defined(CONFIG_SA1111)
#include "ohci-sa1111.c"
#define SA1111_DRIVER ohci_hcd_sa1111_driver
diff --git a/drivers/usb/host/ohci-jz.c b/drivers/usb/host/ohci-jz.c
new file mode 100644
index 00000000000..4c43925509b
--- /dev/null
+++ b/drivers/usb/host/ohci-jz.c
@@ -0,0 +1,258 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ *
+ * Bus Glue for Ingenic Jz47xx.
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Rusell King et al.
+ *
+ * Modified for LH7A404 from ohci-sa1111.c
+ * by Durgesh Pattamatta <pattamattad@sharpsec.com>
+ * Modified for AMD Alchemy Au1xxx
+ * by Matt Porter <mporter@kernel.crashing.org>
+ * Modified for Jz47xx from ohci-au1xxx.c
+ * by Peter <jlwei@ingenic.cn>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/signal.h>
+
+#include <asm/jzsoc.h>
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void jz_start_ohc(struct platform_device *dev)
+{
+ printk(KERN_DEBUG __FILE__
+ ": starting JZ OHCI USB Controller\n");
+
+#ifdef CONFIG_SOC_JZ4750
+ __cpm_enable_uhcphy();
+#endif
+
+ /* enable host controller */
+ __cpm_start_uhc();
+
+ printk(KERN_DEBUG __FILE__
+ ": Clock to USB host has been enabled \n");
+}
+
+static void jz_stop_ohc(struct platform_device *dev)
+{
+ printk(KERN_DEBUG __FILE__
+ ": stopping JZ OHCI USB Controller\n");
+
+#ifdef CONFIG_SOC_JZ4750
+ __cpm_suspend_uhcphy();
+#endif
+ __cpm_stop_uhc();
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_ohci_jz_probe - initialize Jz-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+static int usb_ohci_jz_probe(const struct hc_driver *driver,
+ struct platform_device *dev)
+{
+ int retval;
+ struct usb_hcd *hcd;
+
+ if (dev->resource[1].flags != IORESOURCE_IRQ) {
+ pr_debug("resource[1] is not IORESOURCE_IRQ\n");
+ return -ENOMEM;
+ }
+
+ hcd = usb_create_hcd(driver, &dev->dev, "jz");
+ if (!hcd)
+ return -ENOMEM;
+ hcd->rsrc_start = dev->resource[0].start;
+ hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_debug("request_mem_region failed\n");
+ retval = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ pr_debug("ioremap failed\n");
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+ jz_start_ohc(dev);
+ ohci_hcd_init(hcd_to_ohci(hcd));
+
+ retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED | IRQF_SHARED);
+ if (retval == 0)
+ return retval;
+
+ jz_stop_ohc(dev);
+ iounmap(hcd->regs);
+ err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ err1:
+ usb_put_hcd(hcd);
+ return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_jz_remove - shutdown processing for Jz-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_jz_probe(), first invoking
+ * the HCD's stop() method. It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+static void usb_ohci_jz_remove(struct usb_hcd *hcd, struct platform_device *dev)
+{
+ usb_remove_hcd(hcd);
+ jz_stop_ohc(dev);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_jz_start (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret;
+
+ ohci_dbg (ohci, "ohci_jz_start, ohci:%p", ohci);
+
+ if ((ret = ohci_init (ohci)) < 0)
+ return ret;
+
+ if ((ret = ohci_run (ohci)) < 0) {
+ err ("can't start %s", hcd->self.bus_name);
+ ohci_stop (hcd);
+ return ret;
+ }
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_jz_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "JZ OHCI",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = ohci_jz_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_jz_drv_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ pr_debug ("In ohci_hcd_jz_drv_probe");
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ ret = usb_ohci_jz_probe(&ohci_jz_hc_driver, pdev);
+ return ret;
+}
+
+static int ohci_hcd_jz_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_ohci_jz_remove(hcd, pdev);
+ return 0;
+}
+ /*TBD*/
+/*static int ohci_hcd_jz_drv_suspend(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+ return 0;
+}
+static int ohci_hcd_jz_drv_resume(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+ return 0;
+}
+*/
+
+static struct platform_driver ohci_hcd_jz_driver = {
+ .probe = ohci_hcd_jz_drv_probe,
+ .remove = ohci_hcd_jz_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ /*.suspend = ohci_hcd_jz_drv_suspend, */
+ /*.resume = ohci_hcd_jz_drv_resume, */
+ .driver = {
+ .name = "jz-ohci",
+ .owner = THIS_MODULE,
+ },
+};
+
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3b54b394017..f146de3f34c 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -237,6 +237,227 @@ config FB_TILEBLITTING
comment "Frame buffer hardware drivers"
depends on FB
+config FB_JZSOC
+ tristate "JZSOC LCD controller support"
+ depends on FB && JZSOC
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ JZSOC LCD Controller and Smart LCD Controller driver support.
+
+config FB_JZ4740_SLCD
+ tristate "JZ4740 Smart LCD controller support"
+ depends on FB_JZSOC && SOC_JZ4740
+ default n
+ ---help---
+ This is the frame buffer device driver for the JZ4740 Smart LCD controller.
+ If select this, please set <JZ4740 LCD controller support> to <n>.
+
+choice
+ depends on FB_JZ4740_SLCD
+ prompt "SLCD Panel"
+ default JZ_SLCD_LGDP4551_8BUS
+
+config JZ_SLCD_LGDP4551
+ bool "LG LGDP4551 Smart LCD panel"
+ ---help---
+ Driver for Smart LCD LGDP4551, 8-bit sytem interface, 16BPP.
+
+config JZ_SLCD_SPFD5420A
+ bool "SPFD5420A Smart LCD panel"
+ ---help---
+ Driver for Smart LCD SPFD5420A 18-bit sytem interface, 18BPP.
+
+config JZ_SLCD_TRULY
+ bool "TRULY Smart LCD panel (MAX Pixels 400x240)"
+ ---help---
+
+endchoice
+
+config FB_JZLCD_4730_4740
+ tristate "JZ4730 JZ4740 LCD controller support"
+ depends on FB_JZSOC && (SOC_JZ4730 || SOC_JZ4740)
+ help
+ This is the frame buffer device driver for the JZ4730 and JZ4740 LCD controller.
+config JZLCD_FRAMEBUFFER_MAX
+ int "Default FrameBuffer num"
+ depends on FB_JZLCD_4730_4740
+ default "1"
+ ---help---
+ JZ LCD driver support multi-framebuffers for video applications.
+config JZLCD_FRAMEBUFFER_ROTATE_SUPPORT
+ bool "JZLCD FrameBuffer Rotate Support(For TEST)"
+ depends on FB_JZLCD_4730_4740
+ default n
+ ---help---
+ JZ LCD driver framebuffer rotate support. Rotate angle can be 0,90,180,270.
+ Note, this fearture is implemented by software, and will cost a lot of cpu capcity.
+ That is to say, if you select this function, you system will become slowly.
+ Rotate cost cpu about:
+ ratate angle 0'C: 0% cpu
+ ratate angle 90'C: 40% cpu
+ ratate angle 180'C: 20% cpu
+ ratate angle 270'C: 40% cpu
+
+config JZLCD_FRAMEBUFFER_DEFAULT_ROTATE_ANGLE
+ int "FrameBuffer default rotate angle"
+ depends on JZLCD_FRAMEBUFFER_ROTATE_SUPPORT
+ default 0
+ ---help---
+ JZ LCD driver framebuffer angle value can be:
+ 0: 0'C
+ 1: 90'C
+ 2: 180'C
+ 3: 270'C
+config JZLCD_FRAMEBUFFER_BPP
+ int "FrameBuffer bit per pixel"
+ depends on JZLCD_FRAMEBUFFER_ROTATE_SUPPORT
+ default 32
+ ---help---
+ JZ LCD driver framebuffer support 8bpp, 16bpp, 32bpp
+choice
+ depends on FB_JZLCD_4730_4740
+ prompt "LCD Panel"
+ default JZLCD_SAMSUNG_LTP400WQF01
+
+config JZLCD_SHARP_LQ035Q7
+ bool "SHARP LQ035Q7 TFT panel (240x320)"
+
+config JZLCD_SAMSUNG_LTS350Q1
+ bool "SAMSUNG LTS350Q1 TFT panel (240x320)"
+
+config JZLCD_SAMSUNG_LTV350QVF04
+ bool "SAMSUNG LTV350QV_F04 TFT panel (320x240)"
+
+config JZLCD_SAMSUNG_LTP400WQF01
+ bool "SAMSUNG LTP400WQF01 TFT panel (480x272)(16bits)"
+
+config JZLCD_SAMSUNG_LTP400WQF02
+ bool "SAMSUNG LTP400WQF02 TFT panel (480x272)(18bits)"
+
+config JZLCD_AUO_A030FL01_V1
+ bool "AUO A030FL01_V1 TFT panel (480x272)"
+
+config JZLCD_TRULY_TFTG320240DTSW
+ bool "TRULY TFTG320240DTSW TFT panel (320x240)"
+
+config JZLCD_TRULY_TFTG320240DTSW_SERIAL
+ bool "TRULY TFTG320240DTSW TFT panel (320x240)(8bit-serial mode)"
+
+config JZLCD_TRULY_TFTG240320UTSW_63W_E
+ bool "TRULY TFTG240320UTSW-63W-E TFT panel (240x320,2.5in)"
+
+config JZLCD_FOXCONN_PT035TN01
+ bool "FOXCONN PT035TN01 TFT panel (320x240)"
+
+config JZLCD_INNOLUX_PT035TN01_SERIAL
+ bool "INNOLUX PT035TN01 TFT panel (320x240,3.5in)(8bit-serial mode)"
+
+config JZLCD_TOSHIBA_LTM084P363
+ bool "Toshiba LTM084P363 TFT panel (800x600)"
+
+config JZLCD_HYNIX_HT10X21
+ bool "Hynix HT10X21_300 TFT panel (1024x768)"
+
+config JZLCD_INNOLUX_AT080TN42
+ bool "INNOLUX AT080TN42 TFT panel (800x600)"
+
+config JZLCD_CSTN_800x600
+ bool "800x600 colorDSTN panel"
+
+config JZLCD_CSTN_320x240
+ bool "320x240 colorSTN panel"
+
+config JZLCD_MSTN_480x320
+ bool "480x320 monoSTN panel"
+
+config JZLCD_MSTN_320x240
+ bool "320x240 monoSTN panel"
+
+config JZLCD_MSTN_240x128
+ bool "240x128 monoSTN panel"
+
+config JZLCD_MSTN_INVERSE
+ bool "Use an inverse color display."
+ depends on (JZLCD_MSTN_480x320 || JZLCD_MSTN_240x128)
+
+endchoice
+
+config FB_JZ4750_LCD
+ tristate "JZ4750 LCD Controller support"
+ depends on FB_JZSOC && (SOC_JZ4750 || SOC_JZ4750D || SOC_JZ4750L)
+ ---help---
+ JZ4750 LCD Controller driver.
+ JZ4750 LCD Controller support OSD function(refer jz4750_lcdc_spec.pdf).JZ4750 LCD OSD implement 2 framebuffer layers: foreground0 and foreground1. JZ4750 LCD driver support only foreground0 default.
+
+config FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER
+ bool "JZ4750 LCD driver 2 layers framebuffer support."
+ depends on FB_JZ4750_LCD
+ ---help---
+ JZ4750 LCD driver support only foreground0 by default.
+ If you need both foreground0 and foreground1, please select this.
+
+config FB_JZ4750_TVE
+ tristate "JZ4750 TV Encode support"
+ depends on FB_JZSOC && FB_JZ4750_LCD
+ default n
+
+config JZ4750_IPU_MM
+ tristate "JZ4750 IPU MM support"
+ depends on FB_JZSOC && FB_JZ4750_LCD
+ default y
+ ---help---
+ Enable IPU Memory Management system.
+ It will reserve 16MB / 16MB + 4MB as IPU Framebuffer on JZ4750 / JZ4755.
+ Enable this if you want to use IPU.
+
+config FB_JZ4750_SLCD
+ bool
+ depends on FB_JZ4750_LCD
+ default n
+choice
+ depends on FB_JZ4750_LCD
+ prompt "JZ4750 LCD Panels Support"
+ default JZ4750_LCD_SAMSUNG_LTP400WQF02
+ ---help---
+ Please select the lcd panel in you board
+
+config JZ4750_LCD_SAMSUNG_LTP400WQF01
+ bool "SAMSUNG LTP400WQF01 TFT panel (480x272)(16bits)"
+
+config JZ4750_LCD_SAMSUNG_LTP400WQF02
+ bool "SAMSUNG LTP400WQF02 TFT panel (480x272)(18bits)"
+
+config JZ4750_LCD_AUO_A043FL01V2
+ bool "AUO A043FL01V2 TFT panel (480x272)(24bits)"
+
+config JZ4750_LCD_FOXCONN_PT035TN01
+ bool "FOXCONN PT035TN01 TFT panel (320x240,3.5in)(18bit-parallel mode)"
+
+config JZ4750_LCD_INNOLUX_PT035TN01_SERIAL
+ bool "INNOLUX PT035TN01 TFT panel (320x240,3.5in)(8bit-serial mode)"
+
+config JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA
+ bool "TOPPOLY_TD025THEA7 TFT panel(320x240)(serial RGB delta mode)"
+
+config JZ4750_LCD_TOPPOLY_TD043MGEB1
+ bool "TOPPOLY_TD043MGEB1 TFT panel(800x480)(24bit mode)"
+
+config JZ4750_LCD_TRULY_TFTG320240DTSW_18BIT
+ bool "TRULY_TFTG320240DTSW TFT panel (320x240) (Parallel 18bit mode)"
+
+config JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W
+ bool "TRULY_TFT_GG1P0319LTSW_W (240x320) (Smart LCD 16bit)"
+
+config JZ4750_SLCD_KGM701A3_TFT_SPFD5420A
+ bool "KGM701A3_TFT_SPFD5420A (400x240) (Smart LCD 18bit)"
+ select FB_JZ4750_SLCD
+
+config JZ4750D_VGA_DISPLAY
+ depends on SOC_JZ4750D
+ bool "Jz4750D VGA Display"
+endchoice
config FB_CIRRUS
tristate "Cirrus Logic support"
depends on FB && (ZORRO || PCI)
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 01a819f4737..5a3c60d0477 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -28,6 +28,10 @@ obj-$(CONFIG_FB_DDC) += fb_ddc.o
obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
# Hardware specific drivers go first
+obj-$(CONFIG_FB_JZLCD_4730_4740) += jzlcd.o
+obj-$(CONFIG_FB_JZ4740_SLCD) += jz4740_slcd.o
+obj-$(CONFIG_FB_JZ4750_LCD) += jz4750_lcd.o
+obj-$(CONFIG_FB_JZ4750_TVE) += jz4750_tve.o
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o
obj-$(CONFIG_FB_ARC) += arcfb.o
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 2f50a80b413..92bd3ce1233 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -118,6 +118,14 @@ config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
If unsure, select n.
+config FRAMEBUFFER_CONSOLE_CURSOR_FLASH
+ bool "Framebuffer Console Cursor flash"
+ depends on FRAMEBUFFER_CONSOLE
+ help
+ Enable cursor flush for the framebuffer console. This is done
+ in software and may be significantly slower than a normally oriented
+ display.
+
config FRAMEBUFFER_CONSOLE_ROTATION
bool "Framebuffer Console Rotation"
depends on FRAMEBUFFER_CONSOLE
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 29ff5ea3cc3..0bf06b35ee3 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -367,6 +367,7 @@ static void fbcon_update_softback(struct vc_data *vc)
static void fb_flashcursor(struct work_struct *work)
{
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH
struct fb_info *info = container_of(work, struct fb_info, queue);
struct fbcon_ops *ops = info->fbcon_par;
struct display *p;
@@ -392,6 +393,7 @@ static void fb_flashcursor(struct work_struct *work)
ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
get_color(vc, info, c, 0));
release_console_sem();
+#endif
}
static void cursor_timer_handler(unsigned long dev_addr)
diff --git a/drivers/video/jz4740_slcd.c b/drivers/video/jz4740_slcd.c
new file mode 100644
index 00000000000..41f0928487b
--- /dev/null
+++ b/drivers/video/jz4740_slcd.c
@@ -0,0 +1,1334 @@
+/*
+ * linux/drivers/video/jzslcd.c -- Ingenic On-Chip Smart LCD frame buffer device
+ *
+ * Copyright (C) 2005-2007, Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_legacy.h>
+
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/jzsoc.h>
+
+#include "console/fbcon.h"
+
+#include "jz4740_slcd.h"
+
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
+#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
+#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
+#ifdef DEBUG
+#define print_dbg(f, arg...) printk("dbg::" __FILE__ ",LINE(%d): " f "\n", __LINE__, ## arg)
+#else
+#define print_dbg(f, arg...) do {} while (0)
+#endif
+
+static jz_dma_desc slcd_palette_desc __attribute__ ((aligned (16)));
+static jz_dma_desc slcd_frame_desc __attribute__ ((aligned (16)));
+
+static int dma_chan;
+static dma_addr_t slcd_frame_desc_phys_addr, slcd_palette_desc_phys_addr;
+
+static unsigned char non_link_desp = 0;
+static unsigned char is_set_reg = 0;
+struct lcd_cfb_info {
+ struct fb_info fb;
+ struct display_switch *dispsw;
+ signed int currcon;
+ int func_use_count;
+
+ struct {
+ u16 red, green, blue;
+ } palette[NR_PALETTE];
+#ifdef CONFIG_PM
+ struct pm_dev *pm;
+#endif
+};
+
+struct slcd_reg_info {
+ unsigned int cmd;
+ unsigned int data;
+};
+static struct slcd_reg_info reg_buf;
+static struct lcd_cfb_info *jzslcd_info;
+
+struct jzfb_info {
+ unsigned int cfg; /* panel mode and pin usage etc. */
+ unsigned int w;
+ unsigned int h;
+ unsigned int bpp; /* bit per pixel */
+ unsigned int bus;
+ unsigned int pclk; /* pixel clk */
+
+};
+
+static struct jzfb_info jzfb = {
+#ifdef CONFIG_JZ_SLCD_LGDP4551
+ SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_TYPE_PARALLEL,
+ 400, 240, 16, 8, 16000000 /*16 bpp, 8 bus*/
+// 240, 400, 18, 8, 16000000 /*18 bpp, 8 bus*/
+// 400, 240, 18, 8, 16000000 /*18 bpp, 8 bus*/
+#endif
+
+#ifdef CONFIG_JZ_SLCD_SPFD5420A
+ SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_TYPE_PARALLEL,
+ 400, 240, 18, 18, 16000000 /*18 bpp, 18 bus*/
+#endif
+};
+
+
+static volatile unsigned char *slcd_palette;
+static volatile unsigned char *slcd_frame;
+
+//extern struct display fb_display[MAX_NR_CONSOLES];
+static irqreturn_t slcd_dma_irq(int irq, void *dev_id);
+
+
+static void Mcupanel_RegSet(UINT32 cmd, UINT32 data)
+{
+ switch (jzfb.bus) {
+ case 8:
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff);
+ break;
+ case 9:
+ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2);
+ data = ((data << 6) & 0xfc0000) | ((data << 4) & 0xfc00) | ((data << 2) & 0xfc);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | data;
+ break;
+ case 16:
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | (cmd&0xffff);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff);
+ break;
+ case 18:
+ cmd = ((cmd & 0xff) << 1) | ((cmd & 0xff00) << 2);
+ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd;
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | ((data<<6)&0xfc0000)|((data<<4)&0xfc00) | ((data<<2)&0xfc);
+ break;
+ default:
+ printk("Don't support %d bit Bus\n", jzfb.bus );
+ break;
+ }
+}
+
+/* Sent a command withou data */
+static void Mcupanel_Command(UINT32 cmd) {
+ switch (jzfb.bus) {
+ case 8:
+ case 9:
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0);
+ break;
+ case 16:
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | (cmd&0xffff);
+ break;
+ case 18:
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) << 2) | ((cmd&0xff) << 1);
+ break;
+ default:
+ printk("Don't support %d bit Bus\n", jzfb.bus );
+ break;
+ }
+}
+
+/* Set the start address of screen, for example (0, 0) */
+#ifdef CONFIG_JZ_SLCD_LGDP4551
+static void Mcupanel_SetAddr(UINT16 x, UINT16 y)
+{
+ Mcupanel_RegSet(0x20,x) ;
+ udelay(1);
+ Mcupanel_RegSet(0x21,y) ;
+ udelay(1);
+ Mcupanel_Command(0x22);
+
+}
+#endif
+#ifdef CONFIG_JZ_SLCD_SPFD5420A
+void Mcupanel_SetAddr(u32 x, u32 y) //u32
+{
+ Mcupanel_RegSet(0x200,x) ;
+ udelay(1);
+ Mcupanel_RegSet(0x201,y) ;
+ udelay(1);
+ Mcupanel_Command(0x202);
+
+}
+
+#endif
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int jzfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;
+ unsigned short *ptr, ctmp;
+
+ print_dbg("regno:%d,RGBt:(%d,%d,%d,%d)\t", regno, red, green, blue, transp);
+ if (regno >= NR_PALETTE)
+ return 1;
+
+ cfb->palette[regno].red = red ;
+ cfb->palette[regno].green = green;
+ cfb->palette[regno].blue = blue;
+ if (cfb->fb.var.bits_per_pixel <= 16) {
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ red &= 0xff;
+ green &= 0xff;
+ blue &= 0xff;
+ }
+ switch (cfb->fb.var.bits_per_pixel) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ /* RGB 565 */
+ if (((red >> 3) == 0) && ((red >> 2) != 0))
+ red = 1 << 3;
+ if (((blue >> 3) == 0) && ((blue >> 2) != 0))
+ blue = 1 << 3;
+ ctmp = ((red >> 3) << 11)
+ | ((green >> 2) << 5) | (blue >> 3);
+
+ ptr = (unsigned short *)slcd_palette;
+ ptr = (unsigned short *)(((u32)ptr)|0xa0000000);
+ ptr[regno] = ctmp;
+
+ break;
+
+ case 15:
+ if (regno < 16)
+ ((u32 *)cfb->fb.pseudo_palette)[regno] =
+ ((red >> 3) << 10) |
+ ((green >> 3) << 5) |
+ (blue >> 3);
+ break;
+ case 16:
+ if (regno < 16) {
+ ((u32 *)cfb->fb.pseudo_palette)[regno] =
+ ((red >> 3) << 11) |
+ ((green >> 2) << 5) |
+ (blue >> 3);
+ }
+ break;
+ case 18:
+ case 24:
+ case 32:
+ if (regno < 16)
+ ((u32 *)cfb->fb.pseudo_palette)[regno] =
+ (red << 16) |
+ (green << 8) |
+ (blue << 0);
+
+/* if (regno < 16) {
+ unsigned val;
+ val = chan_to_field(red, &cfb->fb.var.red);
+ val |= chan_to_field(green, &cfb->fb.var.green);
+ val |= chan_to_field(blue, &cfb->fb.var.blue);
+ ((u32 *)cfb->fb.pseudo_palette)[regno] = val;
+ }
+*/
+
+ break;
+ }
+ return 0;
+}
+
+static int jzfb_ioctl (struct fb_info *info, unsigned int cmd, unsigned long arg )
+{
+ int ret = 0;
+ void __user *argp = (void __user *)arg;
+
+ switch (cmd) {
+ case FBIOSETBACKLIGHT:
+ __slcd_set_backlight_level(arg); /* We support 8 levels here. */
+ break;
+ case FBIODISPON:
+ __slcd_display_on();
+ break;
+ case FBIODISPOFF:
+ __slcd_display_off();
+ break;
+ case FBIO_REFRESH_ALWAYS:
+ dprintk("slcd_frame_desc.dcmd = 0x%08x\n", slcd_frame_desc.dcmd);
+ if (slcd_frame_desc.dcmd & DMAC_DCMD_LINK)
+ printk("The Smart LCD refreshes automatically. Option is omitted!\n");
+ else {
+ dprintk("OPEN DMAC_DCMD_LINK \n");
+ slcd_frame_desc.dcmd &= ~DMAC_DCMD_TIE;
+ slcd_frame_desc.dcmd |= DMAC_DCMD_LINK;
+ dma_cache_wback((unsigned long)(&slcd_frame_desc), 16);
+ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_TIE;
+ __dmac_channel_set_doorbell(dma_chan);
+ }
+ break;
+ case FBIO_REFRESH_EVENTS:
+ dprintk("slcd_frame_desc.dcmd = 0x%08x\n", slcd_frame_desc.dcmd);
+ if (!(slcd_frame_desc.dcmd & DMAC_DCMD_LINK))
+ printk("The Smart LCD is refreshed by envents. Option is omitted!\n");
+ else {
+ non_link_desp = 1;
+ REG_DMAC_DCMD(dma_chan) |= DMAC_DCMD_TIE;
+ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_LINK;
+ }
+ break;
+ case FBIO_DO_REFRESH:
+
+ dprintk("slcd_frame_desc.dcmd = 0x%08x\n", slcd_frame_desc.dcmd);
+ if (slcd_frame_desc.dcmd & DMAC_DCMD_LINK)
+ printk("The Smart LCD can refresh automatically. Option is omitted!\n");
+ else {
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ __dmac_channel_set_doorbell(dma_chan);
+ }
+ break;
+ case FBIO_SET_REG:
+ if (copy_from_user(&reg_buf, argp, sizeof(reg_buf)))
+ return -EFAULT;
+ is_set_reg = 1;
+ REG_DMAC_DCMD(dma_chan) |= DMAC_DCMD_TIE;
+ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_LINK;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */
+static int jzfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;
+ unsigned long start;
+ unsigned long off;
+ u32 len;
+
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
+
+ /* frame buffer memory */
+ start = cfb->fb.fix.smem_start;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb.fix.smem_len);
+ start &= PAGE_MASK;
+
+ if ((vma->vm_end - vma->vm_start + off) > len)
+ return -EINVAL;
+ off += start;
+
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ vma->vm_flags |= VM_IO;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Uncacheable */
+
+#if 1
+ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
+// pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; /* Uncacheable */
+ pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; /* Write-Through */
+#endif
+
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+/* checks var and eventually tweaks it to something supported,
+ * DO NOT MODIFY PAR */
+static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ print_dbg("jzfb_check_var");
+ return 0;
+}
+
+
+/*
+ * set the video mode according to info->var
+ */
+static int jzfb_set_par(struct fb_info *info)
+{
+// print_dbg("jzfb_set_par");
+ printk("jzfb_set_par");
+ return 0;
+}
+
+
+/*
+ * (Un)Blank the display.
+ * Fix me: should we use VESA value?
+ */
+static int jzfb_blank(int blank_mode, struct fb_info *info)
+{
+
+ dprintk("fb_blank %d %p", blank_mode, info);
+
+ switch (blank_mode) {
+
+ case FB_BLANK_UNBLANK:
+ /* Turn on panel */
+ break;
+
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_POWERDOWN:
+ /* Turn off panel */
+ break;
+ default:
+ break;
+
+ }
+ return 0;
+}
+
+/*
+ * pan display
+ */
+static int jzfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;
+ int dy;
+
+ if (!var || !cfb) {
+ return -EINVAL;
+ }
+
+ if (var->xoffset - cfb->fb.var.xoffset) {
+ /* No support for X panning for now! */
+ return -EINVAL;
+ }
+
+ dy = var->yoffset - cfb->fb.var.yoffset;
+ print_dbg("var.yoffset: %d", dy);
+ if (dy) {
+
+ print_dbg("Panning screen of %d lines", dy);
+// slcd_frame_desc->databuf += (cfb->fb.fix.line_length * dy);
+// slcd_frame_desc->dsadr += (cfb->fb.fix.line_length * dy);
+ /* TODO: Wait for current frame to finished */
+ }
+
+ return 0;
+}
+
+
+/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */
+static struct fb_ops jzfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = jzfb_setcolreg,
+ .fb_check_var = jzfb_check_var,
+ .fb_set_par = jzfb_set_par,
+ .fb_blank = jzfb_blank,
+ .fb_pan_display = jzfb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_mmap = jzfb_mmap,
+ .fb_ioctl = jzfb_ioctl,
+};
+
+static int jzfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;
+ //struct display *display;
+ int chgvar = 0;
+
+ var->height = jzfb.h ;
+ var->width = jzfb.w ;
+ var->bits_per_pixel = jzfb.bpp;
+
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->activate = cfb->fb.var.activate;
+ var->xres = var->width;
+ var->yres = var->height;
+ var->xres_virtual = var->width;
+ var->yres_virtual = var->height;
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->pixclock = 0;
+ var->left_margin = 0;
+ var->right_margin = 0;
+ var->upper_margin = 0;
+ var->lower_margin = 0;
+ var->hsync_len = 0;
+ var->vsync_len = 0;
+ var->sync = 0;
+ var->activate &= ~FB_ACTIVATE_TEST;
+
+ /*
+ * CONUPDATE and SMOOTH_XPAN are equal. However,
+ * SMOOTH_XPAN is only used internally by fbcon.
+ */
+ if (var->vmode & FB_VMODE_CONUPDATE) {
+ var->vmode |= FB_VMODE_YWRAP;
+ var->xoffset = cfb->fb.var.xoffset;
+ var->yoffset = cfb->fb.var.yoffset;
+ }
+
+ if (var->activate & FB_ACTIVATE_TEST)
+ return 0;
+
+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+ return -EINVAL;
+
+ if (cfb->fb.var.xres != var->xres)
+ chgvar = 1;
+ if (cfb->fb.var.yres != var->yres)
+ chgvar = 1;
+ if (cfb->fb.var.xres_virtual != var->xres_virtual)
+ chgvar = 1;
+ if (cfb->fb.var.yres_virtual != var->yres_virtual)
+ chgvar = 1;
+ if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel)
+ chgvar = 1;
+
+ //display = fb_display + con;
+
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+
+ switch(var->bits_per_pixel){
+ case 1: /* Mono */
+ cfb->fb.fix.visual = FB_VISUAL_MONO01;
+ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8;
+ break;
+ case 2: /* Mono */
+ var->red.offset = 0;
+ var->red.length = 2;
+ var->green.offset = 0;
+ var->green.length = 2;
+ var->blue.offset = 0;
+ var->blue.length = 2;
+
+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8;
+ break;
+ case 4: /* PSEUDOCOLOUR*/
+ var->red.offset = 0;
+ var->red.length = 4;
+ var->green.offset = 0;
+ var->green.length = 4;
+ var->blue.offset = 0;
+ var->blue.length = 4;
+
+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ cfb->fb.fix.line_length = var->xres / 2;
+ break;
+ case 8: /* PSEUDOCOLOUR, 256 */
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+
+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ cfb->fb.fix.line_length = var->xres ;
+ break;
+ case 15: /* DIRECTCOLOUR, 32k */
+ var->bits_per_pixel = 15;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+
+ cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
+ cfb->fb.fix.line_length = var->xres_virtual * 2;
+ break;
+ case 16: /* DIRECTCOLOUR, 64k */
+ var->bits_per_pixel = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+
+ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ cfb->fb.fix.line_length = var->xres_virtual * 2;
+ break;
+ case 18:
+ case 24:
+ case 32:
+ /* DIRECTCOLOUR, 256 */
+ var->bits_per_pixel = 32;
+
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+
+ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ cfb->fb.fix.line_length = var->xres_virtual * 4;
+ break;
+
+ default: /* in theory this should never happen */
+ printk(KERN_WARNING "%s: don't support for %dbpp\n",
+ cfb->fb.fix.id, var->bits_per_pixel);
+ break;
+ }
+
+ cfb->fb.var = *var;
+ cfb->fb.var.activate &= ~FB_ACTIVATE_ALL;
+
+ /*
+ * If we are setting all the virtual consoles, also set the
+ * defaults used to create new consoles.
+ */
+ fb_set_cmap(&cfb->fb.cmap, &cfb->fb);
+ dprintk("jzfb_set_var: after fb_set_cmap...\n");
+
+ return 0;
+}
+
+static struct lcd_cfb_info * jzfb_alloc_fb_info(void)
+{
+ struct lcd_cfb_info *cfb;
+
+ cfb = kmalloc(sizeof(struct lcd_cfb_info) + sizeof(u32) * 16, GFP_KERNEL);
+
+ if (!cfb)
+ return NULL;
+
+ jzslcd_info = cfb;
+
+ memset(cfb, 0, sizeof(struct lcd_cfb_info) );
+
+ cfb->currcon = -1;
+
+
+ strcpy(cfb->fb.fix.id, "jz-slcd");
+ cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+ cfb->fb.fix.type_aux = 0;
+ cfb->fb.fix.xpanstep = 1;
+ cfb->fb.fix.ypanstep = 1;
+ cfb->fb.fix.ywrapstep = 0;
+ cfb->fb.fix.accel = FB_ACCEL_NONE;
+
+ cfb->fb.var.nonstd = 0;
+ cfb->fb.var.activate = FB_ACTIVATE_NOW;
+ cfb->fb.var.height = -1;
+ cfb->fb.var.width = -1;
+ cfb->fb.var.accel_flags = FB_ACCELF_TEXT;
+
+ cfb->fb.fbops = &jzfb_ops;
+ cfb->fb.flags = FBINFO_FLAG_DEFAULT;
+
+ cfb->fb.pseudo_palette = (void *)(cfb + 1);
+
+ switch (jzfb.bpp) {
+ case 1:
+ fb_alloc_cmap(&cfb->fb.cmap, 4, 0);
+ break;
+ case 2:
+ fb_alloc_cmap(&cfb->fb.cmap, 8, 0);
+ break;
+ case 4:
+ fb_alloc_cmap(&cfb->fb.cmap, 32, 0);
+ break;
+ case 8:
+
+ default:
+ fb_alloc_cmap(&cfb->fb.cmap, 256, 0);
+ break;
+ }
+ dprintk("fb_alloc_cmap,fb.cmap.len:%d....\n", cfb->fb.cmap.len);
+
+ return cfb;
+}
+
+/*
+ * Map screen memory
+ */
+static int jzfb_map_smem(struct lcd_cfb_info *cfb)
+{
+ struct page * map = NULL;
+ unsigned char *tmp;
+ unsigned int page_shift, needroom, t;
+
+ t = jzfb.bpp;
+ if (jzfb.bpp == 15)
+ t = 16;
+ if (jzfb.bpp == 18 || jzfb.bpp == 24)
+ t = 32;
+ needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h;
+
+ for (page_shift = 0; page_shift < 12; page_shift++)
+ if ((PAGE_SIZE << page_shift) >= needroom)
+ break;
+
+ slcd_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0);
+ slcd_frame = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift);
+ if ((!slcd_palette) || (!slcd_frame))
+ return -ENOMEM;
+
+ memset((void *)slcd_palette, 0, PAGE_SIZE);
+ memset((void *)slcd_frame, 0, PAGE_SIZE << page_shift);
+
+ map = virt_to_page(slcd_palette);
+ set_bit(PG_reserved, &map->flags);
+
+ for (tmp=(unsigned char *)slcd_frame;
+ tmp < slcd_frame + (PAGE_SIZE << page_shift);
+ tmp += PAGE_SIZE) {
+ map = virt_to_page(tmp);
+ set_bit(PG_reserved, &map->flags);
+ }
+
+ cfb->fb.fix.smem_start = virt_to_phys((void *)slcd_frame);
+
+ cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift);
+
+ cfb->fb.screen_base =
+ (unsigned char *)(((unsigned int)slcd_frame & 0x1fffffff) | 0xa0000000);
+
+ if (!cfb->fb.screen_base) {
+ printk("%s: unable to map screen memory\n", cfb->fb.fix.id);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void jzfb_free_fb_info(struct lcd_cfb_info *cfb)
+{
+ if (cfb) {
+ fb_alloc_cmap(&cfb->fb.cmap, 0, 0);
+ kfree(cfb);
+ }
+}
+
+static void jzfb_unmap_smem(struct lcd_cfb_info *cfb)
+{
+ struct page * map = NULL;
+ unsigned char *tmp;
+ unsigned int page_shift, needroom, t;
+
+ t = jzfb.bpp;
+ if (jzfb.bpp == 18 || jzfb.bpp == 24)
+ t = 32;
+ if (jzfb.bpp == 15)
+ t = 16;
+ needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h;
+ for (page_shift = 0; page_shift < 12; page_shift++)
+ if ((PAGE_SIZE << page_shift) >= needroom)
+ break;
+
+ if (cfb && cfb->fb.screen_base) {
+ iounmap(cfb->fb.screen_base);
+ cfb->fb.screen_base = NULL;
+ release_mem_region(cfb->fb.fix.smem_start,
+ cfb->fb.fix.smem_len);
+ }
+
+ if (slcd_palette) {
+ map = virt_to_page(slcd_palette);
+ clear_bit(PG_reserved, &map->flags);
+ free_pages((int)slcd_palette, 0);
+ }
+
+ if (slcd_frame) {
+
+ for (tmp=(unsigned char *)slcd_frame;
+ tmp < slcd_frame + (PAGE_SIZE << page_shift);
+ tmp += PAGE_SIZE) {
+ map = virt_to_page(tmp);
+ clear_bit(PG_reserved, &map->flags);
+ }
+
+ free_pages((int)slcd_frame, page_shift);
+ }
+}
+
+static void slcd_descriptor_init(void)
+{
+ int i;
+ int frm_size, pal_size;
+ unsigned int next;
+ unsigned int slcd_frame_src_phys_addr, slcd_palette_src_phys_addr, slcd_dma_dst_phys_addr;
+
+ i = jzfb.bpp;
+ if (i == 18 || i == 24)
+ i = 32;
+ if (i == 15)
+ i = 16;
+
+ switch (jzfb.bpp) {
+ case 1:
+ pal_size = 4;
+ break;
+ case 2:
+ pal_size = 8;
+ break;
+ case 4:
+ pal_size = 32;
+ break;
+ case 8:
+ default:
+ pal_size = 512;
+ }
+
+ frm_size = jzfb.w * jzfb.h * jzfb.bpp / 8;
+
+ /*Offset of next descriptor*/
+ slcd_frame_desc_phys_addr = (dma_addr_t)CPHYSADDR((unsigned long)(&slcd_frame_desc));
+ slcd_palette_desc_phys_addr = (dma_addr_t)CPHYSADDR((unsigned long)(&slcd_palette_desc));
+
+ /*Soure address and Target address*/
+ slcd_palette_src_phys_addr = (unsigned int)virt_to_phys(slcd_palette);
+ slcd_frame_src_phys_addr = (unsigned int)virt_to_phys(slcd_frame);
+ slcd_dma_dst_phys_addr = (unsigned int)CPHYSADDR(SLCD_FIFO);
+ next = slcd_frame_desc_phys_addr >> 4;
+
+ /* Prepare Palette Descriptor */
+ slcd_palette_desc.dcmd = DMAC_DCMD_SAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32
+ | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V
+ | DMAC_DCMD_DES_VIE | DMAC_DCMD_LINK;
+ switch (slcd_palette_desc.dcmd & DMAC_DCMD_DS_MASK) {
+ case DMAC_DCMD_DS_32BYTE:
+ pal_size /= 32;
+ break;
+ case DMAC_DCMD_DS_16BYTE:
+ pal_size /= 16;
+ break;
+ case DMAC_DCMD_DS_32BIT:
+ pal_size /= 4;
+ break;
+ case DMAC_DCMD_DS_16BIT:
+ pal_size /= 2;
+ break;
+ case DMAC_DCMD_DS_8BIT:
+ default:
+ break;
+ }
+
+ slcd_palette_desc.dsadr = (unsigned int)virt_to_phys(slcd_palette); /* DMA source address */
+ slcd_palette_desc.dtadr = (unsigned int)CPHYSADDR(SLCD_FIFO); /* DMA target address */
+ slcd_palette_desc.ddadr = (volatile unsigned int)((next << 24) | (pal_size & 0xffffff)); /* offset and size*/
+ dma_cache_wback((unsigned long)(&slcd_palette_desc), 16);
+
+ /*Prepare Frame Descriptor in memory*/
+ switch (jzfb.bpp) {
+ case 8 ... 16:
+ slcd_frame_desc.dcmd = DMAC_DCMD_SAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32
+ | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V
+ | DMAC_DCMD_DES_VIE | DMAC_DCMD_LINK;
+ break;
+
+ case 17 ... 32:
+ slcd_frame_desc.dcmd = DMAC_DCMD_SAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32
+ | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V
+ | DMAC_DCMD_DES_VIE | DMAC_DCMD_LINK;
+ break;
+ }
+ switch (slcd_frame_desc.dcmd & DMAC_DCMD_DS_MASK) {
+ case DMAC_DCMD_DS_32BYTE:
+ frm_size /= 32;
+ break;
+ case DMAC_DCMD_DS_16BYTE:
+ frm_size /= 16;
+ break;
+ case DMAC_DCMD_DS_32BIT:
+ frm_size /= 4;
+ break;
+ case DMAC_DCMD_DS_16BIT:
+ frm_size /= 2;
+ break;
+ case DMAC_DCMD_DS_8BIT:
+ default:
+ break;
+ }
+
+ slcd_frame_desc.dsadr = slcd_frame_src_phys_addr; /* DMA source address */
+ slcd_frame_desc.dtadr = slcd_dma_dst_phys_addr; /* DMA target address */
+ slcd_frame_desc.ddadr = (volatile unsigned int)((next << 24) | (frm_size & 0xffffff)); /* offset and size*/
+ dma_cache_wback((unsigned long)(&slcd_frame_desc), 16);
+}
+
+void slcd_hw_init(void)
+{
+ unsigned int val, pclk;
+ int pll_div;
+
+ REG_LCD_CFG &= ~LCD_CFG_LCDPIN_MASK;
+ REG_LCD_CFG |= LCD_CFG_LCDPIN_SLCD;
+
+ if ((jzfb.bpp == 18) | (jzfb.bpp == 24))
+ jzfb.bpp = 32;
+
+ /* Configure SLCD module for initialize smart lcd registers*/
+ switch (jzfb.bus) {
+ case 8:
+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2
+ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW
+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING
+ | SLCD_CFG_TYPE_PARALLEL;
+ __gpio_as_slcd_8bit();
+ break;
+ case 9:
+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2
+ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW
+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING
+ | SLCD_CFG_TYPE_PARALLEL;
+ __gpio_as_slcd_9bit();
+ break;
+ case 16:
+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_16
+ | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW
+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING
+ | SLCD_CFG_TYPE_PARALLEL;
+ __gpio_as_slcd_16bit();
+ break;
+ case 18:
+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_18
+ | SLCD_CFG_CWIDTH_18BIT | SLCD_CFG_CS_ACTIVE_LOW
+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING
+ | SLCD_CFG_TYPE_PARALLEL;
+ __gpio_as_slcd_18bit();
+ break;
+ default:
+ printk("Error: Don't support BUS %d!\n", jzfb.bus);
+ break;
+ }
+
+ REG_SLCD_CTRL = SLCD_CTRL_DMA_EN;
+ __cpm_stop_lcd();
+ pclk = jzfb.pclk;
+ pll_div = ( REG_CPM_CPCCR & CPM_CPCCR_PCS ); /* clock source,0:pllout/2 1: pllout */
+ pll_div = pll_div ? 1 : 2 ;
+ val = ( __cpm_get_pllout()/pll_div ) / pclk;
+ val--;
+ if ( val > 0x1ff ) {
+ printk("CPM_LPCDR too large, set it to 0x1ff\n");
+ val = 0x1ff;
+ }
+ __cpm_set_pixdiv(val);
+
+ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */
+
+ jz_clocks.pixclk = __cpm_get_pixclk();
+ jz_clocks.lcdclk = __cpm_get_lcdclk();
+ printk("SLCDC: PixClock:%d LcdClock:%d\n",
+ jz_clocks.pixclk, jz_clocks.lcdclk);
+
+ __cpm_start_lcd();
+ udelay(1000);
+ __slcd_display_pin_init();
+ __slcd_special_on();
+
+ /* Configure SLCD module for transfer data to smart lcd GRAM*/
+ switch (jzfb.bus) {
+ case 8:
+ switch (jzfb.bpp) {
+ case 8:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1;
+ break;
+ case 15:
+ case 16:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2;
+ break;
+ case 17 ... 32:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3;
+ break;
+ default:
+ printk("The BPP %d is not supported\n", jzfb.bpp);
+ break;
+ }
+ break;
+ case 9:
+ switch (jzfb.bpp) {
+ case 8:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1;
+ break;
+ case 15 ... 16:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2;
+ break;
+ case 17 ... 32:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_9_x2;
+ break;
+ default:
+ printk("The BPP %d is not supported\n", jzfb.bpp);
+ break;
+ }
+ break;
+ case 16:
+ switch (jzfb.bpp) {
+ case 8:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1;
+ break;
+ case 15 ... 16:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_16;
+ break;
+ case 17 ... 32:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3;
+ break;
+ default:
+ printk("The BPP %d is not supported\n", jzfb.bpp);
+ break;
+ }
+ break;
+ case 18:
+ switch (jzfb.bpp) {
+ case 8:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1;
+ break;
+ case 15:
+ case 16:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_16;
+ break;
+ case 17 ... 32:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_18;
+ break;
+ default:
+ printk("The BPP %d is not supported\n", jzfb.bpp);
+ break;
+ }
+ break;
+ default:
+ printk("Error: The BUS %d is not supported\n", jzfb.bus);
+ break;
+ }
+ dprintk("SLCD_CFG=0x%x\n", REG_SLCD_CFG);
+}
+
+static irqreturn_t slcd_dma_irq(int irq, void *dev_id)
+{
+
+ if (__dmac_channel_transmit_halt_detected(dma_chan)) {
+ dprintk("DMA HALT\n");
+ __dmac_channel_clear_transmit_halt(dma_chan);
+ }
+
+ if (__dmac_channel_address_error_detected(dma_chan)) {
+ dprintk("DMA ADDR ERROR\n");
+ __dmac_channel_clear_address_error(dma_chan);
+ }
+
+ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) {
+ dprintk("DMA DESC INVALID\n");
+ __dmac_channel_clear_descriptor_invalid(dma_chan);
+ }
+
+ if (__dmac_channel_count_terminated_detected(dma_chan)) {
+ dprintk("DMA CT\n");
+ __dmac_channel_clear_count_terminated(dma_chan);
+ if(is_set_reg){
+ printk("Close DMAC_DCMD_LINK \n");
+ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_LINK;
+ }
+ if (non_link_desp) {
+ printk("Close DMAC_DCMD_LINK \n");
+ /*Set to Non-Link Descriptor*/
+ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_LINK;
+ }
+ }
+
+ if (__dmac_channel_transmit_end_detected(dma_chan)) {
+ printk("DMA TT\n");
+ __dmac_channel_clear_transmit_end(dma_chan);
+ if (non_link_desp) {
+ slcd_frame_desc.dcmd |= DMAC_DCMD_TIE;
+ slcd_frame_desc.dcmd &= ~DMAC_DCMD_LINK;
+ dma_cache_wback((unsigned long)(&slcd_frame_desc), 16);
+ non_link_desp = 0;
+ }
+ if (is_set_reg) {
+ is_set_reg = 0;
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_DMAC_DMACR &= ~DMAC_DMACR_DMAE; /* disable DMA */
+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
+ REG_SLCD_CTRL = 0;
+
+ /*
+ *add operation here
+ */
+ Mcupanel_RegSet(reg_buf.cmd, reg_buf.data);
+ Mcupanel_Command(0x0022);/*Write Data to GRAM */
+ mdelay(100);
+ REG_SLCD_CTRL = SLCD_CTRL_DMA_EN;
+ REG_DMAC_DMACR = DMAC_DMACR_DMAE;
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN;
+ __dmac_channel_set_doorbell(dma_chan);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static int slcd_dma_init(void)
+{
+ /* Request DMA channel and setup irq handler */
+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", slcd_dma_irq, 0, NULL);
+ if (dma_chan < 0) {
+ printk("Request DMA Failed\n");
+ return -1;
+ }
+ printk("DMA channel %d is requested by SLCD!\n", dma_chan);
+
+ /*Init the SLCD DMA and Enable*/
+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_SLCD;
+ REG_DMAC_DMACR = DMAC_DMACR_DMAE;
+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /*Descriptor Transfer*/
+
+ if (jzfb.bpp <= 8)
+ REG_DMAC_DDA(dma_chan) = slcd_palette_desc_phys_addr;
+ else
+ REG_DMAC_DDA(dma_chan) = slcd_frame_desc_phys_addr;
+
+ /* DMA doorbell set -- start DMA now ... */
+ __dmac_channel_set_doorbell(dma_chan);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * Suspend the LCDC.
+ */
+static int jzfb_suspend(void)
+{
+
+ __slcd_close_backlight();
+ __dmac_disable_channel(dma_chan);
+ __slcd_dma_disable(); /* Quick Disable */
+ __slcd_special_off();
+ __cpm_stop_lcd();
+ return 0;
+}
+
+/*
+ * Resume the LCDC.
+ */
+
+static int jzfb_resume(void)
+{
+ __cpm_start_lcd();
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ switch (jzfb.bpp) {
+ case 8:
+ /* DATA 8-bit once*/
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1;
+ break;
+ case 15:
+ case 16:
+ case 18:
+ case 24:
+ case 32:
+ /* DATA 8-bit twice*/
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2;
+ break;
+ default:
+ REG_SLCD_CFG = SLCD_CFG_DWIDTH_8_x2;
+ break;
+ }
+ __slcd_display_pin_init();
+ __slcd_special_on();
+
+ if (jzfb.bpp == 32) {
+ /* DATA 8-bit three time*/
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3;
+ }
+ __slcd_dma_enable();
+ udelay(100);
+ __dmac_enable_channel(dma_chan);
+ __dmac_channel_set_doorbell(dma_chan);
+ mdelay(200);
+ __slcd_set_backlight_level(80);
+ return 0;
+}
+
+/*
+ * Power management hook. Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int jzslcd_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
+{
+ int ret;
+ struct lcd_cfb_info *cfb = pm_dev->data;
+
+ if (!cfb) return -EINVAL;
+
+ switch (req) {
+ case PM_SUSPEND:
+ ret = jzfb_suspend();
+ break;
+
+ case PM_RESUME:
+ ret = jzfb_resume();
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+#else
+#define jzfb_suspend NULL
+#define jzfb_resume NULL
+#endif /* CONFIG_PM */
+static int __init jzslcd_fb_init(void)
+{
+
+ struct lcd_cfb_info *cfb;
+ int err = 0;
+
+ /*the parameters of slcd*/
+ cfb = jzfb_alloc_fb_info();
+ if (!cfb)
+ goto failed;
+
+ err = jzfb_map_smem(cfb);
+ if (err)
+ goto failed;
+ jzfb_set_var(&cfb->fb.var, -1, &cfb->fb);
+
+ slcd_hw_init();
+
+ err = register_framebuffer(&cfb->fb);
+ if (err < 0) {
+ printk("jzslcd_fb_init(): slcd register framebuffer err.\n");
+ goto failed;
+ }
+
+ printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+ cfb->fb.node, cfb->fb.fix.id, cfb->fb.fix.smem_len>>10);
+
+ slcd_descriptor_init();
+ err = slcd_dma_init();
+ if (err != 0) {
+ printk("SLCD Init DMA Fail!\n");
+ return err;
+ }
+ mdelay(100);
+ __slcd_set_backlight_level(80);
+
+#ifdef CONFIG_PM
+ /*
+ * Note that the console registers this as well, but we want to
+ * power down the display prior to sleeping.
+ */
+//struct pm_dev __deprecated *pm_register(pm_dev_t type, unsigned long id, pm_callback callback);
+
+ cfb->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, jzslcd_pm_callback);
+ if (cfb->pm)
+ cfb->pm->data = cfb;
+
+#endif
+ return 0;
+
+failed:
+ jzfb_unmap_smem(cfb);
+ jzfb_free_fb_info(cfb);
+
+ return err;
+}
+
+#if 0
+static int jzfb_remove(struct device *dev)
+{
+ struct lcd_cfb_info *cfb = dev_get_drvdata(dev);
+ jzfb_unmap_smem(cfb);
+ jzfb_free_fb_info(cfb);
+ return 0;
+}
+#endif
+
+#if 0
+static struct device_driver jzfb_driver = {
+ .name = "jz-slcd",
+ .bus = &platform_bus_type,
+ .probe = jzfb_probe,
+ .remove = jzfb_remove,
+ .suspend = jzfb_suspend,
+ .resume = jzfb_resume,
+};
+#endif
+
+static void __exit jzslcd_fb_cleanup(void)
+{
+ //driver_unregister(&jzfb_driver);
+ //jzfb_remove();
+}
+
+module_init(jzslcd_fb_init);
+module_exit(jzslcd_fb_cleanup);
+
+MODULE_DESCRIPTION("JzSOC SLCD Controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/jz4740_slcd.h b/drivers/video/jz4740_slcd.h
new file mode 100644
index 00000000000..84754f65447
--- /dev/null
+++ b/drivers/video/jz4740_slcd.h
@@ -0,0 +1,376 @@
+/*
+ * linux/drivers/video/jzslcd.h -- Ingenic On-Chip SLCD frame buffer device
+ *
+ * Copyright (C) 2005-2007, Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __JZSLCD_H__
+#define __JZSLCD_H__
+
+#define UINT16 unsigned short
+#define UINT32 unsigned int
+
+#define NR_PALETTE 256
+/* Jz LCDFB supported I/O controls. */
+#define FBIOSETBACKLIGHT 0x4688
+#define FBIODISPON 0x4689
+#define FBIODISPOFF 0x468a
+#define FBIORESET 0x468b
+#define FBIOPRINT_REG 0x468c
+#define FBIO_REFRESH_ALWAYS 0x468d
+#define FBIO_REFRESH_EVENTS 0x468e
+#define FBIO_DO_REFRESH 0x468f
+#define FBIO_SET_REG 0x4690
+
+#ifdef CONFIG_JZ_SLCD_LGDP4551
+#define PIN_CS_N (32*2+18) /* Chip select :SLCD_WR: GPC18 */
+#define PIN_RESET_N (32*2+21) /* LCD reset :SLCD_RST: GPC21*/
+#define PIN_RS_N (32*2+19)
+
+#define __slcd_special_pin_init() \
+do { \
+ __gpio_as_output(PIN_CS_N); \
+ __gpio_as_output(PIN_RESET_N); \
+ __gpio_clear_pin(PIN_CS_N); /* Clear CS */\
+ mdelay(100); \
+} while(0)
+
+#define __slcd_special_on() \
+do { /* RESET# */ \
+ __gpio_set_pin(PIN_RESET_N); \
+ mdelay(10); \
+ __gpio_clear_pin(PIN_RESET_N); \
+ mdelay(10); \
+ __gpio_set_pin(PIN_RESET_N); \
+ mdelay(100); \
+ Mcupanel_RegSet(0x0015,0x0050); \
+ Mcupanel_RegSet(0x0011,0x0000); \
+ Mcupanel_RegSet(0x0010,0x3628); \
+ Mcupanel_RegSet(0x0012,0x0002); \
+ Mcupanel_RegSet(0x0013,0x0E47); \
+ udelay(100); \
+ Mcupanel_RegSet(0x0012,0x0012); \
+ udelay(100); \
+ Mcupanel_RegSet(0x0010,0x3620); \
+ Mcupanel_RegSet(0x0013,0x2E47); \
+ udelay(50); \
+ Mcupanel_RegSet(0x0030,0x0000); \
+ Mcupanel_RegSet(0x0031,0x0502); \
+ Mcupanel_RegSet(0x0032,0x0307); \
+ Mcupanel_RegSet(0x0033,0x0304); \
+ Mcupanel_RegSet(0x0034,0x0004); \
+ Mcupanel_RegSet(0x0035,0x0401); \
+ Mcupanel_RegSet(0x0036,0x0707); \
+ Mcupanel_RegSet(0x0037,0x0303); \
+ Mcupanel_RegSet(0x0038,0x1E02); \
+ Mcupanel_RegSet(0x0039,0x1E02); \
+ Mcupanel_RegSet(0x0001,0x0000); \
+ Mcupanel_RegSet(0x0002,0x0300); \
+ if (jzfb.bpp == 16) \
+ Mcupanel_RegSet(0x0003,0x10B8); /*8-bit system interface two transfers
+ up:0x10B8 down:0x1088 left:0x1090 right:0x10a0*/ \
+ else \
+ if (jzfb.bpp == 32)\
+ Mcupanel_RegSet(0x0003,0xD0B8);/*8-bit system interface three transfers,666
+ up:0xD0B8 down:0xD088 left:0xD090 right:0xD0A0*/ \
+ Mcupanel_RegSet(0x0008,0x0204);\
+ Mcupanel_RegSet(0x000A,0x0008);\
+ Mcupanel_RegSet(0x0060,0x3100);\
+ Mcupanel_RegSet(0x0061,0x0001);\
+ Mcupanel_RegSet(0x0090,0x0052);\
+ Mcupanel_RegSet(0x0092,0x000F);\
+ Mcupanel_RegSet(0x0093,0x0001);\
+ Mcupanel_RegSet(0x009A,0x0008);\
+ Mcupanel_RegSet(0x00A3,0x0010);\
+ Mcupanel_RegSet(0x0050,0x0000);\
+ Mcupanel_RegSet(0x0051,0x00EF);\
+ Mcupanel_RegSet(0x0052,0x0000);\
+ Mcupanel_RegSet(0x0053,0x018F);\
+ /*===Display_On_Function=== */ \
+ Mcupanel_RegSet(0x0007,0x0001);\
+ Mcupanel_RegSet(0x0007,0x0021);\
+ Mcupanel_RegSet(0x0007,0x0023);\
+ Mcupanel_RegSet(0x0007,0x0033);\
+ Mcupanel_RegSet(0x0007,0x0133);\
+ Mcupanel_Command(0x0022);/*Write Data to GRAM */ \
+ udelay(1); \
+ Mcupanel_SetAddr(0,0); \
+ mdelay(100); \
+} while (0)
+
+#define __slcd_special_off() \
+do { \
+} while(0)
+#endif /*CONFIG_JZ_SLCD_LGDP4551_xxBUS*/
+
+#ifdef CONFIG_JZ_SLCD_SPFD5420A
+
+ //#define PIN_CS_N (32*2+18) // Chip select //GPC18;
+#define PIN_CS_N (32*2+22) // Chip select //GPC18;
+#define PIN_RESET_N (32*1+18) // LCD reset //GPB18;
+#define PIN_RS_N (32*2+19) // LCD RS //GPC19;
+#define PIN_POWER_N (32*3+0) //Power off //GPD0;
+#define PIN_FMARK_N (32*3+1) //fmark //GPD1;
+
+#define GAMMA() \
+do { \
+ Mcupanel_RegSet(0x0300,0x0101); \
+ Mcupanel_RegSet(0x0301,0x0b27); \
+ Mcupanel_RegSet(0x0302,0x132a); \
+ Mcupanel_RegSet(0x0303,0x2a13); \
+ Mcupanel_RegSet(0x0304,0x270b); \
+ Mcupanel_RegSet(0x0305,0x0101); \
+ Mcupanel_RegSet(0x0306,0x1205); \
+ Mcupanel_RegSet(0x0307,0x0512); \
+ Mcupanel_RegSet(0x0308,0x0005); \
+ Mcupanel_RegSet(0x0309,0x0003); \
+ Mcupanel_RegSet(0x030a,0x0f04); \
+ Mcupanel_RegSet(0x030b,0x0f00); \
+ Mcupanel_RegSet(0x030c,0x000f); \
+ Mcupanel_RegSet(0x030d,0x040f); \
+ Mcupanel_RegSet(0x030e,0x0300); \
+ Mcupanel_RegSet(0x030f,0x0500); \
+ /*** secorrect gamma2 ***/ \
+ Mcupanel_RegSet(0x0400,0x3500); \
+ Mcupanel_RegSet(0x0401,0x0001); \
+ Mcupanel_RegSet(0x0404,0x0000); \
+ Mcupanel_RegSet(0x0500,0x0000); \
+ Mcupanel_RegSet(0x0501,0x0000); \
+ Mcupanel_RegSet(0x0502,0x0000); \
+ Mcupanel_RegSet(0x0503,0x0000); \
+ Mcupanel_RegSet(0x0504,0x0000); \
+ Mcupanel_RegSet(0x0505,0x0000); \
+ Mcupanel_RegSet(0x0600,0x0000); \
+ Mcupanel_RegSet(0x0606,0x0000); \
+ Mcupanel_RegSet(0x06f0,0x0000); \
+ Mcupanel_RegSet(0x07f0,0x5420); \
+ Mcupanel_RegSet(0x07f3,0x288a); \
+ Mcupanel_RegSet(0x07f4,0x0022); \
+ Mcupanel_RegSet(0x07f5,0x0001); \
+ Mcupanel_RegSet(0x07f0,0x0000); \
+} while(0)
+
+#define __slcd_special_on() \
+do { \
+ __gpio_set_pin(PIN_RESET_N); \
+ mdelay(10); \
+ __gpio_clear_pin(PIN_RESET_N); \
+ mdelay(10); \
+ __gpio_set_pin(PIN_RESET_N); \
+ mdelay(100); \
+ if (jzfb.bus == 18) {\
+ Mcupanel_RegSet(0x0606,0x0000); \
+ udelay(10); \
+ Mcupanel_RegSet(0x0007,0x0001); \
+ udelay(10); \
+ Mcupanel_RegSet(0x0110,0x0001); \
+ udelay(10); \
+ Mcupanel_RegSet(0x0100,0x17b0); \
+ Mcupanel_RegSet(0x0101,0x0147); \
+ Mcupanel_RegSet(0x0102,0x019d); \
+ Mcupanel_RegSet(0x0103,0x8600); \
+ Mcupanel_RegSet(0x0281,0x0010); \
+ udelay(10); \
+ Mcupanel_RegSet(0x0102,0x01bd); \
+ udelay(10); \
+ /************initial************/\
+ Mcupanel_RegSet(0x0000,0x0000); \
+ Mcupanel_RegSet(0x0001,0x0000); \
+ Mcupanel_RegSet(0x0002,0x0400); \
+ Mcupanel_RegSet(0x0003,0x1288); /*up:0x1288 down:0x12B8 left:0x1290 right:0x12A0*/ \
+ Mcupanel_RegSet(0x0006,0x0000); \
+ Mcupanel_RegSet(0x0008,0x0503); \
+ Mcupanel_RegSet(0x0009,0x0001); \
+ Mcupanel_RegSet(0x000b,0x0010); \
+ Mcupanel_RegSet(0x000c,0x0000); \
+ Mcupanel_RegSet(0x000f,0x0000); \
+ Mcupanel_RegSet(0x0007,0x0001); \
+ Mcupanel_RegSet(0x0010,0x0010); \
+ Mcupanel_RegSet(0x0011,0x0202); \
+ Mcupanel_RegSet(0x0012,0x0300); \
+ Mcupanel_RegSet(0x0020,0x021e); \
+ Mcupanel_RegSet(0x0021,0x0202); \
+ Mcupanel_RegSet(0x0022,0x0100); \
+ Mcupanel_RegSet(0x0090,0x0000); \
+ Mcupanel_RegSet(0x0092,0x0000); \
+ Mcupanel_RegSet(0x0100,0x16b0); \
+ Mcupanel_RegSet(0x0101,0x0147); \
+ Mcupanel_RegSet(0x0102,0x01bd); \
+ Mcupanel_RegSet(0x0103,0x2c00); \
+ Mcupanel_RegSet(0x0107,0x0000); \
+ Mcupanel_RegSet(0x0110,0x0001); \
+ Mcupanel_RegSet(0x0210,0x0000); \
+ Mcupanel_RegSet(0x0211,0x00ef); \
+ Mcupanel_RegSet(0x0212,0x0000); \
+ Mcupanel_RegSet(0x0213,0x018f); \
+ Mcupanel_RegSet(0x0280,0x0000); \
+ Mcupanel_RegSet(0x0281,0x0001); \
+ Mcupanel_RegSet(0x0282,0x0000); \
+ GAMMA(); \
+ Mcupanel_RegSet(0x0007,0x0173); \
+ } else { \
+ Mcupanel_RegSet(0x0600, 0x0001); /*soft reset*/ \
+ mdelay(10); \
+ Mcupanel_RegSet(0x0600, 0x0000); /*soft reset*/ \
+ mdelay(10); \
+ Mcupanel_RegSet(0x0606, 0x0000); /*i80-i/F Endian Control*/ \
+ /*===User setting=== */ \
+ Mcupanel_RegSet(0x0001, 0x0000);/* Driver Output Control-----0x0100 SM(bit10) | 0x400*/ \
+ Mcupanel_RegSet(0x0002, 0x0100); /*LCD Driving Wave Control 0x0100 */ \
+ if (jzfb.bpp == 16) \
+ Mcupanel_RegSet(0x0003, 0x50A8);/*Entry Mode 0x1030*/ \
+ else /*bpp = 18*/ \
+ Mcupanel_RegSet(0x0003, 0x1010 | 0xC8); /*Entry Mode 0x1030*/ \
+ /*#endif */ \
+ Mcupanel_RegSet(0x0006, 0x0000); /*Outline Sharpening Control*/\
+ Mcupanel_RegSet(0x0008, 0x0808); /*Sets the number of lines for front/back porch period*/\
+ Mcupanel_RegSet(0x0009, 0x0001); /*Display Control 3 */\
+ Mcupanel_RegSet(0x000B, 0x0010); /*Low Power Control*/\
+ Mcupanel_RegSet(0x000C, 0x0000); /*External Display Interface Control 1 /*0x0001*/\
+ Mcupanel_RegSet(0x000F, 0x0000); /*External Display Interface Control 2 */\
+ Mcupanel_RegSet(0x0400, 0xB104);/*Base Image Number of Line---GS(bit15) | 0x8000*/ \
+ Mcupanel_RegSet(0x0401, 0x0001); /*Base Image Display 0x0001*/\
+ Mcupanel_RegSet(0x0404, 0x0000); /*Base Image Vertical Scroll Control 0x0000*/\
+ Mcupanel_RegSet(0x0500, 0x0000); /*Partial Image 1: Display Position*/\
+ Mcupanel_RegSet(0x0501, 0x0000); /*RAM Address (Start Line Address) */\
+ Mcupanel_RegSet(0x0502, 0x018f); /*RAM Address (End Line Address) */ \
+ Mcupanel_RegSet(0x0503, 0x0000); /*Partial Image 2: Display Position RAM Address*/\
+ Mcupanel_RegSet(0x0504, 0x0000); /*RAM Address (Start Line Address) */\
+ Mcupanel_RegSet(0x0505, 0x0000); /*RAM Address (End Line Address)*/\
+ /*Panel interface control===*/\
+ Mcupanel_RegSet(0x0010, 0x0011); /*Division Ratio,Clocks per Line 14 */\
+ mdelay(10); \
+ Mcupanel_RegSet(0x0011, 0x0202); /*Division Ratio,Clocks per Line*/\
+ Mcupanel_RegSet(0x0012, 0x0300); /*Sets low power VCOM drive period. */\
+ mdelay(10); \
+ Mcupanel_RegSet(0x0020, 0x021e); /*Panel Interface Control 4 */\
+ Mcupanel_RegSet(0x0021, 0x0202); /*Panel Interface Control 5 */\
+ Mcupanel_RegSet(0x0022, 0x0100); /*Panel Interface Control 6*/\
+ Mcupanel_RegSet(0x0090, 0x0000); /*Frame Marker Control */\
+ Mcupanel_RegSet(0x0092, 0x0000); /*MDDI Sub-display Control */\
+ /*===Gamma setting=== */\
+ Mcupanel_RegSet(0x0300, 0x0101); /*γ Control*/\
+ Mcupanel_RegSet(0x0301, 0x0000); /*γ Control*/\
+ Mcupanel_RegSet(0x0302, 0x0016); /*γ Control*/\
+ Mcupanel_RegSet(0x0303, 0x2913); /*γ Control*/\
+ Mcupanel_RegSet(0x0304, 0x260B); /*γ Control*/\
+ Mcupanel_RegSet(0x0305, 0x0101); /*γ Control*/\
+ Mcupanel_RegSet(0x0306, 0x1204); /*γ Control*/\
+ Mcupanel_RegSet(0x0307, 0x0415); /*γ Control*/\
+ Mcupanel_RegSet(0x0308, 0x0205); /*γ Control*/\
+ Mcupanel_RegSet(0x0309, 0x0303); /*γ Control*/\
+ Mcupanel_RegSet(0x030a, 0x0E05); /*γ Control*/\
+ Mcupanel_RegSet(0x030b, 0x0D01); /*γ Control*/\
+ Mcupanel_RegSet(0x030c, 0x010D); /*γ Control*/\
+ Mcupanel_RegSet(0x030d, 0x050E); /*γ Control*/\
+ Mcupanel_RegSet(0x030e, 0x0303); /*γ Control*/\
+ Mcupanel_RegSet(0x030f, 0x0502); /*γ Control*/\
+ /*===Power on sequence===*/\
+ Mcupanel_RegSet(0x0007, 0x0001); /*Display Control 1*/\
+ Mcupanel_RegSet(0x0110, 0x0001); /*Power supply startup enable bit*/\
+ Mcupanel_RegSet(0x0112, 0x0060); /*Power Control 7*/\
+ Mcupanel_RegSet(0x0100, 0x16B0); /*Power Control 1 */\
+ Mcupanel_RegSet(0x0101, 0x0115); /*Power Control 2*/\
+ Mcupanel_RegSet(0x0102, 0x0119); /*Starts VLOUT3,Sets the VREG1OUT.*/\
+ mdelay(50); \
+ Mcupanel_RegSet(0x0103, 0x2E00); /*set the amplitude of VCOM*/\
+ mdelay(50);\
+ Mcupanel_RegSet(0x0282, 0x0093);/*0x008E);/*0x0093); /*VCOMH voltage*/\
+ Mcupanel_RegSet(0x0281, 0x000A); /*Selects the factor of VREG1OUT to generate VCOMH. */\
+ Mcupanel_RegSet(0x0102, 0x01BE); /*Starts VLOUT3,Sets the VREG1OUT.*/\
+ mdelay(10);\
+ /*Address */\
+ Mcupanel_RegSet(0x0210, 0x0000); /*Window Horizontal RAM Address Start*/\
+ Mcupanel_RegSet(0x0211, 0x00ef); /*Window Horizontal RAM Address End*/\
+ Mcupanel_RegSet(0x0212, 0x0000); /*Window Vertical RAM Address Start*/\
+ Mcupanel_RegSet(0x0213, 0x018f); /*Window Vertical RAM Address End */\
+ Mcupanel_RegSet(0x0200, 0x0000); /*RAM Address Set (Horizontal Address)*/\
+ Mcupanel_RegSet(0x0201, 0x018f); /*RAM Address Set (Vertical Address)*/ \
+ /*===Display_On_Function===*/\
+ Mcupanel_RegSet(0x0007, 0x0021); /*Display Control 1 */\
+ mdelay(50); /*40*/\
+ Mcupanel_RegSet(0x0007, 0x0061); /*Display Control 1 */\
+ mdelay(50); /*100*/\
+ Mcupanel_RegSet(0x0007, 0x0173); /*Display Control 1 */\
+ mdelay(50); /*300*/\
+ }\
+ Mcupanel_Command(0x0202); /*Write Data to GRAM */ \
+ udelay(10);\
+ Mcupanel_SetAddr(0,0);\
+ udelay(100);\
+} while(0)
+
+#define __slcd_special_pin_init() \
+do { \
+ __gpio_as_output(PIN_CS_N); \
+ __gpio_as_output(PIN_RESET_N); \
+ __gpio_clear_pin(PIN_CS_N); /* Clear CS */ \
+ __gpio_as_output(PIN_POWER_N); \
+ mdelay(100); \
+} while(0)
+
+#endif /*CONFIG_JZ_SLCD_SPFD5420A*/
+
+#ifndef __slcd_special_pin_init
+#define __slcd_special_pin_init()
+#endif
+#ifndef __slcd_special_on
+#define __slcd_special_on()
+#endif
+#ifndef __slcd_special_off
+#define __slcd_special_off()
+#endif
+
+/*
+ * Platform specific definition
+ */
+#if defined(CONFIG_SOC_JZ4740)
+#if defined(CONFIG_JZ4740_PAVO)
+#define GPIO_PWM 123 /* GP_D27 */
+#define PWM_CHN 4 /* pwm channel */
+#define PWM_FULL 101
+/* 100 level: 0,1,...,100 */
+#define __slcd_set_backlight_level(n)\
+do { \
+ __gpio_as_output(32*3+27); \
+ __gpio_set_pin(32*3+27); \
+} while (0)
+
+#define __slcd_close_backlight() \
+do { \
+ __gpio_as_output(GPIO_PWM); \
+ __gpio_clear_pin(GPIO_PWM); \
+} while (0)
+
+#else
+
+#define __slcd_set_backlight_level(n)
+#define __slcd_close_backlight()
+
+#endif /* #if defined(CONFIG_MIPS_JZ4740_PAVO) */
+
+#define __slcd_display_pin_init() \
+do { \
+ __slcd_special_pin_init(); \
+} while (0)
+
+#define __slcd_display_on() \
+do { \
+ __slcd_special_on(); \
+ __slcd_set_backlight_level(80); \
+} while (0)
+
+#define __slcd_display_off() \
+do { \
+ __slcd_special_off(); \
+ __slcd_close_backlight(); \
+} while (0)
+
+#endif /* CONFIG_SOC_JZ4740 */
+#endif /*__JZSLCD_H__*/
+
diff --git a/drivers/video/jz4750_lcd.c b/drivers/video/jz4750_lcd.c
new file mode 100644
index 00000000000..6bbc38ebf73
--- /dev/null
+++ b/drivers/video/jz4750_lcd.c
@@ -0,0 +1,2385 @@
+/*
+ * linux/drivers/video/jz4750_lcd.c -- Ingenic Jz4750 LCD frame buffer device
+ *
+ * Copyright (C) 2005-2008, Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * --------------------------------
+ * NOTE:
+ * This LCD driver support TFT16 TFT32 LCD, not support STN and Special TFT LCD
+ * now.
+ * It seems not necessory to support STN and Special TFT.
+ * If it's necessary, update this driver in the future.
+ * <Wolfgang Wang, Jun 10 2008>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/jzsoc.h>
+
+#include "console/fbcon.h"
+
+#include "jz4750_lcd.h"
+#include "jz4750_tve.h"
+
+#ifdef CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A
+#include "jz_kgm_spfd5420a.h"
+#endif
+
+MODULE_DESCRIPTION("Jz4750 LCD Controller driver");
+MODULE_AUTHOR("Wolfgang Wang, <lgwang@ingenic.cn>");
+MODULE_LICENSE("GPL");
+
+
+//#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#define print_dbg(f, arg...) printk("dbg::" __FILE__ ",LINE(%d): " f "\n", __LINE__, ## arg)
+#else
+#define dprintk(x...)
+#define print_dbg(f, arg...) do {} while (0)
+#endif
+
+#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
+#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
+#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
+
+struct lcd_cfb_info {
+ struct fb_info fb;
+ struct display_switch *dispsw;
+ signed int currcon;
+ int func_use_count;
+
+ struct {
+ u16 red, green, blue;
+ } palette[NR_PALETTE];
+#ifdef CONFIG_PM
+ struct pm_dev *pm;
+#endif
+ int b_lcd_display;
+ int b_lcd_pwm;
+ int backlight_level;
+};
+
+static struct lcd_cfb_info *jz4750fb_info;
+static struct jz4750_lcd_dma_desc *dma_desc_base;
+static struct jz4750_lcd_dma_desc *dma0_desc_palette, *dma0_desc0, *dma0_desc1, *dma1_desc0, *dma1_desc1;
+#define DMA_DESC_NUM 6
+
+static unsigned char *lcd_palette;
+static unsigned char *lcd_frame0;
+static unsigned char *lcd_frame1;
+
+static struct jz4750_lcd_dma_desc *dma0_desc_cmd0, *dma0_desc_cmd;
+static unsigned char *lcd_cmdbuf ;
+
+static void jz4750fb_set_mode( struct jz4750lcd_info * lcd_info );
+static void jz4750fb_deep_set_mode( struct jz4750lcd_info * lcd_info );
+
+static int jz4750fb_set_backlight_level(int n);
+static int jz4750fb_lcd_display_on(void);
+static int jz4750fb_lcd_display_off(void);
+
+struct jz4750lcd_info jz4750_lcd_panel = {
+#if defined(CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF02)
+ .panel = {
+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */
+ LCD_CFG_NEWDES | /* 8words descriptor */
+ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */
+ LCD_CFG_MODE_TFT_18BIT | /* output 18bpp */
+ LCD_CFG_HSP | /* Hsync polarity: active low */
+ LCD_CFG_VSP, /* Vsync polarity: leading edge is falling edge */
+ .slcd_cfg = 0,
+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */
+ 480, 272, 60, 41, 10, 2, 2, 2, 2,
+ },
+ .osd = {
+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */
+// LCD_OSDC_ALPHAEN | /* enable alpha */
+ LCD_OSDC_F0EN, /* enable Foreground0 */
+ .osd_ctrl = 0, /* disable ipu, */
+ .rgb_ctrl = 0,
+ .bgcolor = 0x000000, /* set background color Black */
+ .colorkey0 = 0, /* disable colorkey */
+ .colorkey1 = 0, /* disable colorkey */
+ .alpha = 0xA0, /* alpha value */
+ .ipu_restart = 0x80001000, /* ipu restart */
+ .fg_change = FG_CHANGE_ALL, /* change all initially */
+ .fg0 = {32, 0, 0, 480, 272}, /* bpp, x, y, w, h */
+ .fg1 = {32, 0, 0, 720, 573}, /* bpp, x, y, w, h */
+ },
+#elif defined(CONFIG_JZ4750_LCD_AUO_A043FL01V2)
+ .panel = {
+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */
+ LCD_CFG_NEWDES | /* 8words descriptor */
+ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */
+ LCD_CFG_MODE_TFT_24BIT | /* output 18bpp */
+ LCD_CFG_HSP | /* Hsync polarity: active low */
+ LCD_CFG_VSP, /* Vsync polarity: leading edge is falling edge */
+ .slcd_cfg = 0,
+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */
+ 480, 272, 60, 41, 10, 8, 4, 4, 2,
+ },
+ .osd = {
+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */
+// LCD_OSDC_ALPHAEN | /* enable alpha */
+// LCD_OSDC_F1EN | /* enable Foreground1 */
+ LCD_OSDC_F0EN, /* enable Foreground0 */
+ .osd_ctrl = 0, /* disable ipu, */
+ .rgb_ctrl = 0,
+ .bgcolor = 0x000000, /* set background color Black */
+ .colorkey0 = 0, /* disable colorkey */
+ .colorkey1 = 0, /* disable colorkey */
+ .alpha = 0xA0, /* alpha value */
+ .ipu_restart = 0x80001000, /* ipu restart */
+ .fg_change = FG_CHANGE_ALL, /* change all initially */
+ .fg0 = {16, 0, 0, 480, 272}, /* bpp, x, y, w, h */
+ .fg1 = {16, 0, 0, 720, 573}, /* bpp, x, y, w, h */
+ },
+#elif defined(CONFIG_JZ4750_LCD_TOPPOLY_TD043MGEB1)
+ .panel = {
+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */
+ LCD_CFG_NEWDES | /* 8words descriptor */
+ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */
+ LCD_CFG_MODE_TFT_24BIT | /* output 18bpp */
+ LCD_CFG_HSP | /* Hsync polarity: active low */
+ LCD_CFG_VSP, /* Vsync polarity: leading edge is falling edge */
+ .slcd_cfg = 0,
+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */
+ 800, 480, 60, 1, 1, 40, 215, 10, 34,
+ },
+ .osd = {
+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */
+// LCD_OSDC_ALPHAEN | /* enable alpha */
+// LCD_OSDC_F1EN | /* enable Foreground1 */
+ LCD_OSDC_F0EN, /* enable Foreground0 */
+ .osd_ctrl = 0, /* disable ipu, */
+ .rgb_ctrl = 0,
+ .bgcolor = 0xff, /* set background color Black */
+ .colorkey0 = 0, /* disable colorkey */
+ .colorkey1 = 0, /* disable colorkey */
+ .alpha = 0xA0, /* alpha value */
+ .ipu_restart = 0x80001000, /* ipu restart */
+ .fg_change = FG_CHANGE_ALL, /* change all initially */
+ .fg0 = {32, 0, 0, 800, 480}, /* bpp, x, y, w, h */
+ .fg1 = {32, 0, 0, 800, 480}, /* bpp, x, y, w, h */
+ },
+#elif defined(CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W)
+ .panel = {
+ .cfg = LCD_CFG_LCDPIN_SLCD | /* Underrun recover*/
+ LCD_CFG_NEWDES | /* 8words descriptor */
+ LCD_CFG_MODE_SLCD, /* TFT Smart LCD panel */
+ .slcd_cfg = SLCD_CFG_DWIDTH_16BIT | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING | SLCD_CFG_TYPE_PARALLEL,
+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */
+ 240, 320, 60, 0, 0, 0, 0, 0, 0,
+ },
+ .osd = {
+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */
+// LCD_OSDC_ALPHAEN | /* enable alpha */
+// LCD_OSDC_F1EN | /* enable Foreground0 */
+ LCD_OSDC_F0EN, /* enable Foreground0 */
+ .osd_ctrl = 0, /* disable ipu, */
+ .rgb_ctrl = 0,
+ .bgcolor = 0x000000, /* set background color Black */
+ .colorkey0 = 0, /* disable colorkey */
+ .colorkey1 = 0, /* disable colorkey */
+ .alpha = 0xA0, /* alpha value */
+ .ipu_restart = 0x80001000, /* ipu restart */
+ .fg_change = FG_CHANGE_ALL, /* change all initially */
+ .fg0 = {32, 0, 0, 240, 320}, /* bpp, x, y, w, h */
+ .fg1 = {32, 0, 0, 240, 320}, /* bpp, x, y, w, h */
+ },
+
+#elif defined(CONFIG_JZ4750_LCD_FOXCONN_PT035TN01)
+ .panel = {
+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */
+ LCD_CFG_NEWDES | /* 8words descriptor */
+ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */
+// LCD_CFG_MODE_TFT_18BIT | /* output 18bpp */
+ LCD_CFG_MODE_TFT_24BIT | /* output 24bpp */
+ LCD_CFG_HSP | /* Hsync polarity: active low */
+ LCD_CFG_VSP | /* Vsync polarity: leading edge is falling edge */
+ LCD_CFG_PCP, /* Pix-CLK polarity: data translations at falling edge */
+ .slcd_cfg = 0,
+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */
+ 320, 240, 80, 1, 1, 10, 50, 10, 13
+ },
+ .osd = {
+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */
+// LCD_OSDC_ALPHAEN | /* enable alpha */
+// LCD_OSDC_F1EN | /* enable Foreground1 */
+ LCD_OSDC_F0EN, /* enable Foreground0 */
+ .osd_ctrl = 0, /* disable ipu, */
+ .rgb_ctrl = 0,
+ .bgcolor = 0x000000, /* set background color Black */
+ .colorkey0 = 0, /* disable colorkey */
+ .colorkey1 = 0, /* disable colorkey */
+ .alpha = 0xA0, /* alpha value */
+ .ipu_restart = 0x80001000, /* ipu restart */
+ .fg_change = FG_CHANGE_ALL, /* change all initially */
+ .fg0 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */
+ .fg1 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */
+ },
+#elif defined(CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL)
+ .panel = {
+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */
+ LCD_CFG_NEWDES | /* 8words descriptor */
+ LCD_CFG_MODE_SERIAL_TFT | /* Serial TFT panel */
+ LCD_CFG_MODE_TFT_18BIT | /* output 18bpp */
+ LCD_CFG_HSP | /* Hsync polarity: active low */
+ LCD_CFG_VSP | /* Vsync polarity: leading edge is falling edge */
+ LCD_CFG_PCP, /* Pix-CLK polarity: data translations at falling edge */
+ .slcd_cfg = 0,
+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */
+ 320, 240, 60, 1, 1, 10, 50, 10, 13
+ },
+ .osd = {
+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */
+// LCD_OSDC_ALPHAEN | /* enable alpha */
+ LCD_OSDC_F0EN, /* enable Foreground0 */
+ .osd_ctrl = 0, /* disable ipu, */
+ .rgb_ctrl = 0,
+ .bgcolor = 0x000000, /* set background color Black */
+ .colorkey0 = 0, /* disable colorkey */
+ .colorkey1 = 0, /* disable colorkey */
+ .alpha = 0xA0, /* alpha value */
+ .ipu_restart = 0x80001000, /* ipu restart */
+ .fg_change = FG_CHANGE_ALL, /* change all initially */
+ .fg0 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */
+ .fg1 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */
+ },
+#elif defined(CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A)
+ .panel = {
+// .cfg = LCD_CFG_LCDPIN_SLCD | LCD_CFG_RECOVER | /* Underrun recover*/
+ .cfg = LCD_CFG_LCDPIN_SLCD | /* Underrun recover*/
+// LCD_CFG_DITHER | /* dither */
+ LCD_CFG_NEWDES | /* 8words descriptor */
+ LCD_CFG_MODE_SLCD, /* TFT Smart LCD panel */
+ .slcd_cfg = SLCD_CFG_DWIDTH_18BIT | SLCD_CFG_CWIDTH_18BIT | SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING | SLCD_CFG_TYPE_PARALLEL,
+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */
+ 400, 240, 60, 0, 0, 0, 0, 0, 0,
+ },
+ .osd = {
+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */
+// LCD_OSDC_ALPHAEN | /* enable alpha */
+// LCD_OSDC_ALPHAMD | /* alpha blending mode */
+// LCD_OSDC_F1EN | /* enable Foreground1 */
+ LCD_OSDC_F0EN, /* enable Foreground0 */
+ .osd_ctrl = 0, /* disable ipu, */
+ .rgb_ctrl = 0,
+ .bgcolor = 0x000000, /* set background color Black */
+ .colorkey0 = 0, /* disable colorkey */
+ .colorkey1 = 0, /* disable colorkey */
+ .alpha = 0xA0, /* alpha value */
+ .ipu_restart = 0x80001000, /* ipu restart */
+ .fg_change = FG_CHANGE_ALL, /* change all initially */
+// .fg0 = {32, 0, 0, 400, 240}, /* bpp, x, y, w, h */
+ .fg0 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */
+ .fg1 = {32, 0, 0, 400, 240}, /* bpp, x, y, w, h */
+ },
+#elif defined(CONFIG_JZ4750D_VGA_DISPLAY)
+ .panel = {
+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER |/* Underrun recover */
+ LCD_CFG_NEWDES | /* 8words descriptor */
+ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */
+ LCD_CFG_MODE_TFT_24BIT | /* output 18bpp */
+ LCD_CFG_HSP | /* Hsync polarity: active low */
+ LCD_CFG_VSP, /* Vsync polarity: leading edge is falling edge */
+ .slcd_cfg = 0,
+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */
+// 800, 600, 60, 128, 4, 40, 88, 0, 23
+ 640, 480, 54, 96, 2, 16, 48, 10, 33
+// 1280, 720, 50, 152, 15, 22, 200, 14, 1
+ },
+ .osd = {
+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */
+// LCD_OSDC_ALPHAEN | /* enable alpha */
+// LCD_OSDC_F1EN | /* enable Foreground1 */
+ LCD_OSDC_F0EN, /* enable Foreground0 */
+ .osd_ctrl = 0, /* disable ipu, */
+ .rgb_ctrl = 0,
+ .bgcolor = 0x000000, /* set background color Black */
+ .colorkey0 = 0, /* disable colorkey */
+ .colorkey1 = 0, /* disable colorkey */
+ .alpha = 0xA0, /* alpha value */
+ .ipu_restart = 0x80001000, /* ipu restart */
+ .fg_change = FG_CHANGE_ALL, /* change all initially */
+ .fg0 = {32, 0, 0, 640, 480}, /* bpp, x, y, w, h */
+ .fg1 = {32, 0, 0, 640, 480}, /* bpp, x, y, w, h */
+ },
+#else
+#error "Select LCD panel first!!!"
+#endif
+};
+
+struct jz4750lcd_info jz4750_info_tve = {
+ .panel = {
+ .cfg = LCD_CFG_TVEN | /* output to tve */
+ LCD_CFG_NEWDES | /* 8words descriptor */
+ LCD_CFG_RECOVER | /* underrun protect */
+ LCD_CFG_MODE_INTER_CCIR656, /* Interlace CCIR656 mode */
+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst */
+ TVE_WIDTH_PAL, TVE_HEIGHT_PAL, TVE_FREQ_PAL, 0, 0, 0, 0, 0, 0,
+ },
+ .osd = {
+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */
+// LCD_OSDC_ALPHAEN | /* enable alpha */
+ LCD_OSDC_F0EN, /* enable Foreground0 */
+ .osd_ctrl = 0, /* disable ipu, */
+ .rgb_ctrl = LCD_RGBC_YCC, /* enable RGB => YUV */
+ .bgcolor = 0x00000000, /* set background color Black */
+ .colorkey0 = 0, /* disable colorkey */
+ .colorkey1 = 0, /* disable colorkey */
+ .alpha = 0xA0, /* alpha value */
+ .ipu_restart = 0x80000100, /* ipu restart */
+ .fg_change = FG_CHANGE_ALL, /* change all initially */
+ .fg0 = {32,}, /* */
+ .fg0 = {32,},
+ },
+};
+
+
+struct jz4750lcd_info *jz4750_lcd_info = &jz4750_lcd_panel; /* default output to lcd panel */
+
+#ifdef DEBUG
+static void print_lcdc_registers(void) /* debug */
+{
+ /* LCD Controller Resgisters */
+ printk("REG_LCD_CFG:\t0x%08x\n", REG_LCD_CFG);
+ printk("REG_LCD_CTRL:\t0x%08x\n", REG_LCD_CTRL);
+ printk("REG_LCD_STATE:\t0x%08x\n", REG_LCD_STATE);
+ printk("REG_LCD_OSDC:\t0x%08x\n", REG_LCD_OSDC);
+ printk("REG_LCD_OSDCTRL:\t0x%08x\n", REG_LCD_OSDCTRL);
+ printk("REG_LCD_OSDS:\t0x%08x\n", REG_LCD_OSDS);
+ printk("REG_LCD_BGC:\t0x%08x\n", REG_LCD_BGC);
+ printk("REG_LCD_KEK0:\t0x%08x\n", REG_LCD_KEY0);
+ printk("REG_LCD_KEY1:\t0x%08x\n", REG_LCD_KEY1);
+ printk("REG_LCD_ALPHA:\t0x%08x\n", REG_LCD_ALPHA);
+ printk("REG_LCD_IPUR:\t0x%08x\n", REG_LCD_IPUR);
+ printk("REG_LCD_VAT:\t0x%08x\n", REG_LCD_VAT);
+ printk("REG_LCD_DAH:\t0x%08x\n", REG_LCD_DAH);
+ printk("REG_LCD_DAV:\t0x%08x\n", REG_LCD_DAV);
+ printk("REG_LCD_XYP0:\t0x%08x\n", REG_LCD_XYP0);
+ printk("REG_LCD_XYP1:\t0x%08x\n", REG_LCD_XYP1);
+ printk("REG_LCD_SIZE0:\t0x%08x\n", REG_LCD_SIZE0);
+ printk("REG_LCD_SIZE1:\t0x%08x\n", REG_LCD_SIZE1);
+ printk("REG_LCD_RGBC\t0x%08x\n", REG_LCD_RGBC);
+ printk("REG_LCD_VSYNC:\t0x%08x\n", REG_LCD_VSYNC);
+ printk("REG_LCD_HSYNC:\t0x%08x\n", REG_LCD_HSYNC);
+ printk("REG_LCD_PS:\t0x%08x\n", REG_LCD_PS);
+ printk("REG_LCD_CLS:\t0x%08x\n", REG_LCD_CLS);
+ printk("REG_LCD_SPL:\t0x%08x\n", REG_LCD_SPL);
+ printk("REG_LCD_REV:\t0x%08x\n", REG_LCD_REV);
+ printk("REG_LCD_IID:\t0x%08x\n", REG_LCD_IID);
+ printk("REG_LCD_DA0:\t0x%08x\n", REG_LCD_DA0);
+ printk("REG_LCD_SA0:\t0x%08x\n", REG_LCD_SA0);
+ printk("REG_LCD_FID0:\t0x%08x\n", REG_LCD_FID0);
+ printk("REG_LCD_CMD0:\t0x%08x\n", REG_LCD_CMD0);
+ printk("REG_LCD_OFFS0:\t0x%08x\n", REG_LCD_OFFS0);
+ printk("REG_LCD_PW0:\t0x%08x\n", REG_LCD_PW0);
+ printk("REG_LCD_CNUM0:\t0x%08x\n", REG_LCD_CNUM0);
+ printk("REG_LCD_DESSIZE0:\t0x%08x\n", REG_LCD_DESSIZE0);
+ printk("REG_LCD_DA1:\t0x%08x\n", REG_LCD_DA1);
+ printk("REG_LCD_SA1:\t0x%08x\n", REG_LCD_SA1);
+ printk("REG_LCD_FID1:\t0x%08x\n", REG_LCD_FID1);
+ printk("REG_LCD_CMD1:\t0x%08x\n", REG_LCD_CMD1);
+ printk("REG_LCD_OFFS1:\t0x%08x\n", REG_LCD_OFFS1);
+ printk("REG_LCD_PW1:\t0x%08x\n", REG_LCD_PW1);
+ printk("REG_LCD_CNUM1:\t0x%08x\n", REG_LCD_CNUM1);
+ printk("REG_LCD_DESSIZE1:\t0x%08x\n", REG_LCD_DESSIZE1);
+ printk("==================================\n");
+ printk("REG_LCD_VSYNC:\t%d:%d\n", REG_LCD_VSYNC>>16, REG_LCD_VSYNC&0xfff);
+ printk("REG_LCD_HSYNC:\t%d:%d\n", REG_LCD_HSYNC>>16, REG_LCD_HSYNC&0xfff);
+ printk("REG_LCD_VAT:\t%d:%d\n", REG_LCD_VAT>>16, REG_LCD_VAT&0xfff);
+ printk("REG_LCD_DAH:\t%d:%d\n", REG_LCD_DAH>>16, REG_LCD_DAH&0xfff);
+ printk("REG_LCD_DAV:\t%d:%d\n", REG_LCD_DAV>>16, REG_LCD_DAV&0xfff);
+ printk("==================================\n");
+
+ /* Smart LCD Controller Resgisters */
+ printk("REG_SLCD_CFG:\t0x%08x\n", REG_SLCD_CFG);
+ printk("REG_SLCD_CTRL:\t0x%08x\n", REG_SLCD_CTRL);
+ printk("REG_SLCD_STATE:\t0x%08x\n", REG_SLCD_STATE);
+ printk("==================================\n");
+
+ /* TVE Controller Resgisters */
+ printk("REG_TVE_CTRL:\t0x%08x\n", REG_TVE_CTRL);
+ printk("REG_TVE_FRCFG:\t0x%08x\n", REG_TVE_FRCFG);
+ printk("REG_TVE_SLCFG1:\t0x%08x\n", REG_TVE_SLCFG1);
+ printk("REG_TVE_SLCFG2:\t0x%08x\n", REG_TVE_SLCFG2);
+ printk("REG_TVE_SLCFG3:\t0x%08x\n", REG_TVE_SLCFG3);
+ printk("REG_TVE_LTCFG1:\t0x%08x\n", REG_TVE_LTCFG1);
+ printk("REG_TVE_LTCFG2:\t0x%08x\n", REG_TVE_LTCFG2);
+ printk("REG_TVE_CFREQ:\t0x%08x\n", REG_TVE_CFREQ);
+ printk("REG_TVE_CPHASE:\t0x%08x\n", REG_TVE_CPHASE);
+ printk("REG_TVE_CBCRCFG:\t0x%08x\n", REG_TVE_CBCRCFG);
+ printk("REG_TVE_WSSCR:\t0x%08x\n", REG_TVE_WSSCR);
+ printk("REG_TVE_WSSCFG1:\t0x%08x\n", REG_TVE_WSSCFG1);
+ printk("REG_TVE_WSSCFG2:\t0x%08x\n", REG_TVE_WSSCFG2);
+ printk("REG_TVE_WSSCFG3:\t0x%08x\n", REG_TVE_WSSCFG3);
+
+ printk("==================================\n");
+
+ if ( 1 ) {
+ unsigned int * pii = (unsigned int *)dma_desc_base;
+ int i, j;
+ for (j=0;j< DMA_DESC_NUM ; j++) {
+ printk("dma_desc%d(0x%08x):\n", j, (unsigned int)pii);
+ for (i =0; i<8; i++ ) {
+ printk("\t\t0x%08x\n", *pii++);
+ }
+ }
+ }
+}
+#else
+#define print_lcdc_registers()
+#endif
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int jz4750fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;
+ unsigned short *ptr, ctmp;
+
+// print_dbg("regno:%d,RGBt:(%d,%d,%d,%d)\t", regno, red, green, blue, transp);
+ if (regno >= NR_PALETTE)
+ return 1;
+
+ cfb->palette[regno].red = red ;
+ cfb->palette[regno].green = green;
+ cfb->palette[regno].blue = blue;
+ if (cfb->fb.var.bits_per_pixel <= 16) {
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ red &= 0xff;
+ green &= 0xff;
+ blue &= 0xff;
+ }
+ switch (cfb->fb.var.bits_per_pixel) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ if (((jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_MASK) == LCD_CFG_MODE_SINGLE_MSTN ) ||
+ ((jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_MASK) == LCD_CFG_MODE_DUAL_MSTN )) {
+ ctmp = (77L * red + 150L * green + 29L * blue) >> 8;
+ ctmp = ((ctmp >> 3) << 11) | ((ctmp >> 2) << 5) |
+ (ctmp >> 3);
+ } else {
+ /* RGB 565 */
+ if (((red >> 3) == 0) && ((red >> 2) != 0))
+ red = 1 << 3;
+ if (((blue >> 3) == 0) && ((blue >> 2) != 0))
+ blue = 1 << 3;
+ ctmp = ((red >> 3) << 11)
+ | ((green >> 2) << 5) | (blue >> 3);
+ }
+
+ ptr = (unsigned short *)lcd_palette;
+ ptr = (unsigned short *)(((u32)ptr)|0xa0000000);
+ ptr[regno] = ctmp;
+
+ break;
+
+ case 15:
+ if (regno < 16)
+ ((u32 *)cfb->fb.pseudo_palette)[regno] =
+ ((red >> 3) << 10) |
+ ((green >> 3) << 5) |
+ (blue >> 3);
+ break;
+ case 16:
+ if (regno < 16) {
+ ((u32 *)cfb->fb.pseudo_palette)[regno] =
+ ((red >> 3) << 11) |
+ ((green >> 2) << 5) |
+ (blue >> 3);
+ }
+ break;
+ case 17 ... 32:
+ if (regno < 16)
+ ((u32 *)cfb->fb.pseudo_palette)[regno] =
+ (red << 16) |
+ (green << 8) |
+ (blue << 0);
+
+/* if (regno < 16) {
+ unsigned val;
+ val = chan_to_field(red, &cfb->fb.var.red);
+ val |= chan_to_field(green, &cfb->fb.var.green);
+ val |= chan_to_field(blue, &cfb->fb.var.blue);
+ ((u32 *)cfb->fb.pseudo_palette)[regno] = val;
+ }
+*/
+
+ break;
+ }
+ return 0;
+}
+
+
+/*
+ * switch to tve mode from lcd mode
+ * mode:
+ * PANEL_MODE_TVE_PAL: switch to TVE_PAL mode
+ * PANEL_MODE_TVE_NTSC: switch to TVE_NTSC mode
+ */
+static void jz4750lcd_info_switch_to_TVE(int mode)
+{
+ struct jz4750lcd_info *info;
+ struct jz4750lcd_osd_t *osd_lcd;
+ int x, y, w, h;
+
+ info = jz4750_lcd_info = &jz4750_info_tve;
+ osd_lcd = &jz4750_lcd_panel.osd;
+
+ switch ( mode ) {
+ case PANEL_MODE_TVE_PAL:
+ info->panel.cfg |= LCD_CFG_TVEPEH; /* TVE PAL enable extra halfline signal */
+ info->panel.w = TVE_WIDTH_PAL;
+ info->panel.h = TVE_HEIGHT_PAL;
+ info->panel.fclk = TVE_FREQ_PAL;
+ w = ( osd_lcd->fg0.w < TVE_WIDTH_PAL )? osd_lcd->fg0.w:TVE_WIDTH_PAL;
+ h = ( osd_lcd->fg0.h < TVE_HEIGHT_PAL )?osd_lcd->fg0.h:TVE_HEIGHT_PAL;
+// x = ((TVE_WIDTH_PAL - w) >> 2) << 1;
+// y = ((TVE_HEIGHT_PAL - h) >> 2) << 1;
+ x = 0;
+ y = 0;
+
+ info->osd.fg0.bpp = osd_lcd->fg0.bpp;
+ info->osd.fg0.x = x;
+ info->osd.fg0.y = y;
+ info->osd.fg0.w = w;
+ info->osd.fg0.h = h;
+ w = ( osd_lcd->fg1.w < TVE_WIDTH_PAL )? osd_lcd->fg1.w:TVE_WIDTH_PAL;
+ h = ( osd_lcd->fg1.h < TVE_HEIGHT_PAL )?osd_lcd->fg1.h:TVE_HEIGHT_PAL;
+// x = ((TVE_WIDTH_PAL-w) >> 2) << 1;
+// y = ((TVE_HEIGHT_PAL-h) >> 2) << 1;
+ x = 0;
+ y = 0;
+
+ info->osd.fg1.bpp = 32; /* use RGB888 in TVE mode*/
+ info->osd.fg1.x = x;
+ info->osd.fg1.y = y;
+ info->osd.fg1.w = w;
+ info->osd.fg1.h = h;
+ break;
+ case PANEL_MODE_TVE_NTSC:
+ info->panel.cfg &= ~LCD_CFG_TVEPEH; /* TVE NTSC disable extra halfline signal */
+ info->panel.w = TVE_WIDTH_NTSC;
+ info->panel.h = TVE_HEIGHT_NTSC;
+ info->panel.fclk = TVE_FREQ_NTSC;
+ w = ( osd_lcd->fg0.w < TVE_WIDTH_NTSC )? osd_lcd->fg0.w:TVE_WIDTH_NTSC;
+ h = ( osd_lcd->fg0.h < TVE_HEIGHT_NTSC)?osd_lcd->fg0.h:TVE_HEIGHT_NTSC;
+ x = ((TVE_WIDTH_NTSC - w) >> 2) << 1;
+ y = ((TVE_HEIGHT_NTSC - h) >> 2) << 1;
+// x = 0;
+// y = 0;
+ info->osd.fg0.bpp = osd_lcd->fg0.bpp;
+ info->osd.fg0.x = x;
+ info->osd.fg0.y = y;
+ info->osd.fg0.w = w;
+ info->osd.fg0.h = h;
+ w = ( osd_lcd->fg1.w < TVE_WIDTH_NTSC )? osd_lcd->fg1.w:TVE_WIDTH_NTSC;
+ h = ( osd_lcd->fg1.h < TVE_HEIGHT_NTSC)?osd_lcd->fg1.h:TVE_HEIGHT_NTSC;
+ x = ((TVE_WIDTH_NTSC - w) >> 2) << 1;
+ y = ((TVE_HEIGHT_NTSC - h) >> 2) << 1;
+ info->osd.fg1.bpp = 32; /* use RGB888 int TVE mode */
+ info->osd.fg1.x = x;
+ info->osd.fg1.y = y;
+ info->osd.fg1.w = w;
+ info->osd.fg1.h = h;
+ break;
+ default:
+ printk("%s, %s: Unknown tve mode\n", __FILE__, __FUNCTION__);
+ }
+}
+
+static int jz4750fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+
+ void __user *argp = (void __user *)arg;
+
+// struct jz4750lcd_info *lcd_info = jz4750_lcd_info;
+
+
+ switch (cmd) {
+ case FBIOSETBACKLIGHT:
+ jz4750fb_set_backlight_level(arg);
+ break;
+
+ case FBIODISPON:
+ REG_LCD_STATE = 0; /* clear lcdc status */
+ __lcd_slcd_special_on();
+ __lcd_clr_dis();
+ __lcd_set_ena(); /* enable lcdc */
+
+ jz4750fb_lcd_display_on();
+ break;
+
+ case FBIODISPOFF:
+ jz4750fb_lcd_display_off();
+
+ if ( jz4750_lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ||
+ jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) /* */
+ __lcd_clr_ena(); /* Smart lcd and TVE mode only support quick disable */
+ else {
+ int cnt;
+ /* when CPU main freq is 336MHz,wait for 16ms */
+ cnt = 336000 * 16;
+ __lcd_set_dis(); /* regular disable */
+ while(!__lcd_disable_done() && cnt) {
+ cnt--;
+ }
+ if (cnt == 0)
+ printk("LCD disable timeout! REG_LCD_STATE=0x%08xx\n",REG_LCD_STATE);
+ REG_LCD_STATE &= ~LCD_STATE_LDD;
+ }
+ break;
+ case FBIOPRINT_REG:
+ print_lcdc_registers();
+ break;
+ case FBIO_GET_MODE:
+ print_dbg("fbio get mode\n");
+ if (copy_to_user(argp, jz4750_lcd_info, sizeof(struct jz4750lcd_info)))
+ return -EFAULT;
+ break;
+ case FBIO_SET_MODE:
+ print_dbg("fbio set mode\n");
+ if (copy_from_user(jz4750_lcd_info, argp, sizeof(struct jz4750lcd_info)))
+ return -EFAULT;
+ /* set mode */
+ jz4750fb_set_mode(jz4750_lcd_info);
+ break;
+ case FBIO_DEEP_SET_MODE:
+ print_dbg("fbio deep set mode\n");
+ if (copy_from_user(jz4750_lcd_info, argp, sizeof(struct jz4750lcd_info)))
+ return -EFAULT;
+ jz4750fb_deep_set_mode(jz4750_lcd_info);
+ break;
+#ifdef CONFIG_FB_JZ4750_TVE
+ case FBIO_MODE_SWITCH:
+ print_dbg("lcd mode switch between tve and lcd, arg=%lu\n", arg);
+ switch ( arg ) {
+ case PANEL_MODE_TVE_PAL: /* switch to TVE_PAL mode */
+ case PANEL_MODE_TVE_NTSC: /* switch to TVE_NTSC mode */
+ jz4750lcd_info_switch_to_TVE(arg);
+ jz4750tve_init(arg); /* tve controller init */
+ udelay(100);
+ jz4750tve_enable_tve();
+ /* turn off lcd backlight */
+ jz4750fb_lcd_display_off();
+ break;
+ case PANEL_MODE_LCD_PANEL: /* switch to LCD mode */
+ default :
+ /* turn off TVE, turn off DACn... */
+ jz4750tve_disable_tve();
+ jz4750_lcd_info = &jz4750_lcd_panel;
+ /* turn on lcd backlight */
+ jz4750fb_lcd_display_on();
+ break;
+ }
+ jz4750fb_deep_set_mode(jz4750_lcd_info);
+ break;
+ case FBIO_GET_TVE_MODE:
+ print_dbg("fbio get TVE mode\n");
+ if (copy_to_user(argp, jz4750_tve_info, sizeof(struct jz4750tve_info)))
+ return -EFAULT;
+ break;
+ case FBIO_SET_TVE_MODE:
+ print_dbg("fbio set TVE mode\n");
+ if (copy_from_user(jz4750_tve_info, argp, sizeof(struct jz4750tve_info)))
+ return -EFAULT;
+ /* set tve mode */
+ jz4750tve_set_tve_mode(jz4750_tve_info);
+ break;
+#endif
+ default:
+ printk("%s, unknown command(0x%x)", __FILE__, cmd);
+ break;
+ }
+
+ return ret;
+}
+
+/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */
+static int jz4750fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;
+ unsigned long start;
+ unsigned long off;
+ u32 len;
+ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__);
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
+
+ /* frame buffer memory */
+ start = cfb->fb.fix.smem_start;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb.fix.smem_len);
+ start &= PAGE_MASK;
+
+ if ((vma->vm_end - vma->vm_start + off) > len)
+ return -EINVAL;
+ off += start;
+
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ vma->vm_flags |= VM_IO;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Uncacheable */
+
+#if 1
+ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
+ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; /* Uncacheable */
+// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; /* Write-Back */
+#endif
+
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+/* checks var and eventually tweaks it to something supported,
+ * DO NOT MODIFY PAR */
+static int jz4750fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ printk("jz4750fb_check_var, not implement\n");
+ return 0;
+}
+
+
+/*
+ * set the video mode according to info->var
+ */
+static int jz4750fb_set_par(struct fb_info *info)
+{
+ printk("jz4750fb_set_par, not implemented\n");
+ return 0;
+}
+
+
+/*
+ * (Un)Blank the display.
+ * Fix me: should we use VESA value?
+ */
+static int jz4750fb_blank(int blank_mode, struct fb_info *info)
+{
+ dprintk("jz4750 fb_blank %d %p", blank_mode, info);
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ //case FB_BLANK_NORMAL:
+ /* Turn on panel */
+ __lcd_set_ena();
+ jz4750fb_lcd_display_on();
+
+ break;
+
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_POWERDOWN:
+#if 0
+ /* Turn off panel */
+ __lcd_display_off();
+ __lcd_set_dis();
+#endif
+ break;
+ default:
+ break;
+
+ }
+ return 0;
+}
+
+/*
+ * pan display
+ */
+static int jz4750fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;
+ int dy;
+
+ if (!var || !cfb) {
+ return -EINVAL;
+ }
+
+ if (var->xoffset - cfb->fb.var.xoffset) {
+ /* No support for X panning for now! */
+ return -EINVAL;
+ }
+
+ dy = var->yoffset;
+ print_dbg("var.yoffset: %d", dy);
+ if (dy) {
+ dma0_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame0 + (cfb->fb.fix.line_length * dy));
+ dma_cache_wback((unsigned int)(dma0_desc0), sizeof(struct jz4750_lcd_dma_desc));
+
+ }
+ else {
+ dma0_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame0);
+ dma_cache_wback((unsigned int)(dma0_desc0), sizeof(struct jz4750_lcd_dma_desc));
+ }
+
+ return 0;
+}
+
+
+/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */
+static struct fb_ops jz4750fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = jz4750fb_setcolreg,
+ .fb_check_var = jz4750fb_check_var,
+ .fb_set_par = jz4750fb_set_par,
+ .fb_blank = jz4750fb_blank,
+ .fb_pan_display = jz4750fb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_mmap = jz4750fb_mmap,
+ .fb_ioctl = jz4750fb_ioctl,
+};
+
+static int jz4750fb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;
+ struct jz4750lcd_info *lcd_info = jz4750_lcd_info;
+ int chgvar = 0;
+
+ var->height = lcd_info->osd.fg0.h; /* tve mode */
+ var->width = lcd_info->osd.fg0.w;
+ var->bits_per_pixel = lcd_info->osd.fg0.bpp;
+
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->activate = cfb->fb.var.activate;
+ var->xres = var->width;
+ var->yres = var->height;
+ var->xres_virtual = var->width;
+ var->yres_virtual = var->height;
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->pixclock = 0;
+ var->left_margin = 0;
+ var->right_margin = 0;
+ var->upper_margin = 0;
+ var->lower_margin = 0;
+ var->hsync_len = 0;
+ var->vsync_len = 0;
+ var->sync = 0;
+ var->activate &= ~FB_ACTIVATE_TEST;
+
+ /*
+ * CONUPDATE and SMOOTH_XPAN are equal. However,
+ * SMOOTH_XPAN is only used internally by fbcon.
+ */
+ if (var->vmode & FB_VMODE_CONUPDATE) {
+ var->vmode |= FB_VMODE_YWRAP;
+ var->xoffset = cfb->fb.var.xoffset;
+ var->yoffset = cfb->fb.var.yoffset;
+ }
+
+ if (var->activate & FB_ACTIVATE_TEST)
+ return 0;
+
+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+ return -EINVAL;
+
+ if (cfb->fb.var.xres != var->xres)
+ chgvar = 1;
+ if (cfb->fb.var.yres != var->yres)
+ chgvar = 1;
+ if (cfb->fb.var.xres_virtual != var->xres_virtual)
+ chgvar = 1;
+ if (cfb->fb.var.yres_virtual != var->yres_virtual)
+ chgvar = 1;
+ if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel)
+ chgvar = 1;
+
+ //display = fb_display + con;
+
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+
+ switch(var->bits_per_pixel){
+ case 1: /* Mono */
+ cfb->fb.fix.visual = FB_VISUAL_MONO01;
+ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8;
+ break;
+ case 2: /* Mono */
+ var->red.offset = 0;
+ var->red.length = 2;
+ var->green.offset = 0;
+ var->green.length = 2;
+ var->blue.offset = 0;
+ var->blue.length = 2;
+
+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8;
+ break;
+ case 4: /* PSEUDOCOLOUR*/
+ var->red.offset = 0;
+ var->red.length = 4;
+ var->green.offset = 0;
+ var->green.length = 4;
+ var->blue.offset = 0;
+ var->blue.length = 4;
+
+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ cfb->fb.fix.line_length = var->xres / 2;
+ break;
+ case 8: /* PSEUDOCOLOUR, 256 */
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+
+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ cfb->fb.fix.line_length = var->xres ;
+ break;
+ case 15: /* DIRECTCOLOUR, 32k */
+ var->bits_per_pixel = 15;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+
+ cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
+ cfb->fb.fix.line_length = var->xres_virtual * 2;
+ break;
+ case 16: /* DIRECTCOLOUR, 64k */
+ var->bits_per_pixel = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+
+ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ cfb->fb.fix.line_length = var->xres_virtual * 2;
+ break;
+ case 17 ... 32:
+ /* DIRECTCOLOUR, 256 */
+ var->bits_per_pixel = 32;
+
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+
+ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ cfb->fb.fix.line_length = var->xres_virtual * 4;
+ break;
+
+ default: /* in theory this should never happen */
+ printk(KERN_WARNING "%s: don't support for %dbpp\n",
+ cfb->fb.fix.id, var->bits_per_pixel);
+ break;
+ }
+
+ cfb->fb.var = *var;
+ cfb->fb.var.activate &= ~FB_ACTIVATE_ALL;
+
+ /*
+ * Update the old var. The fbcon drivers still use this.
+ * Once they are using cfb->fb.var, this can be dropped.
+ * --rmk
+ */
+ //display->var = cfb->fb.var;
+ /*
+ * If we are setting all the virtual consoles, also set the
+ * defaults used to create new consoles.
+ */
+ fb_set_cmap(&cfb->fb.cmap, &cfb->fb);
+ dprintk("jz4750fb_set_var: after fb_set_cmap...\n");
+
+ return 0;
+}
+
+static struct lcd_cfb_info * jz4750fb_alloc_fb_info(void)
+{
+ struct lcd_cfb_info *cfb;
+
+ cfb = kmalloc(sizeof(struct lcd_cfb_info) + sizeof(u32) * 16, GFP_KERNEL);
+
+ if (!cfb)
+ return NULL;
+
+ jz4750fb_info = cfb;
+
+ memset(cfb, 0, sizeof(struct lcd_cfb_info) );
+
+ cfb->currcon = -1;
+ cfb->backlight_level = LCD_DEFAULT_BACKLIGHT;
+
+ strcpy(cfb->fb.fix.id, "jz-lcd");
+ cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+ cfb->fb.fix.type_aux = 0;
+ cfb->fb.fix.xpanstep = 1;
+ cfb->fb.fix.ypanstep = 1;
+ cfb->fb.fix.ywrapstep = 0;
+ cfb->fb.fix.accel = FB_ACCEL_NONE;
+
+ cfb->fb.var.nonstd = 0;
+ cfb->fb.var.activate = FB_ACTIVATE_NOW;
+ cfb->fb.var.height = -1;
+ cfb->fb.var.width = -1;
+ cfb->fb.var.accel_flags = FB_ACCELF_TEXT;
+
+ cfb->fb.fbops = &jz4750fb_ops;
+ cfb->fb.flags = FBINFO_FLAG_DEFAULT;
+
+ cfb->fb.pseudo_palette = (void *)(cfb + 1);
+
+ switch (jz4750_lcd_info->osd.fg0.bpp) {
+ case 1:
+ fb_alloc_cmap(&cfb->fb.cmap, 4, 0);
+ break;
+ case 2:
+ fb_alloc_cmap(&cfb->fb.cmap, 8, 0);
+ break;
+ case 4:
+ fb_alloc_cmap(&cfb->fb.cmap, 32, 0);
+ break;
+ case 8:
+
+ default:
+ fb_alloc_cmap(&cfb->fb.cmap, 256, 0);
+ break;
+ }
+ dprintk("fb_alloc_cmap,fb.cmap.len:%d....\n", cfb->fb.cmap.len);
+
+ return cfb;
+}
+
+/*
+ * Map screen memory
+ */
+static int jz4750fb_map_smem(struct lcd_cfb_info *cfb)
+{
+ unsigned long page;
+ unsigned int page_shift, needroom, needroom1, bpp, w, h;
+
+ bpp = jz4750_lcd_info->osd.fg0.bpp;
+ if ( bpp == 18 || bpp == 24)
+ bpp = 32;
+ if ( bpp == 15 )
+ bpp = 16;
+#ifndef CONFIG_FB_JZ4750_TVE
+ w = jz4750_lcd_info->osd.fg0.w;
+ h = jz4750_lcd_info->osd.fg0.h;
+#else
+ w = ( jz4750_lcd_info->osd.fg0.w > TVE_WIDTH_PAL )?jz4750_lcd_info->osd.fg0.w:TVE_WIDTH_PAL;
+ h = ( jz4750_lcd_info->osd.fg0.h > TVE_HEIGHT_PAL )?jz4750_lcd_info->osd.fg0.h:TVE_HEIGHT_PAL;
+#endif
+ needroom1 = needroom = ((w * bpp + 7) >> 3) * h;
+#if defined(CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER)
+ bpp = jz4750_lcd_info->osd.fg1.bpp;
+ if ( bpp == 18 || bpp == 24)
+ bpp = 32;
+ if ( bpp == 15 )
+ bpp = 16;
+
+#ifndef CONFIG_FB_JZ4750_TVE
+ w = jz4750_lcd_info->osd.fg1.w;
+ h = jz4750_lcd_info->osd.fg1.h;
+#else
+ w = ( jz4750_lcd_info->osd.fg1.w > TVE_WIDTH_PAL )?jz4750_lcd_info->osd.fg1.w:TVE_WIDTH_PAL;
+ h = ( jz4750_lcd_info->osd.fg1.h > TVE_HEIGHT_PAL )?jz4750_lcd_info->osd.fg1.h:TVE_HEIGHT_PAL;
+#endif
+ needroom += ((w * bpp + 7) >> 3) * h;
+#endif // two layer
+
+
+ for (page_shift = 0; page_shift < 12; page_shift++)
+ if ((PAGE_SIZE << page_shift) >= needroom)
+ break;
+ lcd_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0);
+ lcd_frame0 = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift);
+
+ if ((!lcd_palette) || (!lcd_frame0))
+ return -ENOMEM;
+ memset((void *)lcd_palette, 0, PAGE_SIZE);
+ memset((void *)lcd_frame0, 0, PAGE_SIZE << page_shift);
+
+ dma_desc_base = (struct jz4750_lcd_dma_desc *)((void*)lcd_palette + ((PALETTE_SIZE+3)/4)*4);
+
+#if defined(CONFIG_FB_JZ4750_SLCD)
+
+ lcd_cmdbuf = (unsigned char *)__get_free_pages(GFP_KERNEL, 0);
+ memset((void *)lcd_cmdbuf, 0, PAGE_SIZE);
+
+ { int data, i, *ptr;
+ ptr = (unsigned int *)lcd_cmdbuf;
+ data = WR_GRAM_CMD;
+ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2);
+ for(i = 0; i < 3; i++){
+ ptr[i] = data;
+ }
+ }
+#endif
+
+#if defined(CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER)
+ lcd_frame1 = lcd_frame0 + needroom1;
+#endif
+
+ /*
+ * Set page reserved so that mmap will work. This is necessary
+ * since we'll be remapping normal memory.
+ */
+ page = (unsigned long)lcd_palette;
+ SetPageReserved(virt_to_page((void*)page));
+
+ for (page = (unsigned long)lcd_frame0;
+ page < PAGE_ALIGN((unsigned long)lcd_frame0 + (PAGE_SIZE<<page_shift));
+ page += PAGE_SIZE) {
+ SetPageReserved(virt_to_page((void*)page));
+ }
+
+ cfb->fb.fix.smem_start = virt_to_phys((void *)lcd_frame0);
+ cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift); /* page_shift/2 ??? */
+ cfb->fb.screen_base =
+ (unsigned char *)(((unsigned int)lcd_frame0&0x1fffffff) | 0xa0000000);
+
+ if (!cfb->fb.screen_base) {
+ printk("jz4750fb, %s: unable to map screen memory\n", cfb->fb.fix.id);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void jz4750fb_free_fb_info(struct lcd_cfb_info *cfb)
+{
+ if (cfb) {
+ fb_alloc_cmap(&cfb->fb.cmap, 0, 0);
+ kfree(cfb);
+ }
+}
+
+static void jz4750fb_unmap_smem(struct lcd_cfb_info *cfb)
+{
+ struct page * map = NULL;
+ unsigned char *tmp;
+ unsigned int page_shift, needroom, bpp, w, h;
+
+ bpp = jz4750_lcd_info->osd.fg0.bpp;
+ if ( bpp == 18 || bpp == 24)
+ bpp = 32;
+ if ( bpp == 15 )
+ bpp = 16;
+ w = jz4750_lcd_info->osd.fg0.w;
+ h = jz4750_lcd_info->osd.fg0.h;
+ needroom = ((w * bpp + 7) >> 3) * h;
+#if defined(CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER)
+ bpp = jz4750_lcd_info->osd.fg1.bpp;
+ if ( bpp == 18 || bpp == 24)
+ bpp = 32;
+ if ( bpp == 15 )
+ bpp = 16;
+ w = jz4750_lcd_info->osd.fg1.w;
+ h = jz4750_lcd_info->osd.fg1.h;
+ needroom += ((w * bpp + 7) >> 3) * h;
+#endif
+
+ for (page_shift = 0; page_shift < 12; page_shift++)
+ if ((PAGE_SIZE << page_shift) >= needroom)
+ break;
+
+ if (cfb && cfb->fb.screen_base) {
+ iounmap(cfb->fb.screen_base);
+ cfb->fb.screen_base = NULL;
+ release_mem_region(cfb->fb.fix.smem_start,
+ cfb->fb.fix.smem_len);
+ }
+
+ if (lcd_palette) {
+ map = virt_to_page(lcd_palette);
+ clear_bit(PG_reserved, &map->flags);
+ free_pages((int)lcd_palette, 0);
+ }
+
+ if (lcd_frame0) {
+ for (tmp=(unsigned char *)lcd_frame0;
+ tmp < lcd_frame0 + (PAGE_SIZE << page_shift);
+ tmp += PAGE_SIZE) {
+ map = virt_to_page(tmp);
+ clear_bit(PG_reserved, &map->flags);
+ }
+ free_pages((int)lcd_frame0, page_shift);
+ }
+}
+
+/* initial dma descriptors */
+static void jz4750fb_descriptor_init( struct jz4750lcd_info * lcd_info )
+{
+ unsigned int pal_size;
+
+ switch ( lcd_info->osd.fg0.bpp ) {
+ case 1:
+ pal_size = 4;
+ break;
+ case 2:
+ pal_size = 8;
+ break;
+ case 4:
+ pal_size = 32;
+ break;
+ case 8:
+ default:
+ pal_size = 512;
+ }
+
+ pal_size /= 4;
+
+ dma0_desc_palette = dma_desc_base + 0;
+ dma0_desc0 = dma_desc_base + 1;
+ dma0_desc1 = dma_desc_base + 2;
+ dma0_desc_cmd0 = dma_desc_base + 3; /* use only once */
+ dma0_desc_cmd = dma_desc_base + 4;
+ dma1_desc0 = dma_desc_base + 5;
+ dma1_desc1 = dma_desc_base + 6;
+
+ /*
+ * Normal TFT panel's DMA Chan0:
+ * TO LCD Panel:
+ * no palette: dma0_desc0 <<==>> dma0_desc0
+ * palette : dma0_desc_palette <<==>> dma0_desc0
+ * TO TV Encoder:
+ * no palette: dma0_desc0 <<==>> dma0_desc1
+ * palette: dma0_desc_palette --> dma0_desc0
+ * --> dma0_desc1 --> dma0_desc_palette --> ...
+ *
+ * SMART LCD TFT panel(dma0_desc_cmd)'s DMA Chan0:
+ * TO LCD Panel:
+ * no palette: dma0_desc_cmd <<==>> dma0_desc0
+ * palette : dma0_desc_palette --> dma0_desc_cmd
+ * --> dma0_desc0 --> dma0_desc_palette --> ...
+ * TO TV Encoder:
+ * no palette: dma0_desc_cmd --> dma0_desc0
+ * --> dma0_desc1 --> dma0_desc_cmd --> ...
+ * palette: dma0_desc_palette --> dma0_desc_cmd
+ * --> dma0_desc0 --> dma0_desc1
+ * --> dma0_desc_palette --> ...
+ * DMA Chan1:
+ * TO LCD Panel:
+ * dma1_desc0 <<==>> dma1_desc0
+ * TO TV Encoder:
+ * dma1_desc0 <<==>> dma1_desc1
+ */
+
+#if defined(CONFIG_FB_JZ4750_SLCD)
+ /* First CMD descriptors, use only once, cmd_num isn't 0 */
+ dma0_desc_cmd0->next_desc = (unsigned int)virt_to_phys(dma0_desc0);
+ dma0_desc_cmd0->databuf = (unsigned int)virt_to_phys((void *)lcd_cmdbuf);
+ dma0_desc_cmd0->frame_id = (unsigned int)0x0da0cad0; /* dma0's cmd0 */
+ dma0_desc_cmd0->cmd = LCD_CMD_CMD | 3; /* command */
+ dma0_desc_cmd0->offsize = 0;
+ dma0_desc_cmd0->page_width = 0;
+ dma0_desc_cmd0->cmd_num = 3;
+
+ /* Dummy Command Descriptor, cmd_num is 0 */
+ dma0_desc_cmd->next_desc = (unsigned int)virt_to_phys(dma0_desc0);
+ dma0_desc_cmd->databuf = 0;
+ dma0_desc_cmd->frame_id = (unsigned int)0x0da000cd; /* dma0's cmd0 */
+ dma0_desc_cmd->cmd = LCD_CMD_CMD | 0; /* dummy command */
+ dma0_desc_cmd->cmd_num = 0;
+ dma0_desc_cmd->offsize = 0;
+ dma0_desc_cmd->page_width = 0;
+
+ /* Palette Descriptor */
+ dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd0);
+#else
+ /* Palette Descriptor */
+ dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc0);
+#endif
+ dma0_desc_palette->databuf = (unsigned int)virt_to_phys((void *)lcd_palette);
+ dma0_desc_palette->frame_id = (unsigned int)0xaaaaaaaa;
+ dma0_desc_palette->cmd = LCD_CMD_PAL | pal_size; /* Palette Descriptor */
+
+ /* DMA0 Descriptor0 */
+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */
+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc1);
+ else{ /* Normal TFT LCD */
+#if defined(CONFIG_FB_JZ4750_SLCD)
+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd);
+#else
+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0);
+#endif
+ }
+
+ dma0_desc0->databuf = virt_to_phys((void *)lcd_frame0);
+ dma0_desc0->frame_id = (unsigned int)0x0000da00; /* DMA0'0 */
+
+ /* DMA0 Descriptor1 */
+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */
+
+
+ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup */
+ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_palette);
+ else
+#if defined(CONFIG_FB_JZ4750_SLCD) /* for smatlcd */
+ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd);
+#else
+ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0);
+#endif
+ dma0_desc1->frame_id = (unsigned int)0x0000da01; /* DMA0'1 */
+ }
+
+ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup */
+ REG_LCD_DA0 = virt_to_phys(dma0_desc_palette);
+ else {
+#if defined(CONFIG_FB_JZ4750_SLCD) /* for smartlcd */
+ REG_LCD_DA0 = virt_to_phys(dma0_desc_cmd0); //smart lcd
+#else
+ REG_LCD_DA0 = virt_to_phys(dma0_desc0); //tft
+#endif
+ }
+
+ /* DMA1 Descriptor0 */
+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */
+ dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc1);
+ else /* Normal TFT LCD */
+ dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0);
+
+ dma1_desc0->databuf = virt_to_phys((void *)lcd_frame1);
+ dma1_desc0->frame_id = (unsigned int)0x0000da10; /* DMA1'0 */
+
+ /* DMA1 Descriptor1 */
+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */
+ dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0);
+ dma1_desc1->frame_id = (unsigned int)0x0000da11; /* DMA1'1 */
+ }
+
+ REG_LCD_DA1 = virt_to_phys(dma1_desc0); /* set Dma-chan1's Descripter Addrress */
+ dma_cache_wback_inv((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc));
+
+#if 0
+ /* Palette Descriptor */
+ if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD )
+// dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd);
+ dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd1);
+ else
+ dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc0);
+ dma0_desc_palette->databuf = (unsigned int)virt_to_phys((void *)lcd_palette);
+ dma0_desc_palette->frame_id = (unsigned int)0xaaaaaaaa;
+ dma0_desc_palette->cmd = LCD_CMD_PAL | pal_size; /* Palette Descriptor */
+
+ /* Dummy Command Descriptor, cmd_num is 0 */
+ dma0_desc_cmd->next_desc = (unsigned int)virt_to_phys(dma0_desc0);
+ dma0_desc_cmd->databuf = (unsigned int)virt_to_phys((void *)lcd_cmdbuf);
+ dma0_desc_cmd->frame_id = (unsigned int)0x0da0cad0; /* dma0's cmd0 */
+ dma0_desc_cmd->cmd = LCD_CMD_CMD | 3; /* dummy command */
+ dma0_desc_cmd->offsize = 0; /* dummy command */
+ dma0_desc_cmd->page_width = 0; /* dummy command */
+ dma0_desc_cmd->cmd_num = 3;
+
+//---------------------------------
+ dma0_desc_cmd1->next_desc = (unsigned int)virt_to_phys(dma0_desc0);
+ dma0_desc_cmd1->databuf = 0;
+ dma0_desc_cmd1->frame_id = (unsigned int)0x0da0cad1; /* dma0's cmd0 */
+ dma0_desc_cmd1->cmd = LCD_CMD_CMD | 0; /* dummy command */
+ dma0_desc_cmd1->cmd_num = 0;
+ dma0_desc_cmd1->offsize = 0; /* dummy command */
+ dma0_desc_cmd1->page_width = 0; /* dummy command */
+//-----------------------------------
+ /* DMA0 Descriptor0 */
+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */
+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc1);
+ else{ /* Normal TFT LCD */
+ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup?? */
+// dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_palette); //tft
+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); // smart lcd
+ else if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD )
+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd1);
+// dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd);
+ else
+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0);
+ }
+
+ dma0_desc0->databuf = virt_to_phys((void *)lcd_frame0);
+ dma0_desc0->frame_id = (unsigned int)0x0000da00; /* DMA0'0 */
+
+ /* DMA0 Descriptor1 */
+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */
+ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup?? */
+ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_palette);
+
+ else if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD )
+ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd);
+ else
+ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0);
+ dma0_desc1->frame_id = (unsigned int)0x0000da01; /* DMA0'1 */
+ }
+
+ /* DMA1 Descriptor0 */
+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */
+ dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc1);
+ else /* Normal TFT LCD */
+ dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0);
+
+ dma1_desc0->databuf = virt_to_phys((void *)lcd_frame1);
+ dma1_desc0->frame_id = (unsigned int)0x0000da10; /* DMA1'0 */
+
+ /* DMA1 Descriptor1 */
+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */
+ dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0);
+ dma1_desc1->frame_id = (unsigned int)0x0000da11; /* DMA1'1 */
+ }
+
+ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup?? */
+ REG_LCD_DA0 = virt_to_phys(dma0_desc_palette);
+ else
+// REG_LCD_DA0 = virt_to_phys(dma0_desc_cmd); //smart lcd
+ REG_LCD_DA0 = virt_to_phys(dma0_desc0); //tft
+ REG_LCD_DA1 = virt_to_phys(dma1_desc0); /* set Dma-chan1's Descripter Addrress */
+ dma_cache_wback_inv((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc));
+#endif
+}
+
+static void jz4750fb_set_panel_mode( struct jz4750lcd_info * lcd_info )
+{
+ struct jz4750lcd_panel_t *panel = &lcd_info->panel;
+#ifdef CONFIG_JZ4750D_VGA_DISPLAY
+ REG_TVE_CTRL |= TVE_CTRL_DAPD;
+ REG_TVE_CTRL &= ~( TVE_CTRL_DAPD1 | TVE_CTRL_DAPD2 | TVE_CTRL_DAPD3);
+#endif
+ /* set bpp */
+ lcd_info->panel.ctrl &= ~LCD_CTRL_BPP_MASK;
+ if ( lcd_info->osd.fg0.bpp == 1 )
+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_1;
+ else if ( lcd_info->osd.fg0.bpp == 2 )
+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_2;
+ else if ( lcd_info->osd.fg0.bpp == 4 )
+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_4;
+ else if ( lcd_info->osd.fg0.bpp == 8 )
+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_8;
+ else if ( lcd_info->osd.fg0.bpp == 15 )
+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_16 | LCD_CTRL_RGB555;
+ else if ( lcd_info->osd.fg0.bpp == 16 )
+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_16 | LCD_CTRL_RGB565;
+ else if ( lcd_info->osd.fg0.bpp > 16 && lcd_info->osd.fg0.bpp < 32+1 ) {
+ lcd_info->osd.fg0.bpp = 32;
+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_18_24;
+ }
+ else {
+ printk("The BPP %d is not supported\n", lcd_info->osd.fg0.bpp);
+ lcd_info->osd.fg0.bpp = 32;
+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_18_24;
+ }
+
+ lcd_info->panel.cfg |= LCD_CFG_NEWDES; /* use 8words descriptor always */
+
+ REG_LCD_CTRL = lcd_info->panel.ctrl; /* LCDC Controll Register */
+ REG_LCD_CFG = lcd_info->panel.cfg; /* LCDC Configure Register */
+ REG_SLCD_CFG = lcd_info->panel.slcd_cfg; /* Smart LCD Configure Register */
+
+ if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) /* enable Smart LCD DMA */
+ REG_SLCD_CTRL = SLCD_CTRL_DMA_EN;
+
+ switch ( lcd_info->panel.cfg & LCD_CFG_MODE_MASK ) {
+ case LCD_CFG_MODE_GENERIC_TFT:
+ case LCD_CFG_MODE_INTER_CCIR656:
+ case LCD_CFG_MODE_NONINTER_CCIR656:
+ case LCD_CFG_MODE_SLCD:
+ default: /* only support TFT16 TFT32, not support STN and Special TFT by now(10-06-2008)*/
+ REG_LCD_VAT = (((panel->blw + panel->w + panel->elw + panel->hsw)) << 16) | (panel->vsw + panel->bfw + panel->h + panel->efw);
+ REG_LCD_DAH = ((panel->hsw + panel->blw) << 16) | (panel->hsw + panel->blw + panel->w);
+ REG_LCD_DAV = ((panel->vsw + panel->bfw) << 16) | (panel->vsw + panel->bfw + panel->h);
+ REG_LCD_HSYNC = (0 << 16) | panel->hsw;
+ REG_LCD_VSYNC = (0 << 16) | panel->vsw;
+ break;
+ }
+}
+
+
+static void jz4750fb_set_osd_mode( struct jz4750lcd_info * lcd_info )
+{
+ dprintk("%s, %d\n", __FILE__, __LINE__ );
+ lcd_info->osd.osd_ctrl &= ~(LCD_OSDCTRL_OSDBPP_MASK);
+ if ( lcd_info->osd.fg1.bpp == 15 )
+ lcd_info->osd.osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB555;
+ else if ( lcd_info->osd.fg1.bpp == 16 )
+ lcd_info->osd.osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB565;
+ else {
+ lcd_info->osd.fg1.bpp = 32;
+ lcd_info->osd.osd_ctrl |= LCD_OSDCTRL_OSDBPP_18_24;
+ }
+
+ REG_LCD_OSDC = lcd_info->osd.osd_cfg; /* F0, F1, alpha, */
+
+ REG_LCD_OSDCTRL = lcd_info->osd.osd_ctrl; /* IPUEN, bpp */
+ REG_LCD_RGBC = lcd_info->osd.rgb_ctrl;
+ REG_LCD_BGC = lcd_info->osd.bgcolor;
+ REG_LCD_KEY0 = lcd_info->osd.colorkey0;
+ REG_LCD_KEY1 = lcd_info->osd.colorkey1;
+ REG_LCD_ALPHA = lcd_info->osd.alpha;
+ REG_LCD_IPUR = lcd_info->osd.ipu_restart;
+}
+
+static void jz4750fb_foreground_resize( struct jz4750lcd_info * lcd_info )
+{
+ int fg0_line_size, fg0_frm_size, fg1_line_size, fg1_frm_size;
+ /*
+ * NOTE:
+ * Foreground change sequence:
+ * 1. Change Position Registers -> LCD_OSDCTL.Change;
+ * 2. LCD_OSDCTRL.Change -> descripter->Size
+ * Foreground, only one of the following can be change at one time:
+ * 1. F0 size;
+ * 2. F0 position
+ * 3. F1 size
+ * 4. F1 position
+ */
+
+ /*
+ * The rules of f0, f1's position:
+ * f0.x + f0.w <= panel.w;
+ * f0.y + f0.h <= panel.h;
+ *
+ * When output is LCD panel, fg.y and fg.h can be odd number or even number.
+ * When output is TVE, as the TVE has odd frame and even frame,
+ * to simplified operation, fg.y and fg.h should be even number always.
+ *
+ */
+
+ /* Foreground 0 */
+ if ( lcd_info->osd.fg0.x >= lcd_info->panel.w )
+ lcd_info->osd.fg0.x = lcd_info->panel.w;
+ if ( lcd_info->osd.fg0.y >= lcd_info->panel.h )
+ lcd_info->osd.fg0.y = lcd_info->panel.h;
+ if ( lcd_info->osd.fg0.x + lcd_info->osd.fg0.w > lcd_info->panel.w )
+ lcd_info->osd.fg0.w = lcd_info->panel.w - lcd_info->osd.fg0.x;
+ if ( lcd_info->osd.fg0.y + lcd_info->osd.fg0.h > lcd_info->panel.h )
+ lcd_info->osd.fg0.h = lcd_info->panel.h - lcd_info->osd.fg0.y;
+
+#if 0
+ /* Foreground 1 */
+ /* Case TVE ??? TVE 720x573 or 720x480*/
+ if ( lcd_info->osd.fg1.x >= lcd_info->panel.w )
+ lcd_info->osd.fg1.x = lcd_info->panel.w;
+ if ( lcd_info->osd.fg1.y >= lcd_info->panel.h )
+ lcd_info->osd.fg1.y = lcd_info->panel.h;
+ if ( lcd_info->osd.fg1.x + lcd_info->osd.fg1.w > lcd_info->panel.w )
+ lcd_info->osd.fg1.w = lcd_info->panel.w - lcd_info->osd.fg1.x;
+ if ( lcd_info->osd.fg1.y + lcd_info->osd.fg1.h > lcd_info->panel.h )
+ lcd_info->osd.fg1.h = lcd_info->panel.h - lcd_info->osd.fg1.y;
+#endif
+// fg0_line_size = lcd_info->osd.fg0.w*((lcd_info->osd.fg0.bpp+7)/8);
+ fg0_line_size = (lcd_info->osd.fg0.w*(lcd_info->osd.fg0.bpp)/8);
+ fg0_line_size = ((fg0_line_size+3)>>2)<<2; /* word aligned */
+ fg0_frm_size = fg0_line_size * lcd_info->osd.fg0.h;
+
+ fg1_line_size = lcd_info->osd.fg1.w*((lcd_info->osd.fg1.bpp+7)/8);
+ fg1_line_size = ((fg1_line_size+3)>>2)<<2; /* word aligned */
+ fg1_frm_size = fg1_line_size * lcd_info->osd.fg1.h;
+
+ if ( lcd_info->osd.fg_change ) {
+ if ( lcd_info->osd.fg_change & FG0_CHANGE_POSITION ) { /* F1 change position */
+ REG_LCD_XYP0 = lcd_info->osd.fg0.y << 16 | lcd_info->osd.fg0.x;
+ }
+ if ( lcd_info->osd.fg_change & FG1_CHANGE_POSITION ) { /* F1 change position */
+ REG_LCD_XYP1 = lcd_info->osd.fg1.y << 16 | lcd_info->osd.fg1.x;
+ }
+
+ /* set change */
+ if ( !(lcd_info->osd.osd_ctrl & LCD_OSDCTRL_IPU) &&
+ (lcd_info->osd.fg_change != FG_CHANGE_ALL) )
+ REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES;
+
+ /* wait change ready??? */
+// while ( REG_LCD_OSDS & LCD_OSDS_READY ) /* fix in the future, Wolfgang, 06-20-2008 */
+ print_dbg("wait LCD_OSDS_READY\n");
+
+ if ( lcd_info->osd.fg_change & FG0_CHANGE_SIZE ) { /* change FG0 size */
+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* output to TV */
+ dma0_desc0->cmd = dma0_desc1->cmd = (fg0_frm_size/4)/2;
+ dma0_desc0->offsize = dma0_desc1->offsize
+ = fg0_line_size/4;
+ dma0_desc0->page_width = dma0_desc1->page_width
+ = fg0_line_size/4;
+ dma0_desc1->databuf = virt_to_phys((void *)(lcd_frame0 + fg0_line_size));
+ REG_LCD_DA0 = virt_to_phys(dma0_desc0); //tft
+ }
+ else {
+ dma0_desc0->cmd = dma0_desc1->cmd = fg0_frm_size/4;
+ dma0_desc0->offsize = dma0_desc1->offsize =0;
+ dma0_desc0->page_width = dma0_desc1->page_width = 0;
+ }
+
+ dma0_desc0->desc_size = dma0_desc1->desc_size
+ = lcd_info->osd.fg0.h << 16 | lcd_info->osd.fg0.w;
+ REG_LCD_SIZE0 = (lcd_info->osd.fg0.h<<16)|lcd_info->osd.fg0.w;
+
+ }
+
+ if ( lcd_info->osd.fg_change & FG1_CHANGE_SIZE ) { /* change FG1 size*/
+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* output to TV */
+ dma1_desc0->cmd = dma1_desc1->cmd = (fg1_frm_size/4)/2;
+ dma1_desc0->offsize = dma1_desc1->offsize = fg1_line_size/4;
+ dma1_desc0->page_width = dma1_desc1->page_width = fg1_line_size/4;
+ dma1_desc1->databuf = virt_to_phys((void *)(lcd_frame1 + fg1_line_size));
+ REG_LCD_DA1 = virt_to_phys(dma0_desc1); //tft
+
+ }
+ else {
+ dma1_desc0->cmd = dma1_desc1->cmd = fg1_frm_size/4;
+ dma1_desc0->offsize = dma1_desc1->offsize = 0;
+ dma1_desc0->page_width = dma1_desc1->page_width = 0;
+ }
+
+ dma1_desc0->desc_size = dma1_desc1->desc_size
+ = lcd_info->osd.fg1.h << 16 | lcd_info->osd.fg1.w;
+ REG_LCD_SIZE1 = lcd_info->osd.fg1.h << 16|lcd_info->osd.fg1.w;
+ }
+
+ dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc));
+ lcd_info->osd.fg_change = FG_NOCHANGE; /* clear change flag */
+ }
+}
+
+static void jz4750fb_change_clock( struct jz4750lcd_info * lcd_info )
+{
+
+#if defined(CONFIG_FPGA)
+ REG_LCD_REV = 0x00000004;
+ printk("Fuwa test, pixclk divide REG_LCD_REV=0x%08x\n", REG_LCD_REV);
+ printk("Fuwa test, pixclk %d\n", JZ_EXTAL/(((REG_LCD_REV&0xFF)+1)*2));
+#else
+ unsigned int val = 0;
+ unsigned int pclk;
+ /* Timing setting */
+ __cpm_stop_lcd();
+
+ val = lcd_info->panel.fclk; /* frame clk */
+
+ if ( (lcd_info->panel.cfg & LCD_CFG_MODE_MASK) != LCD_CFG_MODE_SERIAL_TFT) {
+ pclk = val * (lcd_info->panel.w + lcd_info->panel.hsw + lcd_info->panel.elw + lcd_info->panel.blw) * (lcd_info->panel.h + lcd_info->panel.vsw + lcd_info->panel.efw + lcd_info->panel.bfw); /* Pixclk */
+ }
+ else {
+ /* serial mode: Hsync period = 3*Width_Pixel */
+ pclk = val * (lcd_info->panel.w*3 + lcd_info->panel.hsw + lcd_info->panel.elw + lcd_info->panel.blw) * (lcd_info->panel.h + lcd_info->panel.vsw + lcd_info->panel.efw + lcd_info->panel.bfw); /* Pixclk */
+ }
+
+ /********* In TVE mode PCLK = 27MHz ***********/
+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* LCDC output to TVE */
+ REG_CPM_LPCDR |= CPM_LPCDR_LTCS;
+ pclk = 27000000;
+ val = __cpm_get_pllout2() / pclk; /* pclk */
+ val--;
+ __cpm_set_pixdiv(val);
+
+ dprintk("REG_CPM_LPCDR = 0x%08x\n", REG_CPM_LPCDR);
+#if defined(CONFIG_SOC_JZ4750) /* Jz4750D don't use LCLK */
+ val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */
+
+ val =(__cpm_get_pllout()) / val;
+ if ( val > 0x1f ) {
+ printk("lcd clock divide is too large, set it to 0x1f\n");
+ val = 0x1f;
+ }
+ __cpm_set_ldiv( val );
+#endif
+ __cpm_select_pixclk_tve();
+
+ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */
+ }
+ else { /* LCDC output to LCD panel */
+ val = __cpm_get_pllout2() / pclk; /* pclk */
+ val--;
+ dprintk("ratio: val = %d\n", val);
+ if ( val > 0x7ff ) {
+ printk("pixel clock divid is too large, set it to 0x7ff\n");
+ val = 0x7ff;
+ }
+
+ __cpm_set_pixdiv(val);
+
+ dprintk("REG_CPM_LPCDR = 0x%08x\n", REG_CPM_LPCDR);
+#if defined(CONFIG_SOC_JZ4750) /* Jz4750D don't use LCLK */
+ val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */
+ val =__cpm_get_pllout2() / val;
+ if ( val > 0x1f ) {
+ printk("lcd clock divide is too large, set it to 0x1f\n");
+ val = 0x1f;
+ }
+ __cpm_set_ldiv( val );
+#endif
+ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */
+
+ }
+
+ dprintk("REG_CPM_LPCDR=0x%08x\n", REG_CPM_LPCDR);
+ dprintk("REG_CPM_CPCCR=0x%08x\n", REG_CPM_CPCCR);
+
+ jz_clocks.pixclk = __cpm_get_pixclk();
+ printk("LCDC: PixClock:%d\n", jz_clocks.pixclk);
+
+#if defined(CONFIG_SOC_JZ4750) /* Jz4750D don't use LCLK */
+ jz_clocks.lcdclk = __cpm_get_lcdclk();
+ printk("LCDC: LcdClock:%d\n", jz_clocks.lcdclk);
+#endif
+ __cpm_start_lcd();
+ udelay(1000);
+ /*
+ * set lcd device clock and lcd pixel clock.
+ * what about TVE mode???
+ *
+ */
+#endif
+
+}
+
+/*
+ * jz4750fb_set_mode(), set osd configure, resize foreground
+ *
+ */
+static void jz4750fb_set_mode( struct jz4750lcd_info * lcd_info )
+{
+ struct lcd_cfb_info *cfb = jz4750fb_info;
+
+ jz4750fb_set_osd_mode(lcd_info);
+ jz4750fb_foreground_resize(lcd_info);
+ jz4750fb_set_var(&cfb->fb.var, -1, &cfb->fb);
+}
+
+/*
+ * jz4750fb_deep_set_mode,
+ *
+ */
+static void jz4750fb_deep_set_mode( struct jz4750lcd_info * lcd_info )
+{
+ /* configurate sequence:
+ * 1. disable lcdc.
+ * 2. init frame descriptor.
+ * 3. set panel mode
+ * 4. set osd mode
+ * 5. start lcd clock in CPM
+ * 6. enable lcdc.
+ */
+
+ __lcd_clr_ena(); /* Quick Disable */
+ lcd_info->osd.fg_change = FG_CHANGE_ALL; /* change FG0, FG1 size, postion??? */
+ jz4750fb_descriptor_init(lcd_info);
+ jz4750fb_set_panel_mode(lcd_info);
+ jz4750fb_set_mode(lcd_info);
+ jz4750fb_change_clock(lcd_info);
+ __lcd_set_ena(); /* enable lcdc */
+}
+
+
+static irqreturn_t jz4750fb_interrupt_handler(int irq, void *dev_id)
+{
+ unsigned int state;
+ static int irqcnt=0;
+
+ state = REG_LCD_STATE;
+ dprintk("In the lcd interrupt handler, state=0x%x\n", state);
+
+ if (state & LCD_STATE_EOF) /* End of frame */
+ REG_LCD_STATE = state & ~LCD_STATE_EOF;
+
+ if (state & LCD_STATE_IFU0) {
+ printk("%s, InFiFo0 underrun\n", __FUNCTION__);
+ REG_LCD_STATE = state & ~LCD_STATE_IFU0;
+ }
+
+ if (state & LCD_STATE_IFU1) {
+ printk("%s, InFiFo1 underrun\n", __FUNCTION__);
+ REG_LCD_STATE = state & ~LCD_STATE_IFU1;
+ }
+
+ if (state & LCD_STATE_OFU) { /* Out fifo underrun */
+ REG_LCD_STATE = state & ~LCD_STATE_OFU;
+ if ( irqcnt++ > 100 ) {
+ __lcd_disable_ofu_intr();
+ printk("disable Out FiFo underrun irq.\n");
+ }
+ printk("%s, Out FiFo underrun.\n", __FUNCTION__);
+ }
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * Suspend the LCDC.
+ */
+static int jz4750_fb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ printk("%s(): called.\n", __func__);
+
+ __lcd_clr_ena(); /* Quick Disable */
+ jz4750fb_lcd_display_off();
+ __cpm_stop_lcd();
+
+ return 0;
+}
+
+/*
+ * Resume the LCDC.
+ */
+static int jz4750_fb_resume(struct platform_device *pdev)
+{
+ struct lcd_cfb_info *cfb = jz4750fb_info;
+
+ printk("%s(): called.\n", __func__);
+
+ __cpm_start_lcd();
+ __gpio_set_pin(GPIO_DISP_OFF_N);
+ __lcd_special_on();
+ __lcd_set_ena();
+ mdelay(200);
+
+ __lcd_set_backlight_level(cfb->backlight_level);
+
+ return 0;
+}
+
+#else
+#define jzfb_suspend NULL
+#define jzfb_resume NULL
+#endif /* CONFIG_PM */
+
+/* The following routine is only for test */
+
+#ifdef DEBUG
+static void test_gpio(int gpio_num, int delay) {
+ __gpio_as_output(gpio_num);
+ while(1) {
+ __gpio_set_pin(gpio_num);
+ udelay(delay);
+ __gpio_clear_pin(gpio_num);
+ udelay(delay);
+ }
+}
+static void display_v_color_bar(int w, int h, int bpp) {
+ int i, j, wpl, data = 0;
+ int *ptr;
+ ptr = (int *)lcd_frame0;
+// ptr = (int *)lcd_frame1;
+ wpl = w*bpp/32;
+ if (!(bpp > 8))
+ switch(bpp){
+ case 1:
+ for (j = 0;j < h; j++)
+ for (i = 0;i < wpl; i++) {
+ *ptr++ = 0x00ff00ff;
+ }
+ break;
+ case 2:
+ for (j = 0;j < h; j++)
+ for (i = 0;i < wpl; i++) {
+ data = (i%4)*0x55555555;
+ *ptr++ = data;
+ }
+ break;
+ case 4:
+ for (j = 0;j < h; j++)
+ for (i = 0;i < wpl; i++) {
+ data = (i%16)*0x11111111;
+ *ptr++ = data;
+ }
+ break;
+ case 8:
+ for (j = 0;j < h; j++)
+ for (i = 0;i < wpl; i+=2) {
+ data = (i%(256))*0x01010101;
+ *ptr++ = data;
+ *ptr++ = data;
+ }
+ break;
+ }
+ else {
+ switch(bpp) {
+ case 16:
+ for (j = 0;j < h; j++)
+ for (i = 0;i < wpl; i++) {
+ if((i/4)%8==0)
+ *ptr++ = 0xffffffff;
+ else if ((i/4)%8==1)
+ *ptr++ = 0xf800f800;
+ else if ((i/4)%8==2)
+ *ptr++ = 0xffe0ffe0;
+ else if ((i/4)%8==3)
+ *ptr++ = 0x07e007e0;
+ else if ((i/4)%8==4)
+ *ptr++ = 0x07ff07ff;
+ else if ((i/4)%8==5)
+ *ptr++ = 0x001f001f;
+ else if ((i/4)%8==6)
+ *ptr++ = 0xf81ff81f;
+ else if ((i/4)%8==7)
+ *ptr++ = 0x00000000;
+ }
+ break;
+ case 18:
+ case 24:
+ case 32:
+ default:
+#if 1
+ for (j = 0;j < h; j++)
+ for (i = 0;i < wpl; i++) {
+ if((i/8)%8==7)
+ *ptr++ = 0xffffff;
+ else if ((i/8)%8==1)
+ *ptr++ = 0xff0000;
+ else if ((i/8)%8==2)
+ *ptr++ = 0xffff00;
+ else if ((i/8)%8==3)
+ *ptr++ = 0x00ff00;
+ else if ((i/8)%8==4)
+ *ptr++ = 0x00ffff;
+ else if ((i/8)%8==5)
+ *ptr++ = 0x0000ff;
+ else if ((i/8)%8==6)
+ *ptr++ = 0xff00ff;
+ else if ((i/8)%8==0)
+ *ptr++ = 0x000000;
+ }
+#else
+ for (j = 0;j < h; j++)
+ for (i = 0;i < wpl; i++) {
+ if((i/8)%8==7)
+ *ptr++ = 0x00ff0000;
+ else if ((i/8)%8==1)
+ *ptr++ = 0xffff0000;
+ else if ((i/8)%8==2)
+ *ptr++ = 0x20ff0000;
+ else if ((i/8)%8==3)
+ *ptr++ = 0x40ff0000;
+ else if ((i/8)%8==4)
+ *ptr++ = 0x60ff0000;
+ else if ((i/8)%8==5)
+ *ptr++ = 0x80ff0000;
+ else if ((i/8)%8==6)
+ *ptr++ = 0xa0ff0000;
+ else if ((i/8)%8==0)
+ *ptr++ = 0xc0ff0000;
+ }
+#endif
+ break;
+ }
+ }
+}
+static void display_h_color_bar(int w, int h, int bpp) {
+ int i, data = 0;
+ int *ptr;
+ int wpl; //word_per_line
+ ptr = (int *)lcd_frame0;
+// ptr = (int *)lcd_frame1;
+ wpl = w*bpp/32;
+ if (!(bpp > 8))
+ for (i = 0;i < wpl*h;i++) {
+ switch(bpp){
+ case 1:
+ if(i%(wpl*8)==0)
+ data = ((i/(wpl*8))%2)*0xffffffff;
+ *ptr++ = data;
+ break;
+ case 2:
+ if(i%(wpl*8)==0)
+ data = ((i/(wpl*8))%4)*0x55555555;
+ *ptr++ = data;
+ break;
+ case 4:
+ if(i%(wpl*8)==0)
+ data = ((i/(wpl*8))%16)*0x11111111;
+ *ptr++ = data;
+ break;
+ case 8:
+ if(i%(wpl*8)==0)
+ data = ((i/(wpl*8))%256)*0x01010101;
+ *ptr++ = data;
+ break;
+ }
+ }
+ else {
+
+ switch(bpp) {
+ case 15:
+ case 16:
+ for (i = 0;i < wpl*h;i++) {
+ if (((i/(wpl*8)) % 8) == 0)
+ *ptr++ = 0xffffffff;
+ else if (((i/(wpl*8)) % 8) == 1)
+ *ptr++ = 0xf800f800;
+ else if (((i/(wpl*8)) % 8) == 2)
+ *ptr++ = 0xffe0ffe0;
+ else if (((i/(wpl*8)) % 8) == 3)
+ *ptr++ = 0x07e007e0;
+ else if (((i/(wpl*8)) % 8) == 4)
+ *ptr++ = 0x07ff07ff;
+ else if (((i/(wpl*8)) % 8) == 5)
+ *ptr++ = 0x001f001f;
+ else if (((i/(wpl*8)) % 8) == 6)
+ *ptr++ = 0xf81ff81f;
+ else if (((i/(wpl*8)) % 8) == 7)
+ *ptr++ = 0x00000000;
+ }
+ break;
+ case 18:
+ case 24:
+ case 32:
+ default:
+ for (i = 0;i < wpl*h;i++) {
+ if (((i/(wpl*8)) % 8) == 7)
+ *ptr++ = 0xffffff;
+ else if (((i/(wpl*8)) % 8) == 2)
+ *ptr++ = 0xff0000;
+ else if (((i/(wpl*8)) % 8) == 4)
+ *ptr++ = 0xffff00;
+ else if (((i/(wpl*8)) % 8) == 6)
+ *ptr++ = 0x00ff00;
+ else if (((i/(wpl*8)) % 8) == 1)
+ *ptr++ = 0x00ffff;
+ else if (((i/(wpl*8)) % 8) == 3)
+ *ptr++ = 0x0000ff;
+ else if (((i/(wpl*8)) % 8) == 5)
+ *ptr++ = 0x000000;
+ else if (((i/(wpl*8)) % 8) == 0)
+ *ptr++ = 0xff00ff;
+ }
+ break;
+ }
+
+ }
+
+}
+#endif
+
+/* Backlight Control Interface via sysfs
+ *
+ * LCDC:
+ * Enabling LCDC when LCD backlight is off will only affects cfb->display.
+ *
+ * Backlight:
+ * Changing the value of LCD backlight when LCDC is off will only affect the cfb->backlight_level.
+ *
+ * - River.
+ */
+static int jz4750fb_lcd_display_off(void)
+{
+ struct lcd_cfb_info *cfb = jz4750fb_info;
+
+ __lcd_close_backlight();
+ __lcd_display_off();
+
+#ifdef HAVE_LCD_PWM_CONTROL
+ if (cfb->b_lcd_pwm) {
+ __lcd_pwm_stop();
+ cfb->b_lcd_pwm = 0;
+ }
+#endif
+
+ cfb->b_lcd_display = 0;
+
+ return 0;
+}
+
+static int jz4750fb_lcd_display_on(void)
+{
+ struct lcd_cfb_info *cfb = jz4750fb_info;
+
+ __lcd_display_on();
+
+ /* Really restore LCD backlight when LCD backlight is turned on. */
+ if (cfb->backlight_level) {
+#ifdef HAVE_LCD_PWM_CONTROL
+ if (!cfb->b_lcd_pwm) {
+ __lcd_pwm_start();
+ cfb->b_lcd_pwm = 1;
+ }
+#endif
+ __lcd_set_backlight_level(cfb->backlight_level);
+ }
+
+ cfb->b_lcd_display = 1;
+
+ return 0;
+}
+
+static int jz4750fb_set_backlight_level(int n)
+{
+ struct lcd_cfb_info *cfb = jz4750fb_info;
+
+ if (n) {
+ if (n > LCD_MAX_BACKLIGHT)
+ n = LCD_MAX_BACKLIGHT;
+
+ if (n < LCD_MIN_BACKLIGHT)
+ n = LCD_MIN_BACKLIGHT;
+
+ /* Really change the value of backlight when LCDC is enabled. */
+ if (cfb->b_lcd_display) {
+#ifdef HAVE_LCD_PWM_CONTROL
+ if (!cfb->b_lcd_pwm) {
+ __lcd_pwm_start();
+ cfb->b_lcd_pwm = 1;
+ }
+#endif
+ __lcd_set_backlight_level(n);
+ }
+ }else{
+ /* Turn off LCD backlight. */
+ __lcd_close_backlight();
+
+#ifdef HAVE_LCD_PWM_CONTROL
+ if (cfb->b_lcd_pwm) {
+ __lcd_pwm_stop();
+ cfb->b_lcd_pwm = 0;
+ }
+#endif
+ }
+
+ cfb->backlight_level = n;
+
+ return 0;
+}
+
+static ssize_t show_bl_level(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct lcd_cfb_info *cfb = jz4750fb_info;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", cfb->backlight_level);
+}
+
+static ssize_t store_bl_level(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int n;
+ char *ep;
+
+ n = simple_strtoul(buf, &ep, 0);
+ if (*ep && *ep != '\n')
+ return -EINVAL;
+
+ jz4750fb_set_backlight_level(n);
+
+ return count;
+}
+
+static struct device_attribute device_attrs[] = {
+ __ATTR(backlight_level, S_IRUGO | S_IWUSR, show_bl_level, store_bl_level),
+};
+
+static int jz4750fb_device_attr_register(struct fb_info *fb_info)
+{
+ int error = 0;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
+ error = device_create_file(fb_info->dev, &device_attrs[i]);
+
+ if (error)
+ break;
+ }
+
+ if (error) {
+ while (--i >= 0)
+ device_remove_file(fb_info->dev, &device_attrs[i]);
+ }
+
+ return 0;
+}
+
+static int jz4750fb_device_attr_unregister(struct fb_info *fb_info)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
+ device_remove_file(fb_info->dev, &device_attrs[i]);
+
+ return 0;
+}
+/* End */
+
+static int __devinit jz4750_fb_probe(struct platform_device *dev)
+{
+ struct lcd_cfb_info *cfb;
+ int err = 0;
+
+ /* gpio init __gpio_as_lcd */
+ if (jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_TFT_16BIT)
+ __gpio_as_lcd_16bit();
+ else if (jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_TFT_24BIT)
+ __gpio_as_lcd_24bit();
+ else
+ __gpio_as_lcd_18bit();
+ /* In special mode, we only need init special pin,
+ * as general lcd pin has init in uboot */
+#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D)
+ switch (jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_MASK) {
+ case LCD_CFG_MODE_SPECIAL_TFT_1:
+ case LCD_CFG_MODE_SPECIAL_TFT_2:
+ case LCD_CFG_MODE_SPECIAL_TFT_3:
+ __gpio_as_lcd_special();
+ break;
+ default:
+ ;
+ }
+#endif
+ if ( jz4750_lcd_info->osd.fg0.bpp > 16 &&
+ jz4750_lcd_info->osd.fg0.bpp < 32 ) {
+ jz4750_lcd_info->osd.fg0.bpp = 32;
+ }
+
+ switch ( jz4750_lcd_info->osd.fg1.bpp ) {
+ case 15:
+ case 16:
+ break;
+ case 17 ... 32:
+ jz4750_lcd_info->osd.fg1.bpp = 32;
+ break;
+ default:
+ printk("jz4750fb fg1 not support bpp(%d), force to 32bpp\n",
+ jz4750_lcd_info->osd.fg1.bpp);
+ jz4750_lcd_info->osd.fg1.bpp = 32;
+ }
+ __lcd_clr_dis();
+ __lcd_clr_ena();
+
+ /* Configure SLCD module for setting smart lcd control registers */
+#if defined(CONFIG_FB_JZ4750_SLCD)
+ __lcd_as_smart_lcd();
+ __slcd_disable_dma();
+ __init_slcd_bus(); /* Note: modify this depend on you lcd */
+
+#endif
+ /* init clk */
+ jz4750fb_change_clock(jz4750_lcd_info);
+ __lcd_display_pin_init();
+ __lcd_slcd_special_on();
+
+ cfb = jz4750fb_alloc_fb_info();
+ if (!cfb)
+ goto failed;
+
+ err = jz4750fb_map_smem(cfb);
+ if (err)
+ goto failed;
+
+ jz4750fb_deep_set_mode( jz4750_lcd_info );
+
+ err = register_framebuffer(&cfb->fb);
+ if (err < 0) {
+ dprintk("jzfb_init(): register framebuffer err.\n");
+ goto failed;
+ }
+ printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+ cfb->fb.node, cfb->fb.fix.id, cfb->fb.fix.smem_len>>10);
+
+ jz4750fb_device_attr_register(&cfb->fb);
+
+ if (request_irq(IRQ_LCD, jz4750fb_interrupt_handler, IRQF_DISABLED,
+ "lcd", 0)) {
+ err = -EBUSY;
+ goto failed;
+ }
+
+#if 0
+ /*
+ * Note that the console registers this as well, but we want to
+ * power down the display prior to sleeping.
+ */
+ cfb->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, jzlcd_pm_callback);
+ if (cfb->pm)
+ cfb->pm->data = cfb;
+#endif
+
+ __lcd_set_ena(); /* enalbe LCD Controller */
+ jz4750fb_lcd_display_on();
+
+#ifdef DEBUG
+ display_h_color_bar(jz4750_lcd_info->osd.fg0.w, jz4750_lcd_info->osd.fg0.h, jz4750_lcd_info->osd.fg0.bpp);
+#endif
+ print_lcdc_registers();
+
+ return 0;
+
+failed:
+ print_dbg();
+ jz4750fb_unmap_smem(cfb);
+ jz4750fb_free_fb_info(cfb);
+
+ return err;
+}
+
+static int __devexit jz4750_fb_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver jz4750_fb_driver = {
+ .probe = jz4750_fb_probe,
+ .remove = jz4750_fb_remove,
+ .suspend = jz4750_fb_suspend,
+ .resume = jz4750_fb_resume,
+ .driver = {
+ .name = "jz-lcd",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init jz4750_fb_init(void)
+{
+ return platform_driver_register(&jz4750_fb_driver);
+}
+
+static void __exit jz4750_fb_cleanup(void)
+{
+ platform_driver_unregister(&jz4750_fb_driver);
+}
+
+module_init(jz4750_fb_init);
+module_exit(jz4750_fb_cleanup);
diff --git a/drivers/video/jz4750_lcd.h b/drivers/video/jz4750_lcd.h
new file mode 100644
index 00000000000..c0273e91dda
--- /dev/null
+++ b/drivers/video/jz4750_lcd.h
@@ -0,0 +1,789 @@
+/*
+ * linux/drivers/video/jz4750_lcd.h -- Ingenic Jz4750 On-Chip LCD frame buffer device
+ *
+ * Copyright (C) 2005-2008, Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __JZ4750_LCD_H__
+#define __JZ4750_LCD_H__
+
+//#include <asm/io.h>
+
+
+#define NR_PALETTE 256
+#define PALETTE_SIZE (NR_PALETTE*2)
+
+/* use new descriptor(8 words) */
+struct jz4750_lcd_dma_desc {
+ unsigned int next_desc; /* LCDDAx */
+ unsigned int databuf; /* LCDSAx */
+ unsigned int frame_id; /* LCDFIDx */
+ unsigned int cmd; /* LCDCMDx */
+ unsigned int offsize; /* Stride Offsize(in word) */
+ unsigned int page_width; /* Stride Pagewidth(in word) */
+ unsigned int cmd_num; /* Command Number(for SLCD) */
+ unsigned int desc_size; /* Foreground Size */
+};
+
+struct jz4750lcd_panel_t {
+ unsigned int cfg; /* panel mode and pin usage etc. */
+ unsigned int slcd_cfg; /* Smart lcd configurations */
+ unsigned int ctrl; /* lcd controll register */
+ unsigned int w; /* Panel Width(in pixel) */
+ unsigned int h; /* Panel Height(in line) */
+ unsigned int fclk; /* frame clk */
+ unsigned int hsw; /* hsync width, in pclk */
+ unsigned int vsw; /* vsync width, in line count */
+ unsigned int elw; /* end of line, in pclk */
+ unsigned int blw; /* begin of line, in pclk */
+ unsigned int efw; /* end of frame, in line count */
+ unsigned int bfw; /* begin of frame, in line count */
+};
+
+
+struct jz4750lcd_fg_t {
+ int bpp; /* foreground bpp */
+ int x; /* foreground start position x */
+ int y; /* foreground start position y */
+ int w; /* foreground width */
+ int h; /* foreground height */
+};
+
+struct jz4750lcd_osd_t {
+ unsigned int osd_cfg; /* OSDEN, ALHPAEN, F0EN, F1EN, etc */
+ unsigned int osd_ctrl; /* IPUEN, OSDBPP, etc */
+ unsigned int rgb_ctrl; /* RGB Dummy, RGB sequence, RGB to YUV */
+ unsigned int bgcolor; /* background color(RGB888) */
+ unsigned int colorkey0; /* foreground0's Colorkey enable, Colorkey value */
+ unsigned int colorkey1; /* foreground1's Colorkey enable, Colorkey value */
+ unsigned int alpha; /* ALPHAEN, alpha value */
+ unsigned int ipu_restart; /* IPU Restart enable, ipu restart interval time */
+
+#define FG_NOCHANGE 0x0000
+#define FG0_CHANGE_SIZE 0x0001
+#define FG0_CHANGE_POSITION 0x0002
+#define FG1_CHANGE_SIZE 0x0010
+#define FG1_CHANGE_POSITION 0x0020
+#define FG_CHANGE_ALL ( FG0_CHANGE_SIZE | FG0_CHANGE_POSITION | \
+ FG1_CHANGE_SIZE | FG1_CHANGE_POSITION )
+ int fg_change;
+ struct jz4750lcd_fg_t fg0; /* foreground 0 */
+ struct jz4750lcd_fg_t fg1; /* foreground 1 */
+};
+
+struct jz4750lcd_info {
+ struct jz4750lcd_panel_t panel;
+ struct jz4750lcd_osd_t osd;
+};
+
+
+/* Jz LCDFB supported I/O controls. */
+#define FBIOSETBACKLIGHT 0x4688 /* set back light level */
+#define FBIODISPON 0x4689 /* display on */
+#define FBIODISPOFF 0x468a /* display off */
+#define FBIORESET 0x468b /* lcd reset */
+#define FBIOPRINT_REG 0x468c /* print lcd registers(debug) */
+#define FBIOROTATE 0x46a0 /* rotated fb */
+#define FBIOGETBUFADDRS 0x46a1 /* get buffers addresses */
+#define FBIO_GET_MODE 0x46a2 /* get lcd info */
+#define FBIO_SET_MODE 0x46a3 /* set osd mode */
+#define FBIO_DEEP_SET_MODE 0x46a4 /* set panel and osd mode */
+#define FBIO_MODE_SWITCH 0x46a5 /* switch mode between LCD and TVE */
+#define FBIO_GET_TVE_MODE 0x46a6 /* get tve info */
+#define FBIO_SET_TVE_MODE 0x46a7 /* set tve mode */
+
+/*
+ * LCD panel specific definition
+ */
+/* AUO */
+#if defined(CONFIG_JZ4750_LCD_AUO_A043FL01V2)
+#if defined(CONFIG_JZ4750_APUS) /* board pavo */
+ #define SPEN (32*3+29) /*LCD_CS*/
+ #define SPCK (32*3+26) /*LCD_SCL*/
+ #define SPDA (32*3+27) /*LCD_SDA*/
+ #define LCD_RET (32*4+25) /*LCD_DISP_N use for lcd reset*/
+#elif defined(CONFIG_JZ4750_FUWA) || defined(CONFIG_JZ4750D_FUWA1) /* board fpga */
+ #define SPEN (32*3+29) /*LCD_CS*/
+ #define SPCK (32*3+26) /*LCD_SCL*/
+ #define SPDA (32*3+27) /*LCD_SDA*/
+ #define LCD_RET (32*5+2) /*LCD_DISP_N use for lcd reset*/
+#elif defined(CONFIG_JZ4750L_F4750L) /* board pavo */
+ #define SPEN (32*3+30) /*LCD_CS*/
+ #define SPCK (32*3+26) /*LCD_SCL*/
+ #define SPDA (32*3+27) /*LCD_SDA*/
+ #define LCD_RET (32*5+2) /*LCD_DISP_N use for lcd reset*/
+#elif defined(CONFIG_JZ4750D_CETUS) /* board pavo */
+ #define SPEN (32*5+13) /*LCD_CS*/
+ #define SPCK (32*5+10) /*LCD_SCL*/
+ #define SPDA (32*5+11) /*LCD_SDA*/
+ #define LCD_RET (32*4+18) /*LCD_DISP_N use for lcd reset*/
+#else
+#error "driver/video/Jzlcd.h, please define SPI pins on your board."
+#endif
+
+#define __spi_write_reg(reg, val) \
+ do { \
+ unsigned char no; \
+ unsigned short value; \
+ unsigned char a=0; \
+ unsigned char b=0; \
+ __gpio_as_output(SPEN); /* use SPDA */ \
+ __gpio_as_output(SPCK); /* use SPCK */ \
+ __gpio_as_output(SPDA); /* use SPDA */ \
+ a=reg; \
+ b=val; \
+ __gpio_set_pin(SPEN); \
+ __gpio_clear_pin(SPCK); \
+ udelay(50); \
+ __gpio_clear_pin(SPDA); \
+ __gpio_clear_pin(SPEN); \
+ udelay(50); \
+ value=((a<<8)|(b&0xFF)); \
+ for(no=0;no<16;no++) \
+ { \
+ if((value&0x8000)==0x8000){ \
+ __gpio_set_pin(SPDA);} \
+ else{ \
+ __gpio_clear_pin(SPDA); } \
+ udelay(50); \
+ __gpio_set_pin(SPCK); \
+ value=(value<<1); \
+ udelay(50); \
+ __gpio_clear_pin(SPCK); \
+ } \
+ __gpio_set_pin(SPEN); \
+ udelay(400); \
+ } while (0)
+#define __spi_read_reg(reg,val) \
+ do{ \
+ unsigned char no; \
+ unsigned short value; \
+ __gpio_as_output(SPEN); /* use SPDA */ \
+ __gpio_as_output(SPCK); /* use SPCK */ \
+ __gpio_as_output(SPDA); /* use SPDA */ \
+ value = ((reg << 0) | (1 << 7)); \
+ val = 0; \
+ __gpio_as_output(SPDA); \
+ __gpio_set_pin(SPEN); \
+ __gpio_clear_pin(SPCK); \
+ udelay(50); \
+ __gpio_clear_pin(SPDA); \
+ __gpio_clear_pin(SPEN); \
+ udelay(50); \
+ for (no = 0; no < 16; no++ ) { \
+ udelay(50); \
+ if(no < 8) \
+ { \
+ if (value & 0x80) /* send data */ \
+ __gpio_set_pin(SPDA); \
+ else \
+ __gpio_clear_pin(SPDA); \
+ udelay(50); \
+ __gpio_set_pin(SPCK); \
+ value = (value << 1); \
+ udelay(50); \
+ __gpio_clear_pin(SPCK); \
+ if(no == 7) \
+ __gpio_as_input(SPDA); \
+ } \
+ else \
+ { \
+ udelay(100); \
+ __gpio_set_pin(SPCK); \
+ udelay(50); \
+ val = (val << 1); \
+ val |= __gpio_get_pin(SPDA); \
+ __gpio_clear_pin(SPCK); \
+ } \
+ } \
+ __gpio_as_output(SPDA); \
+ __gpio_set_pin(SPEN); \
+ udelay(400); \
+ } while(0)
+
+#define __lcd_special_pin_init() \
+ do { \
+ __gpio_as_output(SPEN); /* use SPDA */ \
+ __gpio_as_output(SPCK); /* use SPCK */ \
+ __gpio_as_output(SPDA); /* use SPDA */ \
+ __gpio_as_output(LCD_RET); \
+ udelay(50); \
+ __gpio_clear_pin(LCD_RET); \
+ udelay(100); \
+ __gpio_set_pin(LCD_RET); \
+ } while (0)
+#define __lcd_special_on() \
+ do { \
+ udelay(50); \
+ __gpio_clear_pin(LCD_RET); \
+ udelay(100); \
+ __gpio_set_pin(LCD_RET); \
+} while (0)
+
+ #define __lcd_special_off() \
+ do { \
+ __gpio_clear_pin(LCD_RET); \
+ } while (0)
+
+#endif /* CONFIG_JZLCD_AUO_A030FL01_V1 */
+
+/* TRULY_TFTG320240DTSW */
+#if defined(CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW_16BIT) || defined(CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW_18BIT)
+
+#if defined(CONFIG_JZ4750_FUWA)
+#define LCD_RESET_PIN (32*3+25)// LCD_REV, GPD25
+#else
+#error "Define LCD_RESET_PIN on your board"
+#endif
+
+#define __lcd_special_on() \
+do { \
+ __gpio_as_output(32*3+30);\
+ __gpio_clear_pin(32*3+30);\
+ __gpio_as_output(LCD_RESET_PIN); \
+ __gpio_set_pin(LCD_RESET_PIN); \
+ udelay(100); \
+ __gpio_clear_pin(LCD_RESET_PIN); \
+ udelay(100); \
+ __gpio_set_pin(LCD_RESET_PIN); \
+} while (0)
+
+#endif /* CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW */
+
+// Wolfgang 2008.02.23
+#if defined(CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA) || defined(CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DUMMY)
+
+#if defined(CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA)
+#define PANEL_MODE 0x02 /* RGB Delta */
+#elif defined(CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DUMMY)
+#define PANEL_MODE 0x00 /* RGB Dummy */
+#endif
+
+#if defined(CONFIG_JZ4750_FUWA) /* board FuWa */
+ #define SPEN (32*3+16) //LCD_D16 - GPD16
+ #define SPCK (32*3+17) //LCD_D17 - GPD17
+ #define SPDA (32*3+21) //LCD_DE - GPD21
+ #define LCD_RET (32*3+25) //LCD_REV - GPD25 //use for lcd reset
+#else
+#error "please define SPI pins on your board."
+#endif
+
+ #define __spi_write_reg1(reg, val) \
+ do { \
+ unsigned char no;\
+ unsigned short value;\
+ unsigned char a=0;\
+ unsigned char b=0;\
+ a=reg;\
+ b=val;\
+ __gpio_set_pin(SPEN);\
+ udelay(100);\
+ __gpio_clear_pin(SPCK);\
+ __gpio_clear_pin(SPDA);\
+ __gpio_clear_pin(SPEN);\
+ udelay(25);\
+ value=((a<<8)|(b&0xFF));\
+ for(no=0;no<16;no++)\
+ {\
+ __gpio_clear_pin(SPCK);\
+ if((value&0x8000)==0x8000)\
+ __gpio_set_pin(SPDA);\
+ else\
+ __gpio_clear_pin(SPDA);\
+ udelay(25);\
+ __gpio_set_pin(SPCK);\
+ value=(value<<1); \
+ udelay(25);\
+ }\
+ __gpio_clear_pin(SPCK);\
+ __gpio_set_pin(SPEN);\
+ udelay(100);\
+ } while (0)
+
+ #define __spi_write_reg(reg, val) \
+ do {\
+ __spi_write_reg1((reg<<2), val); \
+ udelay(100); \
+ }while(0)
+
+ #define __lcd_special_pin_init() \
+ do { \
+ __gpio_as_output(SPEN); /* use SPDA */\
+ __gpio_as_output(SPCK); /* use SPCK */\
+ __gpio_as_output(SPDA); /* use SPDA */\
+ __gpio_as_output(SPDA); /* use reset */\
+ __gpio_as_output(LCD_RET); /* use reset */\
+ __gpio_set_pin(LCD_RET);\
+ mdelay(15);\
+ __gpio_clear_pin(LCD_RET);\
+ mdelay(15);\
+ __gpio_set_pin(LCD_RET);\
+ } while (0)
+
+ #define __lcd_special_on() \
+ do { \
+ mdelay(10); \
+ __spi_write_reg(0x00, 0x10); \
+ __spi_write_reg(0x01, 0xB1); \
+ __spi_write_reg(0x00, 0x10); \
+ __spi_write_reg(0x01, 0xB1); \
+ __spi_write_reg(0x02, PANEL_MODE); /* RGBD MODE */ \
+ __spi_write_reg(0x03, 0x01); /* Noninterlace*/ \
+ mdelay(10); \
+ } while (0)
+
+ #define __lcd_special_off() \
+ do { \
+ } while (0)
+
+#endif /* CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA */
+
+
+#if defined(CONFIG_JZ4750_LCD_FOXCONN_PT035TN01) || defined(CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL)
+
+#if defined(CONFIG_JZ4750_LCD_FOXCONN_PT035TN01) /* board FUWA */
+#define MODE 0xcd /* 24bit parellel RGB */
+#endif
+#if defined(CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL)
+#define MODE 0xc9 /* 8bit serial RGB */
+#endif
+
+#if defined(CONFIG_JZ4750_FUWA) /* board FuWa */
+#if 0
+ #define SPEN (32*5+7) //LCD_SPL GPF7
+ #define SPCK (32*5+6) //LCD_CLS GPF6
+ #define SPDA (32*5+5) //LCD_PS GPF5
+ #define LCD_RET (32*5+4) //LCD_REV GPF4 //use for lcd reset
+#endif
+ #define SPEN (32*3+29) /*LCD_CS*/
+ #define SPCK (32*3+26) /*LCD_SCL*/
+ #define SPDA (32*3+27) /*LCD_SDA*/
+ #define LCD_RET (32*4+25) /*LCD_DISP_N use for lcd reset*/
+#elif defined(CONFIG_JZ4750D_FUWA1)/* board FuWa */
+ #define SPEN (32*4+0) /*LCD_CS*/
+ #define SPCK (32*4+9) /*LCD_SCL*/
+ #define SPDA (32*4+1) /*LCD_SDA*/
+ #define LCD_RET (32*4+3) /*LCD_DISP_N use for lcd reset*/
+#else
+#error "driver/video/Jzlcd.h, please define SPI pins on your board."
+#endif
+
+ #define __spi_write_reg1(reg, val) \
+ do { \
+ unsigned char no;\
+ unsigned short value;\
+ unsigned char a=0;\
+ unsigned char b=0;\
+ a=reg;\
+ b=val;\
+ __gpio_set_pin(SPEN);\
+ __gpio_set_pin(SPCK);\
+ __gpio_clear_pin(SPDA);\
+ __gpio_clear_pin(SPEN);\
+ udelay(25);\
+ value=((a<<8)|(b&0xFF));\
+ for(no=0;no<16;no++)\
+ {\
+ __gpio_clear_pin(SPCK);\
+ if((value&0x8000)==0x8000)\
+ __gpio_set_pin(SPDA);\
+ else\
+ __gpio_clear_pin(SPDA);\
+ udelay(25);\
+ __gpio_set_pin(SPCK);\
+ value=(value<<1); \
+ udelay(25);\
+ }\
+ __gpio_set_pin(SPEN);\
+ udelay(100);\
+ } while (0)
+
+ #define __spi_write_reg(reg, val) \
+ do {\
+ __spi_write_reg1((reg<<2|2), val); \
+ udelay(100); \
+ }while(0)
+
+ #define __lcd_special_pin_init() \
+ do { \
+ __gpio_as_output(SPEN); /* use SPDA */\
+ __gpio_as_output(SPCK); /* use SPCK */\
+ __gpio_as_output(SPDA); /* use SPDA */\
+ __gpio_as_output(LCD_RET);\
+ udelay(50);\
+ __gpio_clear_pin(LCD_RET);\
+ mdelay(150);\
+ __gpio_set_pin(LCD_RET);\
+ } while (0)
+
+ #define __lcd_special_on() \
+ do { \
+ udelay(50);\
+ __gpio_clear_pin(LCD_RET);\
+ mdelay(150);\
+ __gpio_set_pin(LCD_RET);\
+ mdelay(10);\
+ __spi_write_reg(0x00, 0x03); \
+ __spi_write_reg(0x01, 0x40); \
+ __spi_write_reg(0x02, 0x11); \
+ __spi_write_reg(0x03, MODE); /* mode */ \
+ __spi_write_reg(0x04, 0x32); \
+ __spi_write_reg(0x05, 0x0e); \
+ __spi_write_reg(0x07, 0x03); \
+ __spi_write_reg(0x08, 0x08); \
+ __spi_write_reg(0x09, 0x32); \
+ __spi_write_reg(0x0A, 0x88); \
+ __spi_write_reg(0x0B, 0xc6); \
+ __spi_write_reg(0x0C, 0x20); \
+ __spi_write_reg(0x0D, 0x20); \
+ } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level
+
+/* __spi_write_reg(0x02, 0x03); \
+ __spi_write_reg(0x06, 0x40); \
+ __spi_write_reg(0x0a, 0x11); \
+ __spi_write_reg(0x0e, 0xcd); \
+ __spi_write_reg(0x12, 0x32); \
+ __spi_write_reg(0x16, 0x0e); \
+ __spi_write_reg(0x1e, 0x03); \
+ __spi_write_reg(0x22, 0x08); \
+ __spi_write_reg(0x26, 0x40); \
+ __spi_write_reg(0x2a, 0x88); \
+ __spi_write_reg(0x2e, 0x88); \
+ __spi_write_reg(0x32, 0x20); \
+ __spi_write_reg(0x36, 0x20); \
+*/
+// } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level
+
+ #define __lcd_special_off() \
+ do { \
+ __spi_write_reg(0x00, 0x03); \
+ } while (0)
+
+#endif /* CONFIG_JZ4750_LCD_FOXCONN_PT035TN01 or CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL */
+
+#if defined(CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W)
+static inline void CmdWrite(unsigned int cmd)
+{
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); /* wait slcd ready */
+ udelay(30);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd;
+}
+
+static inline void DataWrite(unsigned int data)
+{
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); /* wait slcd ready */
+// udelay(30);
+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | data;
+}
+
+
+static inline void delay(long delay_time)
+{
+ long cnt;
+
+// delay_time *= (384/8);
+ delay_time *= (43/8);
+
+ for (cnt=0;cnt<delay_time;cnt++)
+ {
+ asm("nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ );
+ }
+}
+
+
+/*---- LCD Initial ----*/
+static void SlcdInit(void)
+{
+ delay(10000);
+ CmdWrite(0x0301); //reset
+ delay(10000);
+ CmdWrite(0x0101);
+ CmdWrite(0x0301);
+ CmdWrite(0x0008);
+ CmdWrite(0x2201); //reset
+ CmdWrite(0x0000);
+ CmdWrite(0x0080); //0x0020
+ delay(10000);
+
+ CmdWrite(0x2809);
+ CmdWrite(0x1900);
+ CmdWrite(0x2110);
+ CmdWrite(0x1805);
+ CmdWrite(0x1E01);
+ CmdWrite(0x1847);
+ delay(1000);
+ CmdWrite(0x1867);
+ delay(10000);
+ CmdWrite(0x18F7);
+ delay(10000);
+ CmdWrite(0x2100);
+ CmdWrite(0x2809);
+ CmdWrite(0x1a05);
+ CmdWrite(0x1900);
+ CmdWrite(0x1f64);
+ CmdWrite(0x2070);
+ CmdWrite(0x1e81);
+ CmdWrite(0x1b01);
+
+ CmdWrite(0x0200);
+ CmdWrite(0x0504); //y address increcement
+ CmdWrite(0x0D00); //*240
+ CmdWrite(0x1D08);
+ CmdWrite(0x2300);
+ CmdWrite(0x2D01);
+ CmdWrite(0x337F);
+ CmdWrite(0x3400);
+ CmdWrite(0x3501);
+ CmdWrite(0x3700);
+ CmdWrite(0x42ef); //x start from 239
+ CmdWrite(0x4300);
+ CmdWrite(0x4400); //y start from 0
+ CmdWrite(0x4500);
+ CmdWrite(0x46EF);
+ CmdWrite(0x4700);
+ CmdWrite(0x4800);
+ CmdWrite(0x4901);
+ CmdWrite(0x4A3F);
+ CmdWrite(0x4B00);
+ CmdWrite(0x4C00);
+ CmdWrite(0x4D00);
+ CmdWrite(0x4E00);
+ CmdWrite(0x4F00);
+ CmdWrite(0x5000);
+ CmdWrite(0x7600);
+ CmdWrite(0x8600);
+ CmdWrite(0x8720);
+ CmdWrite(0x8802);
+ CmdWrite(0x8903);
+ CmdWrite(0x8D40);
+ CmdWrite(0x8F05);
+ CmdWrite(0x9005);
+ CmdWrite(0x9144);
+ CmdWrite(0x9244);
+ CmdWrite(0x9344);
+ CmdWrite(0x9433);
+ CmdWrite(0x9505);
+ CmdWrite(0x9605);
+ CmdWrite(0x9744);
+ CmdWrite(0x9844);
+ CmdWrite(0x9944);
+ CmdWrite(0x9A33);
+ CmdWrite(0x9B33);
+ CmdWrite(0x9C33);
+ //==> SETP 3
+ CmdWrite(0x0000);
+ CmdWrite(0x01A0);
+ CmdWrite(0x3B01);
+
+ CmdWrite(0x2809);
+ delay(1000);
+ CmdWrite(0x1900);
+ delay(1000);
+ CmdWrite(0x2110);
+ delay(1000);
+ CmdWrite(0x1805);
+ delay(1000);
+ CmdWrite(0x1E01);
+ delay(1000);
+ CmdWrite(0x1847);
+ delay(1000);
+ CmdWrite(0x1867);
+ delay(1000);
+ CmdWrite(0x18F7);
+ delay(1000);
+ CmdWrite(0x2100);
+ delay(1000);
+ CmdWrite(0x2809);
+ delay(1000);
+ CmdWrite(0x1A05);
+ delay(1000);
+ CmdWrite(0x19E8);
+ delay(1000);
+ CmdWrite(0x1F64);
+ delay(1000);
+ CmdWrite(0x2045);
+ delay(1000);
+ CmdWrite(0x1E81);
+ delay(1000);
+ CmdWrite(0x1B09);
+ delay(1000);
+ CmdWrite(0x0020);
+ delay(1000);
+ CmdWrite(0x0120);
+ delay(1000);
+
+ CmdWrite(0x3B01);
+ delay(1000);
+
+ /* Set Window(239,319), Set Cursor(239,319) */
+ CmdWrite(0x0510);
+ CmdWrite(0x01C0);
+ CmdWrite(0x4500);
+ CmdWrite(0x46EF);
+ CmdWrite(0x4800);
+ CmdWrite(0x4700);
+ CmdWrite(0x4A3F);
+ CmdWrite(0x4901);
+ CmdWrite(0x42EF);
+ CmdWrite(0x443F);
+ CmdWrite(0x4301);
+
+}
+
+#if defined(CONFIG_JZ4750_FUWA)
+//#define PIN_CS_N (32*2+xx) /* a low voltage */
+#define PIN_RD_N (32*3+21) /* LCD_DE: GP D21, a high voltage */
+#define PIN_RESET_N (32*3+25) /* LCD_REV GP D25 */
+#else
+#error "Define special lcd pins for your platform."
+#endif
+
+#define __lcd_slcd_pin_init() \
+ do { \
+ __gpio_as_output(PIN_RD_N); /* RD#: LCD_REV */ \
+ __gpio_as_output(PIN_RESET_N); /* RESET#: LCD_SPL */ \
+ __gpio_set_pin(PIN_RD_N); /*set read signal high */ \
+ __gpio_set_pin(PIN_RESET_N); \
+ mdelay(100); \
+ __gpio_clear_pin(PIN_RESET_N); \
+ mdelay(100); \
+ __gpio_set_pin(PIN_RESET_N); \
+ /* Configure SLCD module */ \
+ REG_LCD_CTRL &= ~(LCD_CTRL_ENA|LCD_CTRL_DIS); /* disable lcdc */ \
+ REG_LCD_CFG = LCD_CFG_LCDPIN_SLCD | 0x0D; /* LCM */ \
+ REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN; /* disable slcd dma */ \
+ REG_SLCD_CFG = SLCD_CFG_DWIDTH_16BIT | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING | SLCD_CFG_TYPE_PARALLEL; \
+ REG_LCD_REV = 0x04; /* lcd clock??? */ \
+ printk("Fuwa test, pixclk divide REG_LCD_REV=0x%08x\n", REG_LCD_REV); \
+}while (0)
+
+#define __lcd_slcd_special_on() \
+ do { \
+ __lcd_slcd_pin_init(); \
+ SlcdInit(); \
+ REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN; /* slcdc dma enable */ \
+ } while (0)
+
+#endif /* #if CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W */
+
+#ifndef __lcd_special_pin_init
+#define __lcd_special_pin_init()
+#endif
+#ifndef __lcd_special_on
+#define __lcd_special_on()
+#endif
+#ifndef __lcd_special_off
+#define __lcd_special_off()
+#endif
+
+
+/*
+ * Platform specific definition
+ */
+#if defined(CONFIG_JZ4750D_VGA_DISPLAY)
+#define __lcd_display_pin_init()
+#define __lcd_display_on()
+#define __lcd_display_off()
+#elif defined(CONFIG_JZ4750_APUS)/* board apus */
+#define __lcd_display_pin_init() \
+do { \
+ __gpio_as_output(GPIO_LCD_VCC_EN_N); \
+ __lcd_special_pin_init(); \
+} while (0)
+
+#define __lcd_display_on() \
+do { \
+ __gpio_clear_pin(GPIO_LCD_VCC_EN_N); \
+ __lcd_special_on(); \
+} while (0)
+
+#define __lcd_display_off() \
+do { \
+ __lcd_special_off(); \
+} while (0)
+
+#elif defined(CONFIG_JZ4750D_CETUS)/* board apus */
+#define __lcd_display_pin_init() \
+do { \
+ __gpio_as_output(GPIO_LCD_VCC_EN_N); \
+ __lcd_special_pin_init(); \
+} while (0)
+
+#define __lcd_display_on() \
+do { \
+ __gpio_set_pin(GPIO_LCD_VCC_EN_N); \
+ __lcd_special_on(); \
+} while (0)
+
+#define __lcd_display_off() \
+do { \
+ __lcd_special_off(); \
+} while (0)
+
+#else /* other boards */
+
+#define __lcd_display_pin_init() \
+do { \
+ __lcd_special_pin_init(); \
+} while (0)
+#define __lcd_display_on() \
+do { \
+ __lcd_special_on(); \
+ __lcd_set_backlight_level(80); \
+} while (0)
+
+#define __lcd_display_off() \
+do { \
+ __lcd_close_backlight(); \
+ __lcd_special_off(); \
+} while (0)
+#endif /* APUS */
+
+
+/*****************************************************************************
+ * LCD display pin dummy macros
+ *****************************************************************************/
+
+#ifndef __lcd_display_pin_init
+#define __lcd_display_pin_init()
+#endif
+#ifndef __lcd_slcd_special_on
+#define __lcd_slcd_special_on()
+#endif
+#ifndef __lcd_display_on
+#define __lcd_display_on()
+#endif
+#ifndef __lcd_display_off
+#define __lcd_display_off()
+#endif
+#ifndef __lcd_set_backlight_level
+#define __lcd_set_backlight_level(n)
+#endif
+
+#endif /* __JZ4750_LCD_H__ */
diff --git a/drivers/video/jz4750_tve.c b/drivers/video/jz4750_tve.c
new file mode 100644
index 00000000000..3a4ea61aea0
--- /dev/null
+++ b/drivers/video/jz4750_tve.c
@@ -0,0 +1,104 @@
+
+/*
+ * linux/drivers/video/jz4750_tve.c -- Ingenic Jz4750 TVE Controller operation
+ * interface.
+ * Copyright (C) 2005-2008, Ingenic Semiconductor Inc.
+ * Author: Wolfgang Wang, <lgwang@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <asm/jzsoc.h>
+#include "jz4750_tve.h"
+
+struct jz4750tve_info jz4750_tve_info_PAL = {
+ .ctrl = (4 << TVE_CTRL_YCDLY_BIT) | TVE_CTRL_SYNCT | TVE_CTRL_PAL | TVE_CTRL_SWRST, /* PAL, SVIDEO */
+ .frcfg = (23 << TVE_FRCFG_L1ST_BIT) | (625 << TVE_FRCFG_NLINE_BIT),
+ .slcfg1 = (800<<TVE_SLCFG1_WHITEL_BIT) | (282<<TVE_SLCFG1_BLACKL_BIT),
+ .slcfg2 = (296<<TVE_SLCFG2_VBLANKL_BIT) | (240<<TVE_SLCFG2_BLANKL_BIT),
+ .slcfg3 = (72 <<TVE_SLCFG3_SYNCL_BIT),
+ .ltcfg1 = (20<<TVE_LTCFG1_FRONTP_BIT) | (63<<TVE_LTCFG1_HSYNCW_BIT) | (78<<TVE_LTCFG1_BACKP_BIT),
+ .ltcfg2 = (1440 << TVE_LTCFG2_ACTLIN_BIT) | (24 << TVE_LTCFG2_PREBW_BIT) | (68 << TVE_LTCFG2_BURSTW_BIT),
+ .cfreq = 0x2a098acb,
+ .cphase = (0 << TVE_CPHASE_INITPH_BIT) | (0 << TVE_CPHASE_ACTPH_BIT) | (1 << TVE_CPHASE_CCRSTP_BIT),
+ .cbcrcfg = (32<<TVE_CBCRCFG_CBBA_BIT) | (59<<TVE_CBCRCFG_CRBA_BIT) | (137<<TVE_CBCRCFG_CBGAIN_BIT) | (137<<TVE_CBCRCFG_CRGAIN_BIT), /* CBGAIN CRGAIN??? */
+ .wsscr = 0x00000070, /* default value */
+ .wsscfg1 = 0x0,
+ .wsscfg2 = 0x0,
+ .wsscfg3 = 0x0,
+};
+
+struct jz4750tve_info jz4750_tve_info_NTSC = {
+ .ctrl = (4 << TVE_CTRL_YCDLY_BIT) | TVE_CTRL_SWRST, /* NTSC, SVIDEO */
+ .frcfg = (21 << TVE_FRCFG_L1ST_BIT) | (525 << TVE_FRCFG_NLINE_BIT),
+ .slcfg1 = (800<<TVE_SLCFG1_WHITEL_BIT) | (282<<TVE_SLCFG1_BLACKL_BIT),
+ .slcfg2 = (296<<TVE_SLCFG2_VBLANKL_BIT) | (240<<TVE_SLCFG2_BLANKL_BIT),
+ .slcfg3 = (72 <<TVE_SLCFG3_SYNCL_BIT),
+ .ltcfg1 = (16<<TVE_LTCFG1_FRONTP_BIT) | (63<<TVE_LTCFG1_HSYNCW_BIT) | (59<<TVE_LTCFG1_BACKP_BIT),
+ .ltcfg2 = (1440 << TVE_LTCFG2_ACTLIN_BIT) | (22 << TVE_LTCFG2_PREBW_BIT) | (68 << TVE_LTCFG2_BURSTW_BIT),
+ .cfreq = 0x21f07c1f,
+ .cphase = (0x17 << TVE_CPHASE_INITPH_BIT) | (0 << TVE_CPHASE_ACTPH_BIT) | (1 << TVE_CPHASE_CCRSTP_BIT),
+ .cbcrcfg = (59<<TVE_CBCRCFG_CBBA_BIT) | (0<<TVE_CBCRCFG_CRBA_BIT) | (137<<TVE_CBCRCFG_CBGAIN_BIT) | (137<<TVE_CBCRCFG_CRGAIN_BIT),
+ .wsscr = 0x00000070, /* default value */
+ .wsscfg1 = 0x0,
+ .wsscfg2 = 0x0,
+ .wsscfg3 = 0x0,
+};
+
+struct jz4750tve_info *jz4750_tve_info = &jz4750_tve_info_PAL; /* default as PAL mode */
+
+void jz4750tve_enable_tve(void)
+{
+ /* enable tve controller, enable DACn??? */
+ jz4750_tve_info->ctrl = (jz4750_tve_info->ctrl | TVE_CTRL_DAPD) & ( ~( TVE_CTRL_DAPD1 | TVE_CTRL_DAPD2));
+ jz4750_tve_info->ctrl &= ~TVE_CTRL_SWRST;
+ REG_TVE_CTRL = jz4750_tve_info->ctrl;
+}
+
+/* turn off TVE, turn off DACn... */
+void jz4750tve_disable_tve(void)
+{
+ jz4750_tve_info->ctrl &= ~TVE_CTRL_DAPD;/* DACn disabled??? */
+ jz4750_tve_info->ctrl |= TVE_CTRL_SWRST;/* DACn disabled??? */
+ REG_TVE_CTRL = jz4750_tve_info->ctrl;
+}
+
+void jz4750tve_set_tve_mode( struct jz4750tve_info *tve )
+{
+ REG_TVE_CTRL = tve->ctrl;
+ REG_TVE_FRCFG = tve->frcfg;
+ REG_TVE_SLCFG1 = tve->slcfg1;
+ REG_TVE_SLCFG2 = tve->slcfg2;
+ REG_TVE_SLCFG3 = tve->slcfg3;
+ REG_TVE_LTCFG1 = tve->ltcfg1;
+ REG_TVE_LTCFG2 = tve->ltcfg2;
+ REG_TVE_CFREQ = tve->cfreq;
+ REG_TVE_CPHASE = tve->cphase;
+ REG_TVE_CBCRCFG = tve->cbcrcfg;
+ REG_TVE_WSSCR = tve->wsscr;
+ REG_TVE_WSSCFG1 = tve->wsscfg1;
+ REG_TVE_WSSCFG2 = tve->wsscfg2;
+ REG_TVE_WSSCFG3 = tve->wsscfg3;
+}
+
+void jz4750tve_init( int tve_mode )
+{
+ switch ( tve_mode ) {
+ case PANEL_MODE_TVE_PAL:
+ jz4750_tve_info = &jz4750_tve_info_PAL;
+ break;
+ case PANEL_MODE_TVE_NTSC:
+ jz4750_tve_info = &jz4750_tve_info_NTSC;
+ break;
+ }
+
+ jz4750tve_set_tve_mode( jz4750_tve_info );
+// jz4750tve_enable_tve();
+}
diff --git a/drivers/video/jz4750_tve.h b/drivers/video/jz4750_tve.h
new file mode 100644
index 00000000000..00eefe98243
--- /dev/null
+++ b/drivers/video/jz4750_tve.h
@@ -0,0 +1,45 @@
+#ifndef __JZ4750_TVE_H__
+#define __JZ4750_TVE_H__
+
+
+#define PANEL_MODE_LCD_PANEL 0
+#define PANEL_MODE_TVE_PAL 1
+#define PANEL_MODE_TVE_NTSC 2
+
+/* TV parameter */
+#define TVE_WIDTH_PAL 720
+#define TVE_HEIGHT_PAL 573
+#define TVE_FREQ_PAL 50
+#define TVE_WIDTH_NTSC 720
+#define TVE_HEIGHT_NTSC 482
+#define TVE_FREQ_NTSC 60
+
+
+/* Structure for TVE */
+struct jz4750tve_info {
+ unsigned int ctrl;
+ unsigned int frcfg;
+ unsigned int slcfg1;
+ unsigned int slcfg2;
+ unsigned int slcfg3;
+ unsigned int ltcfg1;
+ unsigned int ltcfg2;
+ unsigned int cfreq;
+ unsigned int cphase;
+ unsigned int cbcrcfg;
+ unsigned int wsscr;
+ unsigned int wsscfg1;
+ unsigned int wsscfg2;
+ unsigned int wsscfg3;
+};
+
+extern struct jz4750tve_info *jz4750_tve_info;
+
+extern void jz4750tve_enable_tve(void);
+extern void jz4750tve_disable_tve(void);
+
+extern void jz4750tve_set_tve_mode( struct jz4750tve_info *tve );
+extern void jz4750tve_init( int tve_mode );
+
+
+#endif /* __JZ4750_TVE_H__ */
diff --git a/drivers/video/jz_kgm_spfd5420a.h b/drivers/video/jz_kgm_spfd5420a.h
new file mode 100644
index 00000000000..33d8bd5fa45
--- /dev/null
+++ b/drivers/video/jz_kgm_spfd5420a.h
@@ -0,0 +1,385 @@
+/* Set registers of smart lcd acording to the following routines
+ * Note: BUS width and CMD width and register value width
+ * This example: BUS is 8, 9, 16 or 18-bit; CMD and DATA is 16-bit
+ * Configure SLCD module to initialize smart lcd registers
+
+ switch (bus) {
+ case 8:
+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2
+ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW
+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING
+ | SLCD_CFG_TYPE_PARALLEL;
+ __gpio_as_slcd_8bit();
+ break;
+ case 9:
+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2
+ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW
+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING
+ | SLCD_CFG_TYPE_PARALLEL;
+ __gpio_as_slcd_9bit();
+ break;
+ case 16:
+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_16
+ | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW
+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING
+ | SLCD_CFG_TYPE_PARALLEL;
+ __gpio_as_slcd_16bit();
+ break;
+ case 18:
+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_18
+ | SLCD_CFG_CWIDTH_18BIT | SLCD_CFG_CS_ACTIVE_LOW
+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING
+ | SLCD_CFG_TYPE_PARALLEL;
+ __gpio_as_slcd_18bit();
+ break;
+ }
+
+ static void Mcupanel_RegSet(unsigned int cmd, unsigned int data)
+ {
+ switch (bus) {
+ case 8:
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff);
+ break;
+ case 9:
+ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2);
+ data = ((data << 6) & 0xfc0000) | ((data << 4) & 0xfc00) | ((data << 2) & 0xfc);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | data;
+ break;
+ case 16:
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | (cmd&0xffff);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff);
+ break;
+ case 18:
+ cmd = ((cmd & 0xff) << 1) | ((cmd & 0xff00) << 2);
+ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd;
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | ((data<<6)&0xfc0000)|((data<<4)&0xfc00) | ((data<<2)&0xfc);
+ break;
+ default:
+ printk("Don't support %d bit Bus\n", jzfb.bus );
+ break;
+ }
+ }
+
+ static void Mcupanel_Command(unsigned int cmd) {
+ switch (bus) {
+ case 8:
+ case 9:
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0);
+ break;
+ case 16:
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | (cmd&0xffff);
+ break;
+ case 18:
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) << 2) | ((cmd&0xff) << 1);
+ break;
+ default:
+ printk("Don't support %d bit Bus\n", jzfb.bus );
+ break;
+ }
+ }
+
+ *Display----------------------------------------
+ Note: BUS and BPP, send data to gram data register to display
+ BUS: 8, 9, 16 or 18-bit; BPP: 8, 16, 18-bit
+ switch (bus) {
+ case 8:
+ switch (bpp) {
+ case 8:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1;
+ break;
+ case 15:
+ case 16:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2;
+ break;
+ case 17 ... 32:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3;
+ break;
+ default:
+ printk("The BPP %d is not supported\n", jzfb.bpp);
+ break;
+ }
+ break;
+ case 9:
+ switch (bpp) {
+ case 8:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1;
+ break;
+ case 15 ... 16:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2;
+ break;
+ case 17 ... 32:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_9_x2;
+ break;
+ default:
+ printk("The BPP %d is not supported\n", jzfb.bpp);
+ break;
+ }
+ break;
+ case 16:
+ switch (bpp) {
+ case 8:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1;
+ break;
+ case 15 ... 16:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_16;
+ break;
+ case 17 ... 32:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3;
+ break;
+ default:
+ printk("The BPP %d is not supported\n", jzfb.bpp);
+ break;
+ }
+ break;
+ case 18:
+ switch (bpp) {
+ case 8:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1;
+ break;
+ case 15:
+ case 16:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_16;
+ break;
+ case 17 ... 32:
+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK;
+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_18;
+ break;
+ default:
+ printk("The BPP %d is not supported\n", jzfb.bpp);
+ break;
+ }
+ break;
+ default:
+ printk("Error: The BUS %d is not supported\n", jzfb.bus);
+ break;
+ }
+ dprintk("SLCD_CFG=0x%x\n", REG_SLCD_CFG);
+}
+ ************************************************************************************************/
+
+#ifndef __JZ_KGM_SPF5420A_H__
+#define __JZ_KGM_SPF5420A_H__
+
+#include <asm/jzsoc.h>
+
+#if defined(CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A)
+#define WR_GRAM_CMD 0x0202
+
+#if defined(CONFIG_JZ4750_FUWA)
+#define PIN_CS_N (32*3+24) // Chip select //GPD24;
+#define PIN_RESET_N (32*5+6) /* LCD_REV GPF6 */
+#elif defined(CONFIG_JZ4750D_FUWA1)
+#define PIN_CS_N (32*3+24) // Chip select //GPD24;
+#define PIN_RESET_N (32*4+3) /* LCD_REV GPF6 */
+#else
+#error "Define special lcd pins for your platform."
+#endif
+
+/* Sent a command with data (18-bit bus, 16-bit index, 16-bit register value) */
+static void Mcupanel_RegSet(unsigned int cmd, unsigned int data)
+{
+ cmd = ((cmd & 0xff) << 1) | ((cmd & 0xff00) << 2);
+ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2);
+ data = ((data<<6)&0xfc0000)|((data<<4)&0xfc00) | ((data<<2)&0xfc);
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd;
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | data;
+}
+
+/* Sent a command without data (18-bit bus, 16-bit index) */
+static void Mcupanel_Command(unsigned int cmd) {
+ while (REG_SLCD_STATE & SLCD_STATE_BUSY);
+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) << 2) | ((cmd&0xff) << 1);
+}
+
+/* Set the start address of screen, for example (0, 0) */
+void Mcupanel_SetAddr(u32 x, u32 y) //u32
+{
+ Mcupanel_RegSet(0x200,x) ;
+ udelay(1);
+ Mcupanel_RegSet(0x201,y) ;
+ udelay(1);
+ Mcupanel_Command(0x202);
+
+}
+
+#undef __lcd_special_pin_init
+#define __lcd_special_pin_init() \
+do { \
+ __gpio_as_output(PIN_CS_N); \
+ __gpio_as_output(PIN_RESET_N); \
+ __gpio_clear_pin(PIN_CS_N); /* Clear CS */ \
+ mdelay(100); \
+ __gpio_set_pin(PIN_RESET_N); \
+ mdelay(10); \
+ __gpio_clear_pin(PIN_RESET_N); \
+ mdelay(10); \
+ __gpio_set_pin(PIN_RESET_N); \
+ mdelay(100); \
+} while(0)
+
+
+#define GAMMA() \
+do { \
+ Mcupanel_RegSet(0x0300,0x0101); \
+ Mcupanel_RegSet(0x0301,0x0b27); \
+ Mcupanel_RegSet(0x0302,0x132a); \
+ Mcupanel_RegSet(0x0303,0x2a13); \
+ Mcupanel_RegSet(0x0304,0x270b); \
+ Mcupanel_RegSet(0x0305,0x0101); \
+ Mcupanel_RegSet(0x0306,0x1205); \
+ Mcupanel_RegSet(0x0307,0x0512); \
+ Mcupanel_RegSet(0x0308,0x0005); \
+ Mcupanel_RegSet(0x0309,0x0003); \
+ Mcupanel_RegSet(0x030a,0x0f04); \
+ Mcupanel_RegSet(0x030b,0x0f00); \
+ Mcupanel_RegSet(0x030c,0x000f); \
+ Mcupanel_RegSet(0x030d,0x040f); \
+ Mcupanel_RegSet(0x030e,0x0300); \
+ Mcupanel_RegSet(0x030f,0x0500); \
+ /*** secorrect gamma2 ***/ \
+ Mcupanel_RegSet(0x0400,0x3500); \
+ Mcupanel_RegSet(0x0401,0x0001); \
+ Mcupanel_RegSet(0x0404,0x0000); \
+ Mcupanel_RegSet(0x0500,0x0000); \
+ Mcupanel_RegSet(0x0501,0x0000); \
+ Mcupanel_RegSet(0x0502,0x0000); \
+ Mcupanel_RegSet(0x0503,0x0000); \
+ Mcupanel_RegSet(0x0504,0x0000); \
+ Mcupanel_RegSet(0x0505,0x0000); \
+ Mcupanel_RegSet(0x0600,0x0000); \
+ Mcupanel_RegSet(0x0606,0x0000); \
+ Mcupanel_RegSet(0x06f0,0x0000); \
+ Mcupanel_RegSet(0x07f0,0x5420); \
+ Mcupanel_RegSet(0x07f3,0x288a); \
+ Mcupanel_RegSet(0x07f4,0x0022); \
+ Mcupanel_RegSet(0x07f5,0x0001); \
+ Mcupanel_RegSet(0x07f0,0x0000); \
+} while(0)
+
+#define SlcdInit() \
+do { \
+ __gpio_set_pin(PIN_RESET_N); \
+ mdelay(10); \
+ __gpio_clear_pin(PIN_RESET_N); \
+ mdelay(10); \
+ __gpio_set_pin(PIN_RESET_N); \
+ mdelay(100); \
+ Mcupanel_RegSet(0x0600, 0x0001); /*soft reset*/ \
+ mdelay(10); \
+ Mcupanel_RegSet(0x0600, 0x0000); /*soft reset*/ \
+ mdelay(10); \
+ Mcupanel_RegSet(0x0606,0x0000); \
+ udelay(10); \
+ Mcupanel_RegSet(0x0007,0x0001); \
+ udelay(10); \
+ Mcupanel_RegSet(0x0110,0x0001); \
+ udelay(10); \
+ Mcupanel_RegSet(0x0100,0x17b0); \
+ Mcupanel_RegSet(0x0101,0x0147); \
+ Mcupanel_RegSet(0x0102,0x019d); \
+ Mcupanel_RegSet(0x0103,0x8600); \
+ Mcupanel_RegSet(0x0281,0x0010); \
+ udelay(10); \
+ Mcupanel_RegSet(0x0102,0x01bd); \
+ udelay(10); \
+ /************initial************/\
+ Mcupanel_RegSet(0x0000,0x0000); \
+ Mcupanel_RegSet(0x0001,0x0000); \
+ Mcupanel_RegSet(0x0002,0x0400); \
+ Mcupanel_RegSet(0x0003,0x12b8); /*up:0x1288 down:0x12B8 left:0x1290 right:0x12A0*/ \
+ Mcupanel_RegSet(0x0006,0x0000); \
+ Mcupanel_RegSet(0x0008,0x0503); \
+ Mcupanel_RegSet(0x0009,0x0001); \
+ Mcupanel_RegSet(0x000b,0x0010); \
+ Mcupanel_RegSet(0x000c,0x0000); \
+ Mcupanel_RegSet(0x000f,0x0000); \
+ Mcupanel_RegSet(0x0007,0x0001); \
+ Mcupanel_RegSet(0x0010,0x0010); \
+ Mcupanel_RegSet(0x0011,0x0202); \
+ Mcupanel_RegSet(0x0012,0x0300); \
+ Mcupanel_RegSet(0x0020,0x021e); \
+ Mcupanel_RegSet(0x0021,0x0202); \
+ Mcupanel_RegSet(0x0022,0x0100); \
+ Mcupanel_RegSet(0x0090,0x0000); \
+ Mcupanel_RegSet(0x0092,0x0000); \
+ Mcupanel_RegSet(0x0100,0x16b0); \
+ Mcupanel_RegSet(0x0101,0x0147); \
+ Mcupanel_RegSet(0x0102,0x01bd); \
+ Mcupanel_RegSet(0x0103,0x2c00); \
+ Mcupanel_RegSet(0x0107,0x0000); \
+ Mcupanel_RegSet(0x0110,0x0001); \
+ Mcupanel_RegSet(0x0210,0x0000); \
+ Mcupanel_RegSet(0x0211,0x00ef); \
+ Mcupanel_RegSet(0x0212,0x0000); \
+ Mcupanel_RegSet(0x0213,0x018f); \
+ Mcupanel_RegSet(0x0280,0x0000); \
+ Mcupanel_RegSet(0x0281,0x0001); \
+ Mcupanel_RegSet(0x0282,0x0000); \
+ GAMMA(); \
+ Mcupanel_RegSet(0x0007,0x0173); \
+ Mcupanel_Command(0x0202); /*Write Data to GRAM */ \
+ udelay(10);\
+ Mcupanel_SetAddr(0,0);\
+ udelay(100);\
+} while(0)
+
+/*---- LCD Initial ----*/
+#undef __lcd_slcd_pin_init
+#define __lcd_slcd_pin_init() \
+ do { \
+ __lcd_special_pin_init(); \
+}while (0)
+
+#undef __lcd_slcd_special_on
+#define __lcd_slcd_special_on() \
+ do { \
+ __lcd_slcd_pin_init(); \
+ SlcdInit(); \
+ REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN; /* slcdc dma enable */ \
+ } while (0)
+
+#define __init_slcd_bus()\
+do{\
+ __slcd_set_data_18bit();\
+ __slcd_set_cmd_18bit();\
+ __slcd_set_cs_low();\
+ __slcd_set_rs_low();\
+ __slcd_set_clk_falling();\
+ __slcd_set_parallel_type();\
+}while(0)
+#endif /* #if CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A */
+
+#endif /* __JZ_KGM_SPF5420A_H__ */
diff --git a/drivers/video/jz_toppoly_td043mgeb1.h b/drivers/video/jz_toppoly_td043mgeb1.h
new file mode 100644
index 00000000000..c66494ef47e
--- /dev/null
+++ b/drivers/video/jz_toppoly_td043mgeb1.h
@@ -0,0 +1,264 @@
+
+#ifndef __JZ_KGM_TOPPOLY_TD043MGEB1_H__
+#define __JZ_KGM_TOPPOLY_TD043MGEB1_H__
+
+#include <asm/jzsoc.h>
+
+#if defined(CONFIG_JZ4750_LCD_TOPPOLY_TD043MGEB1)
+#if defined(CONFIG_JZ4750_APUS) /* board FuWa */
+ #define SPEN (32*3+29) /*LCD_CS*/
+ #define SPCK (32*3+26) /*LCD_SCL*/
+ #define SPDA (32*3+27) /*LCD_SDA*/
+ #define LCD_RET (32*4+23) /*LCD_DISP_N use for lcd reset*/
+ #define LCD_STBY (32*4+25) /*LCD_STBY, use for lcd standby*/
+#else
+#error "driver/video/Jzlcd.h, please define SPI pins on your board."
+#endif
+
+#define __spi_write_reg(reg, val) \
+ do { \
+ unsigned char no; \
+ unsigned short value; \
+ unsigned char a=0; \
+ unsigned char b=0; \
+ __gpio_as_output(SPEN); /* use SPDA */ \
+ __gpio_as_output(SPCK); /* use SPCK */ \
+ __gpio_as_output(SPDA); /* use SPDA */ \
+ a=reg; \
+ b=val; \
+ __gpio_set_pin(SPEN); \
+ __gpio_clear_pin(SPCK); \
+ udelay(500); \
+ __gpio_clear_pin(SPDA); \
+ __gpio_clear_pin(SPEN); \
+ udelay(500); \
+ value=((a<<8)|(b&0xFF)); \
+ for(no=0;no<16;no++) \
+ { \
+ if((value&0x8000)==0x8000){ \
+ __gpio_set_pin(SPDA);} \
+ else{ \
+ __gpio_clear_pin(SPDA); } \
+ udelay(500); \
+ __gpio_set_pin(SPCK); \
+ value=(value<<1); \
+ udelay(500); \
+ __gpio_clear_pin(SPCK); \
+ } \
+ __gpio_set_pin(SPEN); \
+ udelay(4000); \
+ } while (0)
+#define __spi_read_reg(reg,val) \
+ do{ \
+ unsigned char no; \
+ unsigned short value; \
+ __gpio_as_output(SPEN); /* use SPDA */ \
+ __gpio_as_output(SPCK); /* use SPCK */ \
+ __gpio_as_output(SPDA); /* use SPDA */ \
+ value = ((reg << 0) | (1 << 7)); \
+ val = 0; \
+ __gpio_as_output(SPDA); \
+ __gpio_set_pin(SPEN); \
+ __gpio_clear_pin(SPCK); \
+ udelay(50); \
+ __gpio_clear_pin(SPDA); \
+ __gpio_clear_pin(SPEN); \
+ udelay(50); \
+ for (no = 0; no < 16; no++ ) { \
+ udelay(50); \
+ if(no < 8) \
+ { \
+ if (value & 0x80) /* send data */ \
+ __gpio_set_pin(SPDA); \
+ else \
+ __gpio_clear_pin(SPDA); \
+ udelay(50); \
+ __gpio_set_pin(SPCK); \
+ value = (value << 1); \
+ udelay(50); \
+ __gpio_clear_pin(SPCK); \
+ if(no == 7) \
+ __gpio_as_input(SPDA); \
+ } \
+ else \
+ { \
+ udelay(100); \
+ __gpio_set_pin(SPCK); \
+ udelay(50); \
+ val = (val << 1); \
+ val |= __gpio_get_pin(SPDA); \
+ __gpio_clear_pin(SPCK); \
+ } \
+ } \
+ __gpio_as_output(SPDA); \
+ __gpio_set_pin(SPEN); \
+ udelay(400); \
+ } while(0)
+
+#define __lcd_special_pin_init() \
+ do { \
+ __gpio_as_output(SPEN); /* use SPDA */ \
+ __gpio_as_output(SPCK); /* use SPCK */ \
+ __gpio_as_output(SPDA); /* use SPDA */ \
+ __gpio_as_output(LCD_STBY); \
+ __gpio_as_output(LCD_RET); \
+ udelay(500); \
+ __gpio_clear_pin(LCD_RET); \
+ udelay(1000); \
+ __gpio_set_pin(LCD_RET); \
+ udelay(1000); \
+ __gpio_set_pin(LCD_STBY); \
+ udelay(1000); \
+ } while (0)
+#define __lcd_special_on() \
+ do { \
+} while (0)
+
+ #define __lcd_special_off() \
+ do { \
+ __gpio_clear_pin(LCD_RET); \
+ } while (0)
+
+#endif /* CONFIG_JZLCD_AUO_A030FL01_V1 */
+
+#endif /* __JZ_KGM_TOPPOLY_TD043MGEB1_H__ */
+/* 2.2
+ __spi_write_reg(0x02, 0x07 ); \
+ __spi_write_reg(0x03, 0x5f); \
+ __spi_write_reg(0x04, 0x17); \
+ __spi_write_reg(0x05, 0x20); \
+ __spi_write_reg(0x06, 0x08); \
+ __spi_write_reg(0x07, 0x26); \
+ __spi_write_reg(0x08, 0x13); \
+ __spi_write_reg(0x09, 0x33); \
+ __spi_write_reg(0x0a, 0x20); \
+ __spi_write_reg(0x0b, 0x20); \
+ __spi_write_reg(0x0c, 0x20); \
+ __spi_write_reg(0x0d, 0x20); \
+ __spi_write_reg(0x0e, 0x10); \
+ __spi_write_reg(0x0f, 0x10); \
+ __spi_write_reg(0x10, 0x10); \
+ __spi_write_reg(0x11, 0x15); \
+ __spi_write_reg(0x12, 0xaa); \
+ __spi_write_reg(0x13, 0xff); \
+ __spi_write_reg(0x14, 0x86); \
+ __spi_write_reg(0x15, 0x8e); \
+ __spi_write_reg(0x16, 0xd6); \
+ __spi_write_reg(0x17, 0xfe); \
+ __spi_write_reg(0x18, 0x28); \
+ __spi_write_reg(0x19, 0x52); \
+ __spi_write_reg(0x1a, 0x7c); \
+ __spi_write_reg(0x1b, 0xe9); \
+ __spi_write_reg(0x1c, 0x42); \
+ __spi_write_reg(0x1d, 0x88); \
+ __spi_write_reg(0x1e, 0xb8); \
+ __spi_write_reg(0x1f, 0xff); \
+ __spi_write_reg(0x20, 0xf0); \
+ __spi_write_reg(0x21, 0xf0); \
+ __spi_write_reg(0x22, 0x07); \
+*/
+/* 3.1
+ __spi_write_reg(0x02, 0x07); \
+ __spi_write_reg(0x03, 0x5f); \
+ __spi_write_reg(0x04, 0x17); \
+ __spi_write_reg(0x05, 0x20); \
+ __spi_write_reg(0x06, 0x08); \
+ __spi_write_reg(0x07, 0x20); \
+ __spi_write_reg(0x08, 0x20); \
+ __spi_write_reg(0x09, 0x20); \
+ __spi_write_reg(0x0a, 0x20); \
+ __spi_write_reg(0x0b, 0x20); \
+ __spi_write_reg(0x0c, 0x20); \
+ __spi_write_reg(0x0d, 0x22); \
+ __spi_write_reg(0x0e, 0x10); \
+ __spi_write_reg(0x0f, 0x10); \
+ __spi_write_reg(0x10, 0x10); \
+ __spi_write_reg(0x11, 0x15); \
+ __spi_write_reg(0x12, 0x6a); \
+ __spi_write_reg(0x13, 0xff); \
+ __spi_write_reg(0x14, 0x86); \
+ __spi_write_reg(0x15, 0x7c); \
+ __spi_write_reg(0x16, 0xc2); \
+ __spi_write_reg(0x17, 0xd1); \
+ __spi_write_reg(0x18, 0xf5); \
+ __spi_write_reg(0x19, 0x25); \
+ __spi_write_reg(0x1a, 0x4a); \
+ __spi_write_reg(0x1b, 0xbf); \
+ __spi_write_reg(0x1c, 0x15); \
+ __spi_write_reg(0x1d, 0x6a); \
+ __spi_write_reg(0x1e, 0xa4); \
+ __spi_write_reg(0x1f, 0xff); \
+ __spi_write_reg(0x20, 0xf0); \
+ __spi_write_reg(0x21, 0xf0); \
+ __spi_write_reg(0x22, 0x08); \
+ */
+ /* 2.5
+ __spi_write_reg(0x02, 0x07); \
+ __spi_write_reg(0x03, 0x5f); \
+ __spi_write_reg(0x04, 0x17); \
+ __spi_write_reg(0x05, 0x20); \
+ __spi_write_reg(0x06, 0x08); \
+ __spi_write_reg(0x07, 0x20); \
+ __spi_write_reg(0x08, 0x20); \
+ __spi_write_reg(0x09, 0x20); \
+ __spi_write_reg(0x0a, 0x20); \
+ __spi_write_reg(0x0b, 0x20); \
+ __spi_write_reg(0x0c, 0x20); \
+ __spi_write_reg(0x0d, 0x22); \
+ __spi_write_reg(0x0e, 0x10); \
+ __spi_write_reg(0x0f, 0x10); \
+ __spi_write_reg(0x10, 0x10); \
+ __spi_write_reg(0x11, 0x15); \
+ __spi_write_reg(0x12, 0xaa); \
+ __spi_write_reg(0x13, 0xff); \
+ __spi_write_reg(0x14, 0x86); \
+ __spi_write_reg(0x15, 0x89); \
+ __spi_write_reg(0x16, 0xc6); \
+ __spi_write_reg(0x17, 0xea); \
+ __spi_write_reg(0x18, 0x0c); \
+ __spi_write_reg(0x19, 0x33); \
+ __spi_write_reg(0x1a, 0x5e); \
+ __spi_write_reg(0x1b, 0xd0); \
+ __spi_write_reg(0x1c, 0x33); \
+ __spi_write_reg(0x1d, 0x7e); \
+ __spi_write_reg(0x1e, 0xb3); \
+ __spi_write_reg(0x1f, 0xff); \
+ __spi_write_reg(0x20, 0xf0); \
+ __spi_write_reg(0x21, 0xf0); \
+ __spi_write_reg(0x22, 0x08); \
+*/
+/*
+ __spi_write_reg(0x02, 0x07); \
+ __spi_write_reg(0x03, 0x5f); \
+ __spi_write_reg(0x04, 0x17); \
+ __spi_write_reg(0x05, 0x20); \
+ __spi_write_reg(0x06, 0x08); \
+ __spi_write_reg(0x07, 0x20); \
+ __spi_write_reg(0x08, 0x20); \
+ __spi_write_reg(0x09, 0x20); \
+ __spi_write_reg(0x0a, 0x20); \
+ __spi_write_reg(0x0b, 0x20); \
+ __spi_write_reg(0x0c, 0x20); \
+ __spi_write_reg(0x0d, 0x22); \
+ __spi_write_reg(0x0e, 0x10); \
+ __spi_write_reg(0x0f, 0x10); \
+ __spi_write_reg(0x10, 0x10); \
+ __spi_write_reg(0x11, 0x15); \
+ __spi_write_reg(0x12, 0xaa); \
+ __spi_write_reg(0x13, 0xff); \
+ __spi_write_reg(0x14, 0x86); \
+ __spi_write_reg(0x15, 0x84); \
+ __spi_write_reg(0x16, 0xc3); \
+ __spi_write_reg(0x17, 0xd8); \
+ __spi_write_reg(0x18, 0x01); \
+ __spi_write_reg(0x19, 0x28); \
+ __spi_write_reg(0x1a, 0x53); \
+ __spi_write_reg(0x1b, 0xc5); \
+ __spi_write_reg(0x1c, 0x26); \
+ __spi_write_reg(0x1d, 0x74); \
+ __spi_write_reg(0x1e, 0xae); \
+ __spi_write_reg(0x1f, 0xff); \
+ __spi_write_reg(0x20, 0xf0); \
+ __spi_write_reg(0x21, 0xf0); \
+ __spi_write_reg(0x22, 0x08); \
+ */
diff --git a/drivers/video/jzlcd.c b/drivers/video/jzlcd.c
new file mode 100644
index 00000000000..8eb416af02d
--- /dev/null
+++ b/drivers/video/jzlcd.c
@@ -0,0 +1,1571 @@
+/*
+ * linux/drivers/video/jzlcd.c -- Ingenic On-Chip LCD frame buffer device
+ *
+ * Copyright (C) 2005-2007, Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/kthread.h>
+
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/jzsoc.h>
+
+#include "console/fbcon.h"
+
+#include "jzlcd.h"
+
+#undef CONFIG_PM
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)
+#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)
+#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)
+#ifdef DEBUG
+#define print_dbg(f, arg...) printk("dbg::" __FILE__ ",LINE(%d): " f "\n", __LINE__, ## arg)
+#else
+#define print_dbg(f, arg...) do {} while (0)
+#endif
+
+struct lcd_cfb_info {
+ struct fb_info fb;
+ struct display_switch *dispsw;
+ signed int currcon;
+ int func_use_count;
+
+ struct {
+ u16 red, green, blue;
+ } palette[NR_PALETTE];
+#ifdef CONFIG_PM
+ struct pm_dev *pm;
+#endif
+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)
+ struct task_struct *rotate_daemon_thread;
+#endif
+};
+
+static struct lcd_cfb_info *jzlcd_info;
+
+struct jzfb_info {
+ unsigned int cfg; /* panel mode and pin usage etc. */
+ unsigned int w;
+ unsigned int h;
+ unsigned int bpp; /* bit per pixel */
+ unsigned int fclk; /* frame clk */
+ unsigned int hsw; /* hsync width, in pclk */
+ unsigned int vsw; /* vsync width, in line count */
+ unsigned int elw; /* end of line, in pclk */
+ unsigned int blw; /* begin of line, in pclk */
+ unsigned int efw; /* end of frame, in line count */
+ unsigned int bfw; /* begin of frame, in line count */
+};
+
+static struct jzfb_info jzfb = {
+#if defined(CONFIG_JZLCD_SHARP_LQ035Q7)
+ MODE_TFT_SHARP | PCLK_N | VSYNC_N,
+ 240, 320, 16, 60, 1, 2, 1, 2, 0, 6
+#endif
+#if defined(CONFIG_JZLCD_SAMSUNG_LTS350Q1)
+ MODE_TFT_SAMSUNG | PCLK_N,
+ 240, 320, 16, 60, 1, 2, (254-240), 0, 7, 0
+#endif
+#if defined(CONFIG_JZLCD_SAMSUNG_LTV350QVF04)
+ MODE_TFT_GEN | HSYNC_N | VSYNC_N,
+ 320, 240, 16, 70, 19, 4, 20, 14, 18, 6
+#endif
+#if defined(CONFIG_JZLCD_SAMSUNG_LTP400WQF01)
+ MODE_TFT_GEN | HSYNC_N | VSYNC_N,
+ 480, 272, 16, 60, 41, 10, 2, 2, 2, 2
+#endif
+
+#if defined(CONFIG_JZLCD_SAMSUNG_LTP400WQF02)
+ /* MODE_TFT_18BIT: JZ4740@ version */
+ MODE_TFT_GEN | MODE_TFT_18BIT | HSYNC_N | VSYNC_N,
+ 480, 272, 32, 60, 41, 10, 2, 2, 2, 2
+#endif
+#if defined(CONFIG_JZLCD_TRULY_TFTG320240DTSW)
+ MODE_TFT_GEN | HSYNC_N | VSYNC_N | PCLK_N,
+ 320, 240, 16, 85, 30, 3, 38, 20, 11, 8
+#endif
+#if defined(CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL)
+ MODE_8BIT_SERIAL_TFT | HSYNC_N | VSYNC_N | PCLK_N,
+ /* serial mode 280 lines, parallel mode 240 lines */
+ 320, 280, 32, 60, (30*3), 3, (20*3), (38*3), 46, 23
+#endif
+#if defined(CONFIG_JZLCD_AUO_A030FL01_V1)
+ MODE_TFT_GEN | MODE_TFT_18BIT | HSYNC_N | VSYNC_N,
+ 480, 272, 32, 60, 39, 10, 8, 4, 4, 2
+#endif
+#if defined(CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E)
+ MODE_TFT_GEN | HSYNC_N | VSYNC_N | PCLK_N | DE_N,
+ 320, 240, 16, 60, 3, 3, 3, 3, 3, 85 /* 320x240 */
+#endif
+#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) && defined(CONFIG_JZ4740_PAVO)
+ MODE_TFT_GEN | HSYNC_N | VSYNC_N | MODE_TFT_18BIT | PCLK_N,
+// 320, 240, 18, 110, 1, 1, 10, 50, 10, 13
+ 320, 240, 18, 80, 1, 1, 10, 50, 10, 13
+#endif
+#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) && !(defined(CONFIG_JZ4740_PAVO))
+ MODE_TFT_GEN | HSYNC_N | VSYNC_N | PCLK_N,
+ 320, 240, 16, 110, 1, 1, 10, 50, 10, 13
+#endif
+#if defined(CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL)
+ MODE_8BIT_SERIAL_TFT | PCLK_N | HSYNC_N | VSYNC_N,
+ 320, 240, 32, 60, 1, 1, 10, 50, 10, 13
+#endif
+#if defined(CONFIG_JZLCD_HYNIX_HT10X21)
+ MODE_TFT_GEN | PCLK_N,
+ 1024, 768, 16, 45, 1, 1, 75, 0, 3, 0
+#endif
+#if defined(CONFIG_JZLCD_TOSHIBA_LTM084P363)
+ MODE_TFT_GEN | PCLK_N,
+ 800, 600, 16, 50, 1, 2, 199, 0, 2, 0
+#endif
+#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)
+ MODE_TFT_SHARP | PCLK_N,
+ 800, 600, 16, 40, 1, 1, 255, 0, 34, 0
+#endif
+#if defined(CONFIG_JZLCD_CSTN_800x600)
+ MODE_STN_COLOR_DUAL | STN_DAT_PIN8,
+ 800, 600, 16, 30, 8, 1, 0, 0, 0, 0
+#endif
+#if defined(CONFIG_JZLCD_CSTN_320x240)
+ MODE_STN_COLOR_SINGLE | STN_DAT_PIN8,
+ 320, 240, 16, 120, 8, 1, 8, 0, 0, 0
+#endif
+#if defined(CONFIG_JZLCD_MSTN_640x480)
+ MODE_STN_MONO_DUAL | STN_DAT_PIN4,
+ 640, 480, 8, 110, 4, 1, 4, 0, 0, 0
+#endif
+#if defined(CONFIG_JZLCD_MSTN_320x240)
+ MODE_STN_MONO_SINGLE | STN_DAT_PIN4,
+ 320, 240, 8, 110, 4, 1, 4, 0, 0, 0
+#endif
+#if defined(CONFIG_JZLCD_MSTN_480x320)
+ MODE_STN_MONO_SINGLE | STN_DAT_PIN8
+#if defined(CONFIG_JZLCD_MSTN_INVERSE)
+ | DATA_INVERSE
+#endif
+ , 480, 320, 8, 65, 8, 1, 8, 0, 0, 0
+#endif
+
+#if defined(CONFIG_JZLCD_MSTN_240x128)
+ MODE_STN_MONO_SINGLE | STN_DAT_PIN1
+#if defined(CONFIG_JZLCD_MSTN_INVERSE)
+ | DATA_INVERSE
+#endif
+ , 240, 128, 8, 100, 1, 1, 1, 0, 0, 0
+#endif
+};
+
+static struct lcd_desc *lcd_desc_base;
+static struct lcd_desc *lcd_palette_desc;
+static struct lcd_desc *lcd_frame_desc0;
+static struct lcd_desc *lcd_frame_desc1;
+
+static unsigned char *lcd_palette;
+static unsigned char *lcd_frame[CONFIG_JZLCD_FRAMEBUFFER_MAX];
+struct jz_lcd_buffer_addrs_t jz_lcd_buffer_addrs;
+//extern struct display fb_display[MAX_NR_CONSOLES];
+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)
+static unsigned char *lcd_frame_user_fb;
+/* default rotate angle */
+static volatile int rotate_angle = CONFIG_JZLCD_FRAMEBUFFER_DEFAULT_ROTATE_ANGLE;
+#endif
+
+#ifdef DEBUG
+static void print_regs(void) /* debug */
+{
+ printk("REG_LCD_CFG:\t0x%8.8x\n", REG_LCD_CFG);
+ printk("REG_LCD_VSYNC:\t0x%8.8x\n", REG_LCD_VSYNC);
+ printk("REG_LCD_HSYNC:\t0x%8.8x\n", REG_LCD_HSYNC);
+ printk("REG_LCD_VAT:\t0x%8.8x\n", REG_LCD_VAT);
+ printk("REG_LCD_DAH:\t0x%8.8x\n", REG_LCD_DAH);
+ printk("REG_LCD_DAV:\t0x%8.8x\n", REG_LCD_DAV);
+ printk("REG_LCD_PS:\t0x%8.8x\n", REG_LCD_PS);
+ printk("REG_LCD_CLS:\t0x%8.8x\n", REG_LCD_CLS);
+ printk("REG_LCD_SPL:\t0x%8.8x\n", REG_LCD_SPL);
+ printk("REG_LCD_REV:\t0x%8.8x\n", REG_LCD_REV);
+ printk("REG_LCD_CTRL:\t0x%8.8x\n", REG_LCD_CTRL);
+ printk("REG_LCD_STATE:\t0x%8.8x\n", REG_LCD_STATE);
+ printk("REG_LCD_IID:\t0x%8.8x\n", REG_LCD_IID);
+ printk("REG_LCD_DA0:\t0x%8.8x\n", REG_LCD_DA0);
+ printk("REG_LCD_SA0:\t0x%8.8x\n", REG_LCD_SA0);
+ printk("REG_LCD_FID0:\t0x%8.8x\n", REG_LCD_FID0);
+ printk("REG_LCD_CMD0:\t0x%8.8x\n", REG_LCD_CMD0);
+
+ printk("==================================\n");
+ printk("REG_LCD_VSYNC:\t%d:%d\n", REG_LCD_VSYNC>>16, REG_LCD_VSYNC&0xfff);
+ printk("REG_LCD_HSYNC:\t%d:%d\n", REG_LCD_HSYNC>>16, REG_LCD_HSYNC&0xfff);
+ printk("REG_LCD_VAT:\t%d:%d\n", REG_LCD_VAT>>16, REG_LCD_VAT&0xfff);
+ printk("REG_LCD_DAH:\t%d:%d\n", REG_LCD_DAH>>16, REG_LCD_DAH&0xfff);
+ printk("REG_LCD_DAV:\t%d:%d\n", REG_LCD_DAV>>16, REG_LCD_DAV&0xfff);
+ printk("==================================\n");
+
+}
+#else
+#define print_regs()
+#endif
+
+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)
+static int jzfb_rotate_daemon_thread(void *info)
+{
+ int i,j;
+ struct fb_info *fb = &jzlcd_info->fb;
+
+ while (!kthread_should_stop()) {
+#if (CONFIG_JZLCD_FRAMEBUFFER_BPP == 8)
+ unsigned char *plcd_frame = (unsigned char *)lcd_frame[0];
+ unsigned char *pfb = (unsigned char *) (fb->screen_base);
+#elif (CONFIG_JZLCD_FRAMEBUFFER_BPP == 16)
+ unsigned short *plcd_frame = (unsigned short *)lcd_frame[0];
+ unsigned short *pfb = (unsigned short *) (fb->screen_base);
+#elif (CONFIG_JZLCD_FRAMEBUFFER_BPP == 32)
+ unsigned int *plcd_frame = (unsigned int *)lcd_frame[0];
+ unsigned int *pfb = (unsigned int *) (fb->screen_base);
+#else
+#error "ERROR, rotate not support this bpp."
+#endif
+ switch ( rotate_angle ) {
+ case FB_ROTATE_UR:
+ printk("%s, Warning, this shouldn't reache\n", __FUNCTION__);
+ ssleep(1);
+ break;
+ case FB_ROTATE_UD: /* cost about 30ms, can be accelrated by dma in the future */
+ plcd_frame += jzfb.w*jzfb.h -1;
+ for (i=0;i<jzfb.h*jzfb.w;i++)
+ *plcd_frame-- = *pfb++;
+ msleep(75);
+ break;
+ case FB_ROTATE_CW: /* cost about 80ms */
+ for (i=1;i<fb->var.height+1; i++) {
+ for (j=1; j < fb->var.width+1; j++)
+ plcd_frame[j*fb->var.height-i] = *pfb++;
+ }
+ msleep(100); /* sleep 100ms */
+ break;
+ case FB_ROTATE_CCW: /* cost about 80ms */
+ for (i=0;i<fb->var.height;i++) {
+ for ( j=fb->var.width-1;j>=0;j--)
+ plcd_frame[j*fb->var.height+i] = *pfb++;
+ }
+ msleep(100); /* sleep 100ms */
+ break;
+ default: /* FB_ROTATE_UR */
+ dprintk("Unknown rotate(%d) type\n", rotate_angle);
+ ssleep(1);
+ }
+
+ dma_cache_wback_inv((unsigned int)(lcd_frame_user_fb), fb->fix.smem_len);
+ }
+ return 0;
+}
+/*
+ * rotate param angle:
+ * 0: FB_ROTATE_UR, 0'C
+ * 1: FB_ROTATE_CW, 90'C
+ * 2: FB_ROTATE_UD, 180'C
+ * 3: FB_ROTATE_CCW, 270'C
+ */
+static int jzfb_rotate_change( int angle )
+{
+ struct fb_info *fb = &jzlcd_info->fb;
+
+ /* clear frame buffer */
+ memset((void*)lcd_frame_user_fb, 0x00, fb->fix.smem_len);
+ switch ( angle ) {
+ case FB_ROTATE_UR:
+ fb->var.width = fb->var.xres = fb->var.xres_virtual = jzfb.w;
+ fb->var.height = fb->var.yres = fb->var.yres_virtual = jzfb.h;
+ /* change lcd controller's data buffer to lcd_frame_user_fb*/
+ lcd_frame_desc0->databuf = virt_to_phys((void *)lcd_frame_user_fb);
+ if ( rotate_angle != FB_ROTATE_UR )
+ kthread_stop(jzlcd_info->rotate_daemon_thread);
+ rotate_angle = angle;
+ break;
+ case FB_ROTATE_UD:
+ case FB_ROTATE_CW:
+ case FB_ROTATE_CCW:
+ if ( angle == FB_ROTATE_UD ) {
+ fb->var.width = fb->var.xres = fb->var.xres_virtual = jzfb.w;
+ fb->var.height = fb->var.yres = fb->var.yres_virtual = jzfb.h;
+ }
+ else { /* CW, CCW */
+ fb->var.width = fb->var.xres = fb->var.xres_virtual = jzfb.h;
+ fb->var.height = fb->var.yres = fb->var.yres_virtual = jzfb.w;
+ }
+ /* change lcd controller's data buffer to lcd_frame[0]*/
+ lcd_frame_desc0->databuf = virt_to_phys((void *)lcd_frame[0]);
+ if ( rotate_angle == FB_ROTATE_UR || \
+ jzlcd_info->rotate_daemon_thread == NULL)
+ jzlcd_info->rotate_daemon_thread = kthread_run( jzfb_rotate_daemon_thread, jzlcd_info, "%s", "jzlcd-rotate-daemon"); /* start rotate daemon */
+ rotate_angle = angle;
+ break;
+ default:
+ printk("Invalid angle(%d)\n", (unsigned int)angle);
+ }
+ fb->fix.line_length = fb->var.xres * CONFIG_JZLCD_FRAMEBUFFER_BPP/8;
+ dma_cache_wback_inv((unsigned int)(lcd_frame_desc0), sizeof(struct lcd_desc));
+ return 0;
+}
+
+void jzfb_fb_rotate(struct fb_info *fbi, int angle)
+{
+ jzfb_rotate_change( angle/90 );
+}
+#endif /* #if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) */
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int jzfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;
+ unsigned short *ptr, ctmp;
+
+// print_dbg("regno:%d,RGBt:(%d,%d,%d,%d)\t", regno, red, green, blue, transp);
+ if (regno >= NR_PALETTE)
+ return 1;
+
+ cfb->palette[regno].red = red ;
+ cfb->palette[regno].green = green;
+ cfb->palette[regno].blue = blue;
+ if (cfb->fb.var.bits_per_pixel <= 16) {
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ red &= 0xff;
+ green &= 0xff;
+ blue &= 0xff;
+ }
+ switch (cfb->fb.var.bits_per_pixel) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) ||
+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) {
+ ctmp = (77L * red + 150L * green + 29L * blue) >> 8;
+ ctmp = ((ctmp >> 3) << 11) | ((ctmp >> 2) << 5) |
+ (ctmp >> 3);
+ } else {
+ /* RGB 565 */
+ if (((red >> 3) == 0) && ((red >> 2) != 0))
+ red = 1 << 3;
+ if (((blue >> 3) == 0) && ((blue >> 2) != 0))
+ blue = 1 << 3;
+ ctmp = ((red >> 3) << 11)
+ | ((green >> 2) << 5) | (blue >> 3);
+ }
+
+ ptr = (unsigned short *)lcd_palette;
+ ptr = (unsigned short *)(((u32)ptr)|0xa0000000);
+ ptr[regno] = ctmp;
+
+ break;
+
+ case 15:
+ if (regno < 16)
+ ((u32 *)cfb->fb.pseudo_palette)[regno] =
+ ((red >> 3) << 10) |
+ ((green >> 3) << 5) |
+ (blue >> 3);
+ break;
+ case 16:
+ if (regno < 16) {
+ ((u32 *)cfb->fb.pseudo_palette)[regno] =
+ ((red >> 3) << 11) |
+ ((green >> 2) << 5) |
+ (blue >> 3);
+ }
+ break;
+ case 18:
+ case 24:
+ case 32:
+ if (regno < 16)
+ ((u32 *)cfb->fb.pseudo_palette)[regno] =
+ (red << 16) |
+ (green << 8) |
+ (blue << 0);
+
+/* if (regno < 16) {
+ unsigned val;
+ val = chan_to_field(red, &cfb->fb.var.red);
+ val |= chan_to_field(green, &cfb->fb.var.green);
+ val |= chan_to_field(blue, &cfb->fb.var.blue);
+ ((u32 *)cfb->fb.pseudo_palette)[regno] = val;
+ }
+*/
+
+ break;
+ }
+ return 0;
+}
+
+
+static int jzfb_ioctl (struct fb_info *fb, unsigned int cmd, unsigned long arg )
+{
+ int ret = 0;
+ void __user *argp = (void __user *)arg;
+
+ switch (cmd) {
+ case FBIOSETBACKLIGHT:
+ __lcd_set_backlight_level(arg); /* We support 8 levels here. */
+ break;
+ case FBIODISPON:
+ __lcd_display_on();
+ break;
+ case FBIODISPOFF:
+ __lcd_display_off();
+ break;
+ case FBIOPRINT_REGS:
+ print_regs();
+ break;
+ case FBIOGETBUFADDRS:
+ if ( copy_to_user(argp, &jz_lcd_buffer_addrs,
+ sizeof(struct jz_lcd_buffer_addrs_t)) )
+ return -EFAULT;
+ break;
+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)
+ case FBIOROTATE:
+ ret = jzfb_rotate_change(arg);
+ break;
+#endif /* defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) */
+ default:
+ printk("Warn: Command(%x) not support\n", cmd);
+ ret = -1;
+ break;
+ }
+ return ret;
+
+}
+
+/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */
+static int jzfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;
+ unsigned long start;
+ unsigned long off;
+ u32 len;
+
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
+
+ /* frame buffer memory */
+ start = cfb->fb.fix.smem_start;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb.fix.smem_len);
+ start &= PAGE_MASK;
+
+ if ((vma->vm_end - vma->vm_start + off) > len)
+ return -EINVAL;
+ off += start;
+
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ vma->vm_flags |= VM_IO;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Uncacheable */
+
+#if 1
+ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
+ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; /* Uncacheable */
+// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; /* Write-Through */
+#endif
+
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+/* checks var and eventually tweaks it to something supported,
+ * DO NOT MODIFY PAR */
+static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ print_dbg("jzfb_check_var");
+ return 0;
+}
+
+
+/*
+ * set the video mode according to info->var
+ */
+static int jzfb_set_par(struct fb_info *info)
+{
+ print_dbg("jzfb_set_par");
+ return 0;
+}
+
+
+/*
+ * (Un)Blank the display.
+ * Fix me: should we use VESA value?
+ */
+static int jzfb_blank(int blank_mode, struct fb_info *info)
+{
+
+ dprintk("fb_blank %d %p", blank_mode, info);
+
+ switch (blank_mode) {
+
+ case FB_BLANK_UNBLANK:
+ //case FB_BLANK_NORMAL:
+ /* Turn on panel */
+ __lcd_set_ena();
+ __lcd_display_on();
+ break;
+
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_POWERDOWN:
+#if 0
+ /* Turn off panel */
+ __lcd_set_dis();
+ __lcd_display_off();
+#endif
+ break;
+ default:
+ break;
+
+ }
+ return 0;
+}
+
+/*
+ * pan display
+ */
+static int jzfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;
+ int dy;
+
+ if (!var || !cfb) {
+ return -EINVAL;
+ }
+
+ if (var->xoffset - cfb->fb.var.xoffset) {
+ /* No support for X panning for now! */
+ return -EINVAL;
+ }
+
+ dy = var->yoffset - cfb->fb.var.yoffset;
+ print_dbg("var.yoffset: %d", dy);
+ if (dy) {
+
+ print_dbg("Panning screen of %d lines", dy);
+
+ lcd_frame_desc0->databuf += (cfb->fb.fix.line_length * dy);
+ /* TODO: Wait for current frame to finished */
+ }
+
+ return 0;
+}
+
+
+/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */
+static struct fb_ops jzfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = jzfb_setcolreg,
+ .fb_check_var = jzfb_check_var,
+ .fb_set_par = jzfb_set_par,
+ .fb_blank = jzfb_blank,
+ .fb_pan_display = jzfb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_mmap = jzfb_mmap,
+ .fb_ioctl = jzfb_ioctl,
+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)
+ .fb_rotate = jzfb_fb_rotate,
+#endif
+};
+
+static int jzfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;
+ int chgvar = 0;
+
+ var->height = jzfb.h ;
+ var->width = jzfb.w ;
+ var->bits_per_pixel = jzfb.bpp;
+
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->activate = cfb->fb.var.activate;
+ var->xres = var->width;
+ var->yres = var->height;
+ var->xres_virtual = var->width;
+ var->yres_virtual = var->height;
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->pixclock = 0;
+ var->left_margin = 0;
+ var->right_margin = 0;
+ var->upper_margin = 0;
+ var->lower_margin = 0;
+ var->hsync_len = 0;
+ var->vsync_len = 0;
+ var->sync = 0;
+ var->activate &= ~FB_ACTIVATE_TEST;
+
+ /*
+ * CONUPDATE and SMOOTH_XPAN are equal. However,
+ * SMOOTH_XPAN is only used internally by fbcon.
+ */
+ if (var->vmode & FB_VMODE_CONUPDATE) {
+ var->vmode |= FB_VMODE_YWRAP;
+ var->xoffset = cfb->fb.var.xoffset;
+ var->yoffset = cfb->fb.var.yoffset;
+ }
+
+ if (var->activate & FB_ACTIVATE_TEST)
+ return 0;
+
+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+ return -EINVAL;
+
+ if (cfb->fb.var.xres != var->xres)
+ chgvar = 1;
+ if (cfb->fb.var.yres != var->yres)
+ chgvar = 1;
+ if (cfb->fb.var.xres_virtual != var->xres_virtual)
+ chgvar = 1;
+ if (cfb->fb.var.yres_virtual != var->yres_virtual)
+ chgvar = 1;
+ if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel)
+ chgvar = 1;
+
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+
+ switch(var->bits_per_pixel){
+ case 1: /* Mono */
+ cfb->fb.fix.visual = FB_VISUAL_MONO01;
+ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8;
+ break;
+ case 2: /* Mono */
+ var->red.offset = 0;
+ var->red.length = 2;
+ var->green.offset = 0;
+ var->green.length = 2;
+ var->blue.offset = 0;
+ var->blue.length = 2;
+
+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8;
+ break;
+ case 4: /* PSEUDOCOLOUR*/
+ var->red.offset = 0;
+ var->red.length = 4;
+ var->green.offset = 0;
+ var->green.length = 4;
+ var->blue.offset = 0;
+ var->blue.length = 4;
+
+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ cfb->fb.fix.line_length = var->xres / 2;
+ break;
+ case 8: /* PSEUDOCOLOUR, 256 */
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+
+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ cfb->fb.fix.line_length = var->xres ;
+ break;
+ case 15: /* DIRECTCOLOUR, 32k */
+ var->bits_per_pixel = 15;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+
+ cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
+ cfb->fb.fix.line_length = var->xres_virtual * 2;
+ break;
+ case 16: /* DIRECTCOLOUR, 64k */
+ var->bits_per_pixel = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+
+ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ cfb->fb.fix.line_length = var->xres_virtual * 2;
+ break;
+ case 18:
+ case 24:
+ case 32:
+ /* DIRECTCOLOUR, 16M */
+ var->bits_per_pixel = 32;
+
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+
+ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ cfb->fb.fix.line_length = var->xres_virtual * 4;
+ break;
+
+ default: /* in theory this should never happen */
+ printk(KERN_WARNING "%s: don't support for %dbpp\n",
+ cfb->fb.fix.id, var->bits_per_pixel);
+ break;
+ }
+
+ cfb->fb.var = *var;
+ cfb->fb.var.activate &= ~FB_ACTIVATE_ALL;
+
+ /*
+ * Update the old var. The fbcon drivers still use this.
+ * Once they are using cfb->fb.var, this can be dropped.
+ * --rmk
+ */
+ //display->var = cfb->fb.var;
+ /*
+ * If we are setting all the virtual consoles, also set the
+ * defaults used to create new consoles.
+ */
+ fb_set_cmap(&cfb->fb.cmap, &cfb->fb);
+ dprintk("jzfb_set_var: after fb_set_cmap...\n");
+
+ return 0;
+}
+
+static struct lcd_cfb_info * jzfb_alloc_fb_info(void)
+{
+ struct lcd_cfb_info *cfb;
+
+ cfb = kmalloc(sizeof(struct lcd_cfb_info) + sizeof(u32) * 16, GFP_KERNEL);
+
+ if (!cfb)
+ return NULL;
+
+ jzlcd_info = cfb;
+
+ memset(cfb, 0, sizeof(struct lcd_cfb_info) );
+
+ cfb->currcon = -1;
+
+
+ strcpy(cfb->fb.fix.id, "jz-lcd");
+ cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+ cfb->fb.fix.type_aux = 0;
+ cfb->fb.fix.xpanstep = 1;
+ cfb->fb.fix.ypanstep = 1;
+ cfb->fb.fix.ywrapstep = 0;
+ cfb->fb.fix.accel = FB_ACCEL_NONE;
+
+ cfb->fb.var.nonstd = 0;
+ cfb->fb.var.activate = FB_ACTIVATE_NOW;
+ cfb->fb.var.height = -1;
+ cfb->fb.var.width = -1;
+ cfb->fb.var.accel_flags = FB_ACCELF_TEXT;
+
+ cfb->fb.fbops = &jzfb_ops;
+ cfb->fb.flags = FBINFO_FLAG_DEFAULT;
+
+ cfb->fb.pseudo_palette = (void *)(cfb + 1);
+
+ switch (jzfb.bpp) {
+ case 1:
+ fb_alloc_cmap(&cfb->fb.cmap, 4, 0);
+ break;
+ case 2:
+ fb_alloc_cmap(&cfb->fb.cmap, 8, 0);
+ break;
+ case 4:
+ fb_alloc_cmap(&cfb->fb.cmap, 32, 0);
+ break;
+ case 8:
+
+ default:
+ fb_alloc_cmap(&cfb->fb.cmap, 256, 0);
+ break;
+ }
+ dprintk("fb_alloc_cmap,fb.cmap.len:%d....\n", cfb->fb.cmap.len);
+
+ return cfb;
+}
+
+/*
+ * Map screen memory
+ */
+static int jzfb_map_smem(struct lcd_cfb_info *cfb)
+{
+ struct page * map = NULL;
+ unsigned char *tmp;
+ unsigned int page_shift, needroom, t;
+#if defined(CONFIG_SOC_JZ4740)
+ if (jzfb.bpp == 18 || jzfb.bpp == 24)
+ t = 32;
+ else
+ t = jzfb.bpp;
+#else
+ if (jzfb.bpp == 15)
+ t = 16;
+ else
+ t = jzfb.bpp;
+#endif
+
+ needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h;
+ for (page_shift = 0; page_shift < 12; page_shift++)
+ if ((PAGE_SIZE << page_shift) >= needroom)
+ break;
+
+ /* lcd_palette room total 4KB:
+ * 0 -- 512: lcd palette
+ * 1024 -- [1024+16*3]: lcd descripters
+ * [1024+16*3] -- 4096: reserved
+ */
+ lcd_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0);
+ if ((!lcd_palette))
+ return -ENOMEM;
+
+ memset((void *)lcd_palette, 0, PAGE_SIZE);
+ map = virt_to_page(lcd_palette);
+ set_bit(PG_reserved, &map->flags);
+ lcd_desc_base = (struct lcd_desc *)(lcd_palette + 1024);
+
+ jz_lcd_buffer_addrs.fb_num = CONFIG_JZLCD_FRAMEBUFFER_MAX;
+ printk("jzlcd use %d framebuffer:\n", CONFIG_JZLCD_FRAMEBUFFER_MAX);
+ /* alloc frame buffer space */
+ for ( t = 0; t < CONFIG_JZLCD_FRAMEBUFFER_MAX; t++ ) {
+ lcd_frame[t] = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift);
+ if ((!lcd_frame[t])) {
+ printk("no mem for fb[%d]\n", t);
+ return -ENOMEM;
+ }
+// memset((void *)lcd_frame[t], 0, PAGE_SIZE << page_shift);
+ for (tmp=(unsigned char *)lcd_frame[t];
+ tmp < lcd_frame[t] + (PAGE_SIZE << page_shift);
+ tmp += PAGE_SIZE) {
+ map = virt_to_page(tmp);
+ set_bit(PG_reserved, &map->flags);
+ }
+ jz_lcd_buffer_addrs.fb_phys_addr[t] = virt_to_phys((void *)lcd_frame[t]);
+ printk("jzlcd fb[%d] phys addr =0x%08x\n",
+ t, jz_lcd_buffer_addrs.fb_phys_addr[t]);
+ }
+#if !defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)
+ cfb->fb.fix.smem_start = virt_to_phys((void *)lcd_frame[0]);
+ cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift);
+ cfb->fb.screen_base =
+ (unsigned char *)(((unsigned int)lcd_frame[0] & 0x1fffffff) | 0xa0000000);
+#else /* Framebuffer rotate */
+ lcd_frame_user_fb = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift);
+ if ((!lcd_frame_user_fb)) {
+ printk("no mem for fb[%d]\n", t);
+ return -ENOMEM;
+ }
+ memset((void *)lcd_frame_user_fb, 0, PAGE_SIZE << page_shift);
+ for (tmp=(unsigned char *)lcd_frame_user_fb;
+ tmp < lcd_frame_user_fb + (PAGE_SIZE << page_shift);
+ tmp += PAGE_SIZE) {
+ map = virt_to_page(tmp);
+ set_bit(PG_reserved, &map->flags);
+ }
+
+ printk("Rotate userfb phys addr =0x%08x\n",
+ (unsigned int)virt_to_phys((void *)lcd_frame_user_fb));
+ cfb->fb.fix.smem_start = virt_to_phys((void *)lcd_frame_user_fb);
+ cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift);
+ cfb->fb.screen_base = (unsigned char *)(((unsigned int)lcd_frame_user_fb & 0x1fffffff) | 0xa0000000);
+
+#endif /* #if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) */
+ if (!cfb->fb.screen_base) {
+ printk("%s: unable to map screen memory\n", cfb->fb.fix.id);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void jzfb_free_fb_info(struct lcd_cfb_info *cfb)
+{
+ if (cfb) {
+ fb_alloc_cmap(&cfb->fb.cmap, 0, 0);
+ kfree(cfb);
+ }
+}
+
+static void jzfb_unmap_smem(struct lcd_cfb_info *cfb)
+{
+ struct page * map = NULL;
+ unsigned char *tmp;
+ unsigned int page_shift, needroom, t;
+#if defined(CONFIG_SOC_JZ4740)
+ if (jzfb.bpp == 18 || jzfb.bpp == 24)
+ t = 32;
+ else
+ t = jzfb.bpp;
+#else
+ if (jzfb.bpp == 15)
+ t = 16;
+ else
+ t = jzfb.bpp;
+#endif
+ needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h;
+ for (page_shift = 0; page_shift < 12; page_shift++)
+ if ((PAGE_SIZE << page_shift) >= needroom)
+ break;
+
+ if (cfb && cfb->fb.screen_base) {
+ iounmap(cfb->fb.screen_base);
+ cfb->fb.screen_base = NULL;
+ release_mem_region(cfb->fb.fix.smem_start,
+ cfb->fb.fix.smem_len);
+ }
+
+ if (lcd_palette) {
+ map = virt_to_page(lcd_palette);
+ clear_bit(PG_reserved, &map->flags);
+ free_pages((int)lcd_palette, 0);
+ }
+
+ for ( t=0; t < CONFIG_JZLCD_FRAMEBUFFER_MAX; t++ ) {
+ if (lcd_frame[t]) {
+ for (tmp=(unsigned char *)lcd_frame[t];
+ tmp < lcd_frame[t] + (PAGE_SIZE << page_shift);
+ tmp += PAGE_SIZE) {
+ map = virt_to_page(tmp);
+ clear_bit(PG_reserved, &map->flags);
+ }
+ free_pages((int)lcd_frame[t], page_shift);
+ }
+ }
+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)
+ if (lcd_frame_user_fb) {
+ for (tmp=(unsigned char *)lcd_frame_user_fb;
+ tmp < lcd_frame_user_fb + (PAGE_SIZE << page_shift);
+ tmp += PAGE_SIZE) {
+ map = virt_to_page(tmp);
+ clear_bit(PG_reserved, &map->flags);
+ }
+ free_pages((int)lcd_frame_user_fb, page_shift);
+ }
+
+#endif
+}
+
+static void lcd_descriptor_init(void)
+{
+ int i;
+ unsigned int pal_size;
+ unsigned int frm_size, ln_size;
+ unsigned char dual_panel = 0;
+
+ i = jzfb.bpp;
+#if defined(CONFIG_SOC_JZ4740)
+ if (i == 18 || i == 24)
+ i = 32;
+#else
+ if (i == 15)
+ i = 16;
+#endif
+ frm_size = (jzfb.w*jzfb.h*i)>>3;
+ ln_size = (jzfb.w*i)>>3;
+
+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) {
+ dual_panel = 1;
+ frm_size >>= 1;
+ }
+
+ frm_size = frm_size / 4;
+ ln_size = ln_size / 4;
+
+ switch (jzfb.bpp) {
+ case 1:
+ pal_size = 4;
+ break;
+ case 2:
+ pal_size = 8;
+ break;
+ case 4:
+ pal_size = 32;
+ break;
+ case 8:
+ default:
+ pal_size = 512;
+ }
+
+ pal_size /= 4;
+
+ lcd_frame_desc0 = lcd_desc_base + 0;
+ lcd_frame_desc1 = lcd_desc_base + 1;
+ lcd_palette_desc = lcd_desc_base + 2;
+
+ jz_lcd_buffer_addrs.lcd_desc_phys_addr = (unsigned int)virt_to_phys(lcd_frame_desc0);
+
+ /* Palette Descriptor */
+ lcd_palette_desc->next_desc = (int)virt_to_phys(lcd_frame_desc0);
+ lcd_palette_desc->databuf = (int)virt_to_phys((void *)lcd_palette);
+ lcd_palette_desc->frame_id = (unsigned int)0xdeadbeaf;
+ lcd_palette_desc->cmd = pal_size|LCD_CMD_PAL; /* Palette Descriptor */
+
+ /* Frame Descriptor 0 */
+ if (jzfb.bpp <= 8)
+ lcd_frame_desc0->next_desc = (int)virt_to_phys(lcd_palette_desc);
+ else
+ lcd_frame_desc0->next_desc = (int)virt_to_phys(lcd_frame_desc0);
+ lcd_frame_desc0->databuf = virt_to_phys((void *)lcd_frame[0]);
+ lcd_frame_desc0->frame_id = (unsigned int)0xbeafbeaf;
+ lcd_frame_desc0->cmd = LCD_CMD_SOFINT | LCD_CMD_EOFINT | frm_size;
+ dma_cache_wback_inv((unsigned int)(lcd_palette_desc),0x10);
+ dma_cache_wback_inv((unsigned int)(lcd_frame_desc0),0x10);
+
+ if (!(dual_panel))
+ return;
+
+ /* Frame Descriptor 1 */
+ lcd_frame_desc1->next_desc = (int)virt_to_phys(lcd_frame_desc1);
+ lcd_frame_desc1->databuf = virt_to_phys((void *)(lcd_frame[0] + frm_size * 4));
+ lcd_frame_desc1->frame_id = (unsigned int)0xdeaddead;
+ lcd_frame_desc1->cmd = LCD_CMD_SOFINT | LCD_CMD_EOFINT | frm_size;
+ dma_cache_wback_inv((unsigned int)(lcd_frame_desc1),0x10);
+}
+
+static int lcd_hw_init(void)
+{
+ unsigned int val = 0;
+ unsigned int pclk;
+ unsigned int stnH;
+ int ret = 0;
+
+ /* Setting Control register */
+ switch (jzfb.bpp) {
+ case 1:
+ val |= LCD_CTRL_BPP_1;
+ break;
+ case 2:
+ val |= LCD_CTRL_BPP_2;
+ break;
+ case 4:
+ val |= LCD_CTRL_BPP_4;
+ break;
+ case 8:
+ val |= LCD_CTRL_BPP_8;
+ break;
+ case 15:
+ val |= LCD_CTRL_RGB555;
+ case 16:
+ val |= LCD_CTRL_BPP_16;
+ break;
+#if defined(CONFIG_SOC_JZ4740)
+ case 17 ... 32:
+ val |= LCD_CTRL_BPP_18_24; /* target is 4bytes/pixel */
+ break;
+#endif
+ default:
+ printk("The BPP %d is not supported\n", jzfb.bpp);
+ val |= LCD_CTRL_BPP_16;
+ break;
+ }
+
+ switch (jzfb.cfg & MODE_MASK) {
+ case MODE_STN_MONO_DUAL:
+ case MODE_STN_COLOR_DUAL:
+ case MODE_STN_MONO_SINGLE:
+ case MODE_STN_COLOR_SINGLE:
+ switch (jzfb.bpp) {
+ case 1:
+ case 2:
+ val |= LCD_CTRL_FRC_2;
+ break;
+ case 4:
+ val |= LCD_CTRL_FRC_4;
+ break;
+ case 8:
+ default:
+ val |= LCD_CTRL_FRC_16;
+ break;
+ }
+ break;
+ }
+
+ val |= LCD_CTRL_BST_16; /* Burst Length is 16WORD=64Byte */
+
+ switch (jzfb.cfg & MODE_MASK) {
+ case MODE_STN_MONO_DUAL:
+ case MODE_STN_COLOR_DUAL:
+ case MODE_STN_MONO_SINGLE:
+ case MODE_STN_COLOR_SINGLE:
+ switch (jzfb.cfg & STN_DAT_PINMASK) {
+#define align2(n) (n)=((((n)+1)>>1)<<1)
+#define align4(n) (n)=((((n)+3)>>2)<<2)
+#define align8(n) (n)=((((n)+7)>>3)<<3)
+ case STN_DAT_PIN1:
+ /* Do not adjust the hori-param value. */
+ break;
+ case STN_DAT_PIN2:
+ align2(jzfb.hsw);
+ align2(jzfb.elw);
+ align2(jzfb.blw);
+ break;
+ case STN_DAT_PIN4:
+ align4(jzfb.hsw);
+ align4(jzfb.elw);
+ align4(jzfb.blw);
+ break;
+ case STN_DAT_PIN8:
+ align8(jzfb.hsw);
+ align8(jzfb.elw);
+ align8(jzfb.blw);
+ break;
+ }
+ break;
+ }
+
+ val |= 1 << 26; /* Output FIFO underrun protection */
+ REG_LCD_CTRL = val;
+
+ switch (jzfb.cfg & MODE_MASK) {
+ case MODE_STN_MONO_DUAL:
+ case MODE_STN_COLOR_DUAL:
+ case MODE_STN_MONO_SINGLE:
+ case MODE_STN_COLOR_SINGLE:
+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL) ||
+ ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL))
+ stnH = jzfb.h >> 1;
+ else
+ stnH = jzfb.h;
+
+ REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;
+ REG_LCD_HSYNC = ((jzfb.blw+jzfb.w) << 16) | (jzfb.blw+jzfb.w+jzfb.hsw);
+
+ /* Screen setting */
+ REG_LCD_VAT = ((jzfb.blw + jzfb.w + jzfb.hsw + jzfb.elw) << 16) | (stnH + jzfb.vsw + jzfb.bfw + jzfb.efw);
+ REG_LCD_DAH = (jzfb.blw << 16) | (jzfb.blw + jzfb.w);
+ REG_LCD_DAV = (0 << 16) | (stnH);
+
+ /* AC BIAs signal */
+ REG_LCD_PS = (0 << 16) | (stnH+jzfb.vsw+jzfb.efw+jzfb.bfw);
+
+ break;
+
+ case MODE_TFT_GEN:
+ case MODE_TFT_SHARP:
+ case MODE_TFT_CASIO:
+ case MODE_TFT_SAMSUNG:
+ case MODE_8BIT_SERIAL_TFT:
+ case MODE_TFT_18BIT:
+ REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;
+#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)
+ REG_LCD_DAV = (0 << 16) | ( jzfb.h );
+#else
+ REG_LCD_DAV = ((jzfb.vsw + jzfb.bfw) << 16) | (jzfb.vsw + jzfb.bfw + jzfb.h);
+#endif /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/
+ REG_LCD_VAT = (((jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw)) << 16) | (jzfb.vsw + jzfb.bfw + jzfb.h + jzfb.efw);
+ REG_LCD_HSYNC = (0 << 16) | jzfb.hsw;
+ REG_LCD_DAH = ((jzfb.hsw + jzfb.blw) << 16) | (jzfb.hsw + jzfb.blw + jzfb.w);
+ break;
+ }
+
+ switch (jzfb.cfg & MODE_MASK) {
+ case MODE_TFT_SAMSUNG:
+ {
+ unsigned int total, tp_s, tp_e, ckv_s, ckv_e;
+ unsigned int rev_s, rev_e, inv_s, inv_e;
+ total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw;
+ tp_s = jzfb.blw + jzfb.w + 1;
+ tp_e = tp_s + 1;
+ ckv_s = tp_s - jz_clocks.pixclk/(1000000000/4100);
+ ckv_e = tp_s + total;
+ rev_s = tp_s - 11; /* -11.5 clk */
+ rev_e = rev_s + total;
+ inv_s = tp_s;
+ inv_e = inv_s + total;
+ REG_LCD_CLS = (tp_s << 16) | tp_e;
+ REG_LCD_PS = (ckv_s << 16) | ckv_e;
+ REG_LCD_SPL = (rev_s << 16) | rev_e;
+ REG_LCD_REV = (inv_s << 16) | inv_e;
+ jzfb.cfg |= STFT_REVHI | STFT_SPLHI;
+ break;
+ }
+ case MODE_TFT_SHARP:
+ {
+ unsigned int total, cls_s, cls_e, ps_s, ps_e;
+ unsigned int spl_s, spl_e, rev_s, rev_e;
+ total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw;
+#if !defined(CONFIG_JZLCD_INNOLUX_AT080TN42)
+ spl_s = 1;
+ spl_e = spl_s + 1;
+ cls_s = 0;
+ cls_e = total - 60; /* > 4us (pclk = 80ns) */
+ ps_s = cls_s;
+ ps_e = cls_e;
+ rev_s = total - 40; /* > 3us (pclk = 80ns) */
+ rev_e = rev_s + total;
+ jzfb.cfg |= STFT_PSHI;
+#else /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/
+ spl_s = total - 5; /* LD */
+ spl_e = total - 3;
+ cls_s = 32; /* CKV */
+ cls_e = 145;
+ ps_s = 0; /* OEV */
+ ps_e = 45;
+ rev_s = 0; /* POL */
+ rev_e = 0;
+#endif /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/
+ REG_LCD_SPL = (spl_s << 16) | spl_e;
+ REG_LCD_CLS = (cls_s << 16) | cls_e;
+ REG_LCD_PS = (ps_s << 16) | ps_e;
+ REG_LCD_REV = (rev_s << 16) | rev_e;
+ break;
+ }
+ case MODE_TFT_CASIO:
+ break;
+ }
+
+ /* Configure the LCD panel */
+ REG_LCD_CFG = jzfb.cfg;
+
+ /* Timing setting */
+ __cpm_stop_lcd();
+
+ val = jzfb.fclk; /* frame clk */
+
+ if ( (jzfb.cfg & MODE_MASK) != MODE_8BIT_SERIAL_TFT) {
+ pclk = val * (jzfb.w + jzfb.hsw + jzfb.elw + jzfb.blw) *
+ (jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */
+ }
+ else {
+ /* serial mode: Hsync period = 3*Width_Pixel */
+ pclk = val * (jzfb.w*3 + jzfb.hsw + jzfb.elw + jzfb.blw) *
+ (jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */
+ }
+
+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) ||
+ ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL))
+ pclk = (pclk * 3);
+
+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) ||
+ ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) ||
+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
+ pclk = pclk >> ((jzfb.cfg & STN_DAT_PINMASK) >> 4);
+
+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
+ pclk >>= 1;
+#if defined(CONFIG_SOC_JZ4730)
+ val = __cpm_get_pllout() / pclk;
+ REG_CPM_CFCR2 = val - 1;
+ val = __cpm_get_pllout() / (pclk * 4);
+ val = __cpm_divisor_encode(val);
+ __cpm_set_lcdclk_div(val);
+ REG_CPM_CFCR |= CPM_CFCR_UPE;
+#elif defined(CONFIG_SOC_JZ4740)
+ val = ( __cpm_get_pllout2()) / pclk;
+ val--;
+ if ( val > 0x3ff ) {
+ printk("pixel clock divid is too large, set it to 0x3ff\n");
+ val = 0x3ff;
+ }
+ __cpm_set_pixdiv(val);
+
+ val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */
+ val =__cpm_get_pllout() / val;
+ if ( val > 0x1f ) {
+ printk("lcd clock divide is too large, set it to 0x1f\n");
+ val = 0x1f;
+ }
+ __cpm_set_ldiv( val );
+ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */
+
+#else
+ printk("drivers/video/Jzlcd.c, CONFIG_MIPS, please set chip type.\n");
+#endif /*#ifdef CONFIG_MIPS_JZ4730 */
+
+ jz_clocks.pixclk = __cpm_get_pixclk();
+ jz_clocks.lcdclk = __cpm_get_lcdclk();
+ printk("LCDC: PixClock:%d LcdClock:%d\n",
+ jz_clocks.pixclk, jz_clocks.lcdclk);
+
+ __cpm_start_lcd();
+ udelay(1000);
+ return ret;
+}
+
+static irqreturn_t lcd_interrupt_handler(int irq, void *dev_id)
+{
+ unsigned int state;
+
+ state = REG_LCD_STATE;
+
+ if (state & LCD_STATE_EOF) /* End of frame */
+ REG_LCD_STATE = state & ~LCD_STATE_EOF;
+
+ if (state & LCD_STATE_IFU0) {
+ dprintk("InFiFo0 underrun\n");
+ REG_LCD_STATE = state & ~LCD_STATE_IFU0;
+ }
+
+ if (state & LCD_STATE_OFU) { /* Out fifo underrun */
+ REG_LCD_STATE = state & ~LCD_STATE_OFU;
+ dprintk("Out FiFo underrun.\n");
+ }
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * Suspend the LCDC.
+ */
+static int jzfb_suspend(void)
+{
+ __lcd_clr_ena(); /* Quick Disable */
+ __lcd_display_off();
+ __cpm_stop_lcd();
+
+ return 0;
+}
+
+/*
+ * Resume the LCDC.
+ */
+#ifdef CONFIG_SOC_JZ4730
+static int jzfb_resume(void)
+{
+ __cpm_start_lcd();
+
+ __lcd_display_pin_init();
+
+ __lcd_display_on();
+
+ lcd_hw_init();
+
+ if (jzfb.bpp <= 8)
+ REG_LCD_DA0 = virt_to_phys(lcd_palette_desc);
+ else
+ REG_LCD_DA0 = virt_to_phys(lcd_frame_desc0);
+
+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
+ REG_LCD_DA1 = virt_to_phys(lcd_frame_desc1);
+
+ __lcd_set_ena();
+ return 0;
+}
+
+#else
+/*
+ * Resume the LCDC.
+ */
+static int jzfb_resume(void)
+{
+ __cpm_start_lcd();
+ __gpio_set_pin(GPIO_DISP_OFF_N);
+ __lcd_special_on();
+ __lcd_set_ena();
+ mdelay(200);
+ __lcd_set_backlight_level(80);
+
+ return 0;
+}
+#endif /* CONFIG_MIPS_JZ4730 */
+
+/*
+ * Power management hook. Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int jzlcd_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
+{
+ int ret;
+ struct lcd_cfb_info *cfb = pm_dev->data;
+
+ if (!cfb) return -EINVAL;
+
+ switch (req) {
+ case PM_SUSPEND:
+ ret = jzfb_suspend();
+ break;
+
+ case PM_RESUME:
+ ret = jzfb_resume();
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+#else
+#define jzfb_suspend NULL
+#define jzfb_resume NULL
+#endif /* CONFIG_PM */
+
+static int __init jzfb_init(void)
+{
+ struct lcd_cfb_info *cfb;
+ int err = 0;
+
+ /* In special mode, we only need init special pin,
+ * as general lcd pin has init in uboot */
+#if defined(CONFIG_SOC_JZ4740) || defined(CONFIG_SOC_JZ4750)
+ switch (jzfb.cfg & MODE_MASK) {
+ case LCD_CFG_MODE_SPECIAL_TFT_1:
+ case LCD_CFG_MODE_SPECIAL_TFT_2:
+ case LCD_CFG_MODE_SPECIAL_TFT_3:
+ __gpio_as_lcd_special();
+ break;
+ default:
+ ;
+ }
+#endif
+ __lcd_display_pin_init();
+
+ cfb = jzfb_alloc_fb_info();
+ if (!cfb)
+ goto failed;
+
+ err = jzfb_map_smem(cfb);
+ if (err)
+ goto failed;
+
+ jzfb_set_var(&cfb->fb.var, -1, &cfb->fb);
+
+ lcd_descriptor_init();
+
+ err = lcd_hw_init();
+ if (err)
+ goto failed;
+
+ if (jzfb.bpp <= 8)
+ REG_LCD_DA0 = virt_to_phys(lcd_palette_desc);
+ else
+ REG_LCD_DA0 = virt_to_phys(lcd_frame_desc0);
+
+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
+ REG_LCD_DA1 = virt_to_phys(lcd_frame_desc1);
+
+ __lcd_set_ena();
+
+ if (request_irq(IRQ_LCD, lcd_interrupt_handler, IRQF_DISABLED,
+ "lcd", 0)) {
+ err = -EBUSY;
+ goto failed;
+ }
+
+ __lcd_enable_ofu_intr(); /* enable OutFifo underrun */
+// __lcd_enable_ifu0_intr(); /* needn't enable InFifo underrun */
+
+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)
+ jzfb_rotate_change(rotate_angle);
+ /* sleep n??? */
+#endif
+ err = register_framebuffer(&cfb->fb);
+ if (err < 0) {
+ dprintk("jzfb_init(): register framebuffer err.\n");
+ goto failed;
+ }
+
+ printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+ cfb->fb.node, cfb->fb.fix.id, cfb->fb.fix.smem_len>>10);
+
+#ifdef CONFIG_PM
+ /*
+ * Note that the console registers this as well, but we want to
+ * power down the display prior to sleeping.
+ */
+ cfb->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, jzlcd_pm_callback);
+ if (cfb->pm)
+ cfb->pm->data = cfb;
+#endif
+
+ __lcd_display_on();
+
+ return 0;
+
+failed:
+ jzfb_unmap_smem(cfb);
+ jzfb_free_fb_info(cfb);
+
+ return err;
+}
+
+#if 0
+static int jzfb_remove(struct device *dev)
+{
+ struct lcd_cfb_info *cfb = dev_get_drvdata(dev);
+ jzfb_unmap_smem(cfb);
+ jzfb_free_fb_info(cfb);
+ return 0;
+}
+#endif
+
+#if 0
+static struct device_driver jzfb_driver = {
+ .name = "jz-lcd",
+ .bus = &platform_bus_type,
+ .probe = jzfb_probe,
+ .remove = jzfb_remove,
+ .suspend = jzfb_suspend,
+ .resume = jzfb_resume,
+};
+#endif
+
+static void __exit jzfb_cleanup(void)
+{
+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)
+ kthread_stop(jzlcd_info->rotate_daemon_thread);
+#endif
+// driver_unregister(&jzfb_driver);
+// jzfb_remove();
+}
+
+module_init(jzfb_init);
+module_exit(jzfb_cleanup);
+
+MODULE_DESCRIPTION("JzSOC LCD Controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/jzlcd.h b/drivers/video/jzlcd.h
new file mode 100644
index 00000000000..3676b9bc66c
--- /dev/null
+++ b/drivers/video/jzlcd.h
@@ -0,0 +1,791 @@
+/*
+ * linux/drivers/video/jzlcd.h -- Ingenic On-Chip LCD frame buffer device
+ *
+ * Copyright (C) 2005-2007, Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef __JZLCD_H__
+#define __JZLCD_H__
+
+#include <asm/io.h>
+
+#define NR_PALETTE 256
+
+struct lcd_desc{
+ unsigned int next_desc; /* LCDDAx */
+ unsigned int databuf; /* LCDSAx */
+ unsigned int frame_id; /* LCDFIDx */
+ unsigned int cmd; /* LCDCMDx */
+};
+
+#define MODE_MASK 0x0f
+#define MODE_TFT_GEN 0x00
+#define MODE_TFT_SHARP 0x01
+#define MODE_TFT_CASIO 0x02
+#define MODE_TFT_SAMSUNG 0x03
+#define MODE_CCIR656_NONINT 0x04
+#define MODE_CCIR656_INT 0x05
+#define MODE_STN_COLOR_SINGLE 0x08
+#define MODE_STN_MONO_SINGLE 0x09
+#define MODE_STN_COLOR_DUAL 0x0a
+#define MODE_STN_MONO_DUAL 0x0b
+#define MODE_8BIT_SERIAL_TFT 0x0c
+
+#define MODE_TFT_18BIT (1<<7)
+
+#define STN_DAT_PIN1 (0x00 << 4)
+#define STN_DAT_PIN2 (0x01 << 4)
+#define STN_DAT_PIN4 (0x02 << 4)
+#define STN_DAT_PIN8 (0x03 << 4)
+#define STN_DAT_PINMASK STN_DAT_PIN8
+
+#define STFT_PSHI (1 << 15)
+#define STFT_CLSHI (1 << 14)
+#define STFT_SPLHI (1 << 13)
+#define STFT_REVHI (1 << 12)
+
+#define SYNC_MASTER (0 << 16)
+#define SYNC_SLAVE (1 << 16)
+
+#define DE_P (0 << 9)
+#define DE_N (1 << 9)
+
+#define PCLK_P (0 << 10)
+#define PCLK_N (1 << 10)
+
+#define HSYNC_P (0 << 11)
+#define HSYNC_N (1 << 11)
+
+#define VSYNC_P (0 << 8)
+#define VSYNC_N (1 << 8)
+
+#define DATA_NORMAL (0 << 17)
+#define DATA_INVERSE (1 << 17)
+
+
+/* Jz LCDFB supported I/O controls. */
+#define FBIOSETBACKLIGHT 0x4688
+#define FBIODISPON 0x4689
+#define FBIODISPOFF 0x468a
+#define FBIORESET 0x468b
+#define FBIOPRINT_REGS 0x468c
+#define FBIOGETBUFADDRS 0x468d
+#define FBIOROTATE 0x46a0 /* rotated fb */
+
+struct jz_lcd_buffer_addrs_t {
+ int fb_num;
+ unsigned int lcd_desc_phys_addr;
+ unsigned int fb_phys_addr[CONFIG_JZLCD_FRAMEBUFFER_MAX];
+};
+
+
+/*
+ * LCD panel specific definition
+ */
+#if defined(CONFIG_JZLCD_TRULY_TFTG320240DTSW)
+
+#if defined(CONFIG_JZ4730_PMP)
+#define LCD_RESET_PIN 63
+#endif
+
+#define __lcd_special_on() \
+do { \
+ __gpio_set_pin(LCD_RESET_PIN); \
+ __gpio_as_output(LCD_RESET_PIN); \
+ __gpio_clear_pin(LCD_RESET_PIN); \
+ udelay(100); \
+ __gpio_set_pin(LCD_RESET_PIN); \
+} while (0)
+
+#endif /* CONFIG_JZLCD_TRULY_TFTG320240DTSW */
+
+#if defined(CONFIG_JZLCD_SAMSUNG_LTV350QVF04)
+
+#if defined(CONFIG_JZ4730_FPRINT)
+#define PortSDI 60
+#define PortSCL 61
+#define PortCS 62
+#define PortRST 63
+#define PortSht 64
+#endif
+
+#if defined(CONFIG_JZ4730_GPS)
+#define PortSDI 74
+#define PortSCL 72
+#define PortCS 73
+#define PortRST 60
+#define PortSht 59
+#endif
+
+#ifndef PortSDI
+#define PortSDI 0
+#endif
+#ifndef PortSCL
+#define PortSCL 0
+#endif
+#ifndef PortCS
+#define PortCS 0
+#endif
+#ifndef PortRST
+#define PortRST 0
+#endif
+#ifndef PortSht
+#define PortSht 0
+#endif
+
+#define __lcd_special_pin_init() \
+do { \
+ __gpio_as_output(PortSDI); /* SDI */\
+ __gpio_as_output(PortSCL); /* SCL */ \
+ __gpio_as_output(PortCS); /* CS */ \
+ __gpio_as_output(PortRST); /* Reset */ \
+ __gpio_as_output(PortSht); /* Shut Down # */ \
+ __gpio_set_pin(PortCS); \
+ __gpio_set_pin(PortSCL); \
+ __gpio_set_pin(PortSDI); \
+} while (0)
+
+#define __spi_out(val) \
+do { \
+ int __i__; \
+ unsigned int _t_ = (val); \
+ __gpio_clear_pin(PortCS); \
+ udelay(25); \
+ for (__i__ = 0; __i__ < 24; __i__++ ) { \
+ __gpio_clear_pin(PortSCL); \
+ if (_t_ & 0x800000) \
+ __gpio_set_pin(PortSDI); \
+ else \
+ __gpio_clear_pin(PortSDI); \
+ _t_ <<= 1; \
+ udelay(25); \
+ __gpio_set_pin(PortSCL); \
+ udelay(25); \
+ } \
+ __gpio_set_pin(PortCS); \
+ udelay(25); \
+ __gpio_set_pin(PortSDI); \
+ udelay(25); \
+ __gpio_set_pin(PortSCL); \
+} while (0)
+
+#define __spi_id_op_data(rs, rw, val) \
+ __spi_out((0x1d<<18)|((rs)<<17)|((rw)<<16)|(val))
+
+#define __spi_write_reg(reg, val) \
+do { \
+ __spi_id_op_data(0, 0, (reg)); \
+ __spi_id_op_data(1, 0, (val)); \
+} while (0)
+
+#define __lcd_special_on() \
+do { \
+ __gpio_set_pin(PortSht); \
+ __gpio_clear_pin(PortRST); \
+ mdelay(10); \
+ __gpio_set_pin(PortRST); \
+ mdelay(1); \
+ __spi_write_reg(0x09, 0); \
+ mdelay(10); \
+ __spi_write_reg(0x09, 0x4000); \
+ __spi_write_reg(0x0a, 0x2000); \
+ mdelay(40); \
+ __spi_write_reg(0x09, 0x4055); \
+ mdelay(50); \
+ __spi_write_reg(0x01, 0x409d); \
+ __spi_write_reg(0x02, 0x0204); \
+ __spi_write_reg(0x03, 0x0100); \
+ __spi_write_reg(0x04, 0x3000); \
+ __spi_write_reg(0x05, 0x4003); \
+ __spi_write_reg(0x06, 0x000a); \
+ __spi_write_reg(0x07, 0x0021); \
+ __spi_write_reg(0x08, 0x0c00); \
+ __spi_write_reg(0x10, 0x0103); \
+ __spi_write_reg(0x11, 0x0301); \
+ __spi_write_reg(0x12, 0x1f0f); \
+ __spi_write_reg(0x13, 0x1f0f); \
+ __spi_write_reg(0x14, 0x0707); \
+ __spi_write_reg(0x15, 0x0307); \
+ __spi_write_reg(0x16, 0x0707); \
+ __spi_write_reg(0x17, 0x0000); \
+ __spi_write_reg(0x18, 0x0004); \
+ __spi_write_reg(0x19, 0x0000); \
+ mdelay(60); \
+ __spi_write_reg(0x09, 0x4a55); \
+ __spi_write_reg(0x05, 0x5003); \
+} while (0)
+
+#define __lcd_special_off() \
+do { \
+ __spi_write_reg(0x09, 0x4055); \
+ __spi_write_reg(0x05, 0x4003); \
+ __spi_write_reg(0x0a, 0x0000); \
+ mdelay(10); \
+ __spi_write_reg(0x09, 0x4000); \
+ __gpio_clear_pin(PortSht); \
+} while (0)
+
+#endif /* CONFIG_JZLCD_SAMSUNG_LTV350QVF04 */
+
+#if defined(CONFIG_JZLCD_AUO_A030FL01_V1)
+#if defined(CONFIG_JZ4740_PAVO) /* board pavo */
+ #define SPEN (32*1+18) /*LCD_CS*/
+ #define SPCK (32*1+17) /*LCD_SCL*/
+ #define SPDA (32*2+12) /*LCD_SDA*/
+ #define LCD_RET (32*2+23) /*use for lcd reset*/
+#elif defined(CONFIG_JZ4740_LYRA) /* board lyra */
+ #define SPEN (32*3+19) //LCD_CS
+ #define SPCK (32*3+18) //LCD_SCL
+ #define SPDA (32*3+20) //LCD_SDA
+ #define LCD_RET (32*3+31) //use for lcd reset
+#else
+#error "driver/video/Jzlcd.h, please define SPI pins on your board."
+#endif
+
+#define __spi_write_reg(reg, val) \
+ do { \
+ unsigned char no; \
+ unsigned short value; \
+ unsigned char a=0; \
+ unsigned char b=0; \
+ __gpio_as_output(SPEN); /* use SPDA */ \
+ __gpio_as_output(SPCK); /* use SPCK */ \
+ __gpio_as_output(SPDA); /* use SPDA */ \
+ a=reg; \
+ b=val; \
+ __gpio_set_pin(SPEN); \
+ __gpio_clear_pin(SPCK); \
+ udelay(50); \
+ __gpio_clear_pin(SPDA); \
+ __gpio_clear_pin(SPEN); \
+ udelay(50); \
+ value=((a<<8)|(b&0xFF)); \
+ for(no=0;no<16;no++) \
+ { \
+ if((value&0x8000)==0x8000){ \
+ __gpio_set_pin(SPDA);} \
+ else{ \
+ __gpio_clear_pin(SPDA); } \
+ udelay(400); \
+ __gpio_set_pin(SPCK); \
+ value=(value<<1); \
+ udelay(50); \
+ __gpio_clear_pin(SPCK); \
+ } \
+ __gpio_set_pin(SPEN); \
+ udelay(400); \
+ } while (0)
+#define __spi_read_reg(reg,val) \
+ do{ \
+ unsigned char no; \
+ unsigned short value; \
+ __gpio_as_output(SPEN); /* use SPDA */ \
+ __gpio_as_output(SPCK); /* use SPCK */ \
+ __gpio_as_output(SPDA); /* use SPDA */ \
+ value = ((reg << 0) | (1 << 7)); \
+ val = 0; \
+ __gpio_as_output(SPDA); \
+ __gpio_set_pin(SPEN); \
+ __gpio_set_pin(SPCK); \
+ udelay(1); \
+ __gpio_clear_pin(SPDA); \
+ __gpio_clear_pin(SPEN); \
+ udelay(1); \
+ for (no = 0; no < 16; no++ ) { \
+ __gpio_clear_pin(SPCK); \
+ udelay(1); \
+ if(no < 8) \
+ { \
+ if (value & 0x80) /* send data */ \
+ __gpio_set_pin(SPDA); \
+ else \
+ __gpio_clear_pin(SPDA); \
+ value = (value << 1); \
+ udelay(1); \
+ __gpio_set_pin(SPCK); \
+ udelay(1); \
+ } \
+ else \
+ { \
+ __gpio_as_input(SPDA); \
+ udelay(1); \
+ __gpio_set_pin(SPCK); \
+ udelay(1); \
+ val = (val << 1); \
+ val |= __gpio_get_pin(SPDA); \
+ udelay(1); \
+ } \
+ udelay(400); \
+ } \
+ __gpio_as_output(SPDA); \
+ __gpio_set_pin(SPEN); \
+ udelay(400); \
+ } while(0)
+
+#define __lcd_special_pin_init() \
+ do { \
+ __gpio_as_output(SPEN); /* use SPDA */ \
+ __gpio_as_output(SPCK); /* use SPCK */ \
+ __gpio_as_output(SPDA); /* use SPDA */ \
+ __gpio_as_output(LCD_RET); \
+ udelay(50); \
+ __gpio_clear_pin(LCD_RET); \
+ udelay(100); \
+ __gpio_set_pin(LCD_RET); \
+ } while (0)
+#define __lcd_special_on() \
+ do { \
+ udelay(50); \
+ __gpio_clear_pin(LCD_RET); \
+ udelay(100); \
+ __gpio_set_pin(LCD_RET); \
+ __spi_write_reg(0x0D, 0x44); \
+ __spi_write_reg(0x0D, 0x4D); \
+ __spi_write_reg(0x0B, 0x06); \
+ __spi_write_reg(0x40, 0xC0); \
+ __spi_write_reg(0x42, 0x43); \
+ __spi_write_reg(0x44, 0x28); \
+ __spi_write_reg(0x0D, 0x4F); \
+} while (0)
+
+ #define __lcd_special_off() \
+ do { \
+ __spi_write_reg(0x04, 0x4C); \
+ } while (0)
+
+#endif /* CONFIG_JZLCD_AUO_A030FL01_V1 */
+
+//#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01)
+#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) || defined(CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL)
+
+#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) /* board pmp */
+#define MODE 0xcd /* 24bit parellel RGB */
+#endif
+#if defined(CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL)
+#define MODE 0xc9 /* 8bit serial RGB */
+#endif
+
+#if defined(CONFIG_JZ4730_PMP)
+ #define SPEN 60 //LCD_SPL
+ #define SPCK 61 //LCD_CLS
+ #define SPDA 62 //LCD_PS
+ #define LCD_RET 63 //LCD_REV //use for lcd reset
+#elif defined(CONFIG_JZ4740_LEO) /* board leo */
+ #define SPEN (32*1+18) //LCD_SPL
+ #define SPCK (32*1+17) //LCD_CLS
+ #define SPDA (32*2+22) //LCD_PS
+ #define LCD_RET (32*2+23) //LCD_REV //use for lcd reset
+#elif defined(CONFIG_JZ4740_PAVO) /* board pavo */
+ #define SPEN (32*1+18) //LCD_SPL
+ #define SPCK (32*1+17) //LCD_CLS
+ #define SPDA (32*2+12) //LCD_D12
+ #define LCD_RET (32*2+23) //LCD_REV, GPC23
+#if 0 /*old driver*/
+ #define SPEN (32*1+18) //LCD_SPL
+ #define SPCK (32*1+17) //LCD_CLS
+ #define SPDA (32*2+12) //LCD_D12
+ #define LCD_RET (32*3+27) //PWM4 //use for lcd reset
+#endif
+#else
+#error "driver/video/Jzlcd.h, please define SPI pins on your board."
+#endif
+
+ #define __spi_write_reg1(reg, val) \
+ do { \
+ unsigned char no;\
+ unsigned short value;\
+ unsigned char a=0;\
+ unsigned char b=0;\
+ a=reg;\
+ b=val;\
+ __gpio_set_pin(SPEN);\
+ __gpio_set_pin(SPCK);\
+ __gpio_clear_pin(SPDA);\
+ __gpio_clear_pin(SPEN);\
+ udelay(25);\
+ value=((a<<8)|(b&0xFF));\
+ for(no=0;no<16;no++)\
+ {\
+ __gpio_clear_pin(SPCK);\
+ if((value&0x8000)==0x8000)\
+ __gpio_set_pin(SPDA);\
+ else\
+ __gpio_clear_pin(SPDA);\
+ udelay(25);\
+ __gpio_set_pin(SPCK);\
+ value=(value<<1); \
+ udelay(25);\
+ }\
+ __gpio_set_pin(SPEN);\
+ udelay(100);\
+ } while (0)
+
+ #define __spi_write_reg(reg, val) \
+ do {\
+ __spi_write_reg1((reg<<2|2), val); \
+ udelay(100); \
+ }while(0)
+
+ #define __lcd_special_pin_init() \
+ do { \
+ __gpio_as_output(SPEN); /* use SPDA */\
+ __gpio_as_output(SPCK); /* use SPCK */\
+ __gpio_as_output(SPDA); /* use SPDA */\
+ __gpio_as_output(LCD_RET);\
+ udelay(50);\
+ __gpio_clear_pin(LCD_RET);\
+ mdelay(150);\
+ __gpio_set_pin(LCD_RET);\
+ } while (0)
+
+ #define __lcd_special_on() \
+ do { \
+ udelay(50);\
+ __gpio_clear_pin(LCD_RET);\
+ mdelay(150);\
+ __gpio_set_pin(LCD_RET);\
+ mdelay(10);\
+ __spi_write_reg(0x00, 0x03); \
+ __spi_write_reg(0x01, 0x40); \
+ __spi_write_reg(0x02, 0x11); \
+ __spi_write_reg(0x03, MODE); /* mode */ \
+ __spi_write_reg(0x04, 0x32); \
+ __spi_write_reg(0x05, 0x0e); \
+ __spi_write_reg(0x07, 0x03); \
+ __spi_write_reg(0x08, 0x08); \
+ __spi_write_reg(0x09, 0x32); \
+ __spi_write_reg(0x0A, 0x88); \
+ __spi_write_reg(0x0B, 0xc6); \
+ __spi_write_reg(0x0C, 0x20); \
+ __spi_write_reg(0x0D, 0x20); \
+ } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level
+
+/* __spi_write_reg(0x02, 0x03); \
+ __spi_write_reg(0x06, 0x40); \
+ __spi_write_reg(0x0a, 0x11); \
+ __spi_write_reg(0x0e, 0xcd); \
+ __spi_write_reg(0x12, 0x32); \
+ __spi_write_reg(0x16, 0x0e); \
+ __spi_write_reg(0x1e, 0x03); \
+ __spi_write_reg(0x22, 0x08); \
+ __spi_write_reg(0x26, 0x40); \
+ __spi_write_reg(0x2a, 0x88); \
+ __spi_write_reg(0x2e, 0x88); \
+ __spi_write_reg(0x32, 0x20); \
+ __spi_write_reg(0x36, 0x20); \
+*/
+// } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level
+
+ #define __lcd_special_off() \
+ do { \
+ __spi_write_reg(0x00, 0x03); \
+ } while (0)
+
+#endif /* CONFIG_JZLCD_FOXCONN_PT035TN01 or CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL */
+
+
+#ifndef __lcd_special_pin_init
+#define __lcd_special_pin_init()
+#endif
+#ifndef __lcd_special_on
+#define __lcd_special_on()
+#endif
+#ifndef __lcd_special_off
+#define __lcd_special_off()
+#endif
+
+
+/*
+ * Platform specific definition
+ */
+
+#if defined(CONFIG_JZ4730_GPS)
+
+#define __lcd_set_backlight_level(n) \
+do { \
+ ; \
+} while (0)
+
+#define __lcd_display_pin_init() \
+do { \
+ __lcd_special_pin_init(); \
+ __gpio_as_output(94); /* PWM0 pin */ \
+ __gpio_as_output(95); /* PWM1 pin */ \
+} while (0)
+
+#define __lcd_display_on() \
+do { \
+ __lcd_special_on(); \
+ __gpio_set_pin(94); /* PWM0 pin */ \
+ __gpio_set_pin(95); /* PWM1 pin */ \
+ __lcd_set_backlight_level(8); \
+} while (0)
+
+#define __lcd_display_off() \
+do { \
+ __lcd_special_off(); \
+} while (0)
+
+#endif /* CONFIG_JZ4730_GPS */
+
+#if defined(CONFIG_JZ4730_FPRINT)
+
+#define __lcd_set_backlight_level(n) \
+do { \
+ REG_PWM_DUT(0) = n; \
+ REG_PWM_PER(0) = 7; \
+ REG_PWM_CTR(0) = 0x81; \
+} while (0)
+
+#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01)
+
+#define __lcd_display_pin_init() \
+do { \
+ __lcd_special_pin_init();\
+ __gpio_as_pwm();\
+ __lcd_set_backlight_level(8);\
+} while (0)
+
+#define __lcd_display_on() \
+do { \
+ __lcd_set_backlight_level(8); \
+ __lcd_special_on();\
+} while (0)
+
+#define __lcd_display_off() \
+do { \
+ __lcd_set_backlight_level(0); \
+ __lcd_special_off();\
+} while (0)
+
+#else
+
+#define __lcd_display_pin_init() \
+do { \
+ __gpio_as_output(GPIO_DISP_OFF_N); \
+ __gpio_as_pwm(); \
+ __lcd_set_backlight_level(8); \
+} while (0)
+
+#define __lcd_display_on() \
+do { \
+ __lcd_set_backlight_level(8); \
+ __gpio_set_pin(GPIO_DISP_OFF_N); \
+} while (0)
+
+#define __lcd_display_off() \
+do { \
+ __lcd_set_backlight_level(0); \
+ __gpio_clear_pin(GPIO_DISP_OFF_N); \
+} while (0)
+#endif
+
+#endif /* CONFIG_JZ4730_FPRINT */
+
+#if defined(CONFIG_JZ4730_LIBRA)
+
+#define __lcd_set_backlight_level(n) \
+do { \
+} while (0)
+
+#define __lcd_display_pin_init() \
+do { \
+ __lcd_special_pin_init(); \
+ __gpio_clear_pin(100); \
+ __gpio_as_output(100); \
+ __gpio_as_output(94); \
+ __gpio_as_output(95); \
+ __lcd_set_backlight_level(8); \
+} while (0)
+
+#define __lcd_display_on() \
+do { \
+ __lcd_special_on(); \
+ __gpio_set_pin(100); \
+ __gpio_set_pin(94); \
+ __gpio_set_pin(95); \
+} while (0)
+
+#define __lcd_display_off() \
+do { \
+ __lcd_special_off(); \
+ __gpio_clear_pin(100); \
+ __gpio_clear_pin(94); \
+ __gpio_clear_pin(95); \
+} while (0)
+
+#endif /* CONFIG_JZ4730_LIBRA */
+
+#if defined(CONFIG_JZ4730_PMP)
+
+#define __lcd_set_backlight_level(n) \
+do { \
+ REG_PWM_DUT(0) = n; \
+ REG_PWM_PER(0) = 7; \
+ REG_PWM_CTR(0) = 0x81; \
+} while (0)
+
+#define __lcd_display_pin_init() \
+do { \
+ __gpio_as_output(GPIO_DISP_OFF_N); \
+ __gpio_as_pwm(); \
+ __lcd_set_backlight_level(10); \
+ __lcd_special_pin_init(); \
+} while (0)
+
+#define __lcd_display_on() \
+do { \
+ __lcd_special_on(); \
+ __lcd_set_backlight_level(8); \
+ __gpio_set_pin(GPIO_DISP_OFF_N); \
+} while (0)
+
+#define __lcd_display_off() \
+do { \
+ __lcd_special_off(); \
+ __lcd_set_backlight_level(0); \
+ __gpio_clear_pin(GPIO_DISP_OFF_N); \
+} while (0)
+
+#endif /* CONFIG_JZ4730_PMP */
+
+/*#if defined(CONFIG_JZ4740_LEO) || defined(CONFIG_JZ4740_PAVO)*/
+#if defined(CONFIG_SOC_JZ4740)
+#if defined(CONFIG_JZ4740_PAVO) || defined(CONFIG_JZ4740_LYRA)
+#define GPIO_PWM 123 /* GP_D27 */
+#define PWM_CHN 4 /* pwm channel */
+#define PWM_FULL 101
+/* 100 level: 0,1,...,100 */
+#define __lcd_set_backlight_level(n)\
+do { \
+__gpio_as_output(32*3+27); \
+__gpio_set_pin(32*3+27); \
+} while (0)
+
+#define __lcd_close_backlight() \
+do { \
+__gpio_as_output(GPIO_PWM); \
+__gpio_clear_pin(GPIO_PWM); \
+} while (0)
+
+#elif defined(CONFIG_JZ4720_VIRGO)
+#define GPIO_PWM 119 /* GP_D23 */
+#define PWM_CHN 0 /* pwm channel */
+#define PWM_FULL 101
+/* 100 level: 0,1,...,100 */
+/*#define __lcd_set_backlight_level(n) \
+do { \
+ __gpio_as_pwm(0); \
+ __tcu_disable_pwm_output(PWM_CHN); \
+ __tcu_stop_counter(PWM_CHN); \
+ __tcu_init_pwm_output_high(PWM_CHN); \
+ __tcu_set_pwm_output_shutdown_abrupt(PWM_CHN); \
+ __tcu_select_clk_div1(PWM_CHN); \
+ __tcu_mask_full_match_irq(PWM_CHN); \
+ __tcu_mask_half_match_irq(PWM_CHN); \
+ __tcu_set_count(PWM_CHN,0); \
+ __tcu_set_full_data(PWM_CHN,__cpm_get_extalclk()/1000); \
+ __tcu_set_half_data(PWM_CHN,__cpm_get_extalclk()/1000*n/100); \
+ __tcu_enable_pwm_output(PWM_CHN); \
+ __tcu_select_extalclk(PWM_CHN); \
+ __tcu_start_counter(PWM_CHN); \
+} while (0)
+*/
+
+#define __lcd_set_backlight_level(n) \
+do { \
+ __gpio_as_output(GPIO_PWM); \
+ __gpio_set_pin(GPIO_PWM); \
+} while (0)
+
+#define __lcd_close_backlight() \
+do { \
+__gpio_as_output(GPIO_PWM); \
+__gpio_clear_pin(GPIO_PWM); \
+} while (0)
+
+#else
+#define __lcd_set_backlight_level(n)
+#define __lcd_close_backlight()
+
+#endif /* #if defined(CONFIG_MIPS_JZ4740_PAVO) */
+
+#define __lcd_display_pin_init() \
+do { \
+ __gpio_as_output(GPIO_DISP_OFF_N); \
+ __cpm_start_tcu(); \
+ __lcd_special_pin_init(); \
+} while (0)
+/* __lcd_set_backlight_level(100); \*/
+#define __lcd_display_on() \
+do { \
+ __gpio_set_pin(GPIO_DISP_OFF_N); \
+ __lcd_special_on(); \
+ __lcd_set_backlight_level(80); \
+} while (0)
+
+#define __lcd_display_off() \
+do { \
+ __lcd_special_off(); \
+ __lcd_close_backlight(); \
+ __gpio_clear_pin(GPIO_DISP_OFF_N); \
+} while (0)
+
+#endif /* CONFIG_MIPS_JZ4740_LEO */
+
+#if defined(CONFIG_JZLCD_MSTN_240x128)
+
+#if 0 /* The final version does not use software emulation of VCOM. */
+
+#define GPIO_VSYNC 59
+#define GPIO_VCOM 90
+
+#define REG_VCOM REG_GPIO_GPDR((GPIO_VCOM>>5))
+#define VCOM_BIT (1 << (GPIO_VCOM & 0x1f))
+static unsigned int vcom_static;
+static void vsync_irq(int irq, void *dev_id, struct pt_regs *reg)
+{
+ vcom_static = REG_VCOM;
+ vcom_static ^= VCOM_BIT;
+ REG_VCOM = vcom_static;
+}
+
+#define __lcd_display_pin_init() \
+ __gpio_as_irq_rise_edge(GPIO_VSYNC); \
+ __gpio_as_output(GPIO_VCOM); \
+ { \
+ static int inited = 0; \
+ if (!inited) { \
+ inited = 1; \
+ if (request_irq(IRQ_GPIO_0 + GPIO_VSYNC, vsync_irq, SA_INTERRUPT, \
+ "vsync", 0)) { \
+ err = -EBUSY; \
+ goto failed; \
+ }}}
+
+#endif
+
+/* We uses AC BIAs pin to generate VCOM signal, so above code should be removed.
+ */
+#endif
+/*****************************************************************************
+ * LCD display pin dummy macros
+ *****************************************************************************/
+#ifndef __lcd_display_pin_init
+#define __lcd_display_pin_init()
+#endif
+#ifndef __lcd_display_on
+#define __lcd_display_on()
+#endif
+#ifndef __lcd_display_off
+#define __lcd_display_off()
+#endif
+#ifndef __lcd_set_backlight_level
+#define __lcd_set_backlight_level(n)
+#endif
+
+#endif /* __JZLCD_H__ */
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index b1ccc04f3c9..da5beacad5a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -65,6 +65,15 @@ config WM8350_WATCHDOG
# ALPHA Architecture
# ARM Architecture
+
+config JZ_WDT
+ bool 'JzSoC On-Chip watchdog'
+ help
+ Watchdog timer embedded into JZSOC chips. This will reboot your
+ system when the timeout is reached.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jz_wdt.
config AT91RM9200_WATCHDOG
tristate "AT91RM9200 watchdog"
diff --git a/drivers/watchdog/jz_wdt.c b/drivers/watchdog/jz_wdt.c
new file mode 100644
index 00000000000..593bb87d6ce
--- /dev/null
+++ b/drivers/watchdog/jz_wdt.c
@@ -0,0 +1,203 @@
+/*
+ * linux/drivers/char/jz_wdt.c
+ *
+ * Watchdog driver for the Ingenic JzSOC
+ *
+ * Author: Wei Jianli <jlwei@ingenic.cn>
+ *
+ * 2005 (c) Ingenic Semiconductor. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+//#include <linux/config.h>
+#include <linux/autoconf.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/jzsoc.h>
+
+#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */
+
+static unsigned int timer_margin = TIMER_MARGIN; /* in seconds */
+static unsigned int timer_rate;
+static unsigned int pre_margin;
+static unsigned long jz_wdt_users = 0;
+
+#ifdef MODULE
+MODULE_PARM(timer_margin, "i");
+#endif
+
+static void
+jz_wdt_ping(void)
+{
+ printk("jz_wdt_ping\n");
+ /* reload counter with (new) margin */
+#ifdef CONFIG_SOC_JZ4730
+ pre_margin = 0xffffffff - timer_rate * timer_margin;
+ __wdt_set_count(pre_margin);
+#endif
+#ifdef CONFIG_SOC_JZ4740
+ pre_margin = timer_rate * timer_margin;
+ __wdt_set_count(0);
+ __wdt_set_data(pre_margin);
+#endif
+}
+
+/*
+ * Allow only one person to hold it open
+ */
+
+static int
+jz_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(1, &jz_wdt_users))
+ return -EBUSY;
+
+ printk("jz_wdt_open\n");
+#ifdef CONFIG_SOC_JZ4730
+ if (REG_CPM_OCR & CPM_OCR_EXT_RTC_CLK)
+ timer_rate = 32768;
+ else
+ timer_rate = JZ_EXTAL/128;
+#endif
+
+#ifdef CONFIG_SOC_JZ4740
+ /* Initialize the wdt clocks */
+ __wdt_select_rtcclk();
+ __wdt_select_clk_div1024();
+ __tcu_start_wdt_clock();
+ timer_rate = 32; /* 32768 / 1024 */
+#endif
+
+ jz_wdt_ping();
+ __wdt_start();
+
+ return 0;
+}
+
+static int
+jz_wdt_release(struct inode *inode, struct file *file)
+{
+ /*
+ * Shut off the timer.
+ * Lock it in if it's a module and we defined ...NOWAYOUT
+ */
+ jz_wdt_ping();
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ /* SW can't stop wdt once it was started */
+#endif
+ jz_wdt_users = 0;
+ return 0;
+}
+
+static ssize_t
+jz_wdt_write(struct file *file, const char *data, size_t len, loff_t * ppos)
+{
+ /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ printk("jz_wdt_write\n");
+
+ /* Refresh counter */
+ if (len) {
+ jz_wdt_ping();
+ return 1;
+ }
+ return 0;
+}
+
+static int
+jz_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int new_margin;
+ static struct watchdog_info ident = {
+ .identity = "JzSOC Watchdog",
+ .options = WDIOF_SETTIMEOUT,
+ .firmware_version = 0,
+ };
+
+ switch (cmd) {
+ default:
+ return -ENOIOCTLCMD;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info *) arg, &ident,
+ sizeof (ident));
+ case WDIOC_GETSTATUS:
+ return put_user(0, (int *) arg);
+ case WDIOC_GETBOOTSTATUS:
+#ifdef CONFIG_SOC_JZ4730
+ return put_user(REG_CPM_RSTR, (int *) arg);
+#endif
+#ifdef CONFIG_SOC_JZ4740
+ return put_user(REG_RTC_HWRSR, (int *) arg);
+#endif
+ case WDIOC_KEEPALIVE:
+ jz_wdt_ping();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_margin, (int *) arg))
+ return -EFAULT;
+ if (new_margin < 1)
+ return -EINVAL;
+ timer_margin = new_margin;
+ jz_wdt_ping();
+ /* Fall */
+ case WDIOC_GETTIMEOUT:
+ return put_user(timer_margin, (int *) arg);
+ }
+}
+
+static struct file_operations jz_wdt_fops = {
+ .owner = THIS_MODULE,
+ .write = jz_wdt_write,
+ .ioctl = jz_wdt_ioctl,
+ .open = jz_wdt_open,
+ .release = jz_wdt_release,
+};
+
+static struct miscdevice jz_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "jz_wdt",
+ .fops = &jz_wdt_fops
+};
+
+static int __init
+jz_wdt_init(void)
+{
+ int ret;
+
+ ret = misc_register(&jz_wdt_miscdev);
+
+ if (ret)
+ return ret;
+
+ printk("JzSOC Watchdog Timer: timer margin %d sec\n", timer_margin);
+
+ return 0;
+}
+
+static void __exit
+jz_wdt_exit(void)
+{
+ misc_deregister(&jz_wdt_miscdev);
+}
+
+module_init(jz_wdt_init);
+module_exit(jz_wdt_exit);
+
+MODULE_AUTHOR("Wei Jianli");
+MODULE_LICENSE("GPL");
diff --git a/fs/Kconfig b/fs/Kconfig
index 0e7da7bb5d9..6cbf3a1cf10 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -172,6 +172,8 @@ source "fs/hfsplus/Kconfig"
source "fs/befs/Kconfig"
source "fs/bfs/Kconfig"
source "fs/efs/Kconfig"
+
+
source "fs/jffs2/Kconfig"
# UBIFS File system configuration
source "fs/ubifs/Kconfig"
@@ -252,4 +254,7 @@ endif
source "fs/nls/Kconfig"
source "fs/dlm/Kconfig"
+# Patched by YAFFS
+source "fs/yaffs2/Kconfig"
+
endmenu
diff --git a/fs/Makefile b/fs/Makefile
index af6d04700d9..1bb220aa2d5 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -124,3 +124,7 @@ obj-$(CONFIG_OCFS2_FS) += ocfs2/
obj-$(CONFIG_BTRFS_FS) += btrfs/
obj-$(CONFIG_GFS2_FS) += gfs2/
obj-$(CONFIG_EXOFS_FS) += exofs/
+
+
+# Patched by YAFFS
+obj-$(CONFIG_YAFFS_FS) += yaffs2/
diff --git a/fs/mpage.c b/fs/mpage.c
index 42381bd6543..adbd0e80689 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -52,6 +52,17 @@ static void mpage_end_io_read(struct bio *bio, int err)
if (uptodate) {
SetPageUptodate(page);
+ /*
+ * It seems that there is a IO coherent bug in generic_file_mmap(),
+ * When __do_fault() calls vma->ops->falut(filemap_fault)->aops->readpage(),
+ * the PG_dcache_dirty is not set, so the page should be flushed (often with EXEC flags)
+ * will not be flushed in the update_mmu_cache().
+ *
+ * This causes some larger ELF files failing to execute with errors like illegal instruction...
+ *
+ * - River.
+ */
+ flush_dcache_page(page);
} else {
ClearPageUptodate(page);
SetPageError(page);
diff --git a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig
new file mode 100644
index 00000000000..8cf5e76f3ec
--- /dev/null
+++ b/fs/yaffs2/Kconfig
@@ -0,0 +1,167 @@
+#
+# YAFFS file system configurations
+#
+
+menu "Yaffs2 Filesystems"
+
+config YAFFS_FS
+ tristate "YAFFS2 file system support"
+ default n
+ depends on MTD
+ select YAFFS_YAFFS1
+ select YAFFS_YAFFS2
+ help
+ YAFFS2, or Yet Another Flash Filing System, is a filing system
+ optimised for NAND Flash chips.
+
+ To compile the YAFFS2 file system support as a module, choose M here:
+ the module will be called yaffs2.
+
+ If unsure, say N.
+
+ Further information on YAFFS2 is available at
+ <http://www.aleph1.co.uk/yaffs/>.
+
+config YAFFS_YAFFS1
+ bool "512 byte / page devices"
+ depends on YAFFS_FS
+ default y
+ help
+ Enable YAFFS1 support -- yaffs for 512 byte / page devices
+
+ If unsure, say Y.
+
+config YAFFS_DOES_ECC
+ bool "Lets Yaffs do its own ECC"
+ depends on YAFFS_FS && YAFFS_YAFFS1
+ default n
+ help
+ This enables Yaffs to use its own ECC functions instead of using
+ the ones from the generic MTD-NAND driver.
+
+ If unsure, say N.
+
+config YAFFS_ECC_WRONG_ORDER
+ bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
+ depends on YAFFS_FS && YAFFS_DOES_ECC
+ default n
+ help
+ This makes yaffs_ecc.c use the same ecc byte order as
+ Steven Hill's nand_ecc.c. If not set, then you get the
+ same ecc byte order as SmartMedia.
+
+ If unsure, say N.
+
+config YAFFS_YAFFS2
+ bool "2048 byte (or larger) / page devices"
+ depends on YAFFS_FS
+ default y
+ help
+ Enable YAFFS2 support -- yaffs for >= 2048 byte / page larger devices
+
+ If unsure, say Y.
+
+if SOC_JZ4730 || SOC_JZ4740
+
+choice
+ prompt "ECC type for oob area"
+ depends on YAFFS_YAFFS2
+ default CONFIG_YAFFS_ECC_RS
+ help
+ There are 16 bytes for yaffs2 information in oob which should be checked
+ using some type of ECC.
+
+config YAFFS_ECC_RS
+ bool "Use soft reed solomon ECC for oob area"
+ select REED_SOLOMON
+ select REED_SOLOMON_ENC8
+ select REED_SOLOMON_DEC8
+ help
+ The reed solomon ECC could correct 2 5-bit symbols for 16 bytes in oob.
+ It should be selected for MLC nand.
+
+config YAFFS_ECC_HAMMING
+ bool "Use hamming ECC for oob area"
+ help
+ The hamming ECC could only correct 1 bit for 16 bytes in oob, but it's
+ a bit faster than reed solomon ECC. It should be selected for SLC nand.
+
+endchoice
+
+endif
+
+config YAFFS_AUTO_YAFFS2
+ bool "Autoselect yaffs2 format"
+ depends on YAFFS_YAFFS2
+ default y
+ help
+ Without this, you need to explicitely use yaffs2 as the file
+ system type. With this, you can say "yaffs" and yaffs or yaffs2
+ will be used depending on the device page size.
+
+ If unsure, say Y.
+
+config YAFFS_DISABLE_LAZY_LOAD
+ bool "Disable lazy loading"
+ depends on YAFFS_YAFFS2
+ default n
+ help
+ "Lazy loading" defers loading file details until they are
+ required. This saves mount time, but makes the first look-up
+ a bit longer.
+
+ Lazy loading will only happen if enabled by this option being 'n'
+ and if the appropriate tags are available, else yaffs2 will
+ automatically fall back to immediate loading and do the right
+ thing.
+
+ Lazy laoding will be required by checkpointing.
+
+ Setting this to 'y' will disable lazy loading.
+
+ If unsure, say N.
+
+config YAFFS_DISABLE_WIDE_TNODES
+ bool "Turn off wide tnodes"
+ depends on YAFFS_FS
+ default n
+ help
+ Wide tnodes are only used for large NAND arrays (>=32MB for
+ 512-byte page devices and >=128MB for 2k page devices). They use
+ slightly more RAM but are faster since they eliminate chunk group
+ searching.
+
+ Setting this to 'y' will force tnode width to 16 bits and make
+ large arrays slower.
+
+ If unsure, say N.
+
+config YAFFS_DISABLE_CHUNK_ERASED_CHECK
+ bool "Turn off debug chunk erase check"
+ depends on YAFFS_FS
+ default y
+ help
+ Enabling this turns off the test that chunks are erased in flash
+ before writing to them. This is safe, since the write verification
+ will fail. Suggest enabling the test (ie. say N)
+ during development to help debug things.
+
+ If unsure, say Y.
+
+config YAFFS_SHORT_NAMES_IN_RAM
+ bool "Cache short names in RAM"
+ depends on YAFFS_FS
+ default y
+ help
+ If this config is set, then short names are stored with the
+ yaffs_Object. This costs an extra 16 bytes of RAM per object,
+ but makes look-ups faster.
+
+ If unsure, say Y.
+
+config YAFFS_CHECKPOINT_RESERVED_BLOCKS
+ int 'Reserved blocks for checkpointing'
+ depends on YAFFS_FS
+ default 10
+
+endmenu
diff --git a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile
new file mode 100644
index 00000000000..bf7f54a6ee0
--- /dev/null
+++ b/fs/yaffs2/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the linux YAFFS2 filesystem routines.
+#
+
+obj-y := yaffs2.o
+obj-$(CONFIG_YAFFS_FS) := yaffs_mtdif.o yaffs_mtdif2.o
+obj-$(CONFIG_YAFFS_FS) += yaffs_ecc.o yaffs_fs.o yaffs_guts.o
+obj-$(CONFIG_YAFFS_FS) += yaffs_packedtags2.o yaffs_qsort.o
+obj-$(CONFIG_YAFFS_FS) += yaffs_tagscompat.o yaffs_tagsvalidity.o
+obj-$(CONFIG_YAFFS_FS) += yaffs_checkptrw.o yaffs_nand.o
diff --git a/fs/yaffs2/devextras.h b/fs/yaffs2/devextras.h
new file mode 100644
index 00000000000..9635c7a7381
--- /dev/null
+++ b/fs/yaffs2/devextras.h
@@ -0,0 +1,264 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * This file is just holds extra declarations used during development.
+ * Most of these are from kernel includes placed here so we can use them in
+ * applications.
+ *
+ */
+
+#ifndef __EXTRAS_H__
+#define __EXTRAS_H__
+
+#if defined WIN32
+#define __inline__ __inline
+#define new newHack
+#endif
+
+#if !(defined __KERNEL__) || (defined WIN32)
+
+/* User space defines */
+
+typedef unsigned char __u8;
+typedef unsigned short __u16;
+typedef unsigned __u32;
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+#define prefetch(x) 1
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static __inline__ void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static __inline__ void list_add_tail(struct list_head *new,
+ struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_del(struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static __inline__ void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static __inline__ void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static __inline__ int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static __inline__ void list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+
+ if (first != list) {
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, prefetch(pos->next))
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal
+ * of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/*
+ * File types
+ */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
+#ifndef WIN32
+#include <sys/stat.h>
+#endif
+
+/*
+ * Attribute flags. These should be or-ed together to figure out what
+ * has been changed!
+ */
+#define ATTR_MODE 1
+#define ATTR_UID 2
+#define ATTR_GID 4
+#define ATTR_SIZE 8
+#define ATTR_ATIME 16
+#define ATTR_MTIME 32
+#define ATTR_CTIME 64
+#define ATTR_ATIME_SET 128
+#define ATTR_MTIME_SET 256
+#define ATTR_FORCE 512 /* Not a change, but a change it */
+#define ATTR_ATTR_FLAG 1024
+
+struct iattr {
+ unsigned int ia_valid;
+ unsigned ia_mode;
+ unsigned ia_uid;
+ unsigned ia_gid;
+ unsigned ia_size;
+ unsigned ia_atime;
+ unsigned ia_mtime;
+ unsigned ia_ctime;
+ unsigned int ia_attr_flags;
+};
+
+#define KERN_DEBUG
+
+#else
+
+#ifndef WIN32
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#endif
+
+#endif
+
+#if defined WIN32
+#undef new
+#endif
+
+#endif
diff --git a/fs/yaffs2/moduleconfig.h b/fs/yaffs2/moduleconfig.h
new file mode 100644
index 00000000000..b51a1501088
--- /dev/null
+++ b/fs/yaffs2/moduleconfig.h
@@ -0,0 +1,51 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Martin Fouts <Martin.Fouts@palmsource.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_CONFIG_H__
+#define __YAFFS_CONFIG_H__
+
+#ifdef YAFFS_OUT_OF_TREE
+
+/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */
+#define CONFIG_YAFFS_FS
+#define CONFIG_YAFFS_YAFFS1
+#define CONFIG_YAFFS_YAFFS2
+
+/* These options are independent of each other. Select those that matter. */
+
+/* Default: Not selected */
+/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
+//#define CONFIG_YAFFS_DOES_ECC
+
+/* Default: Not selected */
+/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
+/* CONFIG_YAFFS_DOES_ECC is set */
+//#define CONFIG_YAFFS_ECC_WRONG_ORDER
+
+/* Default: Selected */
+/* Meaning: Disables testing whether chunks are erased before writing to them*/
+#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
+
+/* Default: Selected */
+/* Meaning: Cache short names, taking more RAM, but faster look-ups */
+#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+
+/* Default: 10 */
+/* Meaning: set the count of blocks to reserve for checkpointing */
+#define YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
+
+#endif /* YAFFS_OUT_OF_TREE */
+
+#endif /* __YAFFS_CONFIG_H__ */
diff --git a/fs/yaffs2/utils/Makefile b/fs/yaffs2/utils/Makefile
new file mode 100644
index 00000000000..008f18914f5
--- /dev/null
+++ b/fs/yaffs2/utils/Makefile
@@ -0,0 +1,73 @@
+#Makefile for mkyaffs
+#
+# NB this is not yet suitable for putting into the kernel tree.
+# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
+#
+# Copyright (C) 2002 Aleph One Ltd.
+# for Toby Churchill Ltd and Brightstar Engineering
+#
+# Created by Charles Manning <charles@aleph1.co.uk>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+
+## Change or override KERNELDIR to your kernel
+#KERNELDIR = /usr/src/kernel-headers-2.4.18
+#CFLAGS = -I$(KERNELDIR)/include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL
+
+include ../../../.config
+
+CFLAGS = -I../../../include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL
+CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations
+CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline
+
+ifeq ($(CONFIG_YAFFS_ECC_RS), y)
+CFLAGS+= -DCONFIG_YAFFS_ECC_RS
+endif
+
+ifeq ($(CONFIG_YAFFS_ECC_HAMMING), y)
+CFLAGS+= -DCONFIG_YAFFS_ECC_HAMMING
+endif
+
+ifeq ($(CONFIG_MTD_HW_BCH_ECC), y)
+CFLAGS+= -DCONFIG_MTD_HW_BCH_ECC
+endif
+
+
+## Change if you are using a cross-compiler
+MAKETOOLS = #mipsel-linux-
+
+CC=$(MAKETOOLS)gcc
+
+COMMONLINKS = yaffs_ecc.c
+COMMONOBJS = $(COMMONLINKS:.c=.o)
+
+ifeq ($(CONFIG_YAFFS_ECC_RS), y)
+COMMONOBJS += ssfdc_rs_ecc.o
+endif
+
+MKYAFFSSOURCES = mkyaffsimage.c
+MKYAFFSIMAGEOBJS = $(MKYAFFSSOURCES:.c=.o)
+
+MKYAFFS2SOURCES = mkyaffs2image.c
+MKYAFFS2LINKS = yaffs_packedtags2.c yaffs_tagsvalidity.c
+MKYAFFS2IMAGEOBJS = $(MKYAFFS2SOURCES:.c=.o) $(MKYAFFS2LINKS:.c=.o)
+
+all: mkyaffsimage mkyaffs2image
+
+$(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS):
+ ln -s ../$@ $@
+
+$(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) : %.o: %.c
+ $(CC) -c $(CFLAGS) $< -o $@
+
+mkyaffsimage: $(COMMONOBJS) $(MKYAFFSIMAGEOBJS)
+ $(CC) -o $@ $(COMMONOBJS) $(MKYAFFSIMAGEOBJS)
+
+mkyaffs2image: $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS)
+ $(CC) -o $@ $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS)
+
+
+clean:
+ rm -f $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) $(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS) mkyaffsimage mkyaffs2image core
diff --git a/fs/yaffs2/utils/README b/fs/yaffs2/utils/README
new file mode 100644
index 00000000000..317452bcf6c
--- /dev/null
+++ b/fs/yaffs2/utils/README
@@ -0,0 +1,11 @@
+This directory contains yaffs/yaffs2 tools to make the fs image.
+
+To build the tools, type 'make'.
+
+To make yaffs2 image, use next command:
+
+ $ mkyaffs2image 1 /myroot myroot.yaffs2
+
+To burn the yaffs2 image to the NAND, use next command:
+
+ $ nandwrite -a -o /dev/mtd0 myroot.yaffs2
diff --git a/fs/yaffs2/utils/mkyaffs2image.c b/fs/yaffs2/utils/mkyaffs2image.c
new file mode 100644
index 00000000000..857703355be
--- /dev/null
+++ b/fs/yaffs2/utils/mkyaffs2image.c
@@ -0,0 +1,794 @@
+/*
+ * YAFFS: Yet another FFS. A NAND-flash specific file system.
+ *
+ * makeyaffsimage.c
+ *
+ * Makes a YAFFS file system image that can be used to load up a file system.
+ *
+ * Copyright (C) 2002 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ * Nick Bane modifications flagged NCB
+ *
+ * Endian handling patches by James Ng.
+ *
+ * mkyaffs2image hacks by NCB
+ *
+ * Changes by Sergey Kubushin flagged KSI
+ *
+ */
+
+/* KSI:
+ * All this nightmare should be rewritten from ground up. Why save return
+ * values if nobody checks them? The read/write function returns only one
+ * error, -1. Positive return value does NOT mean read/write operation has
+ * been completed successfully. If somebody opens files, he MUST close them
+ * when they are not longer needed. Only those brave enough can write 64
+ * bytes from a yaffs_PackedTags2 structure. The list is too long, there is
+ * enough bugs here to write a couple of thick books on how NOT to write
+ * programs...
+ *
+ * And BTW, what was one supposed to do with that file that this horror
+ * occasionally managed to generate?
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <string.h>
+#include <unistd.h>
+#include <mtd/mtd-user.h>
+#include "yaffs_ecc.h"
+#include "yaffs_guts.h"
+
+#include "yaffs_packedtags2.h"
+
+unsigned yaffs_traceMask=0;
+
+#define MAX_OBJECTS 100000
+#define MAX_CHUNKSIZE 8192
+#define MAX_SPARESIZE 256
+
+#define PT2_BYTES 25
+
+const char * mkyaffsimage_c_version = "$Id: mkyaffs2image.c,v 1.1.1.1 2008-10-29 14:29:21 lhhuang Exp $";
+
+static int chunkSize = 2048;
+static int spareSize = 64;
+static int layout_no;
+
+static struct nand_oobinfo oob_layout[] = {
+ /* KSI:
+ * Dummy "raw" layout - no ECC, all the bytes are free. Does NOT
+ * really work, only used for compatibility with CVS YAFFS2 that
+ * never ever worked with any stock MTD.
+ */
+ {
+ .useecc = MTD_NANDECC_AUTOPLACE,
+ .eccbytes = 0,
+ .eccpos = {},
+ .oobfree = { {0, 64} }
+ },
+ /* KSI:
+ * Regular MTD AUTOPLACED ECC for large page NAND devices, the
+ * only one existing in stock MTD so far. It corresponds to layout# 1
+ * in command line arguments. Any other layouts could be added to
+ * the list when they made their way in kernel's MTD. The structure
+ * is simply copied from kernel's drivers/mtd/nand/nand_base.c as-is.
+ */
+ /* For 2KB pagesize NAND devices */
+ {
+ .useecc = MTD_NANDECC_AUTOPLACE,
+ .eccbytes = 36,
+ .eccpos = {
+ 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63},
+ .oobfree = {{2, 26}}
+ },
+ /* For 4KB pagesize NAND devices */
+ {
+ .useecc = MTD_NANDECC_AUTOPLACE,
+ .eccbytes = 72,
+ .eccpos = {
+ 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 94, 95, 96, 97, 98, 99},
+ .oobfree = {
+ {2, 26},
+ {100, 28}}
+ },
+ /* For 4KB pagesize with 2 planes NAND devices */
+ {
+ .useecc = MTD_NANDECC_AUTOPLACE,
+ .eccbytes = 72,
+ .eccpos = {
+ 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 94, 95, 96, 97, 98, 99},
+ .oobfree = {
+ {2, 26},
+ {100, 28}}
+ },
+ /* End-of-list marker */
+ {
+ .useecc = -1,
+ }
+};
+
+typedef struct
+{
+ dev_t dev;
+ ino_t ino;
+ int obj;
+} objItem;
+
+
+static objItem obj_list[MAX_OBJECTS];
+static int n_obj = 0;
+static int obj_id = YAFFS_NOBJECT_BUCKETS + 1;
+
+static int nObjects = 0, nDirectories = 0, nPages = 0;
+
+static int outFile;
+
+static int error;
+
+static int convert_endian = 0;
+
+void nandmtd2_pt2buf(unsigned char *buf, yaffs_PackedTags2 *pt);
+void usage(void);
+void process_file(char *file_name);
+
+static int obj_compare(const void *a, const void * b)
+{
+ objItem *oa, *ob;
+
+ oa = (objItem *)a;
+ ob = (objItem *)b;
+
+ if(oa->dev < ob->dev) return -1;
+ if(oa->dev > ob->dev) return 1;
+ if(oa->ino < ob->ino) return -1;
+ if(oa->ino > ob->ino) return 1;
+
+ return 0;
+}
+
+
+static void add_obj_to_list(dev_t dev, ino_t ino, int obj)
+{
+ if(n_obj < MAX_OBJECTS)
+ {
+ obj_list[n_obj].dev = dev;
+ obj_list[n_obj].ino = ino;
+ obj_list[n_obj].obj = obj;
+ n_obj++;
+ qsort(obj_list,n_obj,sizeof(objItem),obj_compare);
+
+ }
+ else
+ {
+ // oops! not enough space in the object array
+ fprintf(stderr,"Not enough space in object array\n");
+ exit(2);
+ }
+}
+
+
+static int find_obj_in_list(dev_t dev, ino_t ino)
+{
+ objItem *i = NULL;
+ objItem test;
+
+ test.dev = dev;
+ test.ino = ino;
+
+ if(n_obj > 0)
+ {
+ i = bsearch(&test,obj_list,n_obj,sizeof(objItem),obj_compare);
+ }
+
+ if(i)
+ {
+ return i->obj;
+ }
+ return -1;
+}
+
+/* KSI:
+ * No big endian for now. This is left for a later time. The existing code
+ * is FUBAR.
+ */
+#if 0
+/* This little function converts a little endian tag to a big endian tag.
+ * NOTE: The tag is not usable after this other than calculating the CRC
+ * with.
+ */
+static void little_to_big_endian(yaffs_Tags *tagsPtr)
+{
+#if 0 // FIXME NCB
+ yaffs_TagsUnion * tags = (yaffs_TagsUnion* )tagsPtr; // Work in bytes.
+ yaffs_TagsUnion temp;
+
+ memset(&temp, 0, sizeof(temp));
+ // Ick, I hate magic numbers.
+ temp.asBytes[0] = ((tags->asBytes[2] & 0x0F) << 4) | ((tags->asBytes[1] & 0xF0) >> 4);
+ temp.asBytes[1] = ((tags->asBytes[1] & 0x0F) << 4) | ((tags->asBytes[0] & 0xF0) >> 4);
+ temp.asBytes[2] = ((tags->asBytes[0] & 0x0F) << 4) | ((tags->asBytes[2] & 0x30) >> 2) | ((tags->asBytes[3] & 0xC0) >> 6);
+ temp.asBytes[3] = ((tags->asBytes[3] & 0x3F) << 2) | ((tags->asBytes[2] & 0xC0) >> 6);
+ temp.asBytes[4] = ((tags->asBytes[6] & 0x03) << 6) | ((tags->asBytes[5] & 0xFC) >> 2);
+ temp.asBytes[5] = ((tags->asBytes[5] & 0x03) << 6) | ((tags->asBytes[4] & 0xFC) >> 2);
+ temp.asBytes[6] = ((tags->asBytes[4] & 0x03) << 6) | (tags->asBytes[7] & 0x3F);
+ temp.asBytes[7] = (tags->asBytes[6] & 0xFC) | ((tags->asBytes[7] & 0xC0) >> 6);
+
+ // Now copy it back.
+ tags->asBytes[0] = temp.asBytes[0];
+ tags->asBytes[1] = temp.asBytes[1];
+ tags->asBytes[2] = temp.asBytes[2];
+ tags->asBytes[3] = temp.asBytes[3];
+ tags->asBytes[4] = temp.asBytes[4];
+ tags->asBytes[5] = temp.asBytes[5];
+ tags->asBytes[6] = temp.asBytes[6];
+ tags->asBytes[7] = temp.asBytes[7];
+#endif
+}
+#endif
+
+void nandmtd2_pt2buf(unsigned char *buf, yaffs_PackedTags2 *pt)
+{
+ int i, j = 0, k, n;
+ unsigned char pt2_byte_buf[PT2_BYTES];
+
+ *((unsigned int *) &pt2_byte_buf[0]) = pt->t.sequenceNumber;
+ *((unsigned int *) &pt2_byte_buf[4]) = pt->t.objectId;
+ *((unsigned int *) &pt2_byte_buf[8]) = pt->t.chunkId;
+ *((unsigned int *) &pt2_byte_buf[12]) = pt->t.byteCount;
+ pt2_byte_buf[16] = pt->ecc.colParity;
+ pt2_byte_buf[17] = pt->ecc.lineParity & 0xff;
+ pt2_byte_buf[18] = (pt->ecc.lineParity >> 8) & 0xff;
+ pt2_byte_buf[19] = (pt->ecc.lineParity >> 16) & 0xff;
+ pt2_byte_buf[20] = (pt->ecc.lineParity >> 24) & 0xff;
+ pt2_byte_buf[21] = pt->ecc.lineParityPrime & 0xff;
+ pt2_byte_buf[22] = (pt->ecc.lineParityPrime >> 8) & 0xff;
+ pt2_byte_buf[23] = (pt->ecc.lineParityPrime >> 16) & 0xff;
+ pt2_byte_buf[24] = (pt->ecc.lineParityPrime >> 24) & 0xff;
+
+ k = oob_layout[layout_no].oobfree[j][0];
+ n = oob_layout[layout_no].oobfree[j][1];
+
+ if (n == 0) {
+ fprintf(stderr, "No OOB space for tags");
+ exit(-1);
+ }
+
+ for (i = 0; i < PT2_BYTES; i++) {
+ if (n == 0) {
+ j++;
+ k = oob_layout[layout_no].oobfree[j][0];
+ n = oob_layout[layout_no].oobfree[j][1];
+ if (n == 0) {
+ fprintf(stderr, "No OOB space for tags");
+ exit(-1);
+ }
+ }
+ buf[k++] = pt2_byte_buf[i];
+ n--;
+ }
+}
+
+static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
+{
+ yaffs_ExtendedTags t;
+ yaffs_PackedTags2 pt;
+ unsigned char spare_buf[MAX_SPARESIZE];
+
+
+ error = write(outFile,data,chunkSize);
+ if(error < 0) return error;
+
+ yaffs_InitialiseTags(&t);
+
+ t.chunkId = chunkId;
+// t.serialNumber = 0;
+ t.serialNumber = 1; // **CHECK**
+ t.byteCount = nBytes;
+ t.objectId = objId;
+
+ t.sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+// added NCB **CHECK**
+ t.chunkUsed = 1;
+
+/* KSI: Broken anyway -- e.g. &t is pointer to a wrong type... */
+#if 0
+ if (convert_endian)
+ {
+ little_to_big_endian(&t);
+ }
+#endif
+
+ nPages++;
+
+ yaffs_PackTags2(&pt,&t);
+
+ memset(spare_buf, 0xff, spareSize);
+
+ if (layout_no == 0) {
+ memcpy(spare_buf, &pt, sizeof(yaffs_PackedTags2));
+ } else {
+ nandmtd2_pt2buf(spare_buf, &pt);
+ }
+
+#ifdef CONFIG_MTD_HW_BCH_ECC
+ /* When programming using usb boot, the data in oob after eccpos should be
+ 0xff to make programming check easy. And eccpos = 24 when using BCH. */
+ memset(spare_buf + 24, 0xff, spareSize - 24);
+#endif
+ return write(outFile,spare_buf,spareSize);
+}
+
+#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \
+ (((x) & 0x0000FF00) << 8 ) | \
+ (((x) & 0x00FF0000) >> 8 ) | \
+ (((x) & 0xFF000000) >> 24))
+
+#define SWAP16(x) ((((x) & 0x00FF) << 8) | \
+ (((x) & 0xFF00) >> 8))
+
+/* KSI: Removed for now. TBD later when the proper util (from scratch) is written */
+#if 0
+// This one is easier, since the types are more standard. No funky shifts here.
+static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh)
+{
+ oh->type = SWAP32(oh->type); // GCC makes enums 32 bits.
+ oh->parentObjectId = SWAP32(oh->parentObjectId); // int
+ oh->sum__NoLongerUsed = SWAP16(oh->sum__NoLongerUsed); // __u16 - Not used, but done for completeness.
+ // name = skip. Char array. Not swapped.
+ oh->yst_mode = SWAP32(oh->yst_mode);
+#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case.
+ // In fact, WinCE would be *THE* place where this would be an issue!
+ oh->notForWinCE[0] = SWAP32(oh->notForWinCE[0]);
+ oh->notForWinCE[1] = SWAP32(oh->notForWinCE[1]);
+ oh->notForWinCE[2] = SWAP32(oh->notForWinCE[2]);
+ oh->notForWinCE[3] = SWAP32(oh->notForWinCE[3]);
+ oh->notForWinCE[4] = SWAP32(oh->notForWinCE[4]);
+#else
+ // Regular POSIX.
+ oh->yst_uid = SWAP32(oh->yst_uid);
+ oh->yst_gid = SWAP32(oh->yst_gid);
+ oh->yst_atime = SWAP32(oh->yst_atime);
+ oh->yst_mtime = SWAP32(oh->yst_mtime);
+ oh->yst_ctime = SWAP32(oh->yst_ctime);
+#endif
+
+ oh->fileSize = SWAP32(oh->fileSize); // Aiee. An int... signed, at that!
+ oh->equivalentObjectId = SWAP32(oh->equivalentObjectId);
+ // alias - char array.
+ oh->yst_rdev = SWAP32(oh->yst_rdev);
+
+#ifdef CONFIG_YAFFS_WINCE
+ oh->win_ctime[0] = SWAP32(oh->win_ctime[0]);
+ oh->win_ctime[1] = SWAP32(oh->win_ctime[1]);
+ oh->win_atime[0] = SWAP32(oh->win_atime[0]);
+ oh->win_atime[1] = SWAP32(oh->win_atime[1]);
+ oh->win_mtime[0] = SWAP32(oh->win_mtime[0]);
+ oh->win_mtime[1] = SWAP32(oh->win_mtime[1]);
+ oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]);
+ oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]);
+ oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]);
+ oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]);
+ oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]);
+ oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]);
+#else
+ oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]);
+ oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]);
+ oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]);
+ oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]);
+ oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]);
+ oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]);
+ oh->roomToGrow[6] = SWAP32(oh->roomToGrow[6]);
+ oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]);
+ oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]);
+ oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]);
+ oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]);
+ oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]);
+#endif
+}
+#endif
+
+static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias)
+{
+ __u8 bytes[MAX_CHUNKSIZE];
+
+
+ yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes;
+
+ memset(bytes,0xff,chunkSize);
+
+ oh->type = t;
+
+ oh->parentObjectId = parent;
+
+ strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
+
+
+ if(t != YAFFS_OBJECT_TYPE_HARDLINK)
+ {
+ oh->yst_mode = s->st_mode;
+ oh->yst_uid = s->st_uid;
+// NCB 12/9/02 oh->yst_gid = s->yst_uid;
+ oh->yst_gid = s->st_gid;
+ oh->yst_atime = s->st_atime;
+ oh->yst_mtime = s->st_mtime;
+ oh->yst_ctime = s->st_ctime;
+ oh->yst_rdev = s->st_rdev;
+ }
+
+ if(t == YAFFS_OBJECT_TYPE_FILE)
+ {
+ oh->fileSize = s->st_size;
+ }
+
+ if(t == YAFFS_OBJECT_TYPE_HARDLINK)
+ {
+ oh->equivalentObjectId = equivalentObj;
+ }
+
+ if(t == YAFFS_OBJECT_TYPE_SYMLINK)
+ {
+ strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH);
+ }
+
+/* KSI: FUBAR. Left for a leter time. */
+#if 0
+ if (convert_endian)
+ {
+ object_header_little_to_big_endian(oh);
+ }
+#endif
+
+ return write_chunk(bytes,objId,0,0xffff);
+
+}
+
+
+static int process_directory(int parent, const char *path)
+{
+
+ DIR *dir;
+ struct dirent *entry;
+
+ nDirectories++;
+
+ dir = opendir(path);
+
+ if(dir)
+ {
+ while((entry = readdir(dir)) != NULL)
+ {
+
+ /* Ignore . and .. */
+ if(strcmp(entry->d_name,".") &&
+ strcmp(entry->d_name,".."))
+ {
+ char full_name[500];
+ struct stat stats;
+ int equivalentObj;
+ int newObj;
+
+ sprintf(full_name,"%s/%s",path,entry->d_name);
+
+ lstat(full_name,&stats);
+
+ if(S_ISLNK(stats.st_mode) ||
+ S_ISREG(stats.st_mode) ||
+ S_ISDIR(stats.st_mode) ||
+ S_ISFIFO(stats.st_mode) ||
+ S_ISBLK(stats.st_mode) ||
+ S_ISCHR(stats.st_mode) ||
+ S_ISSOCK(stats.st_mode))
+ {
+
+ newObj = obj_id++;
+ nObjects++;
+
+ printf("Object %d, %s is a ",newObj,full_name);
+
+ /* We're going to create an object for it */
+ if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0)
+ {
+ /* we need to make a hard link */
+ printf("hard link to object %d\n",equivalentObj);
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL);
+ }
+ else
+ {
+
+ add_obj_to_list(stats.st_dev,stats.st_ino,newObj);
+
+ if(S_ISLNK(stats.st_mode))
+ {
+
+ char symname[500];
+
+ memset(symname,0, sizeof(symname));
+
+ readlink(full_name,symname,sizeof(symname) -1);
+
+ printf("symlink to \"%s\"\n",symname);
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname);
+
+ }
+ else if(S_ISREG(stats.st_mode))
+ {
+ printf("file, ");
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL);
+
+ if(error >= 0)
+ {
+ int h;
+ __u8 bytes[MAX_CHUNKSIZE];
+ int nBytes;
+ int chunk = 0;
+
+ h = open(full_name,O_RDONLY);
+ if(h >= 0)
+ {
+ memset(bytes,0xff,chunkSize);
+ while((nBytes = read(h,bytes,chunkSize)) > 0)
+ {
+ chunk++;
+ write_chunk(bytes,newObj,chunk,nBytes);
+ memset(bytes,0xff,chunkSize);
+ }
+ if(nBytes < 0)
+ error = nBytes;
+
+ printf("%d data chunks written\n",chunk);
+ close(h);
+ }
+ else
+ {
+ perror("Error opening file");
+ }
+
+ }
+
+ }
+ else if(S_ISSOCK(stats.st_mode))
+ {
+ printf("socket\n");
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
+ }
+ else if(S_ISFIFO(stats.st_mode))
+ {
+ printf("fifo\n");
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
+ }
+ else if(S_ISCHR(stats.st_mode))
+ {
+ printf("character device\n");
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
+ }
+ else if(S_ISBLK(stats.st_mode))
+ {
+ printf("block device\n");
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
+ }
+ else if(S_ISDIR(stats.st_mode))
+ {
+ printf("directory\n");
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL);
+// NCB modified 10/9/2001 process_directory(1,full_name);
+ process_directory(newObj,full_name);
+ }
+ }
+ }
+ else
+ {
+ printf(" we don't handle this type\n");
+ }
+ }
+ }
+ /* KSI:
+ * Who is supposed to close those open directories in this
+ * recursive function, lord Byron? Stock "ulimit -n" is 1024
+ * and e.g. stock Fedora /etc directory has more that 1024
+ * directories...
+ */
+ closedir(dir);
+ }
+
+ return 0;
+
+}
+
+void process_file(char *file_name)
+{
+ printf("file, ");
+
+ int h;
+ __u8 bytes[MAX_CHUNKSIZE];
+ int nBytes;
+ int chunk = 0;
+
+ h = open(file_name,O_RDONLY);
+ if(h >= 0)
+ {
+ memset(bytes,0xff,chunkSize);
+ while((nBytes = read(h,bytes,chunkSize)) > 0)
+ {
+ chunk++;
+ write_chunk(bytes,0,chunk,nBytes);
+ memset(bytes,0xff,chunkSize);
+ }
+ if(nBytes < 0) {
+ printf("error occured!\n");
+ }
+ printf("%d data chunks written\n",chunk);
+ close(h);
+ }
+ else
+ {
+ perror("Error opening file");
+ }
+}
+
+
+void usage(void)
+{
+ /* ECC for oob should conform with CONFIG_YAFFS_ECC_XX when building linux kernel, but ecc
+ for oob isn't required when using BCH ECC, as oob will be corrected together with data
+ when using BCH ECC. */
+#if defined(CONFIG_YAFFS_ECC_RS)
+ printf("Reed-solomn ECC will be used for checking 16 bytes for yaffs2 information in oob area.\n"
+ "so, CONFIG_YAFFS_ECC_RS should be selected when building linux kernel.\n");
+#elif defined(CONFIG_YAFFS_ECC_HAMMING)
+ printf("Hamming ECC will be used for checking 16 bytes for yaffs2 information in oob area.\n"
+ "so, CONFIG_YAFFS_ECC_HAMMING should be selected when building linux kernel.\n");
+#endif
+
+ printf("usage: mkyaffs2image layout# source image_file [convert]\n");
+ printf("\n"
+ " layout# NAND OOB layout:\n"
+ " 0 - nand_oob_raw, no used, \n"
+ " 1 - nand_oob_64, for 2KB pagesize, \n"
+ " 2 - nand_oob_128, for 2KB pagesize using multiple planes or 4KB pagesize,\n"
+ " 3 - nand_oob_256, for 4KB pagesize using multiple planes\n");
+ printf(" source the directory tree or file to be converted\n");
+ printf(" image_file the output file to hold the image\n");
+ printf(" 'convert' make a big-endian img on a little-endian machine. BROKEN !\n");
+ printf("\n Example:\n"
+ " mkyaffs2image 1 /nfsroot/root26 root26.yaffs2 \n"
+ " mkyaffs2image 1 uImage uImage.oob \n"
+);
+
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ struct stat stats;
+ int i;
+
+ printf("mkyaffs2image: image building tool for YAFFS2 built "__DATE__"\n");
+
+ if ((argc < 4) || (sscanf(argv[1], "%u", &layout_no) != 1))
+ {
+ usage();
+ }
+
+ switch (layout_no) {
+ case 0:
+ printf("Warning: it isn't used by JZSOC!\n");
+ break;
+ case 1:
+ chunkSize = 2048;
+ spareSize = 64;
+ break;
+ case 2:
+ chunkSize = 4096;
+ spareSize = 128;
+ break;
+ case 3:
+ chunkSize = 8192;
+ spareSize = 256;
+ break;
+ default:
+ usage();
+ }
+
+ i = 0;
+
+ while (oob_layout[i].useecc != -1)
+ i++;
+
+ if (layout_no >= i)
+ usage();
+
+ if ((argc == 5) && (!strncmp(argv[4], "convert", strlen("convert"))))
+ {
+ /* KSI: Broken as of now. TBD. Fail. */
+ usage();
+ convert_endian = 1;
+ }
+
+ if(stat(argv[2],&stats) < 0)
+ {
+ printf("Could not stat %s\n",argv[2]);
+ exit(1);
+ }
+
+ if(!S_ISDIR(stats.st_mode))
+ {
+ printf(" %s is not a directory. For a file, just pad oob to data area.\n",argv[2]);
+// exit(1);
+ }
+
+ outFile = open(argv[3],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE);
+
+
+ if(outFile < 0)
+ {
+ printf("Could not open output file %s\n",argv[3]);
+ exit(1);
+ }
+
+ /* for a file, just pad oob to data area */
+ if(S_ISREG(stats.st_mode))
+ {
+ process_file(argv[2]);
+ close(outFile);
+ exit(0);
+ }
+
+ printf("Processing directory %s into image file %s\n",argv[2],argv[3]);
+ error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL);
+
+ if(error)
+ error = process_directory(YAFFS_OBJECTID_ROOT,argv[2]);
+
+ close(outFile);
+
+ if(error < 0)
+ {
+ perror("operation incomplete");
+ exit(1);
+ }
+ else
+ {
+ printf("Operation complete.\n"
+ "%d objects in %d directories\n"
+ "%d NAND pages\n",nObjects, nDirectories, nPages);
+ }
+
+ close(outFile);
+
+ exit(0);
+}
+
diff --git a/fs/yaffs2/utils/mkyaffsimage.c b/fs/yaffs2/utils/mkyaffsimage.c
new file mode 100644
index 00000000000..06e2ac193d7
--- /dev/null
+++ b/fs/yaffs2/utils/mkyaffsimage.c
@@ -0,0 +1,593 @@
+/*
+ * YAFFS: Yet another FFS. A NAND-flash specific file system.
+ *
+ * makeyaffsimage.c
+ *
+ * Makes a YAFFS file system image that can be used to load up a file system.
+ *
+ * Copyright (C) 2002 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ * Nick Bane modifications flagged NCB
+ *
+ * Endian handling patches by James Ng.
+ *
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <string.h>
+#include <unistd.h>
+#include "yaffs_ecc.h"
+#include "yaffs_guts.h"
+
+
+#define MAX_OBJECTS 10000
+
+const char * mkyaffsimage_c_version = "$Id: mkyaffsimage.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $";
+
+
+typedef struct
+{
+ dev_t dev;
+ ino_t ino;
+ int obj;
+} objItem;
+
+
+static objItem obj_list[MAX_OBJECTS];
+static int n_obj = 0;
+static int obj_id = YAFFS_NOBJECT_BUCKETS + 1;
+
+static int nObjects, nDirectories, nPages;
+
+static int outFile;
+
+static int error;
+
+static int convert_endian = 0;
+
+static int obj_compare(const void *a, const void * b)
+{
+ objItem *oa, *ob;
+
+ oa = (objItem *)a;
+ ob = (objItem *)b;
+
+ if(oa->dev < ob->dev) return -1;
+ if(oa->dev > ob->dev) return 1;
+ if(oa->ino < ob->ino) return -1;
+ if(oa->ino > ob->ino) return 1;
+
+ return 0;
+}
+
+
+static void add_obj_to_list(dev_t dev, ino_t ino, int obj)
+{
+ if(n_obj < MAX_OBJECTS)
+ {
+ obj_list[n_obj].dev = dev;
+ obj_list[n_obj].ino = ino;
+ obj_list[n_obj].obj = obj;
+ n_obj++;
+ qsort(obj_list,n_obj,sizeof(objItem),obj_compare);
+
+ }
+ else
+ {
+ // oops! not enough space in the object array
+ fprintf(stderr,"Not enough space in object array\n");
+ exit(2);
+ }
+}
+
+
+static int find_obj_in_list(dev_t dev, ino_t ino)
+{
+ objItem *i = NULL;
+ objItem test;
+
+ test.dev = dev;
+ test.ino = ino;
+
+ if(n_obj > 0)
+ {
+ i = bsearch(&test,obj_list,n_obj,sizeof(objItem),obj_compare);
+ }
+
+ if(i)
+ {
+ return i->obj;
+ }
+ return -1;
+}
+
+// NCB added 10/9/2002
+static __u16 yaffs_CalcNameSum(const char *name)
+{
+ __u16 sum = 0;
+ __u16 i = 1;
+
+ __u8 *bname = (__u8 *)name;
+
+ while (*bname)
+ {
+ sum += (*bname) * i;
+ i++;
+ bname++;
+ }
+ return sum;
+}
+
+
+static void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
+{
+ yaffs_ECCCalculate(data , spare->ecc1);
+ yaffs_ECCCalculate(&data[256] , spare->ecc2);
+}
+
+static void yaffs_CalcTagsECC(yaffs_Tags *tags)
+{
+ // Todo don't do anything yet. Need to calculate ecc
+ unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
+ unsigned i,j;
+ unsigned ecc = 0;
+ unsigned bit = 0;
+
+ // Clear ECC fields
+ if (!convert_endian)
+ {
+ tags->ecc = 0;
+ }
+ else
+ {
+ // Because we're in "munged tag" mode, we have to clear it manually
+ b[6] &= 0xC0;
+ b[7] &= 0x03;
+ }
+
+ for(i = 0; i < 8; i++)
+ {
+// NCB modified 20-9-02 for(j = 1; j &0x7f; j<<=1)
+ for(j = 1; j &0xff; j<<=1)
+ {
+ bit++;
+ if(b[i] & j)
+ {
+ ecc ^= bit;
+ }
+ }
+ }
+
+ // Write out ECC
+ if (!convert_endian)
+ {
+ tags->ecc = ecc;
+ }
+ else
+ {
+ // We have to munge the ECC again.
+ b[6] |= ((ecc >> 6) & 0x3F);
+ b[7] |= ((ecc & 0x3F) << 2);
+ }
+}
+static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
+{
+ yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
+
+ //yaffs_CalcTagsECC(tagsPtr);
+
+ sparePtr->tagByte0 = tu->asBytes[0];
+ sparePtr->tagByte1 = tu->asBytes[1];
+ sparePtr->tagByte2 = tu->asBytes[2];
+ sparePtr->tagByte3 = tu->asBytes[3];
+ sparePtr->tagByte4 = tu->asBytes[4];
+ sparePtr->tagByte5 = tu->asBytes[5];
+ sparePtr->tagByte6 = tu->asBytes[6];
+ sparePtr->tagByte7 = tu->asBytes[7];
+}
+
+/* This little function converts a little endian tag to a big endian tag.
+ * NOTE: The tag is not usable after this other than calculating the CRC
+ * with.
+ */
+static void little_to_big_endian(yaffs_Tags *tagsPtr)
+{
+ yaffs_TagsUnion * tags = (yaffs_TagsUnion* )tagsPtr; // Work in bytes.
+ yaffs_TagsUnion temp;
+
+ memset(&temp, 0, sizeof(temp));
+ // Ick, I hate magic numbers.
+ temp.asBytes[0] = ((tags->asBytes[2] & 0x0F) << 4) | ((tags->asBytes[1] & 0xF0) >> 4);
+ temp.asBytes[1] = ((tags->asBytes[1] & 0x0F) << 4) | ((tags->asBytes[0] & 0xF0) >> 4);
+ temp.asBytes[2] = ((tags->asBytes[0] & 0x0F) << 4) | ((tags->asBytes[2] & 0x30) >> 2) | ((tags->asBytes[3] & 0xC0) >> 6);
+ temp.asBytes[3] = ((tags->asBytes[3] & 0x3F) << 2) | ((tags->asBytes[2] & 0xC0) >> 6);
+ temp.asBytes[4] = ((tags->asBytes[6] & 0x03) << 6) | ((tags->asBytes[5] & 0xFC) >> 2);
+ temp.asBytes[5] = ((tags->asBytes[5] & 0x03) << 6) | ((tags->asBytes[4] & 0xFC) >> 2);
+ temp.asBytes[6] = ((tags->asBytes[4] & 0x03) << 6) | (tags->asBytes[7] & 0x3F);
+ temp.asBytes[7] = (tags->asBytes[6] & 0xFC) | ((tags->asBytes[7] & 0xC0) >> 6);
+
+ // Now copy it back.
+ tags->asBytes[0] = temp.asBytes[0];
+ tags->asBytes[1] = temp.asBytes[1];
+ tags->asBytes[2] = temp.asBytes[2];
+ tags->asBytes[3] = temp.asBytes[3];
+ tags->asBytes[4] = temp.asBytes[4];
+ tags->asBytes[5] = temp.asBytes[5];
+ tags->asBytes[6] = temp.asBytes[6];
+ tags->asBytes[7] = temp.asBytes[7];
+}
+
+static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
+{
+ yaffs_Tags t;
+ yaffs_Spare s;
+
+ error = write(outFile,data,512);
+ if(error < 0) return error;
+
+ memset(&t,0xff,sizeof (yaffs_Tags));
+ memset(&s,0xff,sizeof (yaffs_Spare));
+
+ t.chunkId = chunkId;
+ t.serialNumber = 0;
+ t.byteCount = nBytes;
+ t.objectId = objId;
+
+ if (convert_endian)
+ {
+ little_to_big_endian(&t);
+ }
+
+ yaffs_CalcTagsECC(&t);
+ yaffs_LoadTagsIntoSpare(&s,&t);
+ yaffs_CalcECC(data,&s);
+
+ nPages++;
+
+ return write(outFile,&s,sizeof(yaffs_Spare));
+
+}
+
+#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \
+ (((x) & 0x0000FF00) << 8 ) | \
+ (((x) & 0x00FF0000) >> 8 ) | \
+ (((x) & 0xFF000000) >> 24))
+
+#define SWAP16(x) ((((x) & 0x00FF) << 8) | \
+ (((x) & 0xFF00) >> 8))
+
+// This one is easier, since the types are more standard. No funky shifts here.
+static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh)
+{
+ oh->type = SWAP32(oh->type); // GCC makes enums 32 bits.
+ oh->parentObjectId = SWAP32(oh->parentObjectId); // int
+ oh->sum__NoLongerUsed = SWAP16(oh->sum__NoLongerUsed); // __u16 - Not used, but done for completeness.
+ // name = skip. Char array. Not swapped.
+ oh->yst_mode = SWAP32(oh->yst_mode);
+#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case.
+ // In fact, WinCE would be *THE* place where this would be an issue!
+ oh->notForWinCE[0] = SWAP32(oh->notForWinCE[0]);
+ oh->notForWinCE[1] = SWAP32(oh->notForWinCE[1]);
+ oh->notForWinCE[2] = SWAP32(oh->notForWinCE[2]);
+ oh->notForWinCE[3] = SWAP32(oh->notForWinCE[3]);
+ oh->notForWinCE[4] = SWAP32(oh->notForWinCE[4]);
+#else
+ // Regular POSIX.
+ oh->yst_uid = SWAP32(oh->yst_uid);
+ oh->yst_gid = SWAP32(oh->yst_gid);
+ oh->yst_atime = SWAP32(oh->yst_atime);
+ oh->yst_mtime = SWAP32(oh->yst_mtime);
+ oh->yst_ctime = SWAP32(oh->yst_ctime);
+#endif
+
+ oh->fileSize = SWAP32(oh->fileSize); // Aiee. An int... signed, at that!
+ oh->equivalentObjectId = SWAP32(oh->equivalentObjectId);
+ // alias - char array.
+ oh->yst_rdev = SWAP32(oh->yst_rdev);
+
+#ifdef CONFIG_YAFFS_WINCE
+ oh->win_ctime[0] = SWAP32(oh->win_ctime[0]);
+ oh->win_ctime[1] = SWAP32(oh->win_ctime[1]);
+ oh->win_atime[0] = SWAP32(oh->win_atime[0]);
+ oh->win_atime[1] = SWAP32(oh->win_atime[1]);
+ oh->win_mtime[0] = SWAP32(oh->win_mtime[0]);
+ oh->win_mtime[1] = SWAP32(oh->win_mtime[1]);
+ oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]);
+ oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]);
+ oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]);
+ oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]);
+ oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]);
+ oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]);
+#else
+ oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]);
+ oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]);
+ oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]);
+ oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]);
+ oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]);
+ oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]);
+ oh->roomToGrow[6] = SWAP32(oh->roomToGrow[6]);
+ oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]);
+ oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]);
+ oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]);
+ oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]);
+ oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]);
+#endif
+}
+
+static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias)
+{
+ __u8 bytes[512];
+
+
+ yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes;
+
+ memset(bytes,0xff,512);
+
+ oh->type = t;
+
+ oh->parentObjectId = parent;
+
+ strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
+
+
+ if(t != YAFFS_OBJECT_TYPE_HARDLINK)
+ {
+ oh->yst_mode = s->st_mode;
+ oh->yst_uid = s->st_uid;
+// NCB 12/9/02 oh->yst_gid = s->yst_uid;
+ oh->yst_gid = s->st_gid;
+ oh->yst_atime = s->st_atime;
+ oh->yst_mtime = s->st_mtime;
+ oh->yst_ctime = s->st_ctime;
+ oh->yst_rdev = s->st_rdev;
+ }
+
+ if(t == YAFFS_OBJECT_TYPE_FILE)
+ {
+ oh->fileSize = s->st_size;
+ }
+
+ if(t == YAFFS_OBJECT_TYPE_HARDLINK)
+ {
+ oh->equivalentObjectId = equivalentObj;
+ }
+
+ if(t == YAFFS_OBJECT_TYPE_SYMLINK)
+ {
+ strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH);
+ }
+
+ if (convert_endian)
+ {
+ object_header_little_to_big_endian(oh);
+ }
+
+ return write_chunk(bytes,objId,0,0xffff);
+
+}
+
+
+static int process_directory(int parent, const char *path)
+{
+
+ DIR *dir;
+ struct dirent *entry;
+
+ nDirectories++;
+
+ dir = opendir(path);
+
+ if(dir)
+ {
+ while((entry = readdir(dir)) != NULL)
+ {
+
+ /* Ignore . and .. */
+ if(strcmp(entry->d_name,".") &&
+ strcmp(entry->d_name,".."))
+ {
+ char full_name[500];
+ struct stat stats;
+ int equivalentObj;
+ int newObj;
+
+ sprintf(full_name,"%s/%s",path,entry->d_name);
+
+ lstat(full_name,&stats);
+
+ if(S_ISLNK(stats.st_mode) ||
+ S_ISREG(stats.st_mode) ||
+ S_ISDIR(stats.st_mode) ||
+ S_ISFIFO(stats.st_mode) ||
+ S_ISBLK(stats.st_mode) ||
+ S_ISCHR(stats.st_mode) ||
+ S_ISSOCK(stats.st_mode))
+ {
+
+ newObj = obj_id++;
+ nObjects++;
+
+ printf("Object %d, %s is a ",newObj,full_name);
+
+ /* We're going to create an object for it */
+ if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0)
+ {
+ /* we need to make a hard link */
+ printf("hard link to object %d\n",equivalentObj);
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL);
+ }
+ else
+ {
+
+ add_obj_to_list(stats.st_dev,stats.st_ino,newObj);
+
+ if(S_ISLNK(stats.st_mode))
+ {
+
+ char symname[500];
+
+ memset(symname,0, sizeof(symname));
+
+ readlink(full_name,symname,sizeof(symname) -1);
+
+ printf("symlink to \"%s\"\n",symname);
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname);
+
+ }
+ else if(S_ISREG(stats.st_mode))
+ {
+ printf("file, ");
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL);
+
+ if(error >= 0)
+ {
+ int h;
+ __u8 bytes[512];
+ int nBytes;
+ int chunk = 0;
+
+ h = open(full_name,O_RDONLY);
+ if(h >= 0)
+ {
+ memset(bytes,0xff,512);
+ while((nBytes = read(h,bytes,512)) > 0)
+ {
+ chunk++;
+ write_chunk(bytes,newObj,chunk,nBytes);
+ memset(bytes,0xff,512);
+ }
+ if(nBytes < 0)
+ error = nBytes;
+
+ printf("%d data chunks written\n",chunk);
+ }
+ else
+ {
+ perror("Error opening file");
+ }
+ close(h);
+
+ }
+
+ }
+ else if(S_ISSOCK(stats.st_mode))
+ {
+ printf("socket\n");
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
+ }
+ else if(S_ISFIFO(stats.st_mode))
+ {
+ printf("fifo\n");
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
+ }
+ else if(S_ISCHR(stats.st_mode))
+ {
+ printf("character device\n");
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
+ }
+ else if(S_ISBLK(stats.st_mode))
+ {
+ printf("block device\n");
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
+ }
+ else if(S_ISDIR(stats.st_mode))
+ {
+ printf("directory\n");
+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL);
+// NCB modified 10/9/2001 process_directory(1,full_name);
+ process_directory(newObj,full_name);
+ }
+ }
+ }
+ else
+ {
+ printf(" we don't handle this type\n");
+ }
+ }
+ }
+ }
+
+ return 0;
+
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct stat stats;
+
+ printf("mkyaffsimage: image building tool for YAFFS built "__DATE__"\n");
+
+ if(argc < 3)
+ {
+ printf("usage: mkyaffsimage dir image_file [convert]\n");
+ printf(" dir the directory tree to be converted\n");
+ printf(" image_file the output file to hold the image\n");
+ printf(" 'convert' produce a big-endian image from a little-endian machine\n");
+ exit(1);
+ }
+
+ if ((argc == 4) && (!strncmp(argv[3], "convert", strlen("convert"))))
+ {
+ convert_endian = 1;
+ }
+
+ if(stat(argv[1],&stats) < 0)
+ {
+ printf("Could not stat %s\n",argv[1]);
+ exit(1);
+ }
+
+ if(!S_ISDIR(stats.st_mode))
+ {
+ printf(" %s is not a directory\n",argv[1]);
+ exit(1);
+ }
+
+ outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE);
+
+
+ if(outFile < 0)
+ {
+ printf("Could not open output file %s\n",argv[2]);
+ exit(1);
+ }
+
+ printf("Processing directory %s into image file %s\n",argv[1],argv[2]);
+ error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL);
+ if(error)
+ error = process_directory(YAFFS_OBJECTID_ROOT,argv[1]);
+
+ close(outFile);
+
+ if(error < 0)
+ {
+ perror("operation incomplete");
+ exit(1);
+ }
+ else
+ {
+ printf("Operation complete.\n"
+ "%d objects in %d directories\n"
+ "%d NAND pages\n",nObjects, nDirectories, nPages);
+ }
+
+ close(outFile);
+
+ exit(0);
+}
+
diff --git a/fs/yaffs2/utils/ssfdc_rs_ecc.c b/fs/yaffs2/utils/ssfdc_rs_ecc.c
new file mode 100644
index 00000000000..9b541b4c1cd
--- /dev/null
+++ b/fs/yaffs2/utils/ssfdc_rs_ecc.c
@@ -0,0 +1,180 @@
+/* Reed-Solomon decoder
+ * Copyright 2002 Phil Karn, KA9Q
+ * May be used under the terms of the GNU Lesser General Public License (LGPL)
+ */
+#include "ssfdc_rs_ecc.h"
+
+#include <string.h>
+
+struct CONV_DATA {
+ unsigned char shift0;
+ unsigned char mask0;
+ unsigned char mask1;
+ unsigned char merge_shift;
+} ConvData [8]= {
+ {0x0, 0xff, 0x01, 0x8}, /* 0 */
+ {0x1, 0x7f, 0x03, 0x7}, /* 1 */
+ {0x2, 0x3f, 0x07, 0x6}, /* 2 */
+ {0x3, 0x1f, 0x0f, 0x5}, /* 3 */
+ {0x4, 0x0f, 0x1f, 0x4}, /* 4 */
+ {0x5, 0x07, 0x3f, 0x3}, /* 5 */
+ {0x6, 0x03, 0x7f, 0x2}, /* 6 */
+ {0x7, 0x01, 0xff, 0x1}, /* 7 */
+};
+
+static void kfree(void *ptr)
+{
+// return 0;
+}
+
+static int modnn(struct rs *rs,int x)
+{
+ while (x >= rs->nn) {
+ x -= rs->nn;
+ x = (x >> rs->mm) + (x & rs->nn);
+ }
+ return x;
+}
+
+void encode_rs(void *p,data_t *data, unsigned short *bb)
+{
+ struct rs *rs = (struct rs *)p;
+ int i, j;
+ data_t feedback;
+
+ memset(bb,0,(rs->nroots)*sizeof(unsigned short));
+
+ for(i=0;i<(rs->nn)-(rs->nroots)-(rs->pad);i++){
+
+ feedback = (rs->index_of)[data[i] ^ bb[0]];
+ if(feedback != ((rs->nn))){
+ for(j=1;j<(rs->nroots);j++)
+ bb[j] ^= (rs->alpha_to)[modnn(rs,feedback + (rs->genpoly)[(rs->nroots)-j])];
+ }
+
+ memmove(&bb[0],&bb[1],sizeof(unsigned short)*((rs->nroots)-1));
+
+ if(feedback != ((rs->nn))) {
+ bb[(rs->nroots)-1] = (rs->alpha_to)[modnn(rs,feedback + (rs->genpoly)[0])];
+ }
+ else
+ bb[(rs->nroots)-1] = 0;
+ }
+
+}
+
+void free_rs_int(void *p)
+{
+ struct rs *rs = (struct rs *)p;
+
+ free(rs->alpha_to);
+ free(rs->index_of);
+ free(rs->genpoly);
+ free(rs);
+}
+
+/*
+ * init_rs_int - Initialize a Reed-Solomon codec
+ * @symsize: symbol size
+ * @gfpoly: Field generator polynomial coefficients
+ * @fcr: first root of RS code generator polynomial, index form
+ * @prim: primitive element to generate polynomial roots
+ * @nroots: RS code generator polynomial degree (number of roots)
+ */
+struct rs *init_rs_int(int symsize,int gfpoly,int fcr,int prim,int nroots,int pad)
+{
+ struct rs *rs;
+#if 0
+ static unsigned int rs0[64]={0};
+ static data_t alpha0[512]={0};
+ static data_t index0[512]={0};
+ static data_t genepoly0[9]={0};
+#endif
+ int i, j, sr,root,iprim;
+
+ rs = ((void *)0);
+ if(symsize < 0 || symsize > 8*sizeof(data_t)){
+ goto done;
+ }
+
+ if(fcr < 0 || fcr >= (1<<symsize))
+ goto done;
+ if(prim <= 0 || prim >= (1<<symsize))
+ goto done;
+ if(nroots < 0 || nroots >= (1<<symsize))
+ goto done;
+ if(pad < 0 || pad >= ((1<<symsize) -1 - nroots))
+ goto done;
+
+ rs = (struct rs *)malloc(sizeof(struct rs));
+// rs = (struct rs *)rs0;
+ if(rs == ((void *)0))
+ goto done;
+ rs->mm = symsize;
+ rs->nn = (1<<symsize)-1;
+ rs->pad = pad;
+ rs->alpha_to = (data_t *)malloc(sizeof(data_t)*(rs->nn+1));
+// rs->alpha_to = alpha0;
+ if(rs->alpha_to == ((void *)0)){
+ kfree(rs);
+ rs = ((void *)0);
+ goto done;
+ }
+ rs->index_of = (data_t *)malloc(sizeof(data_t)*(rs->nn+1));
+// rs->index_of = index0;
+ if(rs->index_of == ((void *)0)){
+ kfree(rs->alpha_to);
+ kfree(rs);
+ rs = ((void *)0);
+ goto done;
+ }
+ rs->index_of[0] = ((rs->nn));
+ rs->alpha_to[((rs->nn))] = 0;
+ sr = 1;
+ for(i=0;i<rs->nn;i++){
+ rs->index_of[sr] = i;
+ rs->alpha_to[i] = sr;
+ sr <<= 1;
+ if(sr & (1<<symsize))
+ sr ^= gfpoly;
+ sr &= rs->nn;
+ }
+ if(sr != 1){
+ kfree(rs->alpha_to);
+ kfree(rs->index_of);
+ kfree(rs);
+ rs = ((void *)0);
+ goto done;
+ }
+ rs->genpoly = (data_t *)malloc(sizeof(data_t)*(nroots+1));
+// rs->genpoly = genepoly0;
+ if(rs->genpoly == ((void *)0)){
+ kfree(rs->alpha_to);
+ kfree(rs->index_of);
+ kfree(rs);
+ rs = ((void *)0);
+ goto done;
+ }
+ rs->fcr = fcr;
+ rs->prim = prim;
+ rs->nroots = nroots;
+ for(iprim=1;(iprim % prim) != 0;iprim += rs->nn)
+ ;
+ rs->iprim = iprim / prim;
+ rs->genpoly[0] = 1;
+ for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) {
+ rs->genpoly[i+1] = 1;
+ for (j = i; j > 0; j--){
+ if (rs->genpoly[j] != 0)
+ rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)];
+ else
+ rs->genpoly[j] = rs->genpoly[j-1];
+ }
+ rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)];
+ }
+ for (i = 0; i <= nroots; i++)
+ rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
+ done:;
+ return rs;
+}
+
diff --git a/fs/yaffs2/utils/ssfdc_rs_ecc.h b/fs/yaffs2/utils/ssfdc_rs_ecc.h
new file mode 100644
index 00000000000..db304bdcd49
--- /dev/null
+++ b/fs/yaffs2/utils/ssfdc_rs_ecc.h
@@ -0,0 +1,29 @@
+#ifndef __SSFDC_RS_ECC_H__
+#define __SSFDC_RS_ECC_H__
+
+/* Stuff common to all the general-purpose Reed-Solomon codecs
+ * Copyright 2004 Phil Karn, KA9Q
+ * May be used under the terms of the GNU Lesser General Public License (LGPL)
+ */
+
+/* Reed-Solomon codec control block */
+typedef unsigned char data_t;
+
+struct rs {
+ int mm; /* Bits per symbol */
+ int nn; /* Symbols per block (= (1<<mm)-1) */
+ data_t *alpha_to; /* log lookup table */
+ data_t *index_of; /* Antilog lookup table */
+ data_t *genpoly; /* Generator polynomial */
+ int nroots; /* Number of generator roots = number of parity symbols */
+ int fcr; /* First consecutive root, index form */
+ int prim; /* Primitive element, index form */
+ int iprim; /* prim-th root of 1, index form */
+ int pad; /* Padding bytes in shortened block */
+};
+
+void encode_rs(void *p,data_t *data, unsigned short *bb);
+struct rs *init_rs_int(int symsize,int gfpoly,int fcr,int prim,int nroots,int pad);
+void free_rs_int(void *p);
+
+#endif /* __SSFDC_RS_ECC_H__ */
diff --git a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c
new file mode 100644
index 00000000000..c8195f0f817
--- /dev/null
+++ b/fs/yaffs2/yaffs_checkptrw.c
@@ -0,0 +1,384 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+const char *yaffs_checkptrw_c_version =
+ "$Id: yaffs_checkptrw.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $";
+
+
+#include "yaffs_checkptrw.h"
+
+
+static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
+{
+
+ int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
+
+ T(YAFFS_TRACE_CHECKPOINT,
+ (TSTR("checkpt blocks available = %d" TENDSTR),
+ blocksAvailable));
+
+
+ return (blocksAvailable <= 0) ? 0 : 1;
+}
+
+
+
+static int yaffs_CheckpointErase(yaffs_Device *dev)
+{
+
+ int i;
+
+
+ if(!dev->eraseBlockInNAND)
+ return 0;
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
+ dev->internalStartBlock,dev->internalEndBlock));
+
+ for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
+ if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
+ if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){
+ bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
+ dev->nErasedBlocks++;
+ dev->nFreeChunks += dev->nChunksPerBlock;
+ }
+ else {
+ dev->markNANDBlockBad(dev,i);
+ bi->blockState = YAFFS_BLOCK_STATE_DEAD;
+ }
+ }
+ }
+
+ dev->blocksInCheckpoint = 0;
+
+ return 1;
+}
+
+
+static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
+{
+ int i;
+ int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
+ T(YAFFS_TRACE_CHECKPOINT,
+ (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
+ dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock));
+
+ if(dev->checkpointNextBlock >= 0 &&
+ dev->checkpointNextBlock <= dev->internalEndBlock &&
+ blocksAvailable > 0){
+
+ for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
+ if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){
+ dev->checkpointNextBlock = i + 1;
+ dev->checkpointCurrentBlock = i;
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i));
+ return;
+ }
+ }
+ }
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
+
+ dev->checkpointNextBlock = -1;
+ dev->checkpointCurrentBlock = -1;
+}
+
+static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
+{
+ int i;
+ yaffs_ExtendedTags tags;
+
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
+ dev->blocksInCheckpoint, dev->checkpointNextBlock));
+
+ if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
+ for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
+ int chunk = i * dev->nChunksPerBlock;
+ int realignedChunk = chunk - dev->chunkOffset;
+
+ dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags);
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
+ i, tags.objectId,tags.sequenceNumber,tags.eccResult));
+
+ if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
+ /* Right kind of block */
+ dev->checkpointNextBlock = tags.objectId;
+ dev->checkpointCurrentBlock = i;
+ dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
+ dev->blocksInCheckpoint++;
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
+ return;
+ }
+ }
+
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
+
+ dev->checkpointNextBlock = -1;
+ dev->checkpointCurrentBlock = -1;
+}
+
+
+int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
+{
+
+ /* Got the functions we need? */
+ if (!dev->writeChunkWithTagsToNAND ||
+ !dev->readChunkWithTagsFromNAND ||
+ !dev->eraseBlockInNAND ||
+ !dev->markNANDBlockBad)
+ return 0;
+
+ if(forWriting && !yaffs_CheckpointSpaceOk(dev))
+ return 0;
+
+ if(!dev->checkpointBuffer)
+ dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
+ if(!dev->checkpointBuffer)
+ return 0;
+
+
+ dev->checkpointPageSequence = 0;
+
+ dev->checkpointOpenForWrite = forWriting;
+
+ dev->checkpointByteCount = 0;
+ dev->checkpointCurrentBlock = -1;
+ dev->checkpointCurrentChunk = -1;
+ dev->checkpointNextBlock = dev->internalStartBlock;
+
+ /* Erase all the blocks in the checkpoint area */
+ if(forWriting){
+ memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
+ dev->checkpointByteOffset = 0;
+ return yaffs_CheckpointErase(dev);
+
+
+ } else {
+ int i;
+ /* Set to a value that will kick off a read */
+ dev->checkpointByteOffset = dev->nDataBytesPerChunk;
+ /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
+ * going to be way more than we need */
+ dev->blocksInCheckpoint = 0;
+ dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
+ dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
+ for(i = 0; i < dev->checkpointMaxBlocks; i++)
+ dev->checkpointBlockList[i] = -1;
+ }
+
+ return 1;
+}
+
+static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
+{
+
+ int chunk;
+ int realignedChunk;
+
+ yaffs_ExtendedTags tags;
+
+ if(dev->checkpointCurrentBlock < 0){
+ yaffs_CheckpointFindNextErasedBlock(dev);
+ dev->checkpointCurrentChunk = 0;
+ }
+
+ if(dev->checkpointCurrentBlock < 0)
+ return 0;
+
+ tags.chunkDeleted = 0;
+ tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
+ tags.chunkId = dev->checkpointPageSequence + 1;
+ tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
+ tags.byteCount = dev->nDataBytesPerChunk;
+ if(dev->checkpointCurrentChunk == 0){
+ /* First chunk we write for the block? Set block state to
+ checkpoint */
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock);
+ bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
+ dev->blocksInCheckpoint++;
+ }
+
+ chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
+
+
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
+ chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId));
+
+ realignedChunk = chunk - dev->chunkOffset;
+
+ dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags);
+ dev->checkpointByteOffset = 0;
+ dev->checkpointPageSequence++;
+ dev->checkpointCurrentChunk++;
+ if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
+ dev->checkpointCurrentChunk = 0;
+ dev->checkpointCurrentBlock = -1;
+ }
+ memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
+
+ return 1;
+}
+
+
+int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
+{
+ int i=0;
+ int ok = 1;
+
+
+ __u8 * dataBytes = (__u8 *)data;
+
+
+
+ if(!dev->checkpointBuffer)
+ return 0;
+
+ while(i < nBytes && ok) {
+
+
+
+ dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
+ dev->checkpointByteOffset++;
+ i++;
+ dataBytes++;
+ dev->checkpointByteCount++;
+
+
+ if(dev->checkpointByteOffset < 0 ||
+ dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
+ ok = yaffs_CheckpointFlushBuffer(dev);
+
+ }
+
+ return i;
+}
+
+int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
+{
+ int i=0;
+ int ok = 1;
+ yaffs_ExtendedTags tags;
+
+
+ int chunk;
+ int realignedChunk;
+
+ __u8 *dataBytes = (__u8 *)data;
+
+ if(!dev->checkpointBuffer)
+ return 0;
+
+ while(i < nBytes && ok) {
+
+
+ if(dev->checkpointByteOffset < 0 ||
+ dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
+
+ if(dev->checkpointCurrentBlock < 0){
+ yaffs_CheckpointFindNextCheckpointBlock(dev);
+ dev->checkpointCurrentChunk = 0;
+ }
+
+ if(dev->checkpointCurrentBlock < 0)
+ ok = 0;
+ else {
+
+ chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
+ dev->checkpointCurrentChunk;
+
+ realignedChunk = chunk - dev->chunkOffset;
+
+ /* read in the next chunk */
+ /* printf("read checkpoint page %d\n",dev->checkpointPage); */
+ dev->readChunkWithTagsFromNAND(dev, realignedChunk,
+ dev->checkpointBuffer,
+ &tags);
+
+ if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
+ tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
+ ok = 0;
+
+ dev->checkpointByteOffset = 0;
+ dev->checkpointPageSequence++;
+ dev->checkpointCurrentChunk++;
+
+ if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
+ dev->checkpointCurrentBlock = -1;
+ }
+ }
+
+ if(ok){
+ *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
+ dev->checkpointByteOffset++;
+ i++;
+ dataBytes++;
+ dev->checkpointByteCount++;
+ }
+ }
+
+ return i;
+}
+
+int yaffs_CheckpointClose(yaffs_Device *dev)
+{
+
+ if(dev->checkpointOpenForWrite){
+ if(dev->checkpointByteOffset != 0)
+ yaffs_CheckpointFlushBuffer(dev);
+ } else {
+ int i;
+ for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]);
+ if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
+ bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
+ else {
+ // Todo this looks odd...
+ }
+ }
+ YFREE(dev->checkpointBlockList);
+ dev->checkpointBlockList = NULL;
+ }
+
+ dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
+ dev->nErasedBlocks -= dev->blocksInCheckpoint;
+
+
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
+ dev->checkpointByteCount));
+
+ if(dev->checkpointBuffer){
+ /* free the buffer */
+ YFREE(dev->checkpointBuffer);
+ dev->checkpointBuffer = NULL;
+ return 1;
+ }
+ else
+ return 0;
+
+}
+
+int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
+{
+ /* Erase the first checksum block */
+
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
+
+ if(!yaffs_CheckpointSpaceOk(dev))
+ return 0;
+
+ return yaffs_CheckpointErase(dev);
+}
+
+
+
diff --git a/fs/yaffs2/yaffs_checkptrw.h b/fs/yaffs2/yaffs_checkptrw.h
new file mode 100644
index 00000000000..da78a06f4ce
--- /dev/null
+++ b/fs/yaffs2/yaffs_checkptrw.h
@@ -0,0 +1,33 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_CHECKPTRW_H__
+#define __YAFFS_CHECKPTRW_H__
+
+#include "yaffs_guts.h"
+
+int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
+
+int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes);
+
+int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes);
+
+int yaffs_CheckpointClose(yaffs_Device *dev);
+
+int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
+
+
+#endif
+
diff --git a/fs/yaffs2/yaffs_ecc.c b/fs/yaffs2/yaffs_ecc.c
new file mode 100644
index 00000000000..f9fab2d7d31
--- /dev/null
+++ b/fs/yaffs2/yaffs_ecc.c
@@ -0,0 +1,446 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This code implements the ECC algorithm used in SmartMedia.
+ *
+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
+ * The two unused bit are set to 1.
+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
+ * blocks are used on a 512-byte NAND page.
+ *
+ */
+
+/* Table generated by gen-ecc.c
+ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
+ * for each byte of data. These are instead provided in a table in bits7..2.
+ * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
+ * this bytes influence on the line parity.
+ */
+
+const char *yaffs_ecc_c_version =
+ "$Id: yaffs_ecc.c,v 1.2 2008-07-17 23:07:00 lhhuang Exp $";
+
+#include "yportenv.h"
+
+#include "yaffs_ecc.h"
+
+static const unsigned char column_parity_table[] = {
+ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
+ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
+ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
+ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
+ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
+ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
+ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
+ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
+ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
+ 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
+ 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
+ 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
+ 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
+ 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
+ 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
+ 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
+ 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+};
+
+/* Count the bits in an unsigned char or a U32 */
+
+static int yaffs_CountBits(unsigned char x)
+{
+ int r = 0;
+ while (x) {
+ if (x & 1)
+ r++;
+ x >>= 1;
+ }
+ return r;
+}
+
+/* Calculate the ECC for a 256-byte block of data */
+void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
+{
+ unsigned int i;
+
+ unsigned char col_parity = 0;
+ unsigned char line_parity = 0;
+ unsigned char line_parity_prime = 0;
+ unsigned char t;
+ unsigned char b;
+
+ for (i = 0; i < 256; i++) {
+ b = column_parity_table[*data++];
+ col_parity ^= b;
+
+ if (b & 0x01) // odd number of bits in the byte
+ {
+ line_parity ^= i;
+ line_parity_prime ^= ~i;
+ }
+
+ }
+
+ ecc[2] = (~col_parity) | 0x03;
+
+ t = 0;
+ if (line_parity & 0x80)
+ t |= 0x80;
+ if (line_parity_prime & 0x80)
+ t |= 0x40;
+ if (line_parity & 0x40)
+ t |= 0x20;
+ if (line_parity_prime & 0x40)
+ t |= 0x10;
+ if (line_parity & 0x20)
+ t |= 0x08;
+ if (line_parity_prime & 0x20)
+ t |= 0x04;
+ if (line_parity & 0x10)
+ t |= 0x02;
+ if (line_parity_prime & 0x10)
+ t |= 0x01;
+ ecc[1] = ~t;
+
+ t = 0;
+ if (line_parity & 0x08)
+ t |= 0x80;
+ if (line_parity_prime & 0x08)
+ t |= 0x40;
+ if (line_parity & 0x04)
+ t |= 0x20;
+ if (line_parity_prime & 0x04)
+ t |= 0x10;
+ if (line_parity & 0x02)
+ t |= 0x08;
+ if (line_parity_prime & 0x02)
+ t |= 0x04;
+ if (line_parity & 0x01)
+ t |= 0x02;
+ if (line_parity_prime & 0x01)
+ t |= 0x01;
+ ecc[0] = ~t;
+
+#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
+ // Swap the bytes into the wrong order
+ t = ecc[0];
+ ecc[0] = ecc[1];
+ ecc[1] = t;
+#endif
+}
+
+
+/* Correct the ECC on a 256 byte block of data */
+
+int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
+ const unsigned char *test_ecc)
+{
+ unsigned char d0, d1, d2; /* deltas */
+
+ d0 = read_ecc[0] ^ test_ecc[0];
+ d1 = read_ecc[1] ^ test_ecc[1];
+ d2 = read_ecc[2] ^ test_ecc[2];
+
+ if ((d0 | d1 | d2) == 0)
+ return 0; /* no error */
+
+ if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
+ ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
+ ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
+ /* Single bit (recoverable) error in data */
+
+ unsigned byte;
+ unsigned bit;
+
+#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
+ // swap the bytes to correct for the wrong order
+ unsigned char t;
+
+ t = d0;
+ d0 = d1;
+ d1 = t;
+#endif
+
+ bit = byte = 0;
+
+ if (d1 & 0x80)
+ byte |= 0x80;
+ if (d1 & 0x20)
+ byte |= 0x40;
+ if (d1 & 0x08)
+ byte |= 0x20;
+ if (d1 & 0x02)
+ byte |= 0x10;
+ if (d0 & 0x80)
+ byte |= 0x08;
+ if (d0 & 0x20)
+ byte |= 0x04;
+ if (d0 & 0x08)
+ byte |= 0x02;
+ if (d0 & 0x02)
+ byte |= 0x01;
+
+ if (d2 & 0x80)
+ bit |= 0x04;
+ if (d2 & 0x20)
+ bit |= 0x02;
+ if (d2 & 0x08)
+ bit |= 0x01;
+
+ data[byte] ^= (1 << bit);
+
+ return 1; /* Corrected the error */
+ }
+
+ if ((yaffs_CountBits(d0) +
+ yaffs_CountBits(d1) +
+ yaffs_CountBits(d2)) == 1) {
+ /* Reccoverable error in ecc */
+
+ read_ecc[0] = test_ecc[0];
+ read_ecc[1] = test_ecc[1];
+ read_ecc[2] = test_ecc[2];
+
+ return 1; /* Corrected the error */
+ }
+
+ /* Unrecoverable error */
+
+ return -1;
+
+}
+
+#if defined(CONFIG_YAFFS_ECC_RS)
+#ifdef __KERNEL__
+#include <linux/rslib.h>
+struct rs_control *rs_decoder;
+#else
+#include "ssfdc_rs_ecc.h"
+void *rs_init_user;
+#endif
+
+/* Transfer 16 bytes to 26 5-bit symbols */
+void Data2Sym(const unsigned char *in, unsigned char *out)
+{
+ int i, j, shift;
+
+ for (i = 0; i < 26; i++){
+ j = (5 * i) >> 3;
+ shift = (5 * i) & 0x7;
+ if (shift > 3)
+ out[i] = ((in[j] >> shift) | (in[j+1] << (8 - shift))) & 0x1f;
+ else
+ out[i] = (in[j] >> shift) & 0x1f;
+ }
+ out[25] &= 0x7; /* the last symbol has only 3 bits */
+}
+
+/* Transfer 26 5-bit symbols to 16 bytes*/
+void Sym2Data(unsigned char *in, unsigned char *out)
+{
+ int i, j,n;
+ unsigned long long ullin = 0,ullout = 0;
+
+ n = 0;
+ for(j = 0;j < 26 / 8;j++)
+ {
+ ullin = *((unsigned long long *)in + j);
+ ullout = 0;
+ for (i = 0; i < 8; i++){
+ ullout |= (((ullin >> (i * 8)) & 0x1f) << (i * 5));
+ }
+ memcpy((out + n),(unsigned char *)&ullout,5);
+ n += 5;
+ }
+ out[15] = ((in[24] & 0x1f)| ((in[25] & 0x3) << 5));
+}
+
+
+/*
+ * It does reed solomon ECC calcs on 16 bytes of oob data
+ */
+void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
+ yaffs_ECCOther * eccOther)
+{
+ unsigned short *par = (unsigned short *)&eccOther->lineParity;
+ unsigned char data5[26];
+
+
+ Data2Sym(data, data5);
+ memset(par, 0, 8);
+
+#ifdef __KERNEL__
+ /* Encode 26 symbols in data5. Store parities of 4 symbols in
+ * buffer par whose size is 8 bytes(2 bytes per symbol) */
+ encode_rs8 (rs_decoder, data5, 26, par, 0);
+#else
+ /* init reed solomon ECC for nand oob area
+ * Symbolsize is 5 (bits)
+ * Primitive polynomial is x^5+x^2+1
+ * first consecutive root is 0
+ * primitive element to generate roots = 1
+ * generator polynomial degree (number of roots) = 4
+ * pad = (1<<Symbolsize-1) - nroot - 26 = 1
+ */
+ rs_init_user = (void *) init_rs_int (5, 0x25, 1, 1, 4, 1);
+ encode_rs(rs_init_user, data5, par);
+ free_rs_int(rs_init_user);
+#endif
+}
+
+#ifdef __KERNEL__
+/*
+ * It does reed solomon ECC correction on 16 bytes of oob data
+ */
+int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
+ yaffs_ECCOther * read_ecc,
+ const yaffs_ECCOther * test_ecc)
+{
+ unsigned short *par = (unsigned short *)&read_ecc->lineParity;
+ unsigned char data5[26];
+ int numerr;
+
+ Data2Sym(data, data5);
+
+ /* Decode 26 symbols in data5. */
+ numerr = decode_rs8 (rs_decoder, data5, par, 26, NULL, 0, NULL, 0, NULL);
+
+ if (numerr == 0)
+ return 0;
+ else if (numerr > 0 && numerr < 3)
+ {
+ Sym2Data(data5,data);
+ return 1;
+ }
+ else
+ return -1;
+}
+#else
+int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
+ yaffs_ECCOther * read_ecc,
+ const yaffs_ECCOther * test_ecc)
+{
+ return 0;
+}
+#endif
+
+#else
+
+static int yaffs_CountBits32(unsigned x)
+{
+ int r = 0;
+ while (x) {
+ if (x & 1)
+ r++;
+ x >>= 1;
+ }
+ return r;
+}
+
+/*
+ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
+ */
+void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
+ yaffs_ECCOther * eccOther)
+{
+ unsigned int i;
+
+ unsigned char col_parity = 0;
+ unsigned line_parity = 0;
+ unsigned line_parity_prime = 0;
+ unsigned char b;
+
+ for (i = 0; i < nBytes; i++) {
+ b = column_parity_table[*data++];
+ col_parity ^= b;
+
+ if (b & 0x01) {
+ /* odd number of bits in the byte */
+ line_parity ^= i;
+ line_parity_prime ^= ~i;
+ }
+
+ }
+
+ eccOther->colParity = (col_parity >> 2) & 0x3f;
+ eccOther->lineParity = line_parity;
+ eccOther->lineParityPrime = line_parity_prime;
+}
+
+int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
+ yaffs_ECCOther * read_ecc,
+ const yaffs_ECCOther * test_ecc)
+{
+ unsigned char cDelta; /* column parity delta */
+ unsigned lDelta; /* line parity delta */
+ unsigned lDeltaPrime; /* line parity delta */
+ unsigned bit;
+
+ cDelta = read_ecc->colParity ^ test_ecc->colParity;
+ lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
+ lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
+
+ if ((cDelta | lDelta | lDeltaPrime) == 0)
+ return 0; /* no error */
+
+ if (lDelta == ~lDeltaPrime &&
+ (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15))
+ {
+ /* Single bit (recoverable) error in data */
+
+ bit = 0;
+
+ if (cDelta & 0x20)
+ bit |= 0x04;
+ if (cDelta & 0x08)
+ bit |= 0x02;
+ if (cDelta & 0x02)
+ bit |= 0x01;
+
+ if(lDelta >= nBytes)
+ return -1;
+
+ data[lDelta] ^= (1 << bit);
+
+ return 1; /* corrected */
+ }
+
+ if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
+ yaffs_CountBits(cDelta)) == 1) {
+ /* Reccoverable error in ecc */
+
+ *read_ecc = *test_ecc;
+ return 1; /* corrected */
+ }
+
+ /* Unrecoverable error */
+
+ return -1;
+
+}
+#endif /* YAFFS_ECC_RS */
diff --git a/fs/yaffs2/yaffs_ecc.h b/fs/yaffs2/yaffs_ecc.h
new file mode 100644
index 00000000000..6754663b413
--- /dev/null
+++ b/fs/yaffs2/yaffs_ecc.h
@@ -0,0 +1,48 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+ /*
+ * This code implements the ECC algorithm used in SmartMedia.
+ *
+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
+ * The two unused bit are set to 1.
+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
+ * blocks are used on a 512-byte NAND page.
+ *
+ */
+
+#ifndef __YAFFS_ECC_H__
+#define __YAFFS_ECC_H__
+
+typedef struct {
+ unsigned char colParity;
+ unsigned lineParity;
+ unsigned lineParityPrime;
+} yaffs_ECCOther;
+
+#if defined(CONFIG_YAFFS_ECC_RS)
+extern struct rs_control *rs_decoder;
+#endif
+
+void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
+int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
+ const unsigned char *test_ecc);
+
+void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
+ yaffs_ECCOther * ecc);
+int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
+ yaffs_ECCOther * read_ecc,
+ const yaffs_ECCOther * test_ecc);
+#endif
diff --git a/fs/yaffs2/yaffs_fs.c b/fs/yaffs2/yaffs_fs.c
new file mode 100644
index 00000000000..7afea40ac1c
--- /dev/null
+++ b/fs/yaffs2/yaffs_fs.c
@@ -0,0 +1,2508 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ * Acknowledgements:
+ * Luc van OostenRyck for numerous patches.
+ * Nick Bane for numerous patches.
+ * Nick Bane for 2.5/2.6 integration.
+ * Andras Toth for mknod rdev issue.
+ * Michael Fischer for finding the problem with inode inconsistency.
+ * Some code bodily lifted from JFFS
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ *
+ * This is the file system front-end to YAFFS that hooks it up to
+ * the VFS.
+ *
+ * Special notes:
+ * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
+ * this superblock
+ * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
+ * superblock
+ * >> inode->u.generic_ip points to the associated yaffs_Object.
+ */
+
+const char *yaffs_fs_c_version =
+ "$Id: yaffs_fs.c,v 1.2 2008-07-17 23:59:16 lhhuang Exp $";
+extern const char *yaffs_guts_c_version;
+
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+#include <linux/config.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
+#include <linux/pagemap.h>
+#include <linux/mtd/mtd.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+
+#include <linux/statfs.h> /* Added NCB 15-8-2003 */
+#include <asm/statfs.h>
+#define UnlockPage(p) unlock_page(p)
+#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
+
+/* FIXME: use sb->s_id instead ? */
+#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
+
+#else
+
+#include <linux/locks.h>
+#define BDEVNAME_SIZE 0
+#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
+#define __user
+#endif
+
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
+#define YPROC_ROOT (&proc_root)
+#else
+#define YPROC_ROOT NULL
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+#define WRITE_SIZE_STR "writesize"
+#define WRITE_SIZE(mtd) ((mtd)->writesize)
+#else
+#define WRITE_SIZE_STR "oobblock"
+#define WRITE_SIZE(mtd) ((mtd)->oobblock)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
+#define YAFFS_USE_WRITE_BEGIN_END 1
+#else
+#define YAFFS_USE_WRITE_BEGIN_END 0
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
+static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
+{
+ uint64_t result = partition_size;
+ do_div(result, block_size);
+ return (uint32_t)result;
+}
+#else
+#define YCALCBLOCKS(s, b) ((s)/(b))
+#endif
+
+
+#include <asm/uaccess.h>
+
+#include "yportenv.h"
+#include "yaffs_guts.h"
+
+unsigned yaffs_traceMask = YAFFS_TRACE_ALWAYS |
+ YAFFS_TRACE_BAD_BLOCKS/* |
+ YAFFS_TRACE_CHECKPOINT*/
+ /* | 0xFFFFFFFF */;
+
+#include <linux/mtd/mtd.h>
+#include "yaffs_mtdif.h"
+#include "yaffs_mtdif2.h"
+
+#if defined(CONFIG_YAFFS_ECC_RS)
+#include <linux/rslib.h>
+#include "yaffs_ecc.h"
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
+/* use iget and read_inode */
+#define Y_IGET(sb, inum) iget((sb), (inum))
+static void yaffs_read_inode(struct inode *inode);
+
+#else
+/* Call local equivalent */
+#define YAFFS_USE_OWN_IGET
+#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
+
+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
+#endif
+
+/*#define T(x) printk x */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
+#define yaffs_InodeToObjectLV(iptr) (iptr)->i_private
+#else
+#define yaffs_InodeToObjectLV(iptr) (iptr)->u.generic_ip
+#endif
+
+#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
+#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
+#else
+#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
+#endif
+
+static void yaffs_put_super(struct super_block *sb);
+
+static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
+ loff_t * pos);
+
+
+static ssize_t yaffs_hold_space(struct file *f);
+static void yaffs_release_space(struct file *f);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_file_flush(struct file *file, fl_owner_t id);
+#else
+static int yaffs_file_flush(struct file *file);
+#endif
+
+static int yaffs_sync_object(struct file *file, struct dentry *dentry,
+ int datasync);
+
+static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *n);
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+ struct nameidata *n);
+#else
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
+#endif
+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry);
+static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
+static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname);
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ dev_t dev);
+#else
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ int dev);
+#endif
+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry);
+static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_sync_fs(struct super_block *sb, int wait);
+static void yaffs_write_super(struct super_block *sb);
+#else
+static int yaffs_sync_fs(struct super_block *sb);
+static int yaffs_write_super(struct super_block *sb);
+#endif
+
+static int yaffs_remount_fs(struct super_block *, int *, char *);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
+#else
+static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
+#endif
+
+#ifdef YAFFS_HAS_PUT_INODE
+static void yaffs_put_inode(struct inode *inode);
+#endif
+
+static void yaffs_delete_inode(struct inode *);
+static void yaffs_clear_inode(struct inode *);
+
+static int yaffs_readpage(struct file *file, struct page *page);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
+#else
+static int yaffs_writepage(struct page *page);
+#endif
+
+#if (YAFFS_USE_WRITE_BEGIN_END != 0)
+static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata);
+static int yaffs_write_end(struct file *filp, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *pg, void *fsdadata);
+#else
+static int yaffs_prepare_write(struct file *f, struct page *pg,
+ unsigned offset, unsigned to);
+static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
+ unsigned to);
+#endif
+
+static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
+ int buflen);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
+#else
+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
+#endif
+
+static struct address_space_operations yaffs_file_address_operations = {
+ .readpage = yaffs_readpage,
+ .writepage = yaffs_writepage,
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+ .write_begin = yaffs_write_begin,
+ .write_end = yaffs_write_end,
+#else
+ .prepare_write = yaffs_prepare_write,
+ .commit_write = yaffs_commit_write,
+#endif
+};
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
+static const struct file_operations yaffs_file_operations = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = generic_file_aio_read,
+ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .flush = yaffs_file_flush,
+ .fsync = yaffs_sync_object,
+ .splice_read = generic_file_splice_read,
+ .splice_write = generic_file_splice_write,
+ .llseek = generic_file_llseek,
+};
+
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
+
+static const struct file_operations yaffs_file_operations = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = generic_file_aio_read,
+ .aio_write = generic_file_aio_write,
+ .mmap = generic_file_mmap,
+ .flush = yaffs_file_flush,
+ .fsync = yaffs_sync_object,
+ .sendfile = generic_file_sendfile,
+};
+
+#else
+
+static const struct file_operations yaffs_file_operations = {
+ .read = generic_file_read,
+ .write = generic_file_write,
+ .mmap = generic_file_mmap,
+ .flush = yaffs_file_flush,
+ .fsync = yaffs_sync_object,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+ .sendfile = generic_file_sendfile,
+#endif
+};
+#endif
+
+static struct inode_operations yaffs_file_inode_operations = {
+ .setattr = yaffs_setattr,
+};
+
+static struct inode_operations yaffs_symlink_inode_operations = {
+ .readlink = yaffs_readlink,
+ .follow_link = yaffs_follow_link,
+ .setattr = yaffs_setattr,
+};
+
+static struct inode_operations yaffs_dir_inode_operations = {
+ .create = yaffs_create,
+ .lookup = yaffs_lookup,
+ .link = yaffs_link,
+ .unlink = yaffs_unlink,
+ .symlink = yaffs_symlink,
+ .mkdir = yaffs_mkdir,
+ .rmdir = yaffs_unlink,
+ .mknod = yaffs_mknod,
+ .rename = yaffs_rename,
+ .setattr = yaffs_setattr,
+};
+
+static struct file_operations yaffs_dir_operations = {
+ .read = generic_read_dir,
+ .readdir = yaffs_readdir,
+ .fsync = yaffs_sync_object,
+};
+
+static struct super_operations yaffs_super_ops = {
+ .statfs = yaffs_statfs,
+
+#ifndef YAFFS_USE_OWN_IGET
+ .read_inode = yaffs_read_inode,
+#endif
+#ifdef YAFFS_HAS_PUT_INODE
+ .put_inode = yaffs_put_inode,
+#endif
+ .put_super = yaffs_put_super,
+ .remount_fs = yaffs_remount_fs,
+ .delete_inode = yaffs_delete_inode,
+ .clear_inode = yaffs_clear_inode,
+ .sync_fs = yaffs_sync_fs,
+ .write_super = yaffs_write_super,
+};
+
+static void yaffs_GrossLock(yaffs_Device * dev)
+{
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs locking\n"));
+
+ down(&dev->grossLock);
+}
+
+static void yaffs_GrossUnlock(yaffs_Device * dev)
+{
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs unlocking\n"));
+ up(&dev->grossLock);
+
+}
+
+static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
+ int buflen)
+{
+ unsigned char *alias;
+ int ret;
+
+ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+
+ yaffs_GrossLock(dev);
+
+ alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
+
+ yaffs_GrossUnlock(dev);
+
+ if (!alias)
+ return -ENOMEM;
+
+ ret = vfs_readlink(dentry, buffer, buflen, alias);
+ kfree(alias);
+ return ret;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
+#else
+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
+#endif
+{
+ unsigned char *alias;
+ int ret;
+ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+
+ yaffs_GrossLock(dev);
+
+ alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
+
+ yaffs_GrossUnlock(dev);
+
+ if (!alias)
+ {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = vfs_follow_link(nd, alias);
+ kfree(alias);
+out:
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
+ return ERR_PTR (ret);
+#else
+ return ret;
+#endif
+}
+
+struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
+ yaffs_Object * obj);
+
+/*
+ * Lookup is used to find objects in the fs
+ */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+ struct nameidata *n)
+#else
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
+#endif
+{
+ yaffs_Object *obj;
+ struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
+
+ yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
+
+ yaffs_GrossLock(dev);
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_lookup for %d:%s\n",
+ yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
+
+ obj =
+ yaffs_FindObjectByName(yaffs_InodeToObject(dir),
+ dentry->d_name.name);
+
+ obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
+
+ /* Can't hold gross lock when calling yaffs_get_inode() */
+ yaffs_GrossUnlock(dev);
+
+ if (obj) {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_lookup found %d\n", obj->objectId));
+
+ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+
+ if (inode) {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_loookup dentry \n"));
+/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
+ * d_add even if NULL inode */
+#if 0
+ /*dget(dentry); // try to solve directory bug */
+ d_add(dentry, inode);
+
+ /* return dentry; */
+ return NULL;
+#endif
+ }
+
+ } else {
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_lookup not found\n"));
+
+ }
+
+/* added NCB for 2.5/6 compatability - forces add even if inode is
+ * NULL which creates dentry hash */
+ d_add(dentry, inode);
+
+ return NULL;
+ /* return (ERR_PTR(-EIO)); */
+
+}
+
+static int yaffs_dump_dev1(yaffs_Device * dev)
+{
+ printk("startBlock......... %d\n", dev->startBlock);
+ printk("endBlock........... %d\n", dev->endBlock);
+ printk("chunkGroupBits..... %d\n", dev->chunkGroupBits);
+ printk("chunkGroupSize..... %d\n", dev->chunkGroupSize);
+ printk("nErasedBlocks...... %d\n", dev->nErasedBlocks);
+ printk("nTnodesCreated..... %d\n", dev->nTnodesCreated);
+ printk("nFreeTnodes........ %d\n", dev->nFreeTnodes);
+ printk("nObjectsCreated.... %d\n", dev->nObjectsCreated);
+ printk("nFreeObjects....... %d\n", dev->nFreeObjects);
+ printk("nFreeChunks........ %d\n", dev->nFreeChunks);
+ printk("nPageWrites........ %d\n", dev->nPageWrites);
+ printk("nPageReads......... %d\n", dev->nPageReads);
+ printk("nBlockErasures..... %d\n", dev->nBlockErasures);
+ printk("nGCCopies.......... %d\n", dev->nGCCopies);
+ printk("garbageCollections. %d\n", dev->garbageCollections);
+
+ printk("passiveGCs......... %d\n", dev->passiveGarbageCollections);
+ printk("nRetriedWrites..... %d\n", dev->nRetriedWrites);
+ printk("nRetireBlocks...... %d\n", dev->nRetiredBlocks);
+ printk("eccFixed........... %d\n", dev->eccFixed);
+ printk("eccUnfixed......... %d\n", dev->eccUnfixed);
+ printk("tagsEccFixed....... %d\n", dev->tagsEccFixed);
+ printk("tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
+ printk("cacheHits.......... %d\n", dev->cacheHits);
+ printk("nDeletedFiles...... %d\n", dev->nDeletedFiles);
+ printk("nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
+ printk("nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
+ printk("useNANDECC......... %d\n", dev->useNANDECC);
+ printk("isYaffs2........... %d\n", dev->isYaffs2);
+
+ return 1;
+}
+
+#ifdef YAFFS_HAS_PUT_INODE
+
+/* For now put inode is just for debugging
+ * Put inode is called when the inode **structure** is put.
+ */
+static void yaffs_put_inode(struct inode *inode)
+{
+ T(YAFFS_TRACE_OS,
+ ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
+ atomic_read(&inode->i_count)));
+
+}
+#endif
+
+/* clear is called to tell the fs to release any per-inode data it holds */
+static void yaffs_clear_inode(struct inode *inode)
+{
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+
+ obj = yaffs_InodeToObject(inode);
+
+ T(YAFFS_TRACE_OS,
+ ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
+ atomic_read(&inode->i_count),
+ obj ? "object exists" : "null object"));
+
+ if (obj) {
+ dev = obj->myDev;
+ yaffs_GrossLock(dev);
+
+ /* Clear the association between the inode and
+ * the yaffs_Object.
+ */
+ obj->myInode = NULL;
+ yaffs_InodeToObjectLV(inode) = NULL;
+
+ /* If the object freeing was deferred, then the real
+ * free happens now.
+ * This should fix the inode inconsistency problem.
+ */
+
+ yaffs_HandleDeferedFree(obj);
+
+ yaffs_GrossUnlock(dev);
+ }
+
+}
+
+/* delete is called when the link count is zero and the inode
+ * is put (ie. nobody wants to know about it anymore, time to
+ * delete the file).
+ * NB Must call clear_inode()
+ */
+static void yaffs_delete_inode(struct inode *inode)
+{
+ yaffs_Object *obj = yaffs_InodeToObject(inode);
+ yaffs_Device *dev;
+
+ T(YAFFS_TRACE_OS,
+ ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
+ atomic_read(&inode->i_count),
+ obj ? "object exists" : "null object"));
+
+ if (obj) {
+ dev = obj->myDev;
+ yaffs_GrossLock(dev);
+ yaffs_DeleteFile(obj);
+ yaffs_GrossUnlock(dev);
+ }
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
+ truncate_inode_pages (&inode->i_data, 0);
+#endif
+ clear_inode(inode);
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_file_flush(struct file *file, fl_owner_t id)
+#else
+static int yaffs_file_flush(struct file *file)
+#endif
+{
+ yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
+
+ yaffs_Device *dev = obj->myDev;
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_file_flush object %d (%s)\n", obj->objectId,
+ obj->dirty ? "dirty" : "clean"));
+
+ yaffs_GrossLock(dev);
+
+ yaffs_FlushFile(obj, 1);
+
+ yaffs_GrossUnlock(dev);
+
+ return 0;
+}
+
+static int yaffs_readpage_nolock(struct file *f, struct page *pg)
+{
+ /* Lifted from jffs2 */
+
+ yaffs_Object *obj;
+ unsigned char *pg_buf;
+ int ret;
+
+ yaffs_Device *dev;
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_readpage at %08x, size %08x\n",
+ (unsigned)(pg->index << PAGE_CACHE_SHIFT),
+ (unsigned)PAGE_CACHE_SIZE));
+
+ obj = yaffs_DentryToObject(f->f_dentry);
+
+ dev = obj->myDev;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+ BUG_ON(!PageLocked(pg));
+#else
+ if (!PageLocked(pg))
+ PAGE_BUG(pg);
+#endif
+
+ pg_buf = kmap(pg);
+ /* FIXME: Can kmap fail? */
+
+ yaffs_GrossLock(dev);
+
+ ret =
+ yaffs_ReadDataFromFile(obj, pg_buf, pg->index << PAGE_CACHE_SHIFT,
+ PAGE_CACHE_SIZE);
+
+ yaffs_GrossUnlock(dev);
+
+ if (ret >= 0)
+ ret = 0;
+
+ if (ret) {
+ ClearPageUptodate(pg);
+ SetPageError(pg);
+ } else {
+ SetPageUptodate(pg);
+ ClearPageError(pg);
+ }
+
+ flush_dcache_page(pg);
+ kunmap(pg);
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_readpage done\n"));
+ return ret;
+}
+
+static int yaffs_readpage_unlock(struct file *f, struct page *pg)
+{
+ int ret = yaffs_readpage_nolock(f, pg);
+ UnlockPage(pg);
+ return ret;
+}
+
+static int yaffs_readpage(struct file *f, struct page *pg)
+{
+ return yaffs_readpage_unlock(f, pg);
+}
+
+/* writepage inspired by/stolen from smbfs */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
+#else
+static int yaffs_writepage(struct page *page)
+#endif
+{
+ struct address_space *mapping = page->mapping;
+ loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
+ struct inode *inode;
+ unsigned long end_index;
+ char *buffer;
+ yaffs_Object *obj;
+ int nWritten = 0;
+ unsigned nBytes;
+
+ if (!mapping)
+ BUG();
+ inode = mapping->host;
+ if (!inode)
+ BUG();
+
+ if (offset > inode->i_size) {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG
+ "yaffs_writepage at %08x, inode size = %08x!!!\n",
+ (unsigned)(page->index << PAGE_CACHE_SHIFT),
+ (unsigned)inode->i_size));
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG " -> don't care!!\n"));
+ unlock_page(page);
+ return 0;
+ }
+
+ end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+
+ /* easy case */
+ if (page->index < end_index) {
+ nBytes = PAGE_CACHE_SIZE;
+ } else {
+ nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
+ }
+
+ get_page(page);
+
+ buffer = kmap(page);
+
+ obj = yaffs_InodeToObject(inode);
+ yaffs_GrossLock(obj->myDev);
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_writepage at %08x, size %08x\n",
+ (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "writepag0: obj = %05x, ino = %05x\n",
+ (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
+
+ nWritten =
+ yaffs_WriteDataToFile(obj, buffer, page->index << PAGE_CACHE_SHIFT,
+ nBytes, 0);
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "writepag1: obj = %05x, ino = %05x\n",
+ (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
+
+ yaffs_GrossUnlock(obj->myDev);
+
+ kunmap(page);
+ SetPageUptodate(page);
+ UnlockPage(page);
+ put_page(page);
+
+ return (nWritten == nBytes) ? 0 : -ENOSPC;
+}
+
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata)
+{
+ struct page *pg = NULL;
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+ uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);
+ uint32_t to = offset + len;
+
+ int ret = 0;
+ int space_held = 0;
+
+ T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n"));
+ /* Get a page */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+ pg = grab_cache_page_write_begin(mapping, index, flags);
+#else
+ pg = __grab_cache_page(mapping, index);
+#endif
+
+ *pagep = pg;
+ if (!pg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ /* Get fs space */
+ space_held = yaffs_hold_space(filp);
+
+ if (!space_held) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ /* Update page if required */
+
+ if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
+ ret = yaffs_readpage_nolock(filp, pg);
+
+ if (ret)
+ goto out;
+
+ /* Happy path return */
+ T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n"));
+
+ return 0;
+
+out:
+ T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));
+ if (space_held)
+ yaffs_release_space(filp);
+ if (pg) {
+ unlock_page(pg);
+ page_cache_release(pg);
+ }
+ return ret;
+}
+
+#else
+
+
+static int yaffs_prepare_write(struct file *f, struct page *pg,
+ unsigned offset, unsigned to)
+{
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_prepair_write\n"));
+ if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
+ return yaffs_readpage_nolock(f, pg);
+
+ return 0;
+
+}
+#endif
+
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+static int yaffs_write_end(struct file *filp, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *pg, void *fsdadata)
+{
+ int ret = 0;
+ void *addr, *kva;
+ uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
+
+ kva = kmap(pg);
+ addr = kva + offset_into_page;
+
+ T(YAFFS_TRACE_OS,
+ ("yaffs_write_end addr %x pos %x nBytes %d\n",
+ (unsigned) addr,
+ (int)pos, copied));
+
+ ret = yaffs_file_write(filp, addr, copied, &pos);
+
+ if (ret != copied) {
+ T(YAFFS_TRACE_OS,
+ ("yaffs_write_end not same size ret %d copied %d\n",
+ ret, copied));
+ SetPageError(pg);
+ ClearPageUptodate(pg);
+ } else {
+ SetPageUptodate(pg);
+ }
+
+ kunmap(pg);
+
+ yaffs_release_space(filp);
+ unlock_page(pg);
+ page_cache_release(pg);
+ return ret;
+}
+#else
+
+
+static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
+ unsigned to)
+{
+
+ void *addr = page_address(pg) + offset;
+ loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
+ int nBytes = to - offset;
+ int nWritten;
+
+ unsigned spos = pos;
+ unsigned saddr = (unsigned)addr;
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_commit_write addr %x pos %x nBytes %d\n", saddr,
+ spos, nBytes));
+
+ nWritten = yaffs_file_write(f, addr, nBytes, &pos);
+
+ if (nWritten != nBytes) {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG
+ "yaffs_commit_write not same size nWritten %d nBytes %d\n",
+ nWritten, nBytes));
+ SetPageError(pg);
+ ClearPageUptodate(pg);
+ } else {
+ SetPageUptodate(pg);
+ }
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_commit_write returning %d\n",
+ nWritten == nBytes ? 0 : nWritten));
+
+ return nWritten == nBytes ? 0 : nWritten;
+
+}
+
+#endif
+
+static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
+{
+ if (inode && obj) {
+
+
+ /* Check mode against the variant type and attempt to repair if broken. */
+ __u32 mode = obj->yst_mode;
+ switch( obj->variantType ){
+ case YAFFS_OBJECT_TYPE_FILE :
+ if( ! S_ISREG(mode) ){
+ obj->yst_mode &= ~S_IFMT;
+ obj->yst_mode |= S_IFREG;
+ }
+
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK :
+ if( ! S_ISLNK(mode) ){
+ obj->yst_mode &= ~S_IFMT;
+ obj->yst_mode |= S_IFLNK;
+ }
+
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY :
+ if( ! S_ISDIR(mode) ){
+ obj->yst_mode &= ~S_IFMT;
+ obj->yst_mode |= S_IFDIR;
+ }
+
+ break;
+ case YAFFS_OBJECT_TYPE_UNKNOWN :
+ case YAFFS_OBJECT_TYPE_HARDLINK :
+ case YAFFS_OBJECT_TYPE_SPECIAL :
+ default:
+ /* TODO? */
+ break;
+ }
+
+ inode->i_ino = obj->objectId;
+ inode->i_mode = obj->yst_mode;
+ inode->i_uid = obj->yst_uid;
+ inode->i_gid = obj->yst_gid;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+ inode->i_blksize = inode->i_sb->s_blocksize;
+#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+
+ inode->i_rdev = old_decode_dev(obj->yst_rdev);
+ inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
+ inode->i_atime.tv_nsec = 0;
+ inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
+ inode->i_mtime.tv_nsec = 0;
+ inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
+ inode->i_ctime.tv_nsec = 0;
+#else
+ inode->i_rdev = obj->yst_rdev;
+ inode->i_atime = obj->yst_atime;
+ inode->i_mtime = obj->yst_mtime;
+ inode->i_ctime = obj->yst_ctime;
+#endif
+ inode->i_size = yaffs_GetObjectFileLength(obj);
+ inode->i_blocks = (inode->i_size + 511) >> 9;
+
+ inode->i_nlink = yaffs_GetObjectLinkCount(obj);
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG
+ "yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
+ inode->i_mode, inode->i_uid, inode->i_gid,
+ (int)inode->i_size, atomic_read(&inode->i_count)));
+
+ switch (obj->yst_mode & S_IFMT) {
+ default: /* fifo, device or socket */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+ init_special_inode(inode, obj->yst_mode,
+ old_decode_dev(obj->yst_rdev));
+#else
+ init_special_inode(inode, obj->yst_mode,
+ (dev_t) (obj->yst_rdev));
+#endif
+ break;
+ case S_IFREG: /* file */
+ inode->i_op = &yaffs_file_inode_operations;
+ inode->i_fop = &yaffs_file_operations;
+ inode->i_mapping->a_ops =
+ &yaffs_file_address_operations;
+ break;
+ case S_IFDIR: /* directory */
+ inode->i_op = &yaffs_dir_inode_operations;
+ inode->i_fop = &yaffs_dir_operations;
+ break;
+ case S_IFLNK: /* symlink */
+ inode->i_op = &yaffs_symlink_inode_operations;
+ break;
+ }
+
+ yaffs_InodeToObjectLV(inode) = obj;
+
+ obj->myInode = inode;
+
+ } else {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_FileInode invalid parameters\n"));
+ }
+
+}
+
+struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
+ yaffs_Object * obj)
+{
+ struct inode *inode;
+
+ if (!sb) {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_get_inode for NULL super_block!!\n"));
+ return NULL;
+
+ }
+
+ if (!obj) {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_get_inode for NULL object!!\n"));
+ return NULL;
+
+ }
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_get_inode for object %d\n", obj->objectId));
+
+ inode = Y_IGET(sb, obj->objectId);
+ if (IS_ERR(inode))
+ return NULL;
+
+ /* NB Side effect: iget calls back to yaffs_read_inode(). */
+ /* iget also increments the inode's i_count */
+ /* NB You can't be holding grossLock or deadlock will happen! */
+
+ return inode;
+}
+
+static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
+ loff_t * pos)
+{
+ yaffs_Object *obj;
+ int nWritten, ipos;
+ struct inode *inode;
+ yaffs_Device *dev;
+
+ obj = yaffs_DentryToObject(f->f_dentry);
+
+ dev = obj->myDev;
+
+ yaffs_GrossLock(dev);
+
+ inode = f->f_dentry->d_inode;
+
+ if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) {
+ ipos = inode->i_size;
+ } else {
+ ipos = *pos;
+ }
+
+ if (!obj) {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_file_write: hey obj is null!\n"));
+ } else {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG
+ "yaffs_file_write about to write writing %d bytes"
+ "to object %d at %d\n",
+ n, obj->objectId, ipos));
+ }
+
+ nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_file_write writing %d bytes, %d written at %d\n",
+ n, nWritten, ipos));
+ if (nWritten > 0) {
+ ipos += nWritten;
+ *pos = ipos;
+ if (ipos > inode->i_size) {
+ inode->i_size = ipos;
+ inode->i_blocks = (ipos + 511) >> 9;
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG
+ "yaffs_file_write size updated to %d bytes, "
+ "%d blocks\n",
+ ipos, (int)(inode->i_blocks)));
+ }
+
+ }
+ yaffs_GrossUnlock(dev);
+ return nWritten == 0 ? -ENOSPC : nWritten;
+}
+
+/* Space holding and freeing is done to ensure we have space available for write_begin/end */
+/* For now we just assume few parallel writes and check against a small number. */
+/* Todo: need to do this with a counter to handle parallel reads better */
+
+static ssize_t yaffs_hold_space(struct file *f)
+{
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+
+ int nFreeChunks;
+
+
+ obj = yaffs_DentryToObject(f->f_dentry);
+
+ dev = obj->myDev;
+
+ yaffs_GrossLock(dev);
+
+ nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
+
+ yaffs_GrossUnlock(dev);
+
+ return (nFreeChunks > 20) ? 1 : 0;
+}
+
+static void yaffs_release_space(struct file *f)
+{
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+
+
+ obj = yaffs_DentryToObject(f->f_dentry);
+
+ dev = obj->myDev;
+
+ yaffs_GrossLock(dev);
+
+
+ yaffs_GrossUnlock(dev);
+}
+
+static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
+{
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+ struct inode *inode = f->f_dentry->d_inode;
+ unsigned long offset, curoffs;
+ struct list_head *i;
+ yaffs_Object *l;
+
+ char name[YAFFS_MAX_NAME_LENGTH + 1];
+
+ obj = yaffs_DentryToObject(f->f_dentry);
+ dev = obj->myDev;
+
+ yaffs_GrossLock(dev);
+
+ offset = f->f_pos;
+
+ T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
+
+ if (offset == 0) {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_readdir: entry . ino %d \n",
+ (int)inode->i_ino));
+ if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR)
+ < 0) {
+ goto out;
+ }
+ offset++;
+ f->f_pos++;
+ }
+ if (offset == 1) {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_readdir: entry .. ino %d \n",
+ (int)f->f_dentry->d_parent->d_inode->i_ino));
+ if (filldir
+ (dirent, "..", 2, offset,
+ f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
+ goto out;
+ }
+ offset++;
+ f->f_pos++;
+ }
+
+ curoffs = 1;
+
+ /* If the directory has changed since the open or last call to
+ readdir, rewind to after the 2 canned entries. */
+
+ if (f->f_version != inode->i_version) {
+ offset = 2;
+ f->f_pos = offset;
+ f->f_version = inode->i_version;
+ }
+
+ list_for_each(i, &obj->variant.directoryVariant.children) {
+ curoffs++;
+ if (curoffs >= offset) {
+ l = list_entry(i, yaffs_Object, siblings);
+
+ yaffs_GetObjectName(l, name,
+ YAFFS_MAX_NAME_LENGTH + 1);
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_readdir: %s inode %d\n", name,
+ yaffs_GetObjectInode(l)));
+
+ if (filldir(dirent,
+ name,
+ strlen(name),
+ offset,
+ yaffs_GetObjectInode(l),
+ yaffs_GetObjectType(l))
+ < 0) {
+ goto up_and_out;
+ }
+
+ offset++;
+ f->f_pos++;
+ }
+ }
+
+ up_and_out:
+ out:
+
+ yaffs_GrossUnlock(dev);
+
+ return 0;
+}
+
+/*
+ * File creation. Allocate an inode, and we're done..
+ *
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
+#define YCRED(x) x
+#else
+#define YCRED(x) (x->cred)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ dev_t rdev)
+#else
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ int rdev)
+#endif
+{
+ struct inode *inode;
+
+ yaffs_Object *obj = NULL;
+ yaffs_Device *dev;
+
+ yaffs_Object *parent = yaffs_InodeToObject(dir);
+
+ int error = -ENOSPC;
+ uid_t uid = YCRED(current)->fsuid;
+ gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+
+ if((dir->i_mode & S_ISGID) && S_ISDIR(mode))
+ mode |= S_ISGID;
+
+ if (parent) {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_mknod: parent object %d type %d\n",
+ parent->objectId, parent->variantType));
+ } else {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_mknod: could not get parent object\n"));
+ return -EPERM;
+ }
+
+ T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
+ "mode %x dev %x\n",
+ dentry->d_name.name, mode, rdev));
+
+ dev = parent->myDev;
+
+ yaffs_GrossLock(dev);
+
+ switch (mode & S_IFMT) {
+ default:
+ /* Special (socket, fifo, device...) */
+ T(YAFFS_TRACE_OS, (KERN_DEBUG
+ "yaffs_mknod: making special\n"));
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+ obj =
+ yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
+ gid, old_encode_dev(rdev));
+#else
+ obj =
+ yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
+ gid, rdev);
+#endif
+ break;
+ case S_IFREG: /* file */
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mknod: making file\n"));
+ obj =
+ yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
+ gid);
+ break;
+ case S_IFDIR: /* directory */
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_mknod: making directory\n"));
+ obj =
+ yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
+ uid, gid);
+ break;
+ case S_IFLNK: /* symlink */
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mknod: making file\n"));
+ obj = NULL; /* Do we ever get here? */
+ break;
+ }
+
+ /* Can not call yaffs_get_inode() with gross lock held */
+ yaffs_GrossUnlock(dev);
+
+ if (obj) {
+ inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
+ d_instantiate(dentry, inode);
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_mknod created object %d count = %d\n",
+ obj->objectId, atomic_read(&inode->i_count)));
+ error = 0;
+ } else {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_mknod failed making object\n"));
+ error = -ENOMEM;
+ }
+
+ return error;
+}
+
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ int retVal;
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mkdir\n"));
+ retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
+#if 0
+ /* attempt to fix dir bug - didn't work */
+ if (!retVal) {
+ dget(dentry);
+ }
+#endif
+ return retVal;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *n)
+#else
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
+#endif
+{
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_create\n"));
+ return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
+}
+
+static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
+{
+ int retVal;
+
+ yaffs_Device *dev;
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_unlink %d:%s\n", (int)(dir->i_ino),
+ dentry->d_name.name));
+
+ dev = yaffs_InodeToObject(dir)->myDev;
+
+ yaffs_GrossLock(dev);
+
+ retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
+
+ if (retVal == YAFFS_OK) {
+ dentry->d_inode->i_nlink--;
+ dir->i_version++;
+ yaffs_GrossUnlock(dev);
+ mark_inode_dirty(dentry->d_inode);
+ return 0;
+ }
+ yaffs_GrossUnlock(dev);
+ return -ENOTEMPTY;
+}
+
+/*
+ * Create a link...
+ */
+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry)
+{
+ struct inode *inode = old_dentry->d_inode;
+ yaffs_Object *obj = NULL;
+ yaffs_Object *link = NULL;
+ yaffs_Device *dev;
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_link\n"));
+
+ obj = yaffs_InodeToObject(inode);
+ dev = obj->myDev;
+
+ yaffs_GrossLock(dev);
+
+ if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
+ {
+ link =
+ yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
+ obj);
+ }
+
+ if (link) {
+ old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
+ d_instantiate(dentry, old_dentry->d_inode);
+ atomic_inc(&old_dentry->d_inode->i_count);
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_link link count %d i_count %d\n",
+ old_dentry->d_inode->i_nlink,
+ atomic_read(&old_dentry->d_inode->i_count)));
+
+ }
+
+ yaffs_GrossUnlock(dev);
+
+ if (link) {
+
+ return 0;
+ }
+
+ return -EPERM;
+}
+
+static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname)
+{
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+ uid_t uid = YCRED(current)->fsuid;
+ gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_symlink\n"));
+
+ dev = yaffs_InodeToObject(dir)->myDev;
+ yaffs_GrossLock(dev);
+ obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
+ S_IFLNK | S_IRWXUGO, uid, gid, symname);
+ yaffs_GrossUnlock(dev);
+
+ if (obj) {
+
+ struct inode *inode;
+
+ inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+ d_instantiate(dentry, inode);
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink created OK\n"));
+ return 0;
+ } else {
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink not created\n"));
+
+ }
+
+ return -ENOMEM;
+}
+
+static int yaffs_sync_object(struct file *file, struct dentry *dentry,
+ int datasync)
+{
+
+ yaffs_Object *obj;
+ yaffs_Device *dev;
+
+ obj = yaffs_DentryToObject(dentry);
+
+ dev = obj->myDev;
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_object\n"));
+ yaffs_GrossLock(dev);
+ yaffs_FlushFile(obj, 1);
+ yaffs_GrossUnlock(dev);
+ return 0;
+}
+
+/*
+ * The VFS layer already does all the dentry stuff for rename.
+ *
+ * NB: POSIX says you can rename an object over an old object of the same name
+ */
+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+{
+ yaffs_Device *dev;
+ int retVal = YAFFS_FAIL;
+ yaffs_Object *target;
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_rename\n"));
+ dev = yaffs_InodeToObject(old_dir)->myDev;
+
+ yaffs_GrossLock(dev);
+
+ /* Check if the target is an existing directory that is not empty. */
+ target =
+ yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
+ new_dentry->d_name.name);
+
+
+
+ if (target &&
+ target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+ !list_empty(&target->variant.directoryVariant.children)) {
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "target is non-empty dir\n"));
+
+ retVal = YAFFS_FAIL;
+ } else {
+
+ /* Now does unlinking internally using shadowing mechanism */
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "calling yaffs_RenameObject\n"));
+
+ retVal =
+ yaffs_RenameObject(yaffs_InodeToObject(old_dir),
+ old_dentry->d_name.name,
+ yaffs_InodeToObject(new_dir),
+ new_dentry->d_name.name);
+
+ }
+ yaffs_GrossUnlock(dev);
+
+ if (retVal == YAFFS_OK) {
+ if(target) {
+ new_dentry->d_inode->i_nlink--;
+ mark_inode_dirty(new_dentry->d_inode);
+ }
+
+ return 0;
+ } else {
+ return -ENOTEMPTY;
+ }
+
+}
+
+static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ int error;
+ yaffs_Device *dev;
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_setattr of object %d\n",
+ yaffs_InodeToObject(inode)->objectId));
+
+ if ((error = inode_change_ok(inode, attr)) == 0) {
+
+ dev = yaffs_InodeToObject(inode)->myDev;
+ yaffs_GrossLock(dev);
+ if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
+ YAFFS_OK) {
+ error = 0;
+ } else {
+ error = -EPERM;
+ }
+ yaffs_GrossUnlock(dev);
+ if (!error)
+ error = inode_setattr(inode, attr);
+ }
+ return error;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+ yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+ struct super_block *sb = dentry->d_sb;
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
+{
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+#else
+static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
+{
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+#endif
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_statfs\n"));
+
+ yaffs_GrossLock(dev);
+
+ buf->f_type = YAFFS_MAGIC;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_namelen = 255;
+ if (sb->s_blocksize > dev->nDataBytesPerChunk) {
+
+ buf->f_blocks =
+ (dev->endBlock - dev->startBlock +
+ 1) * dev->nChunksPerBlock / (sb->s_blocksize /
+ dev->nDataBytesPerChunk);
+ buf->f_bfree =
+ yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize /
+ dev->nDataBytesPerChunk);
+ } else {
+
+ buf->f_blocks =
+ (dev->endBlock - dev->startBlock +
+ 1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk /
+ sb->s_blocksize);
+ buf->f_bfree =
+ yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk /
+ sb->s_blocksize);
+ }
+ buf->f_files = 0;
+ buf->f_ffree = 0;
+ buf->f_bavail = buf->f_bfree;
+
+ yaffs_GrossUnlock(dev);
+ return 0;
+}
+
+
+/**
+static int yaffs_do_sync_fs(struct super_block *sb)
+{
+
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_do_sync_fs\n"));
+
+ if(sb->s_dirt) {
+ yaffs_GrossLock(dev);
+
+ if(dev)
+ yaffs_CheckpointSave(dev);
+
+ yaffs_GrossUnlock(dev);
+
+ sb->s_dirt = 0;
+ }
+ return 0;
+}
+**/
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static void yaffs_write_super(struct super_block *sb)
+#else
+static int yaffs_write_super(struct super_block *sb)
+#endif
+{
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_super\n"));
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+ return 0; /* yaffs_do_sync_fs(sb);*/
+#endif
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_sync_fs(struct super_block *sb, int wait)
+#else
+static int yaffs_sync_fs(struct super_block *sb)
+#endif
+{
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n"));
+
+ return 0; /* yaffs_do_sync_fs(sb);*/
+
+}
+
+#ifdef YAFFS_USE_OWN_IGET
+
+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
+{
+ struct inode *inode;
+ yaffs_Object *obj;
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+
+ T(YAFFS_TRACE_OS,
+ ("yaffs_iget for %lu\n", ino));
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ /* NB This is called as a side effect of other functions, but
+ * we had to release the lock to prevent deadlocks, so
+ * need to lock again.
+ */
+
+ yaffs_GrossLock(dev);
+
+ obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
+
+ yaffs_FillInodeFromObject(inode, obj);
+
+ yaffs_GrossUnlock(dev);
+
+ unlock_new_inode(inode);
+ return inode;
+}
+
+#else
+
+static void yaffs_read_inode(struct inode *inode)
+{
+ /* NB This is called as a side effect of other functions, but
+ * we had to release the lock to prevent deadlocks, so
+ * need to lock again.
+ */
+
+ yaffs_Object *obj;
+ yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
+
+ T(YAFFS_TRACE_OS,
+ ("yaffs_read_inode for %d\n", (int)inode->i_ino));
+
+ yaffs_GrossLock(dev);
+
+ obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
+
+ yaffs_FillInodeFromObject(inode, obj);
+
+ yaffs_GrossUnlock(dev);
+}
+
+#endif
+
+static LIST_HEAD(yaffs_dev_list);
+
+static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+
+ if( *flags & MS_RDONLY ) {
+ struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_remount_fs: %s: RO\n", dev->name ));
+
+ yaffs_GrossLock(dev);
+
+ yaffs_FlushEntireDeviceCache(dev);
+
+ yaffs_CheckpointSave(dev);
+
+ if (mtd->sync)
+ mtd->sync(mtd);
+
+ yaffs_GrossUnlock(dev);
+ }
+ else {
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_remount_fs: %s: RW\n", dev->name ));
+ }
+
+ return 0;
+}
+
+static void yaffs_put_super(struct super_block *sb)
+{
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_put_super\n"));
+
+ yaffs_GrossLock(dev);
+
+ yaffs_FlushEntireDeviceCache(dev);
+
+ yaffs_CheckpointSave(dev);
+
+ if (dev->putSuperFunc) {
+ dev->putSuperFunc(sb);
+ }
+
+ yaffs_Deinitialise(dev);
+
+ yaffs_GrossUnlock(dev);
+
+ /* we assume this is protected by lock_kernel() in mount/umount */
+ list_del(&dev->devList);
+
+ if(dev->spareBuffer){
+ YFREE(dev->spareBuffer);
+ dev->spareBuffer = NULL;
+ }
+
+ kfree(dev);
+}
+
+
+static void yaffs_MTDPutSuper(struct super_block *sb)
+{
+
+ struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
+
+ if (mtd->sync) {
+ mtd->sync(mtd);
+ }
+
+ put_mtd_device(mtd);
+}
+
+
+static void yaffs_MarkSuperBlockDirty(void *vsb)
+{
+ struct super_block *sb = (struct super_block *)vsb;
+
+ T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_MarkSuperBlockDirty() sb = %p\n",sb));
+// if(sb)
+// sb->s_dirt = 1;
+}
+
+static struct super_block *yaffs_internal_read_super(int yaffsVersion,
+ struct super_block *sb,
+ void *data, int silent)
+{
+ int nBlocks;
+ struct inode *inode = NULL;
+ struct dentry *root;
+ yaffs_Device *dev = 0;
+ char devname_buf[BDEVNAME_SIZE + 1];
+ struct mtd_info *mtd;
+ int err;
+
+ sb->s_magic = YAFFS_MAGIC;
+ sb->s_op = &yaffs_super_ops;
+
+ if (!sb)
+ printk(KERN_INFO "yaffs: sb is NULL\n");
+ else if (!sb->s_dev)
+ printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
+ else if (!yaffs_devname(sb, devname_buf))
+ printk(KERN_INFO "yaffs: devname is NULL\n");
+ else
+ printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
+ sb->s_dev,
+ yaffs_devname(sb, devname_buf));
+
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
+ T(YAFFS_TRACE_OS,
+ ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
+
+#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
+ T(YAFFS_TRACE_OS,
+ ("yaffs: Write verification disabled. All guarantees "
+ "null and void\n"));
+#endif
+
+ T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
+ "\"%s\"\n",
+ MAJOR(sb->s_dev), MINOR(sb->s_dev),
+ yaffs_devname(sb, devname_buf)));
+
+ /* Check it's an mtd device..... */
+ if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) {
+ return NULL; /* This isn't an mtd device */
+ }
+ /* Get the device */
+ mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
+ if (!mtd) {
+ T(YAFFS_TRACE_ALWAYS,
+ ("yaffs: MTD device #%u doesn't appear to exist\n",
+ MINOR(sb->s_dev)));
+ return NULL;
+ }
+ /* Check it's NAND */
+ if (mtd->type != MTD_NANDFLASH) {
+ T(YAFFS_TRACE_ALWAYS,
+ ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
+ return NULL;
+ }
+
+ T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
+ T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
+ T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
+ T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
+ T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
+ T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
+ T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ T(YAFFS_TRACE_OS, (" writesize %d\n", mtd->writesize));
+#else
+ T(YAFFS_TRACE_OS, (" oobblock %d\n", mtd->oobblock));
+#endif
+ T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
+ T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
+ T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
+
+#ifdef CONFIG_YAFFS_AUTO_YAFFS2
+
+ if (yaffsVersion == 1 &&
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ mtd->writesize >= 2048) {
+#else
+ mtd->oobblock >= 2048) {
+#endif
+ T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
+ yaffsVersion = 2;
+ }
+
+ /* Added NCB 26/5/2006 for completeness */
+ if (yaffsVersion == 2 &&
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ mtd->writesize == 512) {
+#else
+ mtd->oobblock == 512) {
+#endif
+ T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
+ yaffsVersion = 1;
+ }
+
+#endif
+
+ if (yaffsVersion == 2) {
+ /* Check for version 2 style functions */
+ if (!mtd->erase ||
+ !mtd->block_isbad ||
+ !mtd->block_markbad ||
+ !mtd->read ||
+ !mtd->write ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ !mtd->read_oob || !mtd->write_oob) {
+#else
+ !mtd->write_ecc ||
+ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
+#endif
+ T(YAFFS_TRACE_ALWAYS,
+ ("yaffs: MTD device does not support required "
+ "functions\n"));;
+ return NULL;
+ }
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+#else
+ if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+#endif
+ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) {
+ T(YAFFS_TRACE_ALWAYS,
+ ("yaffs: MTD device does not have the "
+ "right page sizes\n"));
+ return NULL;
+ }
+ } else {
+ /* Check for V1 style functions */
+ if (!mtd->erase ||
+ !mtd->read ||
+ !mtd->write ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ !mtd->read_oob || !mtd->write_oob) {
+#else
+ !mtd->write_ecc ||
+ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
+#endif
+ T(YAFFS_TRACE_ALWAYS,
+ ("yaffs: MTD device does not support required "
+ "functions\n"));;
+ return NULL;
+ }
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ if (mtd->writesize < YAFFS_BYTES_PER_CHUNK ||
+#else
+ if (mtd->oobblock < YAFFS_BYTES_PER_CHUNK ||
+#endif
+ mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
+ T(YAFFS_TRACE_ALWAYS,
+ ("yaffs: MTD device does not support have the "
+ "right page sizes\n"));
+ return NULL;
+ }
+ }
+
+ /* OK, so if we got here, we have an MTD that's NAND and looks
+ * like it has the right capabilities
+ * Set the yaffs_Device up for mtd
+ */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+ sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
+#else
+ sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
+#endif
+ if (!dev) {
+ /* Deep shit could not allocate device structure */
+ T(YAFFS_TRACE_ALWAYS,
+ ("yaffs_read_super: Failed trying to allocate "
+ "yaffs_Device. \n"));
+ return NULL;
+ }
+
+ memset(dev, 0, sizeof(yaffs_Device));
+ dev->genericDevice = mtd;
+ dev->name = mtd->name;
+
+ /* Set up the memory size parameters.... */
+ dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
+ dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
+ dev->nReservedBlocks = 5;
+ dev->nShortOpCaches = 10; /* Enable short op caching */
+
+ /* ... and the functions. */
+ if (yaffsVersion == 2) {
+ int block_shift;
+ dev->writeChunkWithTagsToNAND =
+ nandmtd2_WriteChunkWithTagsToNAND;
+ dev->readChunkWithTagsFromNAND =
+ nandmtd2_ReadChunkWithTagsFromNAND;
+ dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
+ dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
+ dev->spareBuffer = YMALLOC(mtd->oobsize);
+ dev->isYaffs2 = 1;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ dev->nDataBytesPerChunk = mtd->writesize;
+ dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
+#else
+ dev->nDataBytesPerChunk = mtd->oobblock;
+ dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
+#endif
+ block_shift = ffs(mtd->erasesize) - 1;
+// nBlocks = mtd->size / mtd->erasesize;
+ nBlocks = mtd->size >> block_shift;
+ dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS;
+ dev->startBlock = 0;
+ dev->endBlock = nBlocks - 1;
+ } else {
+ nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
+ dev->startBlock = 0;
+ dev->endBlock = nBlocks - 1;
+ dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
+ dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
+ dev->isYaffs2 = 0;
+ }
+ /* ... and common functions */
+ dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
+ dev->initialiseNAND = nandmtd_InitialiseNAND;
+
+ dev->putSuperFunc = yaffs_MTDPutSuper;
+
+ dev->superBlock = (void *)sb;
+ dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
+
+
+#ifndef CONFIG_YAFFS_DOES_ECC
+ dev->useNANDECC = 1;
+#endif
+
+#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
+ dev->wideTnodesDisabled = 1;
+#endif
+
+ /* we assume this is protected by lock_kernel() in mount/umount */
+ list_add_tail(&dev->devList, &yaffs_dev_list);
+
+ init_MUTEX(&dev->grossLock);
+
+ yaffs_GrossLock(dev);
+
+ err = yaffs_GutsInitialise(dev);
+
+ T(YAFFS_TRACE_OS,
+ ("yaffs_read_super: guts initialised %s\n",
+ (err == YAFFS_OK) ? "OK" : "FAILED"));
+
+ /* Release lock before yaffs_get_inode() */
+ yaffs_GrossUnlock(dev);
+
+ /* Create root inode */
+ if (err == YAFFS_OK)
+ inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
+ yaffs_Root(dev));
+
+ if (!inode)
+ return NULL;
+ inode->i_op = &yaffs_dir_inode_operations;
+ inode->i_fop = &yaffs_dir_operations;
+
+ T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
+
+ root = d_alloc_root(inode);
+
+ T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
+
+ if (!root) {
+ iput(inode);
+ return NULL;
+ }
+ sb->s_root = root;
+ T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
+ return sb;
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
+ int silent)
+{
+ return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_read_super(struct file_system_type *fs,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
+{
+
+ return get_sb_bdev(fs, flags, dev_name, data,
+ yaffs_internal_read_super_mtd, mnt);
+}
+#else
+static struct super_block *yaffs_read_super(struct file_system_type *fs,
+ int flags, const char *dev_name,
+ void *data)
+{
+
+ return get_sb_bdev(fs, flags, dev_name, data,
+ yaffs_internal_read_super_mtd);
+}
+#endif
+
+static struct file_system_type yaffs_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "yaffs",
+ .get_sb = yaffs_read_super,
+ .kill_sb = kill_block_super,
+ .fs_flags = FS_REQUIRES_DEV,
+};
+#else
+static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
+ int silent)
+{
+ return yaffs_internal_read_super(1, sb, data, silent);
+}
+
+static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
+ FS_REQUIRES_DEV);
+#endif
+
+
+#ifdef CONFIG_YAFFS_YAFFS2
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
+ int silent)
+{
+ return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs2_read_super(struct file_system_type *fs,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
+{
+ return get_sb_bdev(fs, flags, dev_name, data,
+ yaffs2_internal_read_super_mtd, mnt);
+}
+#else
+static struct super_block *yaffs2_read_super(struct file_system_type *fs,
+ int flags, const char *dev_name,
+ void *data)
+{
+
+ return get_sb_bdev(fs, flags, dev_name, data,
+ yaffs2_internal_read_super_mtd);
+}
+#endif
+
+static struct file_system_type yaffs2_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "yaffs2",
+ .get_sb = yaffs2_read_super,
+ .kill_sb = kill_block_super,
+ .fs_flags = FS_REQUIRES_DEV,
+};
+#else
+static struct super_block *yaffs2_read_super(struct super_block *sb,
+ void *data, int silent)
+{
+ return yaffs_internal_read_super(2, sb, data, silent);
+}
+
+static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
+ FS_REQUIRES_DEV);
+#endif
+
+#endif /* CONFIG_YAFFS_YAFFS2 */
+
+static struct proc_dir_entry *my_proc_entry;
+
+static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
+{
+ buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
+ buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
+ buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
+ buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
+ buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
+ buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
+ buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
+ buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
+ buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
+ buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
+ buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
+ buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
+ buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
+ buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
+ buf +=
+ sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
+ buf +=
+ sprintf(buf, "passiveGCs......... %d\n",
+ dev->passiveGarbageCollections);
+ buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
+ buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
+ buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
+ buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
+ buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
+ buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
+ buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
+ buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
+ buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
+ buf +=
+ sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
+ buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
+ buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
+
+ return buf;
+}
+
+static int yaffs_proc_read(char *page,
+ char **start,
+ off_t offset, int count, int *eof, void *data)
+{
+ struct list_head *item;
+ char *buf = page;
+ int step = offset;
+ int n = 0;
+
+ /* Get proc_file_read() to step 'offset' by one on each sucessive call.
+ * We use 'offset' (*ppos) to indicate where we are in devList.
+ * This also assumes the user has posted a read buffer large
+ * enough to hold the complete output; but that's life in /proc.
+ */
+
+ *(int *)start = 1;
+
+ /* Print header first */
+ if (step == 0) {
+ buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
+ "\n%s\n%s\n", yaffs_fs_c_version,
+ yaffs_guts_c_version);
+ }
+
+ /* hold lock_kernel while traversing yaffs_dev_list */
+ lock_kernel();
+
+ /* Locate and print the Nth entry. Order N-squared but N is small. */
+ list_for_each(item, &yaffs_dev_list) {
+ yaffs_Device *dev = list_entry(item, yaffs_Device, devList);
+ if (n < step) {
+ n++;
+ continue;
+ }
+ buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
+ buf = yaffs_dump_dev(buf, dev);
+ break;
+ }
+ unlock_kernel();
+
+ return buf - page < count ? buf - page : count;
+}
+
+/**
+ * Set the verbosity of the warnings and error messages.
+ *
+ */
+
+static struct {
+ char *mask_name;
+ unsigned mask_bitfield;
+} mask_flags[] = {
+ {"allocate", YAFFS_TRACE_ALLOCATE},
+ {"always", YAFFS_TRACE_ALWAYS},
+ {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
+ {"buffers", YAFFS_TRACE_BUFFERS},
+ {"bug", YAFFS_TRACE_BUG},
+ {"deletion", YAFFS_TRACE_DELETION},
+ {"erase", YAFFS_TRACE_ERASE},
+ {"error", YAFFS_TRACE_ERROR},
+ {"gc_detail", YAFFS_TRACE_GC_DETAIL},
+ {"gc", YAFFS_TRACE_GC},
+ {"mtd", YAFFS_TRACE_MTD},
+ {"nandaccess", YAFFS_TRACE_NANDACCESS},
+ {"os", YAFFS_TRACE_OS},
+ {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
+ {"scan", YAFFS_TRACE_SCAN},
+ {"tracing", YAFFS_TRACE_TRACING},
+ {"write", YAFFS_TRACE_WRITE},
+ {"all", 0xffffffff},
+ {"none", 0},
+ {NULL, 0},
+};
+
+static int yaffs_proc_write(struct file *file, const char *buf,
+ unsigned long count, void *data)
+{
+ unsigned rg = 0, mask_bitfield;
+ char *end, *mask_name;
+ int i;
+ int done = 0;
+ int add, len = 0;
+ int pos = 0;
+
+ rg = yaffs_traceMask;
+
+ while (!done && (pos < count)) {
+ done = 1;
+ while ((pos < count) && isspace(buf[pos])) {
+ pos++;
+ }
+
+ switch (buf[pos]) {
+ case '+':
+ case '-':
+ case '=':
+ add = buf[pos];
+ pos++;
+ break;
+
+ default:
+ add = ' ';
+ break;
+ }
+ mask_name = NULL;
+ mask_bitfield = simple_strtoul(buf + pos, &end, 0);
+ if (end > buf + pos) {
+ mask_name = "numeral";
+ len = end - (buf + pos);
+ done = 0;
+ } else {
+
+ for (i = 0; mask_flags[i].mask_name != NULL; i++) {
+ len = strlen(mask_flags[i].mask_name);
+ if (strncmp(buf + pos, mask_flags[i].mask_name, len) == 0) {
+ mask_name = mask_flags[i].mask_name;
+ mask_bitfield = mask_flags[i].mask_bitfield;
+ done = 0;
+ break;
+ }
+ }
+ }
+
+ if (mask_name != NULL) {
+ pos += len;
+ done = 0;
+ switch(add) {
+ case '-':
+ rg &= ~mask_bitfield;
+ break;
+ case '+':
+ rg |= mask_bitfield;
+ break;
+ case '=':
+ rg = mask_bitfield;
+ break;
+ default:
+ rg |= mask_bitfield;
+ break;
+ }
+ }
+ }
+
+ yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
+
+ if (rg & YAFFS_TRACE_ALWAYS) {
+ for (i = 0; mask_flags[i].mask_name != NULL; i++) {
+ char flag;
+ flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
+ printk("%c%s\n", flag, mask_flags[i].mask_name);
+ }
+ }
+
+ return count;
+}
+
+/* Stuff to handle installation of file systems */
+struct file_system_to_install {
+ struct file_system_type *fst;
+ int installed;
+};
+
+static struct file_system_to_install fs_to_install[] = {
+//#ifdef CONFIG_YAFFS_YAFFS1
+ {&yaffs_fs_type, 0},
+//#endif
+//#ifdef CONFIG_YAFFS_YAFFS2
+ {&yaffs2_fs_type, 0},
+//#endif
+ {NULL, 0}
+};
+
+static int __init init_yaffs_fs(void)
+{
+ int error = 0;
+ struct file_system_to_install *fsinst;
+
+ T(YAFFS_TRACE_ALWAYS,
+ ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
+
+ /* Install the proc_fs entry */
+ my_proc_entry = create_proc_entry("yaffs",
+ S_IRUGO | S_IFREG,
+ YPROC_ROOT);
+
+ if (my_proc_entry) {
+ my_proc_entry->write_proc = yaffs_proc_write;
+ my_proc_entry->read_proc = yaffs_proc_read;
+ my_proc_entry->data = NULL;
+ } else {
+ return -ENOMEM;
+ }
+
+ /* Now add the file system entries */
+
+ fsinst = fs_to_install;
+
+ while (fsinst->fst && !error) {
+ error = register_filesystem(fsinst->fst);
+ if (!error) {
+ fsinst->installed = 1;
+ }
+ fsinst++;
+ }
+
+ /* Any errors? uninstall */
+ if (error) {
+ fsinst = fs_to_install;
+
+ while (fsinst->fst) {
+ if (fsinst->installed) {
+ unregister_filesystem(fsinst->fst);
+ fsinst->installed = 0;
+ }
+ fsinst++;
+ }
+ }
+
+#if defined(CONFIG_YAFFS_ECC_RS)
+ /* init reed solomon ECC for nand oob area
+ * Symbolsize is 5 (bits)
+ * Primitive polynomial is x^5+x^2+1
+ * first consecutive root is 0
+ * primitive element to generate roots = 1
+ * generator polynomial degree (number of roots) = 4
+ */
+ rs_decoder = init_rs (5, 0x25, 1, 1, 4);
+#endif
+ return error;
+}
+
+static void __exit exit_yaffs_fs(void)
+{
+
+ struct file_system_to_install *fsinst;
+
+ T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
+ " removing. \n"));
+
+ remove_proc_entry("yaffs", YPROC_ROOT);
+
+ fsinst = fs_to_install;
+
+ while (fsinst->fst) {
+ if (fsinst->installed) {
+ unregister_filesystem(fsinst->fst);
+ fsinst->installed = 0;
+ }
+ fsinst++;
+ }
+
+#if defined(CONFIG_YAFFS_ECC_RS)
+ free_rs(rs_decoder);
+#endif
+}
+
+module_init(init_yaffs_fs)
+module_exit(exit_yaffs_fs)
+
+MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
+MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
+MODULE_LICENSE("GPL");
diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c
new file mode 100644
index 00000000000..d00022ace80
--- /dev/null
+++ b/fs/yaffs2/yaffs_guts.c
@@ -0,0 +1,6676 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+const char *yaffs_guts_c_version =
+ "$Id: yaffs_guts.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $";
+
+#include "yportenv.h"
+
+#include "yaffsinterface.h"
+#include "yaffs_guts.h"
+#include "yaffs_tagsvalidity.h"
+
+#include "yaffs_tagscompat.h"
+#ifndef CONFIG_YAFFS_OWN_SORT
+#include "yaffs_qsort.h"
+#endif
+#include "yaffs_nand.h"
+
+#include "yaffs_checkptrw.h"
+
+#include "yaffs_nand.h"
+#include "yaffs_packedtags2.h"
+
+
+#ifdef CONFIG_YAFFS_WINCE
+void yfsd_LockYAFFS(BOOL fsLockOnly);
+void yfsd_UnlockYAFFS(BOOL fsLockOnly);
+#endif
+
+#define YAFFS_PASSIVE_GC_CHUNKS 2
+
+#include "yaffs_ecc.h"
+
+
+/* Robustification (if it ever comes about...) */
+static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND);
+static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk);
+static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
+ const __u8 * data,
+ const yaffs_ExtendedTags * tags);
+static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
+ const yaffs_ExtendedTags * tags);
+
+/* Other local prototypes */
+static int yaffs_UnlinkObject( yaffs_Object *obj);
+static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
+
+static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
+
+static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device * dev,
+ const __u8 * buffer,
+ yaffs_ExtendedTags * tags,
+ int useReserve);
+static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode,
+ int chunkInNAND, int inScan);
+
+static yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number,
+ yaffs_ObjectType type);
+static void yaffs_AddObjectToDirectory(yaffs_Object * directory,
+ yaffs_Object * obj);
+static int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name,
+ int force, int isShrink, int shadows);
+static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj);
+static int yaffs_CheckStructures(void);
+static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level,
+ int chunkOffset, int *limit);
+static int yaffs_DoGenericObjectDeletion(yaffs_Object * in);
+
+static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blockNo);
+
+static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo);
+static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer,
+ int lineNo);
+
+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
+ int chunkInNAND);
+
+static int yaffs_UnlinkWorker(yaffs_Object * obj);
+static void yaffs_DestroyObject(yaffs_Object * obj);
+
+static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId,
+ int chunkInObject);
+
+loff_t yaffs_GetFileSize(yaffs_Object * obj);
+
+static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr);
+
+static void yaffs_VerifyFreeChunks(yaffs_Device * dev);
+
+#ifdef YAFFS_PARANOID
+static int yaffs_CheckFileSanity(yaffs_Object * in);
+#else
+#define yaffs_CheckFileSanity(in)
+#endif
+
+static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in);
+static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId);
+
+static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
+
+
+
+/* Function to calculate chunk and offset */
+
+static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, __u32 *chunk, __u32 *offset)
+{
+ if(dev->chunkShift){
+ /* Easy-peasy power of 2 case */
+ *chunk = (__u32)(addr >> dev->chunkShift);
+ *offset = (__u32)(addr & dev->chunkMask);
+ }
+ else if(dev->crumbsPerChunk)
+ {
+ /* Case where we're using "crumbs" */
+ *offset = (__u32)(addr & dev->crumbMask);
+ addr >>= dev->crumbShift;
+ *chunk = ((__u32)addr)/dev->crumbsPerChunk;
+ *offset += ((addr - (*chunk * dev->crumbsPerChunk)) << dev->crumbShift);
+ }
+ else
+ YBUG();
+}
+
+/* Function to return the number of shifts for a power of 2 greater than or equal
+ * to the given number
+ * Note we don't try to cater for all possible numbers and this does not have to
+ * be hellishly efficient.
+ */
+
+static __u32 ShiftsGE(__u32 x)
+{
+ int extraBits;
+ int nShifts;
+
+ nShifts = extraBits = 0;
+
+ while(x>1){
+ if(x & 1) extraBits++;
+ x>>=1;
+ nShifts++;
+ }
+
+ if(extraBits)
+ nShifts++;
+
+ return nShifts;
+}
+
+/* Function to return the number of shifts to get a 1 in bit 0
+ */
+
+static __u32 ShiftDiv(__u32 x)
+{
+ int nShifts;
+
+ nShifts = 0;
+
+ if(!x) return 0;
+
+ while( !(x&1)){
+ x>>=1;
+ nShifts++;
+ }
+
+ return nShifts;
+}
+
+
+
+/*
+ * Temporary buffer manipulations.
+ */
+
+static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo)
+{
+ int i, j;
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+ if (dev->tempBuffer[i].line == 0) {
+ dev->tempBuffer[i].line = lineNo;
+ if ((i + 1) > dev->maxTemp) {
+ dev->maxTemp = i + 1;
+ for (j = 0; j <= i; j++)
+ dev->tempBuffer[j].maxLine =
+ dev->tempBuffer[j].line;
+ }
+
+ return dev->tempBuffer[i].buffer;
+ }
+ }
+
+ T(YAFFS_TRACE_BUFFERS,
+ (TSTR("Out of temp buffers at line %d, other held by lines:"),
+ lineNo));
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+ T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line));
+ }
+ T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));
+
+ /*
+ * If we got here then we have to allocate an unmanaged one
+ * This is not good.
+ */
+
+ dev->unmanagedTempAllocations++;
+ return YMALLOC(dev->nDataBytesPerChunk);
+
+}
+
+static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer,
+ int lineNo)
+{
+ int i;
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+ if (dev->tempBuffer[i].buffer == buffer) {
+ dev->tempBuffer[i].line = 0;
+ return;
+ }
+ }
+
+ if (buffer) {
+ /* assume it is an unmanaged one. */
+ T(YAFFS_TRACE_BUFFERS,
+ (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),
+ lineNo));
+ YFREE(buffer);
+ dev->unmanagedTempDeallocations++;
+ }
+
+}
+
+/*
+ * Determine if we have a managed buffer.
+ */
+int yaffs_IsManagedTempBuffer(yaffs_Device * dev, const __u8 * buffer)
+{
+ int i;
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+ if (dev->tempBuffer[i].buffer == buffer)
+ return 1;
+
+ }
+
+ for (i = 0; i < dev->nShortOpCaches; i++) {
+ if( dev->srCache[i].data == buffer )
+ return 1;
+
+ }
+
+ if (buffer == dev->checkpointBuffer)
+ return 1;
+
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR)));
+ return 0;
+}
+
+/*
+ * Chunk bitmap manipulations
+ */
+
+static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device * dev, int blk)
+{
+ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
+ blk));
+ YBUG();
+ }
+ return dev->chunkBits +
+ (dev->chunkBitmapStride * (blk - dev->internalStartBlock));
+}
+
+static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device * dev, int blk)
+{
+ __u8 *blkBits = yaffs_BlockBits(dev, blk);
+
+ memset(blkBits, 0, dev->chunkBitmapStride);
+}
+
+static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device * dev, int blk, int chunk)
+{
+ __u8 *blkBits = yaffs_BlockBits(dev, blk);
+
+ blkBits[chunk / 8] &= ~(1 << (chunk & 7));
+}
+
+static Y_INLINE void yaffs_SetChunkBit(yaffs_Device * dev, int blk, int chunk)
+{
+ __u8 *blkBits = yaffs_BlockBits(dev, blk);
+
+ blkBits[chunk / 8] |= (1 << (chunk & 7));
+}
+
+static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device * dev, int blk, int chunk)
+{
+ __u8 *blkBits = yaffs_BlockBits(dev, blk);
+ return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
+}
+
+static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device * dev, int blk)
+{
+ __u8 *blkBits = yaffs_BlockBits(dev, blk);
+ int i;
+ for (i = 0; i < dev->chunkBitmapStride; i++) {
+ if (*blkBits)
+ return 1;
+ blkBits++;
+ }
+ return 0;
+}
+
+/*
+ * Simple hash function. Needs to have a reasonable spread
+ */
+
+static Y_INLINE int yaffs_HashFunction(int n)
+{
+ n = abs(n);
+ return (n % YAFFS_NOBJECT_BUCKETS);
+}
+
+/*
+ * Access functions to useful fake objects
+ */
+
+yaffs_Object *yaffs_Root(yaffs_Device * dev)
+{
+ return dev->rootDir;
+}
+
+yaffs_Object *yaffs_LostNFound(yaffs_Device * dev)
+{
+ return dev->lostNFoundDir;
+}
+
+
+/*
+ * Erased NAND checking functions
+ */
+
+int yaffs_CheckFF(__u8 * buffer, int nBytes)
+{
+ /* Horrible, slow implementation */
+ while (nBytes--) {
+ if (*buffer != 0xFF)
+ return 0;
+ buffer++;
+ }
+ return 1;
+}
+
+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
+ int chunkInNAND)
+{
+
+ int retval = YAFFS_OK;
+ __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
+ yaffs_ExtendedTags tags;
+ int result;
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
+
+ if(tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
+ retval = YAFFS_FAIL;
+
+
+ if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
+ T(YAFFS_TRACE_NANDACCESS,
+ (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
+ retval = YAFFS_FAIL;
+ }
+
+ yaffs_ReleaseTempBuffer(dev, data, __LINE__);
+
+ return retval;
+
+}
+
+static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
+ const __u8 * data,
+ yaffs_ExtendedTags * tags,
+ int useReserve)
+{
+ int chunk;
+
+ int writeOk = 0;
+ int erasedOk = 1;
+ int attempts = 0;
+ yaffs_BlockInfo *bi;
+
+ yaffs_InvalidateCheckpoint(dev);
+
+ do {
+ chunk = yaffs_AllocateChunk(dev, useReserve,&bi);
+
+ if (chunk >= 0) {
+ /* First check this chunk is erased, if it needs checking.
+ * The checking policy (unless forced always on) is as follows:
+ * Check the first page we try to write in a block.
+ * - If the check passes then we don't need to check any more.
+ * - If the check fails, we check again...
+ * If the block has been erased, we don't need to check.
+ *
+ * However, if the block has been prioritised for gc, then
+ * we think there might be something odd about this block
+ * and stop using it.
+ *
+ * Rationale:
+ * We should only ever see chunks that have not been erased
+ * if there was a partially written chunk due to power loss
+ * This checking policy should catch that case with very
+ * few checks and thus save a lot of checks that are most likely not
+ * needed.
+ */
+
+ if(bi->gcPrioritise){
+ yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
+ } else {
+#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
+
+ bi->skipErasedCheck = 0;
+
+#endif
+ if(!bi->skipErasedCheck){
+ erasedOk = yaffs_CheckChunkErased(dev, chunk);
+ if(erasedOk && !bi->gcPrioritise)
+ bi->skipErasedCheck = 1;
+ }
+
+ if (!erasedOk) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("**>> yaffs chunk %d was not erased"
+ TENDSTR), chunk));
+ } else {
+ writeOk =
+ yaffs_WriteChunkWithTagsToNAND(dev, chunk,
+ data, tags);
+ }
+
+ attempts++;
+
+ if (writeOk) {
+ /*
+ * Copy the data into the robustification buffer.
+ * NB We do this at the end to prevent duplicates in the case of a write error.
+ * Todo
+ */
+ yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
+
+ } else {
+ /* The erased check or write failed */
+ yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
+ }
+ }
+ }
+
+ } while (chunk >= 0 && !writeOk);
+
+ if (attempts > 1) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("**>> yaffs write required %d attempts" TENDSTR),
+ attempts));
+ dev->nRetriedWrites += (attempts - 1);
+ }
+
+ return chunk;
+}
+
+/*
+ * Block retiring for handling a broken block.
+ */
+
+static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND)
+{
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
+
+ yaffs_InvalidateCheckpoint(dev);
+
+ yaffs_MarkBlockBad(dev, blockInNAND);
+
+ bi->blockState = YAFFS_BLOCK_STATE_DEAD;
+ bi->gcPrioritise = 0;
+ bi->needsRetiring = 0;
+
+ dev->nRetiredBlocks++;
+}
+
+/*
+ * Functions for robustisizing TODO
+ *
+ */
+
+static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
+ const __u8 * data,
+ const yaffs_ExtendedTags * tags)
+{
+}
+
+static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
+ const yaffs_ExtendedTags * tags)
+{
+}
+
+void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
+{
+ if(!bi->gcPrioritise){
+ bi->gcPrioritise = 1;
+ dev->hasPendingPrioritisedGCs = 1;
+ bi->chunkErrorStrikes ++;
+
+ if(bi->chunkErrorStrikes > 3){
+ bi->needsRetiring = 1; /* Too many stikes, so retire this */
+ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
+
+ }
+
+ }
+}
+
+static void yaffs_ReportOddballBlocks(yaffs_Device *dev)
+{
+ int i;
+
+ for(i = dev->internalStartBlock; i <= dev->internalEndBlock && (yaffs_traceMask & YAFFS_TRACE_BAD_BLOCKS); i++){
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
+ if(bi->needsRetiring || bi->gcPrioritise)
+ T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("yaffs block %d%s%s" TENDSTR),
+ i,
+ bi->needsRetiring ? " needs retiring" : "",
+ bi->gcPrioritise ? " gc prioritised" : ""));
+
+ }
+}
+
+static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk)
+{
+
+ int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
+
+ yaffs_HandleChunkError(dev,bi);
+
+ if(erasedOk ) {
+ /* Was an actual write failure, so mark the block for retirement */
+ bi->needsRetiring = 1;
+ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+ (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
+ }
+
+ /* Delete the chunk */
+ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
+}
+
+
+/*---------------- Name handling functions ------------*/
+
+static __u16 yaffs_CalcNameSum(const YCHAR * name)
+{
+ __u16 sum = 0;
+ __u16 i = 1;
+
+ YUCHAR *bname = (YUCHAR *) name;
+ if (bname) {
+ while ((*bname) && (i <= YAFFS_MAX_NAME_LENGTH)) {
+
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
+ sum += yaffs_toupper(*bname) * i;
+#else
+ sum += (*bname) * i;
+#endif
+ i++;
+ bname++;
+ }
+ }
+ return sum;
+}
+
+static void yaffs_SetObjectName(yaffs_Object * obj, const YCHAR * name)
+{
+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+ if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) {
+ yaffs_strcpy(obj->shortName, name);
+ } else {
+ obj->shortName[0] = _Y('\0');
+ }
+#endif
+ obj->sum = yaffs_CalcNameSum(name);
+}
+
+/*-------------------- TNODES -------------------
+
+ * List of spare tnodes
+ * The list is hooked together using the first pointer
+ * in the tnode.
+ */
+
+/* yaffs_CreateTnodes creates a bunch more tnodes and
+ * adds them to the tnode free list.
+ * Don't use this function directly
+ */
+
+static int yaffs_CreateTnodes(yaffs_Device * dev, int nTnodes)
+{
+ int i;
+ int tnodeSize;
+ yaffs_Tnode *newTnodes;
+ __u8 *mem;
+ yaffs_Tnode *curr;
+ yaffs_Tnode *next;
+ yaffs_TnodeList *tnl;
+
+ if (nTnodes < 1)
+ return YAFFS_OK;
+
+ /* Calculate the tnode size in bytes for variable width tnode support.
+ * Must be a multiple of 32-bits */
+ tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
+
+ /* make these things */
+
+ newTnodes = YMALLOC(nTnodes * tnodeSize);
+ mem = (__u8 *)newTnodes;
+
+ if (!newTnodes) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
+ return YAFFS_FAIL;
+ }
+
+ /* Hook them into the free list */
+#if 0
+ for (i = 0; i < nTnodes - 1; i++) {
+ newTnodes[i].internal[0] = &newTnodes[i + 1];
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+ newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
+#endif
+ }
+
+ newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+ newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
+#endif
+ dev->freeTnodes = newTnodes;
+#else
+ /* New hookup for wide tnodes */
+ for(i = 0; i < nTnodes -1; i++) {
+ curr = (yaffs_Tnode *) &mem[i * tnodeSize];
+ next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
+ curr->internal[0] = next;
+ }
+
+ curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
+ curr->internal[0] = dev->freeTnodes;
+ dev->freeTnodes = (yaffs_Tnode *)mem;
+
+#endif
+
+
+ dev->nFreeTnodes += nTnodes;
+ dev->nTnodesCreated += nTnodes;
+
+ /* Now add this bunch of tnodes to a list for freeing up.
+ * NB If we can't add this to the management list it isn't fatal
+ * but it just means we can't free this bunch of tnodes later.
+ */
+
+ tnl = YMALLOC(sizeof(yaffs_TnodeList));
+ if (!tnl) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("yaffs: Could not add tnodes to management list" TENDSTR)));
+
+ } else {
+ tnl->tnodes = newTnodes;
+ tnl->next = dev->allocatedTnodeList;
+ dev->allocatedTnodeList = tnl;
+ }
+
+ T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
+
+ return YAFFS_OK;
+}
+
+/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
+
+static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device * dev)
+{
+ yaffs_Tnode *tn = NULL;
+
+ /* If there are none left make more */
+ if (!dev->freeTnodes) {
+ yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
+ }
+
+ if (dev->freeTnodes) {
+ tn = dev->freeTnodes;
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+ if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
+ /* Hoosterman, this thing looks like it isn't in the list */
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
+ }
+#endif
+ dev->freeTnodes = dev->freeTnodes->internal[0];
+ dev->nFreeTnodes--;
+ }
+
+ return tn;
+}
+
+static yaffs_Tnode *yaffs_GetTnode(yaffs_Device * dev)
+{
+ yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
+
+ if(tn)
+ memset(tn, 0, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
+
+ return tn;
+}
+
+/* FreeTnode frees up a tnode and puts it back on the free list */
+static void yaffs_FreeTnode(yaffs_Device * dev, yaffs_Tnode * tn)
+{
+ if (tn) {
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+ if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
+ /* Hoosterman, this thing looks like it is already in the list */
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
+ }
+ tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
+#endif
+ tn->internal[0] = dev->freeTnodes;
+ dev->freeTnodes = tn;
+ dev->nFreeTnodes++;
+ }
+}
+
+static void yaffs_DeinitialiseTnodes(yaffs_Device * dev)
+{
+ /* Free the list of allocated tnodes */
+ yaffs_TnodeList *tmp;
+
+ while (dev->allocatedTnodeList) {
+ tmp = dev->allocatedTnodeList->next;
+
+ YFREE(dev->allocatedTnodeList->tnodes);
+ YFREE(dev->allocatedTnodeList);
+ dev->allocatedTnodeList = tmp;
+
+ }
+
+ dev->freeTnodes = NULL;
+ dev->nFreeTnodes = 0;
+}
+
+static void yaffs_InitialiseTnodes(yaffs_Device * dev)
+{
+ dev->allocatedTnodeList = NULL;
+ dev->freeTnodes = NULL;
+ dev->nFreeTnodes = 0;
+ dev->nTnodesCreated = 0;
+
+}
+
+
+void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, unsigned val)
+{
+ __u32 *map = (__u32 *)tn;
+ __u32 bitInMap;
+ __u32 bitInWord;
+ __u32 wordInMap;
+ __u32 mask;
+
+ pos &= YAFFS_TNODES_LEVEL0_MASK;
+ val >>= dev->chunkGroupBits;
+
+ bitInMap = pos * dev->tnodeWidth;
+ wordInMap = bitInMap /32;
+ bitInWord = bitInMap & (32 -1);
+
+ mask = dev->tnodeMask << bitInWord;
+
+ map[wordInMap] &= ~mask;
+ map[wordInMap] |= (mask & (val << bitInWord));
+
+ if(dev->tnodeWidth > (32-bitInWord)) {
+ bitInWord = (32 - bitInWord);
+ wordInMap++;;
+ mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
+ map[wordInMap] &= ~mask;
+ map[wordInMap] |= (mask & (val >> bitInWord));
+ }
+}
+
+__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos)
+{
+ __u32 *map = (__u32 *)tn;
+ __u32 bitInMap;
+ __u32 bitInWord;
+ __u32 wordInMap;
+ __u32 val;
+
+ pos &= YAFFS_TNODES_LEVEL0_MASK;
+
+ bitInMap = pos * dev->tnodeWidth;
+ wordInMap = bitInMap /32;
+ bitInWord = bitInMap & (32 -1);
+
+ val = map[wordInMap] >> bitInWord;
+
+ if(dev->tnodeWidth > (32-bitInWord)) {
+ bitInWord = (32 - bitInWord);
+ wordInMap++;;
+ val |= (map[wordInMap] << bitInWord);
+ }
+
+ val &= dev->tnodeMask;
+ val <<= dev->chunkGroupBits;
+
+ return val;
+}
+
+/* ------------------- End of individual tnode manipulation -----------------*/
+
+/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
+ * The look up tree is represented by the top tnode and the number of topLevel
+ * in the tree. 0 means only the level 0 tnode is in the tree.
+ */
+
+/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
+static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev,
+ yaffs_FileStructure * fStruct,
+ __u32 chunkId)
+{
+
+ yaffs_Tnode *tn = fStruct->top;
+ __u32 i;
+ int requiredTallness;
+ int level = fStruct->topLevel;
+
+ /* Check sane level and chunk Id */
+ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) {
+ return NULL;
+ }
+
+ if (chunkId > YAFFS_MAX_CHUNK_ID) {
+ return NULL;
+ }
+
+ /* First check we're tall enough (ie enough topLevel) */
+
+ i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
+ requiredTallness = 0;
+ while (i) {
+ i >>= YAFFS_TNODES_INTERNAL_BITS;
+ requiredTallness++;
+ }
+
+ if (requiredTallness > fStruct->topLevel) {
+ /* Not tall enough, so we can't find it, return NULL. */
+ return NULL;
+ }
+
+ /* Traverse down to level 0 */
+ while (level > 0 && tn) {
+ tn = tn->
+ internal[(chunkId >>
+ ( YAFFS_TNODES_LEVEL0_BITS +
+ (level - 1) *
+ YAFFS_TNODES_INTERNAL_BITS)
+ ) &
+ YAFFS_TNODES_INTERNAL_MASK];
+ level--;
+
+ }
+
+ return tn;
+}
+
+/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
+ * This happens in two steps:
+ * 1. If the tree isn't tall enough, then make it taller.
+ * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
+ *
+ * Used when modifying the tree.
+ *
+ * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
+ * be plugged into the ttree.
+ */
+
+static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device * dev,
+ yaffs_FileStructure * fStruct,
+ __u32 chunkId,
+ yaffs_Tnode *passedTn)
+{
+
+ int requiredTallness;
+ int i;
+ int l;
+ yaffs_Tnode *tn;
+
+ __u32 x;
+
+
+ /* Check sane level and page Id */
+ if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL) {
+ return NULL;
+ }
+
+ if (chunkId > YAFFS_MAX_CHUNK_ID) {
+ return NULL;
+ }
+
+ /* First check we're tall enough (ie enough topLevel) */
+
+ x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
+ requiredTallness = 0;
+ while (x) {
+ x >>= YAFFS_TNODES_INTERNAL_BITS;
+ requiredTallness++;
+ }
+
+
+ if (requiredTallness > fStruct->topLevel) {
+ /* Not tall enough,gotta make the tree taller */
+ for (i = fStruct->topLevel; i < requiredTallness; i++) {
+
+ tn = yaffs_GetTnode(dev);
+
+ if (tn) {
+ tn->internal[0] = fStruct->top;
+ fStruct->top = tn;
+ } else {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("yaffs: no more tnodes" TENDSTR)));
+ }
+ }
+
+ fStruct->topLevel = requiredTallness;
+ }
+
+ /* Traverse down to level 0, adding anything we need */
+
+ l = fStruct->topLevel;
+ tn = fStruct->top;
+
+ if(l > 0) {
+ while (l > 0 && tn) {
+ x = (chunkId >>
+ ( YAFFS_TNODES_LEVEL0_BITS +
+ (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
+ YAFFS_TNODES_INTERNAL_MASK;
+
+
+ if((l>1) && !tn->internal[x]){
+ /* Add missing non-level-zero tnode */
+ tn->internal[x] = yaffs_GetTnode(dev);
+
+ } else if(l == 1) {
+ /* Looking from level 1 at level 0 */
+ if (passedTn) {
+ /* If we already have one, then release it.*/
+ if(tn->internal[x])
+ yaffs_FreeTnode(dev,tn->internal[x]);
+ tn->internal[x] = passedTn;
+
+ } else if(!tn->internal[x]) {
+ /* Don't have one, none passed in */
+ tn->internal[x] = yaffs_GetTnode(dev);
+ }
+ }
+
+ tn = tn->internal[x];
+ l--;
+ }
+ } else {
+ /* top is level 0 */
+ if(passedTn) {
+ memcpy(tn,passedTn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
+ yaffs_FreeTnode(dev,passedTn);
+ }
+ }
+
+ return tn;
+}
+
+static int yaffs_FindChunkInGroup(yaffs_Device * dev, int theChunk,
+ yaffs_ExtendedTags * tags, int objectId,
+ int chunkInInode)
+{
+ int j;
+
+ for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
+ if (yaffs_CheckChunkBit
+ (dev, theChunk / dev->nChunksPerBlock,
+ theChunk % dev->nChunksPerBlock)) {
+ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
+ tags);
+ if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
+ /* found it; */
+ return theChunk;
+
+ }
+ }
+ theChunk++;
+ }
+ return -1;
+}
+
+
+/* DeleteWorker scans backwards through the tnode tree and deletes all the
+ * chunks and tnodes in the file
+ * Returns 1 if the tree was deleted.
+ * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
+ */
+
+static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level,
+ int chunkOffset, int *limit)
+{
+ int i;
+ int chunkInInode;
+ int theChunk;
+ yaffs_ExtendedTags tags;
+ int foundChunk;
+ yaffs_Device *dev = in->myDev;
+
+ int allDone = 1;
+
+ if (tn) {
+ if (level > 0) {
+
+ for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
+ i--) {
+ if (tn->internal[i]) {
+ if (limit && (*limit) < 0) {
+ allDone = 0;
+ } else {
+ allDone =
+ yaffs_DeleteWorker(in,
+ tn->
+ internal
+ [i],
+ level -
+ 1,
+ (chunkOffset
+ <<
+ YAFFS_TNODES_INTERNAL_BITS)
+ + i,
+ limit);
+ }
+ if (allDone) {
+ yaffs_FreeTnode(dev,
+ tn->
+ internal[i]);
+ tn->internal[i] = NULL;
+ }
+ }
+
+ }
+ return (allDone) ? 1 : 0;
+ } else if (level == 0) {
+ int hitLimit = 0;
+
+ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
+ i--) {
+ theChunk = yaffs_GetChunkGroupBase(dev,tn,i);
+ if (theChunk) {
+
+ chunkInInode =
+ (chunkOffset <<
+ YAFFS_TNODES_LEVEL0_BITS) + i;
+
+ foundChunk =
+ yaffs_FindChunkInGroup(dev,
+ theChunk,
+ &tags,
+ in->objectId,
+ chunkInInode);
+
+ if (foundChunk > 0) {
+ yaffs_DeleteChunk(dev,
+ foundChunk, 1,
+ __LINE__);
+ in->nDataChunks--;
+ if (limit) {
+ *limit = *limit - 1;
+ if (*limit <= 0) {
+ hitLimit = 1;
+ }
+ }
+
+ }
+
+ yaffs_PutLevel0Tnode(dev,tn,i,0);
+ }
+
+ }
+ return (i < 0) ? 1 : 0;
+
+ }
+
+ }
+
+ return 1;
+
+}
+
+static void yaffs_SoftDeleteChunk(yaffs_Device * dev, int chunk)
+{
+
+ yaffs_BlockInfo *theBlock;
+
+ T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
+
+ theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
+ if (theBlock) {
+ theBlock->softDeletions++;
+ dev->nFreeChunks++;
+ }
+}
+
+/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
+ * All soft deleting does is increment the block's softdelete count and pulls the chunk out
+ * of the tnode.
+ * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
+ */
+
+static int yaffs_SoftDeleteWorker(yaffs_Object * in, yaffs_Tnode * tn,
+ __u32 level, int chunkOffset)
+{
+ int i;
+ int theChunk;
+ int allDone = 1;
+ yaffs_Device *dev = in->myDev;
+
+ if (tn) {
+ if (level > 0) {
+
+ for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
+ i--) {
+ if (tn->internal[i]) {
+ allDone =
+ yaffs_SoftDeleteWorker(in,
+ tn->
+ internal[i],
+ level - 1,
+ (chunkOffset
+ <<
+ YAFFS_TNODES_INTERNAL_BITS)
+ + i);
+ if (allDone) {
+ yaffs_FreeTnode(dev,
+ tn->
+ internal[i]);
+ tn->internal[i] = NULL;
+ } else {
+ /* Hoosterman... how could this happen? */
+ }
+ }
+ }
+ return (allDone) ? 1 : 0;
+ } else if (level == 0) {
+
+ for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
+ theChunk = yaffs_GetChunkGroupBase(dev,tn,i);
+ if (theChunk) {
+ /* Note this does not find the real chunk, only the chunk group.
+ * We make an assumption that a chunk group is not larger than
+ * a block.
+ */
+ yaffs_SoftDeleteChunk(dev, theChunk);
+ yaffs_PutLevel0Tnode(dev,tn,i,0);
+ }
+
+ }
+ return 1;
+
+ }
+
+ }
+
+ return 1;
+
+}
+
+static void yaffs_SoftDeleteFile(yaffs_Object * obj)
+{
+ if (obj->deleted &&
+ obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
+ if (obj->nDataChunks <= 0) {
+ /* Empty file with no duplicate object headers, just delete it immediately */
+ yaffs_FreeTnode(obj->myDev,
+ obj->variant.fileVariant.top);
+ obj->variant.fileVariant.top = NULL;
+ T(YAFFS_TRACE_TRACING,
+ (TSTR("yaffs: Deleting empty file %d" TENDSTR),
+ obj->objectId));
+ yaffs_DoGenericObjectDeletion(obj);
+ } else {
+ yaffs_SoftDeleteWorker(obj,
+ obj->variant.fileVariant.top,
+ obj->variant.fileVariant.
+ topLevel, 0);
+ obj->softDeleted = 1;
+ }
+ }
+}
+
+/* Pruning removes any part of the file structure tree that is beyond the
+ * bounds of the file (ie that does not point to chunks).
+ *
+ * A file should only get pruned when its size is reduced.
+ *
+ * Before pruning, the chunks must be pulled from the tree and the
+ * level 0 tnode entries must be zeroed out.
+ * Could also use this for file deletion, but that's probably better handled
+ * by a special case.
+ */
+
+static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device * dev, yaffs_Tnode * tn,
+ __u32 level, int del0)
+{
+ int i;
+ int hasData;
+
+ if (tn) {
+ hasData = 0;
+
+ for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
+ if (tn->internal[i] && level > 0) {
+ tn->internal[i] =
+ yaffs_PruneWorker(dev, tn->internal[i],
+ level - 1,
+ (i == 0) ? del0 : 1);
+ }
+
+ if (tn->internal[i]) {
+ hasData++;
+ }
+ }
+
+ if (hasData == 0 && del0) {
+ /* Free and return NULL */
+
+ yaffs_FreeTnode(dev, tn);
+ tn = NULL;
+ }
+
+ }
+
+ return tn;
+
+}
+
+static int yaffs_PruneFileStructure(yaffs_Device * dev,
+ yaffs_FileStructure * fStruct)
+{
+ int i;
+ int hasData;
+ int done = 0;
+ yaffs_Tnode *tn;
+
+ if (fStruct->topLevel > 0) {
+ fStruct->top =
+ yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
+
+ /* Now we have a tree with all the non-zero branches NULL but the height
+ * is the same as it was.
+ * Let's see if we can trim internal tnodes to shorten the tree.
+ * We can do this if only the 0th element in the tnode is in use
+ * (ie all the non-zero are NULL)
+ */
+
+ while (fStruct->topLevel && !done) {
+ tn = fStruct->top;
+
+ hasData = 0;
+ for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
+ if (tn->internal[i]) {
+ hasData++;
+ }
+ }
+
+ if (!hasData) {
+ fStruct->top = tn->internal[0];
+ fStruct->topLevel--;
+ yaffs_FreeTnode(dev, tn);
+ } else {
+ done = 1;
+ }
+ }
+ }
+
+ return YAFFS_OK;
+}
+
+/*-------------------- End of File Structure functions.-------------------*/
+
+/* yaffs_CreateFreeObjects creates a bunch more objects and
+ * adds them to the object free list.
+ */
+static int yaffs_CreateFreeObjects(yaffs_Device * dev, int nObjects)
+{
+ int i;
+ yaffs_Object *newObjects;
+ yaffs_ObjectList *list;
+
+ if (nObjects < 1)
+ return YAFFS_OK;
+
+ /* make these things */
+ newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
+
+ if (!newObjects) {
+ T(YAFFS_TRACE_ALLOCATE,
+ (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
+ return YAFFS_FAIL;
+ }
+
+ /* Hook them into the free list */
+ for (i = 0; i < nObjects - 1; i++) {
+ newObjects[i].siblings.next =
+ (struct list_head *)(&newObjects[i + 1]);
+ }
+
+ newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
+ dev->freeObjects = newObjects;
+ dev->nFreeObjects += nObjects;
+ dev->nObjectsCreated += nObjects;
+
+ /* Now add this bunch of Objects to a list for freeing up. */
+
+ list = YMALLOC(sizeof(yaffs_ObjectList));
+ if (!list) {
+ T(YAFFS_TRACE_ALLOCATE,
+ (TSTR("Could not add objects to management list" TENDSTR)));
+ } else {
+ list->objects = newObjects;
+ list->next = dev->allocatedObjectList;
+ dev->allocatedObjectList = list;
+ }
+
+ return YAFFS_OK;
+}
+
+
+/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
+static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device * dev)
+{
+ yaffs_Object *tn = NULL;
+
+ /* If there are none left make more */
+ if (!dev->freeObjects) {
+ yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
+ }
+
+ if (dev->freeObjects) {
+ tn = dev->freeObjects;
+ dev->freeObjects =
+ (yaffs_Object *) (dev->freeObjects->siblings.next);
+ dev->nFreeObjects--;
+
+ /* Now sweeten it up... */
+
+ memset(tn, 0, sizeof(yaffs_Object));
+ tn->myDev = dev;
+ tn->chunkId = -1;
+ tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
+ INIT_LIST_HEAD(&(tn->hardLinks));
+ INIT_LIST_HEAD(&(tn->hashLink));
+ INIT_LIST_HEAD(&tn->siblings);
+
+ /* Add it to the lost and found directory.
+ * NB Can't put root or lostNFound in lostNFound so
+ * check if lostNFound exists first
+ */
+ if (dev->lostNFoundDir) {
+ yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
+ }
+ }
+
+ return tn;
+}
+
+static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device * dev, int number,
+ __u32 mode)
+{
+
+ yaffs_Object *obj =
+ yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
+ if (obj) {
+ obj->fake = 1; /* it is fake so it has no NAND presence... */
+ obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
+ obj->unlinkAllowed = 0; /* ... or unlink it */
+ obj->deleted = 0;
+ obj->unlinked = 0;
+ obj->yst_mode = mode;
+ obj->myDev = dev;
+ obj->chunkId = 0; /* Not a valid chunk. */
+ }
+
+ return obj;
+
+}
+
+static void yaffs_UnhashObject(yaffs_Object * tn)
+{
+ int bucket;
+ yaffs_Device *dev = tn->myDev;
+
+ /* If it is still linked into the bucket list, free from the list */
+ if (!list_empty(&tn->hashLink)) {
+ list_del_init(&tn->hashLink);
+ bucket = yaffs_HashFunction(tn->objectId);
+ dev->objectBucket[bucket].count--;
+ }
+
+}
+
+/* FreeObject frees up a Object and puts it back on the free list */
+static void yaffs_FreeObject(yaffs_Object * tn)
+{
+
+ yaffs_Device *dev = tn->myDev;
+
+#ifdef __KERNEL__
+ if (tn->myInode) {
+ /* We're still hooked up to a cached inode.
+ * Don't delete now, but mark for later deletion
+ */
+ tn->deferedFree = 1;
+ return;
+ }
+#endif
+
+ yaffs_UnhashObject(tn);
+
+ /* Link into the free list. */
+ tn->siblings.next = (struct list_head *)(dev->freeObjects);
+ dev->freeObjects = tn;
+ dev->nFreeObjects++;
+}
+
+#ifdef __KERNEL__
+
+void yaffs_HandleDeferedFree(yaffs_Object * obj)
+{
+ if (obj->deferedFree) {
+ yaffs_FreeObject(obj);
+ }
+}
+
+#endif
+
+static void yaffs_DeinitialiseObjects(yaffs_Device * dev)
+{
+ /* Free the list of allocated Objects */
+
+ yaffs_ObjectList *tmp;
+
+ while (dev->allocatedObjectList) {
+ tmp = dev->allocatedObjectList->next;
+ YFREE(dev->allocatedObjectList->objects);
+ YFREE(dev->allocatedObjectList);
+
+ dev->allocatedObjectList = tmp;
+ }
+
+ dev->freeObjects = NULL;
+ dev->nFreeObjects = 0;
+}
+
+static void yaffs_InitialiseObjects(yaffs_Device * dev)
+{
+ int i;
+
+ dev->allocatedObjectList = NULL;
+ dev->freeObjects = NULL;
+ dev->nFreeObjects = 0;
+
+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+ INIT_LIST_HEAD(&dev->objectBucket[i].list);
+ dev->objectBucket[i].count = 0;
+ }
+
+}
+
+static int yaffs_FindNiceObjectBucket(yaffs_Device * dev)
+{
+ static int x = 0;
+ int i;
+ int l = 999;
+ int lowest = 999999;
+
+ /* First let's see if we can find one that's empty. */
+
+ for (i = 0; i < 10 && lowest > 0; i++) {
+ x++;
+ x %= YAFFS_NOBJECT_BUCKETS;
+ if (dev->objectBucket[x].count < lowest) {
+ lowest = dev->objectBucket[x].count;
+ l = x;
+ }
+
+ }
+
+ /* If we didn't find an empty list, then try
+ * looking a bit further for a short one
+ */
+
+ for (i = 0; i < 10 && lowest > 3; i++) {
+ x++;
+ x %= YAFFS_NOBJECT_BUCKETS;
+ if (dev->objectBucket[x].count < lowest) {
+ lowest = dev->objectBucket[x].count;
+ l = x;
+ }
+
+ }
+
+ return l;
+}
+
+static int yaffs_CreateNewObjectNumber(yaffs_Device * dev)
+{
+ int bucket = yaffs_FindNiceObjectBucket(dev);
+
+ /* Now find an object value that has not already been taken
+ * by scanning the list.
+ */
+
+ int found = 0;
+ struct list_head *i;
+
+ __u32 n = (__u32) bucket;
+
+ /* yaffs_CheckObjectHashSanity(); */
+
+ while (!found) {
+ found = 1;
+ n += YAFFS_NOBJECT_BUCKETS;
+ if (1 || dev->objectBucket[bucket].count > 0) {
+ list_for_each(i, &dev->objectBucket[bucket].list) {
+ /* If there is already one in the list */
+ if (i
+ && list_entry(i, yaffs_Object,
+ hashLink)->objectId == n) {
+ found = 0;
+ }
+ }
+ }
+ }
+
+
+ return n;
+}
+
+static void yaffs_HashObject(yaffs_Object * in)
+{
+ int bucket = yaffs_HashFunction(in->objectId);
+ yaffs_Device *dev = in->myDev;
+
+ list_add(&in->hashLink, &dev->objectBucket[bucket].list);
+ dev->objectBucket[bucket].count++;
+
+}
+
+yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number)
+{
+ int bucket = yaffs_HashFunction(number);
+ struct list_head *i;
+ yaffs_Object *in;
+
+ list_for_each(i, &dev->objectBucket[bucket].list) {
+ /* Look if it is in the list */
+ if (i) {
+ in = list_entry(i, yaffs_Object, hashLink);
+ if (in->objectId == number) {
+#ifdef __KERNEL__
+ /* Don't tell the VFS about this one if it is defered free */
+ if (in->deferedFree)
+ return NULL;
+#endif
+
+ return in;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number,
+ yaffs_ObjectType type)
+{
+
+ yaffs_Object *theObject;
+
+ if (number < 0) {
+ number = yaffs_CreateNewObjectNumber(dev);
+ }
+
+ theObject = yaffs_AllocateEmptyObject(dev);
+
+ if (theObject) {
+ theObject->fake = 0;
+ theObject->renameAllowed = 1;
+ theObject->unlinkAllowed = 1;
+ theObject->objectId = number;
+ yaffs_HashObject(theObject);
+ theObject->variantType = type;
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_WinFileTimeNow(theObject->win_atime);
+ theObject->win_ctime[0] = theObject->win_mtime[0] =
+ theObject->win_atime[0];
+ theObject->win_ctime[1] = theObject->win_mtime[1] =
+ theObject->win_atime[1];
+
+#else
+
+ theObject->yst_atime = theObject->yst_mtime =
+ theObject->yst_ctime = Y_CURRENT_TIME;
+#endif
+ switch (type) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ theObject->variant.fileVariant.fileSize = 0;
+ theObject->variant.fileVariant.scannedFileSize = 0;
+ theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
+ theObject->variant.fileVariant.topLevel = 0;
+ theObject->variant.fileVariant.top =
+ yaffs_GetTnode(dev);
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ INIT_LIST_HEAD(&theObject->variant.directoryVariant.
+ children);
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* No action required */
+ break;
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* todo this should not happen */
+ break;
+ }
+ }
+
+ return theObject;
+}
+
+static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device * dev,
+ int number,
+ yaffs_ObjectType type)
+{
+ yaffs_Object *theObject = NULL;
+
+ if (number > 0) {
+ theObject = yaffs_FindObjectByNumber(dev, number);
+ }
+
+ if (!theObject) {
+ theObject = yaffs_CreateNewObject(dev, number, type);
+ }
+
+ return theObject;
+
+}
+
+
+static YCHAR *yaffs_CloneString(const YCHAR * str)
+{
+ YCHAR *newStr = NULL;
+
+ if (str && *str) {
+ newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
+ yaffs_strcpy(newStr, str);
+ }
+
+ return newStr;
+
+}
+
+/*
+ * Mknod (create) a new object.
+ * equivalentObject only has meaning for a hard link;
+ * aliasString only has meaning for a sumlink.
+ * rdev only has meaning for devices (a subset of special objects)
+ */
+
+static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
+ yaffs_Object * parent,
+ const YCHAR * name,
+ __u32 mode,
+ __u32 uid,
+ __u32 gid,
+ yaffs_Object * equivalentObject,
+ const YCHAR * aliasString, __u32 rdev)
+{
+ yaffs_Object *in;
+
+ yaffs_Device *dev = parent->myDev;
+
+ /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
+ if (yaffs_FindObjectByName(parent, name)) {
+ return NULL;
+ }
+
+ in = yaffs_CreateNewObject(dev, -1, type);
+
+ if (in) {
+ in->chunkId = -1;
+ in->valid = 1;
+ in->variantType = type;
+
+ in->yst_mode = mode;
+
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_WinFileTimeNow(in->win_atime);
+ in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
+ in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
+
+#else
+ in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
+
+ in->yst_rdev = rdev;
+ in->yst_uid = uid;
+ in->yst_gid = gid;
+#endif
+ in->nDataChunks = 0;
+
+ yaffs_SetObjectName(in, name);
+ in->dirty = 1;
+
+ yaffs_AddObjectToDirectory(parent, in);
+
+ in->myDev = parent->myDev;
+
+ switch (type) {
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ in->variant.symLinkVariant.alias =
+ yaffs_CloneString(aliasString);
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ in->variant.hardLinkVariant.equivalentObject =
+ equivalentObject;
+ in->variant.hardLinkVariant.equivalentObjectId =
+ equivalentObject->objectId;
+ list_add(&in->hardLinks, &equivalentObject->hardLinks);
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* do nothing */
+ break;
+ }
+
+ if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
+ /* Could not create the object header, fail the creation */
+ yaffs_DestroyObject(in);
+ in = NULL;
+ }
+
+ }
+
+ return in;
+}
+
+yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name,
+ __u32 mode, __u32 uid, __u32 gid)
+{
+ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
+ uid, gid, NULL, NULL, 0);
+}
+
+yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name,
+ __u32 mode, __u32 uid, __u32 gid)
+{
+ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
+ mode, uid, gid, NULL, NULL, 0);
+}
+
+yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name,
+ __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
+{
+ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
+ uid, gid, NULL, NULL, rdev);
+}
+
+yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name,
+ __u32 mode, __u32 uid, __u32 gid,
+ const YCHAR * alias)
+{
+ return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
+ uid, gid, NULL, alias, 0);
+}
+
+/* yaffs_Link returns the object id of the equivalent object.*/
+yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name,
+ yaffs_Object * equivalentObject)
+{
+ /* Get the real object in case we were fed a hard link as an equivalent object */
+ equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
+
+ if (yaffs_MknodObject
+ (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
+ equivalentObject, NULL, 0)) {
+ return equivalentObject;
+ } else {
+ return NULL;
+ }
+
+}
+
+static int yaffs_ChangeObjectName(yaffs_Object * obj, yaffs_Object * newDir,
+ const YCHAR * newName, int force, int shadows)
+{
+ int unlinkOp;
+ int deleteOp;
+
+ yaffs_Object *existingTarget;
+
+ if (newDir == NULL) {
+ newDir = obj->parent; /* use the old directory */
+ }
+
+ if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("tragendy: yaffs_ChangeObjectName: newDir is not a directory"
+ TENDSTR)));
+ YBUG();
+ }
+
+ /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
+ if (obj->myDev->isYaffs2) {
+ unlinkOp = (newDir == obj->myDev->unlinkedDir);
+ } else {
+ unlinkOp = (newDir == obj->myDev->unlinkedDir
+ && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
+ }
+
+ deleteOp = (newDir == obj->myDev->deletedDir);
+
+ existingTarget = yaffs_FindObjectByName(newDir, newName);
+
+ /* If the object is a file going into the unlinked directory,
+ * then it is OK to just stuff it in since duplicate names are allowed.
+ * else only proceed if the new name does not exist and if we're putting
+ * it into a directory.
+ */
+ if ((unlinkOp ||
+ deleteOp ||
+ force ||
+ (shadows > 0) ||
+ !existingTarget) &&
+ newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
+ yaffs_SetObjectName(obj, newName);
+ obj->dirty = 1;
+
+ yaffs_AddObjectToDirectory(newDir, obj);
+
+ if (unlinkOp)
+ obj->unlinked = 1;
+
+ /* If it is a deletion then we mark it as a shrink for gc purposes. */
+ if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows)>= 0)
+ return YAFFS_OK;
+ }
+
+ return YAFFS_FAIL;
+}
+
+int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName,
+ yaffs_Object * newDir, const YCHAR * newName)
+{
+ yaffs_Object *obj;
+ yaffs_Object *existingTarget;
+ int force = 0;
+
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
+ /* Special case for case insemsitive systems (eg. WinCE).
+ * While look-up is case insensitive, the name isn't.
+ * Therefore we might want to change x.txt to X.txt
+ */
+ if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0) {
+ force = 1;
+ }
+#endif
+
+ obj = yaffs_FindObjectByName(oldDir, oldName);
+ /* Check new name to long. */
+ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK &&
+ yaffs_strlen(newName) > YAFFS_MAX_ALIAS_LENGTH)
+ /* ENAMETOOLONG */
+ return YAFFS_FAIL;
+ else if (obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK &&
+ yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
+ /* ENAMETOOLONG */
+ return YAFFS_FAIL;
+
+ if (obj && obj->renameAllowed) {
+
+ /* Now do the handling for an existing target, if there is one */
+
+ existingTarget = yaffs_FindObjectByName(newDir, newName);
+ if (existingTarget &&
+ existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+ !list_empty(&existingTarget->variant.directoryVariant.children)) {
+ /* There is a target that is a non-empty directory, so we fail */
+ return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
+ } else if (existingTarget && existingTarget != obj) {
+ /* Nuke the target first, using shadowing,
+ * but only if it isn't the same object
+ */
+ yaffs_ChangeObjectName(obj, newDir, newName, force,
+ existingTarget->objectId);
+ yaffs_UnlinkObject(existingTarget);
+ }
+
+ return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+ }
+ return YAFFS_FAIL;
+}
+
+/*------------------------- Block Management and Page Allocation ----------------*/
+
+static int yaffs_InitialiseBlocks(yaffs_Device * dev)
+{
+ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
+
+ dev->allocationBlock = -1; /* force it to get a new one */
+
+ /* Todo we're assuming the malloc will pass. */
+ dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
+ if(!dev->blockInfo){
+ dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
+ dev->blockInfoAlt = 1;
+ }
+ else
+ dev->blockInfoAlt = 0;
+
+ /* Set up dynamic blockinfo stuff. */
+ dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
+ dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
+ if(!dev->chunkBits){
+ dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
+ dev->chunkBitsAlt = 1;
+ }
+ else
+ dev->chunkBitsAlt = 0;
+
+ if (dev->blockInfo && dev->chunkBits) {
+ memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
+ memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
+ return YAFFS_OK;
+ }
+
+ return YAFFS_FAIL;
+
+}
+
+static void yaffs_DeinitialiseBlocks(yaffs_Device * dev)
+{
+ if(dev->blockInfoAlt)
+ YFREE_ALT(dev->blockInfo);
+ else
+ YFREE(dev->blockInfo);
+ dev->blockInfoAlt = 0;
+
+ dev->blockInfo = NULL;
+
+ if(dev->chunkBitsAlt)
+ YFREE_ALT(dev->chunkBits);
+ else
+ YFREE(dev->chunkBits);
+ dev->chunkBitsAlt = 0;
+ dev->chunkBits = NULL;
+}
+
+static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device * dev,
+ yaffs_BlockInfo * bi)
+{
+ int i;
+ __u32 seq;
+ yaffs_BlockInfo *b;
+
+ if (!dev->isYaffs2)
+ return 1; /* disqualification only applies to yaffs2. */
+
+ if (!bi->hasShrinkHeader)
+ return 1; /* can gc */
+
+ /* Find the oldest dirty sequence number if we don't know it and save it
+ * so we don't have to keep recomputing it.
+ */
+ if (!dev->oldestDirtySequence) {
+ seq = dev->sequenceNumber;
+
+ for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
+ i++) {
+ b = yaffs_GetBlockInfo(dev, i);
+ if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
+ (b->pagesInUse - b->softDeletions) <
+ dev->nChunksPerBlock && b->sequenceNumber < seq) {
+ seq = b->sequenceNumber;
+ }
+ }
+ dev->oldestDirtySequence = seq;
+ }
+
+ /* Can't do gc of this block if there are any blocks older than this one that have
+ * discarded pages.
+ */
+ return (bi->sequenceNumber <= dev->oldestDirtySequence);
+
+}
+
+/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
+ * for garbage collection.
+ */
+
+static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev,
+ int aggressive)
+{
+
+ int b = dev->currentDirtyChecker;
+
+ int i;
+ int iterations;
+ int dirtiest = -1;
+ int pagesInUse;
+ int prioritised=0;
+ yaffs_BlockInfo *bi;
+ static int nonAggressiveSkip = 0;
+ int pendingPrioritisedExist = 0;
+
+ /* First let's see if we need to grab a prioritised block */
+ if(dev->hasPendingPrioritisedGCs){
+ for(i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++){
+
+ bi = yaffs_GetBlockInfo(dev, i);
+ if(bi->gcPrioritise) {
+ pendingPrioritisedExist = 1;
+ if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
+ yaffs_BlockNotDisqualifiedFromGC(dev, bi)){
+ pagesInUse = (bi->pagesInUse - bi->softDeletions);
+ dirtiest = i;
+ prioritised = 1;
+ aggressive = 1; /* Fool the non-aggressive skip logiv below */
+ }
+ }
+ }
+
+ if(!pendingPrioritisedExist) /* None found, so we can clear this */
+ dev->hasPendingPrioritisedGCs = 0;
+ }
+
+ /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
+ * search harder.
+ * else (we're doing a leasurely gc), then we only bother to do this if the
+ * block has only a few pages in use.
+ */
+
+ nonAggressiveSkip--;
+
+ if (!aggressive && (nonAggressiveSkip > 0)) {
+ return -1;
+ }
+
+ if(!prioritised)
+ pagesInUse =
+ (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
+
+ if (aggressive) {
+ iterations =
+ dev->internalEndBlock - dev->internalStartBlock + 1;
+ } else {
+ iterations =
+ dev->internalEndBlock - dev->internalStartBlock + 1;
+ iterations = iterations / 16;
+ if (iterations > 200) {
+ iterations = 200;
+ }
+ }
+
+ for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
+ b++;
+ if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
+ b = dev->internalStartBlock;
+ }
+
+ if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("**>> Block %d is not valid" TENDSTR), b));
+ YBUG();
+ }
+
+ bi = yaffs_GetBlockInfo(dev, b);
+
+#if 0
+ if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
+ dirtiest = b;
+ pagesInUse = 0;
+ }
+ else
+#endif
+
+ if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
+ (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
+ yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
+ dirtiest = b;
+ pagesInUse = (bi->pagesInUse - bi->softDeletions);
+ }
+ }
+
+ dev->currentDirtyChecker = b;
+
+ if (dirtiest > 0) {
+ T(YAFFS_TRACE_GC,
+ (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
+ dev->nChunksPerBlock - pagesInUse,prioritised));
+ }
+
+ dev->oldestDirtySequence = 0;
+
+ if (dirtiest > 0) {
+ nonAggressiveSkip = 4;
+ }
+
+ return dirtiest;
+}
+
+static void yaffs_BlockBecameDirty(yaffs_Device * dev, int blockNo)
+{
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
+
+ int erasedOk = 0;
+
+ /* If the block is still healthy erase it and mark as clean.
+ * If the block has had a data failure, then retire it.
+ */
+
+ T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
+ (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
+ blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
+
+ bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
+
+ if (!bi->needsRetiring) {
+ yaffs_InvalidateCheckpoint(dev);
+ erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
+ if (!erasedOk) {
+ dev->nErasureFailures++;
+ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+ (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
+ }
+ }
+
+ if (erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE)) {
+ int i;
+ for (i = 0; i < dev->nChunksPerBlock; i++) {
+ if (!yaffs_CheckChunkErased
+ (dev, blockNo * dev->nChunksPerBlock + i)) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ (">>Block %d erasure supposedly OK, but chunk %d not erased"
+ TENDSTR), blockNo, i));
+ }
+ }
+ }
+
+ if (erasedOk) {
+ /* Clean it up... */
+ bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
+ dev->nErasedBlocks++;
+ bi->pagesInUse = 0;
+ bi->softDeletions = 0;
+ bi->hasShrinkHeader = 0;
+ bi->skipErasedCheck = 1; /* This is clean, so no need to check */
+ bi->gcPrioritise = 0;
+ yaffs_ClearChunkBits(dev, blockNo);
+
+ T(YAFFS_TRACE_ERASE,
+ (TSTR("Erased block %d" TENDSTR), blockNo));
+ } else {
+ dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */
+
+ yaffs_RetireBlock(dev, blockNo);
+ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+ (TSTR("**>> Block %d retired" TENDSTR), blockNo));
+ }
+}
+
+static int yaffs_FindBlockForAllocation(yaffs_Device * dev)
+{
+ int i;
+
+ yaffs_BlockInfo *bi;
+
+ if (dev->nErasedBlocks < 1) {
+ /* Hoosterman we've got a problem.
+ * Can't get space to gc
+ */
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR)));
+
+ return -1;
+ }
+
+ /* Find an empty block. */
+
+ for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
+ dev->allocationBlockFinder++;
+ if (dev->allocationBlockFinder < dev->internalStartBlock
+ || dev->allocationBlockFinder > dev->internalEndBlock) {
+ dev->allocationBlockFinder = dev->internalStartBlock;
+ }
+
+ bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
+
+ if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
+ bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
+ dev->sequenceNumber++;
+ bi->sequenceNumber = dev->sequenceNumber;
+ dev->nErasedBlocks--;
+ T(YAFFS_TRACE_ALLOCATE,
+ (TSTR("Allocated block %d, seq %d, %d left" TENDSTR),
+ dev->allocationBlockFinder, dev->sequenceNumber,
+ dev->nErasedBlocks));
+ return dev->allocationBlockFinder;
+ }
+ }
+
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("yaffs tragedy: no more eraased blocks, but there should have been %d"
+ TENDSTR), dev->nErasedBlocks));
+
+ return -1;
+}
+
+
+// Check if there's space to allocate...
+// Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
+static int yaffs_CheckSpaceForAllocation(yaffs_Device * dev)
+{
+ int reservedChunks;
+ int reservedBlocks = dev->nReservedBlocks;
+ int checkpointBlocks;
+
+ checkpointBlocks = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint;
+ if(checkpointBlocks < 0)
+ checkpointBlocks = 0;
+
+ reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
+
+ return (dev->nFreeChunks > reservedChunks);
+}
+
+static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr)
+{
+ int retVal;
+ yaffs_BlockInfo *bi;
+
+ if (dev->allocationBlock < 0) {
+ /* Get next block to allocate off */
+ dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
+ dev->allocationPage = 0;
+ }
+
+ if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
+ /* Not enough space to allocate unless we're allowed to use the reserve. */
+ return -1;
+ }
+
+ if (dev->nErasedBlocks < dev->nReservedBlocks
+ && dev->allocationPage == 0) {
+ T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
+ }
+
+ /* Next page please.... */
+ if (dev->allocationBlock >= 0) {
+ bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
+
+ retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
+ dev->allocationPage;
+ bi->pagesInUse++;
+ yaffs_SetChunkBit(dev, dev->allocationBlock,
+ dev->allocationPage);
+
+ dev->allocationPage++;
+
+ dev->nFreeChunks--;
+
+ /* If the block is full set the state to full */
+ if (dev->allocationPage >= dev->nChunksPerBlock) {
+ bi->blockState = YAFFS_BLOCK_STATE_FULL;
+ dev->allocationBlock = -1;
+ }
+
+ if(blockUsedPtr)
+ *blockUsedPtr = bi;
+
+ return retVal;
+ }
+
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
+
+ return -1;
+}
+
+static int yaffs_GetErasedChunks(yaffs_Device * dev)
+{
+ int n;
+
+ n = dev->nErasedBlocks * dev->nChunksPerBlock;
+
+ if (dev->allocationBlock > 0) {
+ n += (dev->nChunksPerBlock - dev->allocationPage);
+ }
+
+ return n;
+
+}
+
+static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block)
+{
+ int oldChunk;
+ int newChunk;
+ int chunkInBlock;
+ int markNAND;
+ int retVal = YAFFS_OK;
+ int cleanups = 0;
+ int i;
+ int isCheckpointBlock;
+
+ int chunksBefore = yaffs_GetErasedChunks(dev);
+ int chunksAfter;
+
+ yaffs_ExtendedTags tags;
+
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
+
+ yaffs_Object *object;
+
+ isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
+
+ bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
+
+ T(YAFFS_TRACE_TRACING,
+ (TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR), block,
+ bi->pagesInUse, bi->hasShrinkHeader));
+
+ /*yaffs_VerifyFreeChunks(dev); */
+
+ bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
+
+ /* Take off the number of soft deleted entries because
+ * they're going to get really deleted during GC.
+ */
+ dev->nFreeChunks -= bi->softDeletions;
+
+ dev->isDoingGC = 1;
+
+ if (isCheckpointBlock ||
+ !yaffs_StillSomeChunkBits(dev, block)) {
+ T(YAFFS_TRACE_TRACING,
+ (TSTR
+ ("Collecting block %d that has no chunks in use" TENDSTR),
+ block));
+ yaffs_BlockBecameDirty(dev, block);
+ } else {
+
+ __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
+
+ for (chunkInBlock = 0, oldChunk = block * dev->nChunksPerBlock;
+ chunkInBlock < dev->nChunksPerBlock
+ && yaffs_StillSomeChunkBits(dev, block);
+ chunkInBlock++, oldChunk++) {
+ if (yaffs_CheckChunkBit(dev, block, chunkInBlock)) {
+
+ /* This page is in use and might need to be copied off */
+
+ markNAND = 1;
+
+ yaffs_InitialiseTags(&tags);
+
+ yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
+ buffer, &tags);
+
+ object =
+ yaffs_FindObjectByNumber(dev,
+ tags.objectId);
+
+ T(YAFFS_TRACE_GC_DETAIL,
+ (TSTR
+ ("Collecting page %d, %d %d %d " TENDSTR),
+ chunkInBlock, tags.objectId, tags.chunkId,
+ tags.byteCount));
+
+ if (!object) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("page %d in gc has no object "
+ TENDSTR), oldChunk));
+ }
+
+ if (object && object->deleted
+ && tags.chunkId != 0) {
+ /* Data chunk in a deleted file, throw it away
+ * It's a soft deleted data chunk,
+ * No need to copy this, just forget about it and
+ * fix up the object.
+ */
+
+ object->nDataChunks--;
+
+ if (object->nDataChunks <= 0) {
+ /* remeber to clean up the object */
+ dev->gcCleanupList[cleanups] =
+ tags.objectId;
+ cleanups++;
+ }
+ markNAND = 0;
+ } else if (0
+ /* Todo object && object->deleted && object->nDataChunks == 0 */
+ ) {
+ /* Deleted object header with no data chunks.
+ * Can be discarded and the file deleted.
+ */
+ object->chunkId = 0;
+ yaffs_FreeTnode(object->myDev,
+ object->variant.
+ fileVariant.top);
+ object->variant.fileVariant.top = NULL;
+ yaffs_DoGenericObjectDeletion(object);
+
+ } else if (object) {
+ /* It's either a data chunk in a live file or
+ * an ObjectHeader, so we're interested in it.
+ * NB Need to keep the ObjectHeaders of deleted files
+ * until the whole file has been deleted off
+ */
+ tags.serialNumber++;
+
+ dev->nGCCopies++;
+
+ if (tags.chunkId == 0) {
+ /* It is an object Id,
+ * We need to nuke the shrinkheader flags first
+ * We no longer want the shrinkHeader flag since its work is done
+ * and if it is left in place it will mess up scanning.
+ * Also, clear out any shadowing stuff
+ */
+
+ yaffs_ObjectHeader *oh;
+ oh = (yaffs_ObjectHeader *)buffer;
+ oh->isShrink = 0;
+ oh->shadowsObject = -1;
+ tags.extraShadows = 0;
+ tags.extraIsShrinkHeader = 0;
+ }
+
+ newChunk =
+ yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
+
+ if (newChunk < 0) {
+ retVal = YAFFS_FAIL;
+ } else {
+
+ /* Ok, now fix up the Tnodes etc. */
+
+ if (tags.chunkId == 0) {
+ /* It's a header */
+ object->chunkId = newChunk;
+ object->serial = tags.serialNumber;
+ } else {
+ /* It's a data chunk */
+ yaffs_PutChunkIntoFile
+ (object,
+ tags.chunkId,
+ newChunk, 0);
+ }
+ }
+ }
+
+ yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
+
+ }
+ }
+
+ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+
+
+ /* Do any required cleanups */
+ for (i = 0; i < cleanups; i++) {
+ /* Time to delete the file too */
+ object =
+ yaffs_FindObjectByNumber(dev,
+ dev->gcCleanupList[i]);
+ if (object) {
+ yaffs_FreeTnode(dev,
+ object->variant.fileVariant.
+ top);
+ object->variant.fileVariant.top = NULL;
+ T(YAFFS_TRACE_GC,
+ (TSTR
+ ("yaffs: About to finally delete object %d"
+ TENDSTR), object->objectId));
+ yaffs_DoGenericObjectDeletion(object);
+ object->myDev->nDeletedFiles--;
+ }
+
+ }
+
+ }
+
+ if (chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev))) {
+ T(YAFFS_TRACE_GC,
+ (TSTR
+ ("gc did not increase free chunks before %d after %d"
+ TENDSTR), chunksBefore, chunksAfter));
+ }
+
+ dev->isDoingGC = 0;
+
+ return YAFFS_OK;
+}
+
+/* New garbage collector
+ * If we're very low on erased blocks then we do aggressive garbage collection
+ * otherwise we do "leasurely" garbage collection.
+ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
+ * Passive gc only inspects smaller areas and will only accept more dirty blocks.
+ *
+ * The idea is to help clear out space in a more spread-out manner.
+ * Dunno if it really does anything useful.
+ */
+static int yaffs_CheckGarbageCollection(yaffs_Device * dev)
+{
+ int block;
+ int aggressive;
+ int gcOk = YAFFS_OK;
+ int maxTries = 0;
+
+ int checkpointBlockAdjust;
+
+ if (dev->isDoingGC) {
+ /* Bail out so we don't get recursive gc */
+ return YAFFS_OK;
+ }
+
+ /* This loop should pass the first time.
+ * We'll only see looping here if the erase of the collected block fails.
+ */
+
+ do {
+ maxTries++;
+
+ checkpointBlockAdjust = (dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint);
+ if(checkpointBlockAdjust < 0)
+ checkpointBlockAdjust = 0;
+
+ if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust)) {
+ /* We need a block soon...*/
+ aggressive = 1;
+ } else {
+ /* We're in no hurry */
+ aggressive = 0;
+ }
+
+ block = yaffs_FindBlockForGarbageCollection(dev, aggressive);
+
+ if (block > 0) {
+ dev->garbageCollections++;
+ if (!aggressive) {
+ dev->passiveGarbageCollections++;
+ }
+
+ T(YAFFS_TRACE_GC,
+ (TSTR
+ ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
+ dev->nErasedBlocks, aggressive));
+
+ gcOk = yaffs_GarbageCollectBlock(dev, block);
+ }
+
+ if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
+ T(YAFFS_TRACE_GC,
+ (TSTR
+ ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
+ TENDSTR), dev->nErasedBlocks, maxTries, block));
+ }
+ } while ((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0)
+ && (maxTries < 2));
+
+ return aggressive ? gcOk : YAFFS_OK;
+}
+
+/*------------------------- TAGS --------------------------------*/
+
+static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId,
+ int chunkInObject)
+{
+ return (tags->chunkId == chunkInObject &&
+ tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
+
+}
+
+
+/*-------------------- Data file manipulation -----------------*/
+
+static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode,
+ yaffs_ExtendedTags * tags)
+{
+ /*Get the Tnode, then get the level 0 offset chunk offset */
+ yaffs_Tnode *tn;
+ int theChunk = -1;
+ yaffs_ExtendedTags localTags;
+ int retVal = -1;
+
+ yaffs_Device *dev = in->myDev;
+
+ if (!tags) {
+ /* Passed a NULL, so use our own tags space */
+ tags = &localTags;
+ }
+
+ tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
+
+ if (tn) {
+ theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);
+
+ retVal =
+ yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
+ chunkInInode);
+ }
+ return retVal;
+}
+
+static int yaffs_FindAndDeleteChunkInFile(yaffs_Object * in, int chunkInInode,
+ yaffs_ExtendedTags * tags)
+{
+ /* Get the Tnode, then get the level 0 offset chunk offset */
+ yaffs_Tnode *tn;
+ int theChunk = -1;
+ yaffs_ExtendedTags localTags;
+
+ yaffs_Device *dev = in->myDev;
+ int retVal = -1;
+
+ if (!tags) {
+ /* Passed a NULL, so use our own tags space */
+ tags = &localTags;
+ }
+
+ tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
+
+ if (tn) {
+
+ theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);
+
+ retVal =
+ yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
+ chunkInInode);
+
+ /* Delete the entry in the filestructure (if found) */
+ if (retVal != -1) {
+ yaffs_PutLevel0Tnode(dev,tn,chunkInInode,0);
+ }
+ } else {
+ /*T(("No level 0 found for %d\n", chunkInInode)); */
+ }
+
+ if (retVal == -1) {
+ /* T(("Could not find %d to delete\n",chunkInInode)); */
+ }
+ return retVal;
+}
+
+#ifdef YAFFS_PARANOID
+
+static int yaffs_CheckFileSanity(yaffs_Object * in)
+{
+ int chunk;
+ int nChunks;
+ int fSize;
+ int failed = 0;
+ int objId;
+ yaffs_Tnode *tn;
+ yaffs_Tags localTags;
+ yaffs_Tags *tags = &localTags;
+ int theChunk;
+ int chunkDeleted;
+
+ if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
+ /* T(("Object not a file\n")); */
+ return YAFFS_FAIL;
+ }
+
+ objId = in->objectId;
+ fSize = in->variant.fileVariant.fileSize;
+ nChunks =
+ (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
+
+ for (chunk = 1; chunk <= nChunks; chunk++) {
+ tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
+ chunk);
+
+ if (tn) {
+
+ theChunk = yaffs_GetChunkGroupBase(dev,tn,chunk);
+
+ if (yaffs_CheckChunkBits
+ (dev, theChunk / dev->nChunksPerBlock,
+ theChunk % dev->nChunksPerBlock)) {
+
+ yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
+ tags,
+ &chunkDeleted);
+ if (yaffs_TagsMatch
+ (tags, in->objectId, chunk, chunkDeleted)) {
+ /* found it; */
+
+ }
+ } else {
+
+ failed = 1;
+ }
+
+ } else {
+ /* T(("No level 0 found for %d\n", chunk)); */
+ }
+ }
+
+ return failed ? YAFFS_FAIL : YAFFS_OK;
+}
+
+#endif
+
+static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode,
+ int chunkInNAND, int inScan)
+{
+ /* NB inScan is zero unless scanning.
+ * For forward scanning, inScan is > 0;
+ * for backward scanning inScan is < 0
+ */
+
+ yaffs_Tnode *tn;
+ yaffs_Device *dev = in->myDev;
+ int existingChunk;
+ yaffs_ExtendedTags existingTags;
+ yaffs_ExtendedTags newTags;
+ unsigned existingSerial, newSerial;
+
+ if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
+ /* Just ignore an attempt at putting a chunk into a non-file during scanning
+ * If it is not during Scanning then something went wrong!
+ */
+ if (!inScan) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("yaffs tragedy:attempt to put data chunk into a non-file"
+ TENDSTR)));
+ YBUG();
+ }
+
+ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
+ return YAFFS_OK;
+ }
+
+ tn = yaffs_AddOrFindLevel0Tnode(dev,
+ &in->variant.fileVariant,
+ chunkInInode,
+ NULL);
+ if (!tn) {
+ return YAFFS_FAIL;
+ }
+
+ existingChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);
+
+ if (inScan != 0) {
+ /* If we're scanning then we need to test for duplicates
+ * NB This does not need to be efficient since it should only ever
+ * happen when the power fails during a write, then only one
+ * chunk should ever be affected.
+ *
+ * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
+ * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
+ */
+
+ if (existingChunk != 0) {
+ /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
+ * thus we have to do a FindChunkInFile to get the real chunk id.
+ *
+ * We have a duplicate now we need to decide which one to use:
+ *
+ * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
+ * Forward scanning YAFFS2: The new one is what we use, dump the old one.
+ * YAFFS1: Get both sets of tags and compare serial numbers.
+ */
+
+ if (inScan > 0) {
+ /* Only do this for forward scanning */
+ yaffs_ReadChunkWithTagsFromNAND(dev,
+ chunkInNAND,
+ NULL, &newTags);
+
+ /* Do a proper find */
+ existingChunk =
+ yaffs_FindChunkInFile(in, chunkInInode,
+ &existingTags);
+ }
+
+ if (existingChunk <= 0) {
+ /*Hoosterman - how did this happen? */
+
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("yaffs tragedy: existing chunk < 0 in scan"
+ TENDSTR)));
+
+ }
+
+ /* NB The deleted flags should be false, otherwise the chunks will
+ * not be loaded during a scan
+ */
+
+ newSerial = newTags.serialNumber;
+ existingSerial = existingTags.serialNumber;
+
+ if ((inScan > 0) &&
+ (in->myDev->isYaffs2 ||
+ existingChunk <= 0 ||
+ ((existingSerial + 1) & 3) == newSerial)) {
+ /* Forward scanning.
+ * Use new
+ * Delete the old one and drop through to update the tnode
+ */
+ yaffs_DeleteChunk(dev, existingChunk, 1,
+ __LINE__);
+ } else {
+ /* Backward scanning or we want to use the existing one
+ * Use existing.
+ * Delete the new one and return early so that the tnode isn't changed
+ */
+ yaffs_DeleteChunk(dev, chunkInNAND, 1,
+ __LINE__);
+ return YAFFS_OK;
+ }
+ }
+
+ }
+
+ if (existingChunk == 0) {
+ in->nDataChunks++;
+ }
+
+ yaffs_PutLevel0Tnode(dev,tn,chunkInInode,chunkInNAND);
+
+ return YAFFS_OK;
+}
+
+static int yaffs_ReadChunkDataFromObject(yaffs_Object * in, int chunkInInode,
+ __u8 * buffer)
+{
+ int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
+
+ if (chunkInNAND >= 0) {
+ return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
+ buffer,NULL);
+ } else {
+ T(YAFFS_TRACE_NANDACCESS,
+ (TSTR("Chunk %d not found zero instead" TENDSTR),
+ chunkInNAND));
+ /* get sane (zero) data if you read a hole */
+ memset(buffer, 0, in->myDev->nDataBytesPerChunk);
+ return 0;
+ }
+
+}
+
+void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn)
+{
+ int block;
+ int page;
+ yaffs_ExtendedTags tags;
+ yaffs_BlockInfo *bi;
+
+ if (chunkId <= 0)
+ return;
+
+ dev->nDeletions++;
+ block = chunkId / dev->nChunksPerBlock;
+ page = chunkId % dev->nChunksPerBlock;
+
+ bi = yaffs_GetBlockInfo(dev, block);
+
+ T(YAFFS_TRACE_DELETION,
+ (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
+
+ if (markNAND &&
+ bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
+
+ yaffs_InitialiseTags(&tags);
+
+ tags.chunkDeleted = 1;
+
+ yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
+ yaffs_HandleUpdateChunk(dev, chunkId, &tags);
+ } else {
+ dev->nUnmarkedDeletions++;
+ }
+
+ /* Pull out of the management area.
+ * If the whole block became dirty, this will kick off an erasure.
+ */
+ if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
+ bi->blockState == YAFFS_BLOCK_STATE_FULL ||
+ bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+ bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
+ dev->nFreeChunks++;
+
+ yaffs_ClearChunkBit(dev, block, page);
+
+ bi->pagesInUse--;
+
+ if (bi->pagesInUse == 0 &&
+ !bi->hasShrinkHeader &&
+ bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
+ bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+ yaffs_BlockBecameDirty(dev, block);
+ }
+
+ } else {
+ /* T(("Bad news deleting chunk %d\n",chunkId)); */
+ }
+
+}
+
+static int yaffs_WriteChunkDataToObject(yaffs_Object * in, int chunkInInode,
+ const __u8 * buffer, int nBytes,
+ int useReserve)
+{
+ /* Find old chunk Need to do this to get serial number
+ * Write new one and patch into tree.
+ * Invalidate old tags.
+ */
+
+ int prevChunkId;
+ yaffs_ExtendedTags prevTags;
+
+ int newChunkId;
+ yaffs_ExtendedTags newTags;
+
+ yaffs_Device *dev = in->myDev;
+
+ yaffs_CheckGarbageCollection(dev);
+
+ /* Get the previous chunk at this location in the file if it exists */
+ prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
+
+ /* Set up new tags */
+ yaffs_InitialiseTags(&newTags);
+
+ newTags.chunkId = chunkInInode;
+ newTags.objectId = in->objectId;
+ newTags.serialNumber =
+ (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
+ newTags.byteCount = nBytes;
+
+ newChunkId =
+ yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
+ useReserve);
+
+ if (newChunkId >= 0) {
+ yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
+
+ if (prevChunkId >= 0) {
+ yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
+
+ }
+
+ yaffs_CheckFileSanity(in);
+ }
+ return newChunkId;
+
+}
+
+/* UpdateObjectHeader updates the header on NAND for an object.
+ * If name is not NULL, then that new name is used.
+ */
+int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name, int force,
+ int isShrink, int shadows)
+{
+
+ yaffs_BlockInfo *bi;
+
+ yaffs_Device *dev = in->myDev;
+
+ int prevChunkId;
+ int retVal = 0;
+ int result = 0;
+
+ int newChunkId;
+ yaffs_ExtendedTags newTags;
+
+ __u8 *buffer = NULL;
+ YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
+
+ yaffs_ObjectHeader *oh = NULL;
+
+ if (!in->fake || force) {
+
+ yaffs_CheckGarbageCollection(dev);
+
+ buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
+ oh = (yaffs_ObjectHeader *) buffer;
+
+ prevChunkId = in->chunkId;
+
+ if (prevChunkId >= 0) {
+ result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
+ buffer, NULL);
+ memcpy(oldName, oh->name, sizeof(oh->name));
+ }
+
+ memset(buffer, 0xFF, dev->nDataBytesPerChunk);
+
+ oh->type = in->variantType;
+ oh->yst_mode = in->yst_mode;
+ oh->shadowsObject = shadows;
+
+#ifdef CONFIG_YAFFS_WINCE
+ oh->win_atime[0] = in->win_atime[0];
+ oh->win_ctime[0] = in->win_ctime[0];
+ oh->win_mtime[0] = in->win_mtime[0];
+ oh->win_atime[1] = in->win_atime[1];
+ oh->win_ctime[1] = in->win_ctime[1];
+ oh->win_mtime[1] = in->win_mtime[1];
+#else
+ oh->yst_uid = in->yst_uid;
+ oh->yst_gid = in->yst_gid;
+ oh->yst_atime = in->yst_atime;
+ oh->yst_mtime = in->yst_mtime;
+ oh->yst_ctime = in->yst_ctime;
+ oh->yst_rdev = in->yst_rdev;
+#endif
+ if (in->parent) {
+ oh->parentObjectId = in->parent->objectId;
+ } else {
+ oh->parentObjectId = 0;
+ }
+
+ if (name && *name) {
+ memset(oh->name, 0, sizeof(oh->name));
+ yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
+ } else if (prevChunkId) {
+ memcpy(oh->name, oldName, sizeof(oh->name));
+ } else {
+ memset(oh->name, 0, sizeof(oh->name));
+ }
+
+ oh->isShrink = isShrink;
+
+ switch (in->variantType) {
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* Should not happen */
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+ oh->fileSize =
+ (oh->parentObjectId == YAFFS_OBJECTID_DELETED
+ || oh->parentObjectId ==
+ YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
+ fileVariant.fileSize;
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ oh->equivalentObjectId =
+ in->variant.hardLinkVariant.equivalentObjectId;
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ yaffs_strncpy(oh->alias,
+ in->variant.symLinkVariant.alias,
+ YAFFS_MAX_ALIAS_LENGTH);
+ oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
+ break;
+ }
+
+ /* Tags */
+ yaffs_InitialiseTags(&newTags);
+ in->serial++;
+ newTags.chunkId = 0;
+ newTags.objectId = in->objectId;
+ newTags.serialNumber = in->serial;
+
+ /* Add extra info for file header */
+
+ newTags.extraHeaderInfoAvailable = 1;
+ newTags.extraParentObjectId = oh->parentObjectId;
+ newTags.extraFileLength = oh->fileSize;
+ newTags.extraIsShrinkHeader = oh->isShrink;
+ newTags.extraEquivalentObjectId = oh->equivalentObjectId;
+ newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
+ newTags.extraObjectType = in->variantType;
+
+ /* Create new chunk in NAND */
+ newChunkId =
+ yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
+ (prevChunkId >= 0) ? 1 : 0);
+
+ if (newChunkId >= 0) {
+
+ in->chunkId = newChunkId;
+
+ if (prevChunkId >= 0) {
+ yaffs_DeleteChunk(dev, prevChunkId, 1,
+ __LINE__);
+ }
+
+ if(!yaffs_ObjectHasCachedWriteData(in))
+ in->dirty = 0;
+
+ /* If this was a shrink, then mark the block that the chunk lives on */
+ if (isShrink) {
+ bi = yaffs_GetBlockInfo(in->myDev,
+ newChunkId /in->myDev-> nChunksPerBlock);
+ bi->hasShrinkHeader = 1;
+ }
+
+ }
+
+ retVal = newChunkId;
+
+ }
+
+ if (buffer)
+ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+
+ return retVal;
+}
+
+/*------------------------ Short Operations Cache ----------------------------------------
+ * In many situations where there is no high level buffering (eg WinCE) a lot of
+ * reads might be short sequential reads, and a lot of writes may be short
+ * sequential writes. eg. scanning/writing a jpeg file.
+ * In these cases, a short read/write cache can provide a huge perfomance benefit
+ * with dumb-as-a-rock code.
+ * In Linux, the page cache provides read buffering aand the short op cache provides write
+ * buffering.
+ *
+ * There are a limited number (~10) of cache chunks per device so that we don't
+ * need a very intelligent search.
+ */
+
+static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
+{
+ yaffs_Device *dev = obj->myDev;
+ int i;
+ yaffs_ChunkCache *cache;
+ int nCaches = obj->myDev->nShortOpCaches;
+
+ for(i = 0; i < nCaches; i++){
+ cache = &dev->srCache[i];
+ if (cache->object == obj &&
+ cache->dirty)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void yaffs_FlushFilesChunkCache(yaffs_Object * obj)
+{
+ yaffs_Device *dev = obj->myDev;
+ int lowest = -99; /* Stop compiler whining. */
+ int i;
+ yaffs_ChunkCache *cache;
+ int chunkWritten = 0;
+ int nCaches = obj->myDev->nShortOpCaches;
+
+ if (nCaches > 0) {
+ do {
+ cache = NULL;
+
+ /* Find the dirty cache for this object with the lowest chunk id. */
+ for (i = 0; i < nCaches; i++) {
+ if (dev->srCache[i].object == obj &&
+ dev->srCache[i].dirty) {
+ if (!cache
+ || dev->srCache[i].chunkId <
+ lowest) {
+ cache = &dev->srCache[i];
+ lowest = cache->chunkId;
+ }
+ }
+ }
+
+ if (cache && !cache->locked) {
+ /* Write it out and free it up */
+
+ chunkWritten =
+ yaffs_WriteChunkDataToObject(cache->object,
+ cache->chunkId,
+ cache->data,
+ cache->nBytes,
+ 1);
+ cache->dirty = 0;
+ cache->object = NULL;
+ }
+
+ } while (cache && chunkWritten > 0);
+
+ if (cache) {
+ /* Hoosterman, disk full while writing cache out. */
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
+
+ }
+ }
+
+}
+
+/*yaffs_FlushEntireDeviceCache(dev)
+ *
+ *
+ */
+
+void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
+{
+ yaffs_Object *obj;
+ int nCaches = dev->nShortOpCaches;
+ int i;
+
+ /* Find a dirty object in the cache and flush it...
+ * until there are no further dirty objects.
+ */
+ do {
+ obj = NULL;
+ for( i = 0; i < nCaches && !obj; i++) {
+ if (dev->srCache[i].object &&
+ dev->srCache[i].dirty)
+ obj = dev->srCache[i].object;
+
+ }
+ if(obj)
+ yaffs_FlushFilesChunkCache(obj);
+
+ } while(obj);
+
+}
+
+
+/* Grab us a cache chunk for use.
+ * First look for an empty one.
+ * Then look for the least recently used non-dirty one.
+ * Then look for the least recently used dirty one...., flush and look again.
+ */
+static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device * dev)
+{
+ int i;
+ int usage;
+ int theOne;
+
+ if (dev->nShortOpCaches > 0) {
+ for (i = 0; i < dev->nShortOpCaches; i++) {
+ if (!dev->srCache[i].object)
+ return &dev->srCache[i];
+ }
+
+ return NULL;
+
+ theOne = -1;
+ usage = 0; /* just to stop the compiler grizzling */
+
+ for (i = 0; i < dev->nShortOpCaches; i++) {
+ if (!dev->srCache[i].dirty &&
+ ((dev->srCache[i].lastUse < usage && theOne >= 0) ||
+ theOne < 0)) {
+ usage = dev->srCache[i].lastUse;
+ theOne = i;
+ }
+ }
+
+
+ return theOne >= 0 ? &dev->srCache[theOne] : NULL;
+ } else {
+ return NULL;
+ }
+
+}
+
+static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device * dev)
+{
+ yaffs_ChunkCache *cache;
+ yaffs_Object *theObj;
+ int usage;
+ int i;
+ int pushout;
+
+ if (dev->nShortOpCaches > 0) {
+ /* Try find a non-dirty one... */
+
+ cache = yaffs_GrabChunkCacheWorker(dev);
+
+ if (!cache) {
+ /* They were all dirty, find the last recently used object and flush
+ * its cache, then find again.
+ * NB what's here is not very accurate, we actually flush the object
+ * the last recently used page.
+ */
+
+ /* With locking we can't assume we can use entry zero */
+
+ theObj = NULL;
+ usage = -1;
+ cache = NULL;
+ pushout = -1;
+
+ for (i = 0; i < dev->nShortOpCaches; i++) {
+ if (dev->srCache[i].object &&
+ !dev->srCache[i].locked &&
+ (dev->srCache[i].lastUse < usage || !cache))
+ {
+ usage = dev->srCache[i].lastUse;
+ theObj = dev->srCache[i].object;
+ cache = &dev->srCache[i];
+ pushout = i;
+ }
+ }
+
+ if (!cache || cache->dirty) {
+ /* Flush and try again */
+ yaffs_FlushFilesChunkCache(theObj);
+ cache = yaffs_GrabChunkCacheWorker(dev);
+ }
+
+ }
+ return cache;
+ } else
+ return NULL;
+
+}
+
+/* Find a cached chunk */
+static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object * obj,
+ int chunkId)
+{
+ yaffs_Device *dev = obj->myDev;
+ int i;
+ if (dev->nShortOpCaches > 0) {
+ for (i = 0; i < dev->nShortOpCaches; i++) {
+ if (dev->srCache[i].object == obj &&
+ dev->srCache[i].chunkId == chunkId) {
+ dev->cacheHits++;
+
+ return &dev->srCache[i];
+ }
+ }
+ }
+ return NULL;
+}
+
+/* Mark the chunk for the least recently used algorithym */
+static void yaffs_UseChunkCache(yaffs_Device * dev, yaffs_ChunkCache * cache,
+ int isAWrite)
+{
+
+ if (dev->nShortOpCaches > 0) {
+ if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
+ /* Reset the cache usages */
+ int i;
+ for (i = 1; i < dev->nShortOpCaches; i++) {
+ dev->srCache[i].lastUse = 0;
+ }
+ dev->srLastUse = 0;
+ }
+
+ dev->srLastUse++;
+
+ cache->lastUse = dev->srLastUse;
+
+ if (isAWrite) {
+ cache->dirty = 1;
+ }
+ }
+}
+
+/* Invalidate a single cache page.
+ * Do this when a whole page gets written,
+ * ie the short cache for this page is no longer valid.
+ */
+static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId)
+{
+ if (object->myDev->nShortOpCaches > 0) {
+ yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
+
+ if (cache) {
+ cache->object = NULL;
+ }
+ }
+}
+
+/* Invalidate all the cache pages associated with this object
+ * Do this whenever ther file is deleted or resized.
+ */
+static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in)
+{
+ int i;
+ yaffs_Device *dev = in->myDev;
+
+ if (dev->nShortOpCaches > 0) {
+ /* Invalidate it. */
+ for (i = 0; i < dev->nShortOpCaches; i++) {
+ if (dev->srCache[i].object == in) {
+ dev->srCache[i].object = NULL;
+ }
+ }
+ }
+}
+
+/*--------------------- Checkpointing --------------------*/
+
+
+static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev,int head)
+{
+ yaffs_CheckpointValidity cp;
+ cp.structType = sizeof(cp);
+ cp.magic = YAFFS_MAGIC;
+ cp.version = YAFFS_CHECKPOINT_VERSION;
+ cp.head = (head) ? 1 : 0;
+
+ return (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp))?
+ 1 : 0;
+}
+
+static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
+{
+ yaffs_CheckpointValidity cp;
+ int ok;
+
+ ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
+
+ if(ok)
+ ok = (cp.structType == sizeof(cp)) &&
+ (cp.magic == YAFFS_MAGIC) &&
+ (cp.version == YAFFS_CHECKPOINT_VERSION) &&
+ (cp.head == ((head) ? 1 : 0));
+ return ok ? 1 : 0;
+}
+
+static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
+ yaffs_Device *dev)
+{
+ cp->nErasedBlocks = dev->nErasedBlocks;
+ cp->allocationBlock = dev->allocationBlock;
+ cp->allocationPage = dev->allocationPage;
+ cp->nFreeChunks = dev->nFreeChunks;
+
+ cp->nDeletedFiles = dev->nDeletedFiles;
+ cp->nUnlinkedFiles = dev->nUnlinkedFiles;
+ cp->nBackgroundDeletions = dev->nBackgroundDeletions;
+ cp->sequenceNumber = dev->sequenceNumber;
+ cp->oldestDirtySequence = dev->oldestDirtySequence;
+
+}
+
+static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
+ yaffs_CheckpointDevice *cp)
+{
+ dev->nErasedBlocks = cp->nErasedBlocks;
+ dev->allocationBlock = cp->allocationBlock;
+ dev->allocationPage = cp->allocationPage;
+ dev->nFreeChunks = cp->nFreeChunks;
+
+ dev->nDeletedFiles = cp->nDeletedFiles;
+ dev->nUnlinkedFiles = cp->nUnlinkedFiles;
+ dev->nBackgroundDeletions = cp->nBackgroundDeletions;
+ dev->sequenceNumber = cp->sequenceNumber;
+ dev->oldestDirtySequence = cp->oldestDirtySequence;
+}
+
+
+static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
+{
+ yaffs_CheckpointDevice cp;
+ __u32 nBytes;
+ __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
+
+ int ok;
+
+ /* Write device runtime values*/
+ yaffs_DeviceToCheckpointDevice(&cp,dev);
+ cp.structType = sizeof(cp);
+
+ ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
+
+ /* Write block info */
+ if(ok) {
+ nBytes = nBlocks * sizeof(yaffs_BlockInfo);
+ ok = (yaffs_CheckpointWrite(dev,dev->blockInfo,nBytes) == nBytes);
+ }
+
+ /* Write chunk bits */
+ if(ok) {
+ nBytes = nBlocks * dev->chunkBitmapStride;
+ ok = (yaffs_CheckpointWrite(dev,dev->chunkBits,nBytes) == nBytes);
+ }
+ return ok ? 1 : 0;
+
+}
+
+static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
+{
+ yaffs_CheckpointDevice cp;
+ __u32 nBytes;
+ __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
+
+ int ok;
+
+ ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
+ if(!ok)
+ return 0;
+
+ if(cp.structType != sizeof(cp))
+ return 0;
+
+
+ yaffs_CheckpointDeviceToDevice(dev,&cp);
+
+ nBytes = nBlocks * sizeof(yaffs_BlockInfo);
+
+ ok = (yaffs_CheckpointRead(dev,dev->blockInfo,nBytes) == nBytes);
+
+ if(!ok)
+ return 0;
+ nBytes = nBlocks * dev->chunkBitmapStride;
+
+ ok = (yaffs_CheckpointRead(dev,dev->chunkBits,nBytes) == nBytes);
+
+ return ok ? 1 : 0;
+}
+
+static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
+ yaffs_Object *obj)
+{
+
+ cp->objectId = obj->objectId;
+ cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
+ cp->chunkId = obj->chunkId;
+ cp->variantType = obj->variantType;
+ cp->deleted = obj->deleted;
+ cp->softDeleted = obj->softDeleted;
+ cp->unlinked = obj->unlinked;
+ cp->fake = obj->fake;
+ cp->renameAllowed = obj->renameAllowed;
+ cp->unlinkAllowed = obj->unlinkAllowed;
+ cp->serial = obj->serial;
+ cp->nDataChunks = obj->nDataChunks;
+
+ if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
+ cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
+ else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
+ cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
+}
+
+static void yaffs_CheckpointObjectToObject( yaffs_Object *obj,yaffs_CheckpointObject *cp)
+{
+
+ yaffs_Object *parent;
+
+ obj->objectId = cp->objectId;
+
+ if(cp->parentId)
+ parent = yaffs_FindOrCreateObjectByNumber(
+ obj->myDev,
+ cp->parentId,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+ else
+ parent = NULL;
+
+ if(parent)
+ yaffs_AddObjectToDirectory(parent, obj);
+
+ obj->chunkId = cp->chunkId;
+ obj->variantType = cp->variantType;
+ obj->deleted = cp->deleted;
+ obj->softDeleted = cp->softDeleted;
+ obj->unlinked = cp->unlinked;
+ obj->fake = cp->fake;
+ obj->renameAllowed = cp->renameAllowed;
+ obj->unlinkAllowed = cp->unlinkAllowed;
+ obj->serial = cp->serial;
+ obj->nDataChunks = cp->nDataChunks;
+
+ if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
+ obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
+ else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
+ obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
+
+ if(obj->objectId >= YAFFS_NOBJECT_BUCKETS)
+ obj->lazyLoaded = 1;
+}
+
+
+
+static int yaffs_CheckpointTnodeWorker(yaffs_Object * in, yaffs_Tnode * tn,
+ __u32 level, int chunkOffset)
+{
+ int i;
+ yaffs_Device *dev = in->myDev;
+ int ok = 1;
+ int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
+
+ if (tn) {
+ if (level > 0) {
+
+ for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){
+ if (tn->internal[i]) {
+ ok = yaffs_CheckpointTnodeWorker(in,
+ tn->internal[i],
+ level - 1,
+ (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
+ }
+ }
+ } else if (level == 0) {
+ __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
+ /* printf("write tnode at %d\n",baseOffset); */
+ ok = (yaffs_CheckpointWrite(dev,&baseOffset,sizeof(baseOffset)) == sizeof(baseOffset));
+ if(ok)
+ ok = (yaffs_CheckpointWrite(dev,tn,nTnodeBytes) == nTnodeBytes);
+ }
+ }
+
+ return ok;
+
+}
+
+static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
+{
+ __u32 endMarker = ~0;
+ int ok = 1;
+
+ if(obj->variantType == YAFFS_OBJECT_TYPE_FILE){
+ ok = yaffs_CheckpointTnodeWorker(obj,
+ obj->variant.fileVariant.top,
+ obj->variant.fileVariant.topLevel,
+ 0);
+ if(ok)
+ ok = (yaffs_CheckpointWrite(obj->myDev,&endMarker,sizeof(endMarker)) ==
+ sizeof(endMarker));
+ }
+
+ return ok ? 1 : 0;
+}
+
+static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
+{
+ __u32 baseChunk;
+ int ok = 1;
+ yaffs_Device *dev = obj->myDev;
+ yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
+ yaffs_Tnode *tn;
+
+ ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk));
+
+ while(ok && (~baseChunk)){
+ /* Read level 0 tnode */
+
+ /* printf("read tnode at %d\n",baseChunk); */
+ tn = yaffs_GetTnodeRaw(dev);
+ if(tn)
+ ok = (yaffs_CheckpointRead(dev,tn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8) ==
+ (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
+ else
+ ok = 0;
+
+ if(tn && ok){
+ ok = yaffs_AddOrFindLevel0Tnode(dev,
+ fileStructPtr,
+ baseChunk,
+ tn) ? 1 : 0;
+ }
+
+ if(ok)
+ ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk));
+
+ }
+
+ return ok ? 1 : 0;
+}
+
+
+static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
+{
+ yaffs_Object *obj;
+ yaffs_CheckpointObject cp;
+ int i;
+ int ok = 1;
+ struct list_head *lh;
+
+
+ /* Iterate through the objects in each hash entry,
+ * dumping them to the checkpointing stream.
+ */
+
+ for(i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++){
+ list_for_each(lh, &dev->objectBucket[i].list) {
+ if (lh) {
+ obj = list_entry(lh, yaffs_Object, hashLink);
+ if (!obj->deferedFree) {
+ yaffs_ObjectToCheckpointObject(&cp,obj);
+ cp.structType = sizeof(cp);
+
+ T(YAFFS_TRACE_CHECKPOINT,(
+ TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
+ cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj));
+
+ ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
+
+ if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){
+ ok = yaffs_WriteCheckpointTnodes(obj);
+ }
+ }
+ }
+ }
+ }
+
+ /* Dump end of list */
+ memset(&cp,0xFF,sizeof(yaffs_CheckpointObject));
+ cp.structType = sizeof(cp);
+
+ if(ok)
+ ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
+
+ return ok ? 1 : 0;
+}
+
+static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
+{
+ yaffs_Object *obj;
+ yaffs_CheckpointObject cp;
+ int ok = 1;
+ int done = 0;
+ yaffs_Object *hardList = NULL;
+
+ while(ok && !done) {
+ ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
+ if(cp.structType != sizeof(cp)) {
+ /* printf("structure parsing failed\n"); */
+ ok = 0;
+ }
+
+ if(ok && cp.objectId == ~0)
+ done = 1;
+ else if(ok){
+ obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType);
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
+ cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj));
+ if(obj) {
+ yaffs_CheckpointObjectToObject(obj,&cp);
+ if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
+ ok = yaffs_ReadCheckpointTnodes(obj);
+ } else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
+ obj->hardLinks.next =
+ (struct list_head *)
+ hardList;
+ hardList = obj;
+ }
+
+ }
+ }
+ }
+
+ if(ok)
+ yaffs_HardlinkFixup(dev,hardList);
+
+ return ok ? 1 : 0;
+}
+
+static int yaffs_WriteCheckpointData(yaffs_Device *dev)
+{
+
+ int ok;
+
+ ok = yaffs_CheckpointOpen(dev,1);
+
+ if(ok)
+ ok = yaffs_WriteCheckpointValidityMarker(dev,1);
+ if(ok)
+ ok = yaffs_WriteCheckpointDevice(dev);
+ if(ok)
+ ok = yaffs_WriteCheckpointObjects(dev);
+ if(ok)
+ ok = yaffs_WriteCheckpointValidityMarker(dev,0);
+
+ if(!yaffs_CheckpointClose(dev))
+ ok = 0;
+
+ if(ok)
+ dev->isCheckpointed = 1;
+ else
+ dev->isCheckpointed = 0;
+
+ return dev->isCheckpointed;
+}
+
+static int yaffs_ReadCheckpointData(yaffs_Device *dev)
+{
+ int ok;
+
+ ok = yaffs_CheckpointOpen(dev,0); /* open for read */
+
+ if(ok)
+ ok = yaffs_ReadCheckpointValidityMarker(dev,1);
+ if(ok)
+ ok = yaffs_ReadCheckpointDevice(dev);
+ if(ok)
+ ok = yaffs_ReadCheckpointObjects(dev);
+ if(ok)
+ ok = yaffs_ReadCheckpointValidityMarker(dev,0);
+
+
+
+ if(!yaffs_CheckpointClose(dev))
+ ok = 0;
+
+ if(ok)
+ dev->isCheckpointed = 1;
+ else
+ dev->isCheckpointed = 0;
+
+ return ok ? 1 : 0;
+
+}
+
+static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
+{
+ if(dev->isCheckpointed ||
+ dev->blocksInCheckpoint > 0){
+ dev->isCheckpointed = 0;
+ yaffs_CheckpointInvalidateStream(dev);
+ if(dev->superBlock && dev->markSuperBlockDirty)
+ dev->markSuperBlockDirty(dev->superBlock);
+ }
+}
+
+
+int yaffs_CheckpointSave(yaffs_Device *dev)
+{
+ yaffs_ReportOddballBlocks(dev);
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
+
+ if(!dev->isCheckpointed)
+ yaffs_WriteCheckpointData(dev);
+
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
+
+ return dev->isCheckpointed;
+}
+
+int yaffs_CheckpointRestore(yaffs_Device *dev)
+{
+ int retval;
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
+
+ retval = yaffs_ReadCheckpointData(dev);
+
+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
+
+ yaffs_ReportOddballBlocks(dev);
+
+ return retval;
+}
+
+/*--------------------- File read/write ------------------------
+ * Read and write have very similar structures.
+ * In general the read/write has three parts to it
+ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
+ * Some complete chunks
+ * An incomplete chunk to end off with
+ *
+ * Curve-balls: the first chunk might also be the last chunk.
+ */
+
+int yaffs_ReadDataFromFile(yaffs_Object * in, __u8 * buffer, loff_t offset,
+ int nBytes)
+{
+
+ int chunk;
+ int start;
+ int nToCopy;
+ int n = nBytes;
+ int nDone = 0;
+ yaffs_ChunkCache *cache;
+
+ yaffs_Device *dev;
+
+ dev = in->myDev;
+
+ while (n > 0) {
+ //chunk = offset / dev->nDataBytesPerChunk + 1;
+ //start = offset % dev->nDataBytesPerChunk;
+ yaffs_AddrToChunk(dev,offset,&chunk,&start);
+ chunk++;
+
+ /* OK now check for the curveball where the start and end are in
+ * the same chunk.
+ */
+ if ((start + n) < dev->nDataBytesPerChunk) {
+ nToCopy = n;
+ } else {
+ nToCopy = dev->nDataBytesPerChunk - start;
+ }
+
+ cache = yaffs_FindChunkCache(in, chunk);
+
+ /* If the chunk is already in the cache or it is less than a whole chunk
+ * then use the cache (if there is caching)
+ * else bypass the cache.
+ */
+ if (cache || nToCopy != dev->nDataBytesPerChunk) {
+ if (dev->nShortOpCaches > 0) {
+
+ /* If we can't find the data in the cache, then load it up. */
+
+ if (!cache) {
+ cache = yaffs_GrabChunkCache(in->myDev);
+ cache->object = in;
+ cache->chunkId = chunk;
+ cache->dirty = 0;
+ cache->locked = 0;
+ yaffs_ReadChunkDataFromObject(in, chunk,
+ cache->
+ data);
+ cache->nBytes = 0;
+ }
+
+ yaffs_UseChunkCache(dev, cache, 0);
+
+ cache->locked = 1;
+
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_UnlockYAFFS(TRUE);
+#endif
+ memcpy(buffer, &cache->data[start], nToCopy);
+
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_LockYAFFS(TRUE);
+#endif
+ cache->locked = 0;
+ } else {
+ /* Read into the local buffer then copy..*/
+
+ __u8 *localBuffer =
+ yaffs_GetTempBuffer(dev, __LINE__);
+ yaffs_ReadChunkDataFromObject(in, chunk,
+ localBuffer);
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_UnlockYAFFS(TRUE);
+#endif
+ memcpy(buffer, &localBuffer[start], nToCopy);
+
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_LockYAFFS(TRUE);
+#endif
+ yaffs_ReleaseTempBuffer(dev, localBuffer,
+ __LINE__);
+ }
+
+ } else {
+#ifdef CONFIG_YAFFS_WINCE
+ __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
+
+ /* Under WinCE can't do direct transfer. Need to use a local buffer.
+ * This is because we otherwise screw up WinCE's memory mapper
+ */
+ yaffs_ReadChunkDataFromObject(in, chunk, localBuffer);
+
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_UnlockYAFFS(TRUE);
+#endif
+ memcpy(buffer, localBuffer, dev->nDataBytesPerChunk);
+
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_LockYAFFS(TRUE);
+ yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
+#endif
+
+#else
+ /* A full chunk. Read directly into the supplied buffer. */
+ yaffs_ReadChunkDataFromObject(in, chunk, buffer);
+#endif
+ }
+
+ n -= nToCopy;
+ offset += nToCopy;
+ buffer += nToCopy;
+ nDone += nToCopy;
+
+ }
+
+ return nDone;
+}
+
+int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset,
+ int nBytes, int writeThrough)
+{
+
+ int chunk;
+ int start;
+ int nToCopy;
+ int n = nBytes;
+ int nDone = 0;
+ int nToWriteBack;
+ int startOfWrite = offset;
+ int chunkWritten = 0;
+ int nBytesRead;
+
+ yaffs_Device *dev;
+
+ dev = in->myDev;
+
+ while (n > 0 && chunkWritten >= 0) {
+ //chunk = offset / dev->nDataBytesPerChunk + 1;
+ //start = offset % dev->nDataBytesPerChunk;
+ yaffs_AddrToChunk(dev,offset,&chunk,&start);
+ chunk++;
+
+ /* OK now check for the curveball where the start and end are in
+ * the same chunk.
+ */
+
+ if ((start + n) < dev->nDataBytesPerChunk) {
+ nToCopy = n;
+
+ /* Now folks, to calculate how many bytes to write back....
+ * If we're overwriting and not writing to then end of file then
+ * we need to write back as much as was there before.
+ */
+
+ nBytesRead =
+ in->variant.fileVariant.fileSize -
+ ((chunk - 1) * dev->nDataBytesPerChunk);
+
+ if (nBytesRead > dev->nDataBytesPerChunk) {
+ nBytesRead = dev->nDataBytesPerChunk;
+ }
+
+ nToWriteBack =
+ (nBytesRead >
+ (start + n)) ? nBytesRead : (start + n);
+
+ } else {
+ nToCopy = dev->nDataBytesPerChunk - start;
+ nToWriteBack = dev->nDataBytesPerChunk;
+ }
+
+ if (nToCopy != dev->nDataBytesPerChunk) {
+ /* An incomplete start or end chunk (or maybe both start and end chunk) */
+ if (dev->nShortOpCaches > 0) {
+ yaffs_ChunkCache *cache;
+ /* If we can't find the data in the cache, then load the cache */
+ cache = yaffs_FindChunkCache(in, chunk);
+
+ if (!cache
+ && yaffs_CheckSpaceForAllocation(in->
+ myDev)) {
+ cache = yaffs_GrabChunkCache(in->myDev);
+ cache->object = in;
+ cache->chunkId = chunk;
+ cache->dirty = 0;
+ cache->locked = 0;
+ yaffs_ReadChunkDataFromObject(in, chunk,
+ cache->
+ data);
+ }
+ else if(cache &&
+ !cache->dirty &&
+ !yaffs_CheckSpaceForAllocation(in->myDev)){
+ /* Drop the cache if it was a read cache item and
+ * no space check has been made for it.
+ */
+ cache = NULL;
+ }
+
+ if (cache) {
+ yaffs_UseChunkCache(dev, cache, 1);
+ cache->locked = 1;
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_UnlockYAFFS(TRUE);
+#endif
+
+ memcpy(&cache->data[start], buffer,
+ nToCopy);
+
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_LockYAFFS(TRUE);
+#endif
+ cache->locked = 0;
+ cache->nBytes = nToWriteBack;
+
+ if (writeThrough) {
+ chunkWritten =
+ yaffs_WriteChunkDataToObject
+ (cache->object,
+ cache->chunkId,
+ cache->data, cache->nBytes,
+ 1);
+ cache->dirty = 0;
+ }
+
+ } else {
+ chunkWritten = -1; /* fail the write */
+ }
+ } else {
+ /* An incomplete start or end chunk (or maybe both start and end chunk)
+ * Read into the local buffer then copy, then copy over and write back.
+ */
+
+ __u8 *localBuffer =
+ yaffs_GetTempBuffer(dev, __LINE__);
+
+ yaffs_ReadChunkDataFromObject(in, chunk,
+ localBuffer);
+
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_UnlockYAFFS(TRUE);
+#endif
+
+ memcpy(&localBuffer[start], buffer, nToCopy);
+
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_LockYAFFS(TRUE);
+#endif
+ chunkWritten =
+ yaffs_WriteChunkDataToObject(in, chunk,
+ localBuffer,
+ nToWriteBack,
+ 0);
+
+ yaffs_ReleaseTempBuffer(dev, localBuffer,
+ __LINE__);
+
+ }
+
+ } else {
+
+#ifdef CONFIG_YAFFS_WINCE
+ /* Under WinCE can't do direct transfer. Need to use a local buffer.
+ * This is because we otherwise screw up WinCE's memory mapper
+ */
+ __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_UnlockYAFFS(TRUE);
+#endif
+ memcpy(localBuffer, buffer, dev->nDataBytesPerChunk);
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_LockYAFFS(TRUE);
+#endif
+ chunkWritten =
+ yaffs_WriteChunkDataToObject(in, chunk, localBuffer,
+ dev->nDataBytesPerChunk,
+ 0);
+ yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
+#else
+ /* A full chunk. Write directly from the supplied buffer. */
+ chunkWritten =
+ yaffs_WriteChunkDataToObject(in, chunk, buffer,
+ dev->nDataBytesPerChunk,
+ 0);
+#endif
+ /* Since we've overwritten the cached data, we better invalidate it. */
+ yaffs_InvalidateChunkCache(in, chunk);
+ }
+
+ if (chunkWritten >= 0) {
+ n -= nToCopy;
+ offset += nToCopy;
+ buffer += nToCopy;
+ nDone += nToCopy;
+ }
+
+ }
+
+ /* Update file object */
+
+ if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize) {
+ in->variant.fileVariant.fileSize = (startOfWrite + nDone);
+ }
+
+ in->dirty = 1;
+
+ return nDone;
+}
+
+
+/* ---------------------- File resizing stuff ------------------ */
+
+static void yaffs_PruneResizedChunks(yaffs_Object * in, int newSize)
+{
+
+ yaffs_Device *dev = in->myDev;
+ int oldFileSize = in->variant.fileVariant.fileSize;
+
+ int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
+
+ int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
+ dev->nDataBytesPerChunk;
+ int i;
+ int chunkId;
+
+ /* Delete backwards so that we don't end up with holes if
+ * power is lost part-way through the operation.
+ */
+ for (i = lastDel; i >= startDel; i--) {
+ /* NB this could be optimised somewhat,
+ * eg. could retrieve the tags and write them without
+ * using yaffs_DeleteChunk
+ */
+
+ chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
+ if (chunkId > 0) {
+ if (chunkId <
+ (dev->internalStartBlock * dev->nChunksPerBlock)
+ || chunkId >=
+ ((dev->internalEndBlock +
+ 1) * dev->nChunksPerBlock)) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("Found daft chunkId %d for %d" TENDSTR),
+ chunkId, i));
+ } else {
+ in->nDataChunks--;
+ yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
+ }
+ }
+ }
+
+}
+
+int yaffs_ResizeFile(yaffs_Object * in, loff_t newSize)
+{
+
+ int oldFileSize = in->variant.fileVariant.fileSize;
+ int newSizeOfPartialChunk;
+ int newFullChunks;
+
+ yaffs_Device *dev = in->myDev;
+
+ yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
+
+ yaffs_FlushFilesChunkCache(in);
+ yaffs_InvalidateWholeChunkCache(in);
+
+ yaffs_CheckGarbageCollection(dev);
+
+ if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
+ return yaffs_GetFileSize(in);
+ }
+
+ if (newSize == oldFileSize) {
+ return oldFileSize;
+ }
+
+ if (newSize < oldFileSize) {
+
+ yaffs_PruneResizedChunks(in, newSize);
+
+ if (newSizeOfPartialChunk != 0) {
+ int lastChunk = 1 + newFullChunks;
+
+ __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
+
+ /* Got to read and rewrite the last chunk with its new size and zero pad */
+ yaffs_ReadChunkDataFromObject(in, lastChunk,
+ localBuffer);
+
+ memset(localBuffer + newSizeOfPartialChunk, 0,
+ dev->nDataBytesPerChunk - newSizeOfPartialChunk);
+
+ yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
+ newSizeOfPartialChunk, 1);
+
+ yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
+ }
+
+ in->variant.fileVariant.fileSize = newSize;
+
+ yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
+ } else {
+ /* newsSize > oldFileSize */
+ in->variant.fileVariant.fileSize = newSize;
+ }
+
+
+
+ /* Write a new object header.
+ * show we've shrunk the file, if need be
+ * Do this only if the file is not in the deleted directories.
+ */
+ if (in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
+ in->parent->objectId != YAFFS_OBJECTID_DELETED) {
+ yaffs_UpdateObjectHeader(in, NULL, 0,
+ (newSize < oldFileSize) ? 1 : 0, 0);
+ }
+
+ return newSize;
+}
+
+loff_t yaffs_GetFileSize(yaffs_Object * obj)
+{
+ obj = yaffs_GetEquivalentObject(obj);
+
+ switch (obj->variantType) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ return obj->variant.fileVariant.fileSize;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ return yaffs_strlen(obj->variant.symLinkVariant.alias);
+ default:
+ return 0;
+ }
+}
+
+
+
+int yaffs_FlushFile(yaffs_Object * in, int updateTime)
+{
+ int retVal;
+ if (in->dirty) {
+ yaffs_FlushFilesChunkCache(in);
+ if (updateTime) {
+#ifdef CONFIG_YAFFS_WINCE
+ yfsd_WinFileTimeNow(in->win_mtime);
+#else
+
+ in->yst_mtime = Y_CURRENT_TIME;
+
+#endif
+ }
+
+ retVal =
+ (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
+ 0) ? YAFFS_OK : YAFFS_FAIL;
+ } else {
+ retVal = YAFFS_OK;
+ }
+
+ return retVal;
+
+}
+
+static int yaffs_DoGenericObjectDeletion(yaffs_Object * in)
+{
+
+ /* First off, invalidate the file's data in the cache, without flushing. */
+ yaffs_InvalidateWholeChunkCache(in);
+
+ if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
+ /* Move to the unlinked directory so we have a record that it was deleted. */
+ yaffs_ChangeObjectName(in, in->myDev->deletedDir, NULL, 0, 0);
+
+ }
+
+ yaffs_RemoveObjectFromDirectory(in);
+ yaffs_DeleteChunk(in->myDev, in->chunkId, 1, __LINE__);
+ in->chunkId = -1;
+
+ yaffs_FreeObject(in);
+ return YAFFS_OK;
+
+}
+
+/* yaffs_DeleteFile deletes the whole file data
+ * and the inode associated with the file.
+ * It does not delete the links associated with the file.
+ */
+static int yaffs_UnlinkFile(yaffs_Object * in)
+{
+
+ int retVal;
+ int immediateDeletion = 0;
+
+ if (1) {
+#ifdef __KERNEL__
+ if (!in->myInode) {
+ immediateDeletion = 1;
+
+ }
+#else
+ if (in->inUse <= 0) {
+ immediateDeletion = 1;
+
+ }
+#endif
+ if (immediateDeletion) {
+ retVal =
+ yaffs_ChangeObjectName(in, in->myDev->deletedDir,
+ NULL, 0, 0);
+ T(YAFFS_TRACE_TRACING,
+ (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
+ in->objectId));
+ in->deleted = 1;
+ in->myDev->nDeletedFiles++;
+ if (0 && in->myDev->isYaffs2) {
+ yaffs_ResizeFile(in, 0);
+ }
+ yaffs_SoftDeleteFile(in);
+ } else {
+ retVal =
+ yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
+ NULL, 0, 0);
+ }
+
+ }
+ return retVal;
+}
+
+int yaffs_DeleteFile(yaffs_Object * in)
+{
+ int retVal = YAFFS_OK;
+
+ if (in->nDataChunks > 0) {
+ /* Use soft deletion if there is data in the file */
+ if (!in->unlinked) {
+ retVal = yaffs_UnlinkFile(in);
+ }
+ if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
+ in->deleted = 1;
+ in->myDev->nDeletedFiles++;
+ yaffs_SoftDeleteFile(in);
+ }
+ return in->deleted ? YAFFS_OK : YAFFS_FAIL;
+ } else {
+ /* The file has no data chunks so we toss it immediately */
+ yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
+ in->variant.fileVariant.top = NULL;
+ yaffs_DoGenericObjectDeletion(in);
+
+ return YAFFS_OK;
+ }
+}
+
+static int yaffs_DeleteDirectory(yaffs_Object * in)
+{
+ /* First check that the directory is empty. */
+ if (list_empty(&in->variant.directoryVariant.children)) {
+ return yaffs_DoGenericObjectDeletion(in);
+ }
+
+ return YAFFS_FAIL;
+
+}
+
+static int yaffs_DeleteSymLink(yaffs_Object * in)
+{
+ YFREE(in->variant.symLinkVariant.alias);
+
+ return yaffs_DoGenericObjectDeletion(in);
+}
+
+static int yaffs_DeleteHardLink(yaffs_Object * in)
+{
+ /* remove this hardlink from the list assocaited with the equivalent
+ * object
+ */
+ list_del(&in->hardLinks);
+ return yaffs_DoGenericObjectDeletion(in);
+}
+
+static void yaffs_DestroyObject(yaffs_Object * obj)
+{
+ switch (obj->variantType) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ yaffs_DeleteFile(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ yaffs_DeleteDirectory(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ yaffs_DeleteSymLink(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ yaffs_DeleteHardLink(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ yaffs_DoGenericObjectDeletion(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ break; /* should not happen. */
+ }
+}
+
+static int yaffs_UnlinkWorker(yaffs_Object * obj)
+{
+
+ if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
+ return yaffs_DeleteHardLink(obj);
+ } else if (!list_empty(&obj->hardLinks)) {
+ /* Curve ball: We're unlinking an object that has a hardlink.
+ *
+ * This problem arises because we are not strictly following
+ * The Linux link/inode model.
+ *
+ * We can't really delete the object.
+ * Instead, we do the following:
+ * - Select a hardlink.
+ * - Unhook it from the hard links
+ * - Unhook it from its parent directory (so that the rename can work)
+ * - Rename the object to the hardlink's name.
+ * - Delete the hardlink
+ */
+
+ yaffs_Object *hl;
+ int retVal;
+ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
+
+ hl = list_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
+
+ list_del_init(&hl->hardLinks);
+ list_del_init(&hl->siblings);
+
+ yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
+
+ retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
+
+ if (retVal == YAFFS_OK) {
+ retVal = yaffs_DoGenericObjectDeletion(hl);
+ }
+ return retVal;
+
+ } else {
+ switch (obj->variantType) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ return yaffs_UnlinkFile(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ return yaffs_DeleteDirectory(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ return yaffs_DeleteSymLink(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ return yaffs_DoGenericObjectDeletion(obj);
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ default:
+ return YAFFS_FAIL;
+ }
+ }
+}
+
+
+static int yaffs_UnlinkObject( yaffs_Object *obj)
+{
+
+ if (obj && obj->unlinkAllowed) {
+ return yaffs_UnlinkWorker(obj);
+ }
+
+ return YAFFS_FAIL;
+
+}
+int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name)
+{
+ yaffs_Object *obj;
+
+ obj = yaffs_FindObjectByName(dir, name);
+ return yaffs_UnlinkObject(obj);
+}
+
+/*----------------------- Initialisation Scanning ---------------------- */
+
+static void yaffs_HandleShadowedObject(yaffs_Device * dev, int objId,
+ int backwardScanning)
+{
+ yaffs_Object *obj;
+
+ if (!backwardScanning) {
+ /* Handle YAFFS1 forward scanning case
+ * For YAFFS1 we always do the deletion
+ */
+
+ } else {
+ /* Handle YAFFS2 case (backward scanning)
+ * If the shadowed object exists then ignore.
+ */
+ if (yaffs_FindObjectByNumber(dev, objId)) {
+ return;
+ }
+ }
+
+ /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
+ * We put it in unlinked dir to be cleaned up after the scanning
+ */
+ obj =
+ yaffs_FindOrCreateObjectByNumber(dev, objId,
+ YAFFS_OBJECT_TYPE_FILE);
+ yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
+ obj->variant.fileVariant.shrinkSize = 0;
+ obj->valid = 1; /* So that we don't read any other info for this file */
+
+}
+
+typedef struct {
+ int seq;
+ int block;
+} yaffs_BlockIndex;
+
+
+static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
+{
+ yaffs_Object *hl;
+ yaffs_Object *in;
+
+ while (hardList) {
+ hl = hardList;
+ hardList = (yaffs_Object *) (hardList->hardLinks.next);
+
+ in = yaffs_FindObjectByNumber(dev,
+ hl->variant.hardLinkVariant.
+ equivalentObjectId);
+
+ if (in) {
+ /* Add the hardlink pointers */
+ hl->variant.hardLinkVariant.equivalentObject = in;
+ list_add(&hl->hardLinks, &in->hardLinks);
+ } else {
+ /* Todo Need to report/handle this better.
+ * Got a problem... hardlink to a non-existant object
+ */
+ hl->variant.hardLinkVariant.equivalentObject = NULL;
+ INIT_LIST_HEAD(&hl->hardLinks);
+
+ }
+
+ }
+
+}
+
+
+
+
+
+static int ybicmp(const void *a, const void *b){
+ register int aseq = ((yaffs_BlockIndex *)a)->seq;
+ register int bseq = ((yaffs_BlockIndex *)b)->seq;
+ register int ablock = ((yaffs_BlockIndex *)a)->block;
+ register int bblock = ((yaffs_BlockIndex *)b)->block;
+ if( aseq == bseq )
+ return ablock - bblock;
+ else
+ return aseq - bseq;
+
+}
+
+static int yaffs_Scan(yaffs_Device * dev)
+{
+ yaffs_ExtendedTags tags;
+ int blk;
+ int blockIterator;
+ int startIterator;
+ int endIterator;
+ int nBlocksToScan = 0;
+ int result;
+
+ int chunk;
+ int c;
+ int deleted;
+ yaffs_BlockState state;
+ yaffs_Object *hardList = NULL;
+ yaffs_Object *hl;
+ yaffs_BlockInfo *bi;
+ int sequenceNumber;
+ yaffs_ObjectHeader *oh;
+ yaffs_Object *in;
+ yaffs_Object *parent;
+ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
+
+ __u8 *chunkData;
+
+ yaffs_BlockIndex *blockIndex = NULL;
+
+ if (dev->isYaffs2) {
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("yaffs_Scan is not for YAFFS2!" TENDSTR)));
+ return YAFFS_FAIL;
+ }
+
+ //TODO Throw all the yaffs2 stuuf out of yaffs_Scan since it is only for yaffs1 format.
+
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),
+ dev->internalStartBlock, dev->internalEndBlock));
+
+ chunkData = yaffs_GetTempBuffer(dev, __LINE__);
+
+ dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+ if (dev->isYaffs2) {
+ blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
+ }
+
+ /* Scan all the blocks to determine their state */
+ for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
+ bi = yaffs_GetBlockInfo(dev, blk);
+ yaffs_ClearChunkBits(dev, blk);
+ bi->pagesInUse = 0;
+ bi->softDeletions = 0;
+
+ yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
+
+ bi->blockState = state;
+ bi->sequenceNumber = sequenceNumber;
+
+ T(YAFFS_TRACE_SCAN_DEBUG,
+ (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
+ state, sequenceNumber));
+
+ if (state == YAFFS_BLOCK_STATE_DEAD) {
+ T(YAFFS_TRACE_BAD_BLOCKS,
+ (TSTR("block %d is bad" TENDSTR), blk));
+ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
+ T(YAFFS_TRACE_SCAN_DEBUG,
+ (TSTR("Block empty " TENDSTR)));
+ dev->nErasedBlocks++;
+ dev->nFreeChunks += dev->nChunksPerBlock;
+ } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+
+ /* Determine the highest sequence number */
+ if (dev->isYaffs2 &&
+ sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
+ sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
+
+ blockIndex[nBlocksToScan].seq = sequenceNumber;
+ blockIndex[nBlocksToScan].block = blk;
+
+ nBlocksToScan++;
+
+ if (sequenceNumber >= dev->sequenceNumber) {
+ dev->sequenceNumber = sequenceNumber;
+ }
+ } else if (dev->isYaffs2) {
+ /* TODO: Nasty sequence number! */
+ T(YAFFS_TRACE_SCAN,
+ (TSTR
+ ("Block scanning block %d has bad sequence number %d"
+ TENDSTR), blk, sequenceNumber));
+
+ }
+ }
+ }
+
+ /* Sort the blocks
+ * Dungy old bubble sort for now...
+ */
+ if (dev->isYaffs2) {
+ yaffs_BlockIndex temp;
+ int i;
+ int j;
+
+ for (i = 0; i < nBlocksToScan; i++)
+ for (j = i + 1; j < nBlocksToScan; j++)
+ if (blockIndex[i].seq > blockIndex[j].seq) {
+ temp = blockIndex[j];
+ blockIndex[j] = blockIndex[i];
+ blockIndex[i] = temp;
+ }
+ }
+
+ /* Now scan the blocks looking at the data. */
+ if (dev->isYaffs2) {
+ startIterator = 0;
+ endIterator = nBlocksToScan - 1;
+ T(YAFFS_TRACE_SCAN_DEBUG,
+ (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
+ } else {
+ startIterator = dev->internalStartBlock;
+ endIterator = dev->internalEndBlock;
+ }
+
+ /* For each block.... */
+ for (blockIterator = startIterator; blockIterator <= endIterator;
+ blockIterator++) {
+
+ if (dev->isYaffs2) {
+ /* get the block to scan in the correct order */
+ blk = blockIndex[blockIterator].block;
+ } else {
+ blk = blockIterator;
+ }
+
+ bi = yaffs_GetBlockInfo(dev, blk);
+ state = bi->blockState;
+
+ deleted = 0;
+
+ /* For each chunk in each block that needs scanning....*/
+ for (c = 0; c < dev->nChunksPerBlock &&
+ state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
+ /* Read the tags and decide what to do */
+ chunk = blk * dev->nChunksPerBlock + c;
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
+ &tags);
+
+ /* Let's have a good look at this chunk... */
+
+ if (!dev->isYaffs2 && tags.chunkDeleted) {
+ /* YAFFS1 only...
+ * A deleted chunk
+ */
+ deleted++;
+ dev->nFreeChunks++;
+ /*T((" %d %d deleted\n",blk,c)); */
+ } else if (!tags.chunkUsed) {
+ /* An unassigned chunk in the block
+ * This means that either the block is empty or
+ * this is the one being allocated from
+ */
+
+ if (c == 0) {
+ /* We're looking at the first chunk in the block so the block is unused */
+ state = YAFFS_BLOCK_STATE_EMPTY;
+ dev->nErasedBlocks++;
+ } else {
+ /* this is the block being allocated from */
+ T(YAFFS_TRACE_SCAN,
+ (TSTR
+ (" Allocating from %d %d" TENDSTR),
+ blk, c));
+ state = YAFFS_BLOCK_STATE_ALLOCATING;
+ dev->allocationBlock = blk;
+ dev->allocationPage = c;
+ dev->allocationBlockFinder = blk;
+ /* Set it to here to encourage the allocator to go forth from here. */
+
+ /* Yaffs2 sanity check:
+ * This should be the one with the highest sequence number
+ */
+ if (dev->isYaffs2
+ && (dev->sequenceNumber !=
+ bi->sequenceNumber)) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("yaffs: Allocation block %d was not highest sequence id:"
+ " block seq = %d, dev seq = %d"
+ TENDSTR), blk,bi->sequenceNumber,dev->sequenceNumber));
+ }
+ }
+
+ dev->nFreeChunks += (dev->nChunksPerBlock - c);
+ } else if (tags.chunkId > 0) {
+ /* chunkId > 0 so it is a data chunk... */
+ unsigned int endpos;
+
+ yaffs_SetChunkBit(dev, blk, c);
+ bi->pagesInUse++;
+
+ in = yaffs_FindOrCreateObjectByNumber(dev,
+ tags.
+ objectId,
+ YAFFS_OBJECT_TYPE_FILE);
+ /* PutChunkIntoFile checks for a clash (two data chunks with
+ * the same chunkId).
+ */
+ yaffs_PutChunkIntoFile(in, tags.chunkId, chunk,
+ 1);
+ endpos =
+ (tags.chunkId - 1) * dev->nDataBytesPerChunk +
+ tags.byteCount;
+ if (in->variantType == YAFFS_OBJECT_TYPE_FILE
+ && in->variant.fileVariant.scannedFileSize <
+ endpos) {
+ in->variant.fileVariant.
+ scannedFileSize = endpos;
+ if (!dev->useHeaderFileSize) {
+ in->variant.fileVariant.
+ fileSize =
+ in->variant.fileVariant.
+ scannedFileSize;
+ }
+
+ }
+ /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
+ } else {
+ /* chunkId == 0, so it is an ObjectHeader.
+ * Thus, we read in the object header and make the object
+ */
+ yaffs_SetChunkBit(dev, blk, c);
+ bi->pagesInUse++;
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
+ chunkData,
+ NULL);
+
+ oh = (yaffs_ObjectHeader *) chunkData;
+
+ in = yaffs_FindObjectByNumber(dev,
+ tags.objectId);
+ if (in && in->variantType != oh->type) {
+ /* This should not happen, but somehow
+ * Wev'e ended up with an objectId that has been reused but not yet
+ * deleted, and worse still it has changed type. Delete the old object.
+ */
+
+ yaffs_DestroyObject(in);
+
+ in = 0;
+ }
+
+ in = yaffs_FindOrCreateObjectByNumber(dev,
+ tags.
+ objectId,
+ oh->type);
+
+ if (oh->shadowsObject > 0) {
+ yaffs_HandleShadowedObject(dev,
+ oh->
+ shadowsObject,
+ 0);
+ }
+
+ if (in->valid) {
+ /* We have already filled this one. We have a duplicate and need to resolve it. */
+
+ unsigned existingSerial = in->serial;
+ unsigned newSerial = tags.serialNumber;
+
+ if (dev->isYaffs2 ||
+ ((existingSerial + 1) & 3) ==
+ newSerial) {
+ /* Use new one - destroy the exisiting one */
+ yaffs_DeleteChunk(dev,
+ in->chunkId,
+ 1, __LINE__);
+ in->valid = 0;
+ } else {
+ /* Use existing - destroy this one. */
+ yaffs_DeleteChunk(dev, chunk, 1,
+ __LINE__);
+ }
+ }
+
+ if (!in->valid &&
+ (tags.objectId == YAFFS_OBJECTID_ROOT ||
+ tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
+ /* We only load some info, don't fiddle with directory structure */
+ in->valid = 1;
+ in->variantType = oh->type;
+
+ in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+ in->win_atime[0] = oh->win_atime[0];
+ in->win_ctime[0] = oh->win_ctime[0];
+ in->win_mtime[0] = oh->win_mtime[0];
+ in->win_atime[1] = oh->win_atime[1];
+ in->win_ctime[1] = oh->win_ctime[1];
+ in->win_mtime[1] = oh->win_mtime[1];
+#else
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
+#endif
+ in->chunkId = chunk;
+
+ } else if (!in->valid) {
+ /* we need to load this info */
+
+ in->valid = 1;
+ in->variantType = oh->type;
+
+ in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+ in->win_atime[0] = oh->win_atime[0];
+ in->win_ctime[0] = oh->win_ctime[0];
+ in->win_mtime[0] = oh->win_mtime[0];
+ in->win_atime[1] = oh->win_atime[1];
+ in->win_ctime[1] = oh->win_ctime[1];
+ in->win_mtime[1] = oh->win_mtime[1];
+#else
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
+#endif
+ in->chunkId = chunk;
+
+ yaffs_SetObjectName(in, oh->name);
+ in->dirty = 0;
+
+ /* directory stuff...
+ * hook up to parent
+ */
+
+ parent =
+ yaffs_FindOrCreateObjectByNumber
+ (dev, oh->parentObjectId,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+ if (parent->variantType ==
+ YAFFS_OBJECT_TYPE_UNKNOWN) {
+ /* Set up as a directory */
+ parent->variantType =
+ YAFFS_OBJECT_TYPE_DIRECTORY;
+ INIT_LIST_HEAD(&parent->variant.
+ directoryVariant.
+ children);
+ } else if (parent->variantType !=
+ YAFFS_OBJECT_TYPE_DIRECTORY)
+ {
+ /* Hoosterman, another problem....
+ * We're trying to use a non-directory as a directory
+ */
+
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("yaffs tragedy: attempting to use non-directory as"
+ " a directory in scan. Put in lost+found."
+ TENDSTR)));
+ parent = dev->lostNFoundDir;
+ }
+
+ yaffs_AddObjectToDirectory(parent, in);
+
+ if (0 && (parent == dev->deletedDir ||
+ parent == dev->unlinkedDir)) {
+ in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
+ dev->nDeletedFiles++;
+ }
+ /* Note re hardlinks.
+ * Since we might scan a hardlink before its equivalent object is scanned
+ * we put them all in a list.
+ * After scanning is complete, we should have all the objects, so we run through this
+ * list and fix up all the chains.
+ */
+
+ switch (in->variantType) {
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* Todo got a problem */
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+ if (dev->isYaffs2
+ && oh->isShrink) {
+ /* Prune back the shrunken chunks */
+ yaffs_PruneResizedChunks
+ (in, oh->fileSize);
+ /* Mark the block as having a shrinkHeader */
+ bi->hasShrinkHeader = 1;
+ }
+
+ if (dev->useHeaderFileSize)
+
+ in->variant.fileVariant.
+ fileSize =
+ oh->fileSize;
+
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ in->variant.hardLinkVariant.
+ equivalentObjectId =
+ oh->equivalentObjectId;
+ in->hardLinks.next =
+ (struct list_head *)
+ hardList;
+ hardList = in;
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ in->variant.symLinkVariant.
+ alias =
+ yaffs_CloneString(oh->alias);
+ break;
+ }
+
+ if (parent == dev->deletedDir) {
+ yaffs_DestroyObject(in);
+ bi->hasShrinkHeader = 1;
+ }
+ }
+ }
+ }
+
+ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+ /* If we got this far while scanning, then the block is fully allocated.*/
+ state = YAFFS_BLOCK_STATE_FULL;
+ }
+
+ bi->blockState = state;
+
+ /* Now let's see if it was dirty */
+ if (bi->pagesInUse == 0 &&
+ !bi->hasShrinkHeader &&
+ bi->blockState == YAFFS_BLOCK_STATE_FULL) {
+ yaffs_BlockBecameDirty(dev, blk);
+ }
+
+ }
+
+ if (blockIndex) {
+ YFREE(blockIndex);
+ }
+
+
+ /* Ok, we've done all the scanning.
+ * Fix up the hard link chains.
+ * We should now have scanned all the objects, now it's time to add these
+ * hardlinks.
+ */
+
+ yaffs_HardlinkFixup(dev,hardList);
+
+ /* Handle the unlinked files. Since they were left in an unlinked state we should
+ * just delete them.
+ */
+ {
+ struct list_head *i;
+ struct list_head *n;
+
+ yaffs_Object *l;
+ /* Soft delete all the unlinked files */
+ list_for_each_safe(i, n,
+ &dev->unlinkedDir->variant.directoryVariant.
+ children) {
+ if (i) {
+ l = list_entry(i, yaffs_Object, siblings);
+ yaffs_DestroyObject(l);
+ }
+ }
+ }
+
+ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
+
+ T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
+
+ return YAFFS_OK;
+}
+
+static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
+{
+ __u8 *chunkData;
+ yaffs_ObjectHeader *oh;
+ yaffs_Device *dev = in->myDev;
+ yaffs_ExtendedTags tags;
+ int result;
+
+#if 0
+ T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR),
+ in->objectId,
+ in->lazyLoaded ? "not yet" : "already"));
+#endif
+
+ if(in->lazyLoaded){
+ in->lazyLoaded = 0;
+ chunkData = yaffs_GetTempBuffer(dev, __LINE__);
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev,in->chunkId,chunkData,&tags);
+ oh = (yaffs_ObjectHeader *) chunkData;
+
+ in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+ in->win_atime[0] = oh->win_atime[0];
+ in->win_ctime[0] = oh->win_ctime[0];
+ in->win_mtime[0] = oh->win_mtime[0];
+ in->win_atime[1] = oh->win_atime[1];
+ in->win_ctime[1] = oh->win_ctime[1];
+ in->win_mtime[1] = oh->win_mtime[1];
+#else
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
+
+#endif
+ yaffs_SetObjectName(in, oh->name);
+
+ if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
+ in->variant.symLinkVariant.alias =
+ yaffs_CloneString(oh->alias);
+
+ yaffs_ReleaseTempBuffer(dev,chunkData, __LINE__);
+ }
+}
+
+static int yaffs_ScanBackwards(yaffs_Device * dev)
+{
+ yaffs_ExtendedTags tags;
+ int blk;
+ int blockIterator;
+ int startIterator;
+ int endIterator;
+ int nBlocksToScan = 0;
+
+ int chunk;
+ int result;
+ int c;
+ int deleted;
+ yaffs_BlockState state;
+ yaffs_Object *hardList = NULL;
+ yaffs_BlockInfo *bi;
+ int sequenceNumber;
+ yaffs_ObjectHeader *oh;
+ yaffs_Object *in;
+ yaffs_Object *parent;
+ int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
+ int itsUnlinked;
+ __u8 *chunkData;
+
+ int fileSize;
+ int isShrink;
+ int foundChunksInBlock;
+ int equivalentObjectId;
+
+
+ yaffs_BlockIndex *blockIndex = NULL;
+ int altBlockIndex = 0;
+
+ if (!dev->isYaffs2) {
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
+ return YAFFS_FAIL;
+ }
+
+ T(YAFFS_TRACE_SCAN,
+ (TSTR
+ ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..."
+ TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
+
+
+ dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+ blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
+
+ if(!blockIndex) {
+ blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
+ altBlockIndex = 1;
+ }
+
+ if(!blockIndex) {
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));
+ return YAFFS_FAIL;
+ }
+
+ chunkData = yaffs_GetTempBuffer(dev, __LINE__);
+
+ /* Scan all the blocks to determine their state */
+ for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
+ bi = yaffs_GetBlockInfo(dev, blk);
+ yaffs_ClearChunkBits(dev, blk);
+ bi->pagesInUse = 0;
+ bi->softDeletions = 0;
+
+ yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
+
+ bi->blockState = state;
+ bi->sequenceNumber = sequenceNumber;
+
+ if(bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
+ bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
+
+ T(YAFFS_TRACE_SCAN_DEBUG,
+ (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
+ state, sequenceNumber));
+
+
+ if(state == YAFFS_BLOCK_STATE_CHECKPOINT){
+ /* todo .. fix free space ? */
+
+ } else if (state == YAFFS_BLOCK_STATE_DEAD) {
+ T(YAFFS_TRACE_BAD_BLOCKS,
+ (TSTR("block %d is bad" TENDSTR), blk));
+ } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
+ T(YAFFS_TRACE_SCAN_DEBUG,
+ (TSTR("Block empty " TENDSTR)));
+ dev->nErasedBlocks++;
+ dev->nFreeChunks += dev->nChunksPerBlock;
+ } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+
+ /* Determine the highest sequence number */
+ if (dev->isYaffs2 &&
+ sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
+ sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
+
+ blockIndex[nBlocksToScan].seq = sequenceNumber;
+ blockIndex[nBlocksToScan].block = blk;
+
+ nBlocksToScan++;
+
+ if (sequenceNumber >= dev->sequenceNumber) {
+ dev->sequenceNumber = sequenceNumber;
+ }
+ } else if (dev->isYaffs2) {
+ /* TODO: Nasty sequence number! */
+ T(YAFFS_TRACE_SCAN,
+ (TSTR
+ ("Block scanning block %d has bad sequence number %d"
+ TENDSTR), blk, sequenceNumber));
+
+ }
+ }
+ }
+
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
+
+
+
+ YYIELD();
+
+ /* Sort the blocks */
+#ifndef CONFIG_YAFFS_USE_OWN_SORT
+ {
+ /* Use qsort now. */
+ qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);
+ }
+#else
+ {
+ /* Dungy old bubble sort... */
+
+ yaffs_BlockIndex temp;
+ int i;
+ int j;
+
+ for (i = 0; i < nBlocksToScan; i++)
+ for (j = i + 1; j < nBlocksToScan; j++)
+ if (blockIndex[i].seq > blockIndex[j].seq) {
+ temp = blockIndex[j];
+ blockIndex[j] = blockIndex[i];
+ blockIndex[i] = temp;
+ }
+ }
+#endif
+
+ YYIELD();
+
+ T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
+
+ /* Now scan the blocks looking at the data. */
+ startIterator = 0;
+ endIterator = nBlocksToScan - 1;
+ T(YAFFS_TRACE_SCAN_DEBUG,
+ (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
+
+ /* For each block.... backwards */
+ for (blockIterator = endIterator; blockIterator >= startIterator;
+ blockIterator--) {
+ /* Cooperative multitasking! This loop can run for so
+ long that watchdog timers expire. */
+ YYIELD();
+
+ /* get the block to scan in the correct order */
+ blk = blockIndex[blockIterator].block;
+
+ bi = yaffs_GetBlockInfo(dev, blk);
+ state = bi->blockState;
+
+ deleted = 0;
+
+ /* For each chunk in each block that needs scanning.... */
+ foundChunksInBlock = 0;
+ for (c = dev->nChunksPerBlock - 1; c >= 0 &&
+ (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+ state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
+ /* Scan backwards...
+ * Read the tags and decide what to do
+ */
+ chunk = blk * dev->nChunksPerBlock + c;
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
+ &tags);
+
+ /* Let's have a good look at this chunk... */
+
+ if (!tags.chunkUsed) {
+ /* An unassigned chunk in the block.
+ * If there are used chunks after this one, then
+ * it is a chunk that was skipped due to failing the erased
+ * check. Just skip it so that it can be deleted.
+ * But, more typically, We get here when this is an unallocated
+ * chunk and his means that either the block is empty or
+ * this is the one being allocated from
+ */
+
+ if(foundChunksInBlock)
+ {
+ /* This is a chunk that was skipped due to failing the erased check */
+
+ } else if (c == 0) {
+ /* We're looking at the first chunk in the block so the block is unused */
+ state = YAFFS_BLOCK_STATE_EMPTY;
+ dev->nErasedBlocks++;
+ } else {
+ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+ state == YAFFS_BLOCK_STATE_ALLOCATING) {
+ if(dev->sequenceNumber == bi->sequenceNumber) {
+ /* this is the block being allocated from */
+
+ T(YAFFS_TRACE_SCAN,
+ (TSTR
+ (" Allocating from %d %d"
+ TENDSTR), blk, c));
+
+ state = YAFFS_BLOCK_STATE_ALLOCATING;
+ dev->allocationBlock = blk;
+ dev->allocationPage = c;
+ dev->allocationBlockFinder = blk;
+ }
+ else {
+ /* This is a partially written block that is not
+ * the current allocation block. This block must have
+ * had a write failure, so set up for retirement.
+ */
+
+ bi->needsRetiring = 1;
+ bi->gcPrioritise = 1;
+
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("Partially written block %d being set for retirement" TENDSTR),
+ blk));
+ }
+
+ }
+
+ }
+
+ dev->nFreeChunks++;
+
+ } else if (tags.chunkId > 0) {
+ /* chunkId > 0 so it is a data chunk... */
+ unsigned int endpos;
+ __u32 chunkBase =
+ (tags.chunkId - 1) * dev->nDataBytesPerChunk;
+
+ foundChunksInBlock = 1;
+
+
+ yaffs_SetChunkBit(dev, blk, c);
+ bi->pagesInUse++;
+
+ in = yaffs_FindOrCreateObjectByNumber(dev,
+ tags.
+ objectId,
+ YAFFS_OBJECT_TYPE_FILE);
+ if (in->variantType == YAFFS_OBJECT_TYPE_FILE
+ && chunkBase <
+ in->variant.fileVariant.shrinkSize) {
+ /* This has not been invalidated by a resize */
+ yaffs_PutChunkIntoFile(in, tags.chunkId,
+ chunk, -1);
+
+ /* File size is calculated by looking at the data chunks if we have not
+ * seen an object header yet. Stop this practice once we find an object header.
+ */
+ endpos =
+ (tags.chunkId -
+ 1) * dev->nDataBytesPerChunk +
+ tags.byteCount;
+
+ if (!in->valid && /* have not got an object header yet */
+ in->variant.fileVariant.
+ scannedFileSize < endpos) {
+ in->variant.fileVariant.
+ scannedFileSize = endpos;
+ in->variant.fileVariant.
+ fileSize =
+ in->variant.fileVariant.
+ scannedFileSize;
+ }
+
+ } else {
+ /* This chunk has been invalidated by a resize, so delete */
+ yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
+
+ }
+ } else {
+ /* chunkId == 0, so it is an ObjectHeader.
+ * Thus, we read in the object header and make the object
+ */
+ foundChunksInBlock = 1;
+
+ yaffs_SetChunkBit(dev, blk, c);
+ bi->pagesInUse++;
+
+ oh = NULL;
+ in = NULL;
+
+ if (tags.extraHeaderInfoAvailable) {
+ in = yaffs_FindOrCreateObjectByNumber
+ (dev, tags.objectId,
+ tags.extraObjectType);
+ }
+
+ if (!in ||
+#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
+ !in->valid ||
+#endif
+ tags.extraShadows ||
+ (!in->valid &&
+ (tags.objectId == YAFFS_OBJECTID_ROOT ||
+ tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
+ ) {
+
+ /* If we don't have valid info then we need to read the chunk
+ * TODO In future we can probably defer reading the chunk and
+ * living with invalid data until needed.
+ */
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev,
+ chunk,
+ chunkData,
+ NULL);
+
+ oh = (yaffs_ObjectHeader *) chunkData;
+
+ if (!in)
+ in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
+
+ }
+
+ if (!in) {
+ /* TODO Hoosterman we have a problem! */
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("yaffs tragedy: Could not make object for object %d "
+ "at chunk %d during scan"
+ TENDSTR), tags.objectId, chunk));
+
+ }
+
+ if (in->valid) {
+ /* We have already filled this one.
+ * We have a duplicate that will be discarded, but
+ * we first have to suck out resize info if it is a file.
+ */
+
+ if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
+ ((oh &&
+ oh-> type == YAFFS_OBJECT_TYPE_FILE)||
+ (tags.extraHeaderInfoAvailable &&
+ tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))
+ ) {
+ __u32 thisSize =
+ (oh) ? oh->fileSize : tags.
+ extraFileLength;
+ __u32 parentObjectId =
+ (oh) ? oh->
+ parentObjectId : tags.
+ extraParentObjectId;
+ unsigned isShrink =
+ (oh) ? oh->isShrink : tags.
+ extraIsShrinkHeader;
+
+ /* If it is deleted (unlinked at start also means deleted)
+ * we treat the file size as being zeroed at this point.
+ */
+ if (parentObjectId ==
+ YAFFS_OBJECTID_DELETED
+ || parentObjectId ==
+ YAFFS_OBJECTID_UNLINKED) {
+ thisSize = 0;
+ isShrink = 1;
+ }
+
+ if (isShrink &&
+ in->variant.fileVariant.
+ shrinkSize > thisSize) {
+ in->variant.fileVariant.
+ shrinkSize =
+ thisSize;
+ }
+
+ if (isShrink) {
+ bi->hasShrinkHeader = 1;
+ }
+
+ }
+ /* Use existing - destroy this one. */
+ yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
+
+ }
+
+ if (!in->valid &&
+ (tags.objectId == YAFFS_OBJECTID_ROOT ||
+ tags.objectId ==
+ YAFFS_OBJECTID_LOSTNFOUND)) {
+ /* We only load some info, don't fiddle with directory structure */
+ in->valid = 1;
+
+ if(oh) {
+ in->variantType = oh->type;
+
+ in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+ in->win_atime[0] = oh->win_atime[0];
+ in->win_ctime[0] = oh->win_ctime[0];
+ in->win_mtime[0] = oh->win_mtime[0];
+ in->win_atime[1] = oh->win_atime[1];
+ in->win_ctime[1] = oh->win_ctime[1];
+ in->win_mtime[1] = oh->win_mtime[1];
+#else
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
+
+#endif
+ } else {
+ in->variantType = tags.extraObjectType;
+ in->lazyLoaded = 1;
+ }
+
+ in->chunkId = chunk;
+
+ } else if (!in->valid) {
+ /* we need to load this info */
+
+ in->valid = 1;
+ in->chunkId = chunk;
+
+ if(oh) {
+ in->variantType = oh->type;
+
+ in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+ in->win_atime[0] = oh->win_atime[0];
+ in->win_ctime[0] = oh->win_ctime[0];
+ in->win_mtime[0] = oh->win_mtime[0];
+ in->win_atime[1] = oh->win_atime[1];
+ in->win_ctime[1] = oh->win_ctime[1];
+ in->win_mtime[1] = oh->win_mtime[1];
+#else
+ in->yst_uid = oh->yst_uid;
+ in->yst_gid = oh->yst_gid;
+ in->yst_atime = oh->yst_atime;
+ in->yst_mtime = oh->yst_mtime;
+ in->yst_ctime = oh->yst_ctime;
+ in->yst_rdev = oh->yst_rdev;
+#endif
+
+ if (oh->shadowsObject > 0)
+ yaffs_HandleShadowedObject(dev,
+ oh->
+ shadowsObject,
+ 1);
+
+
+ yaffs_SetObjectName(in, oh->name);
+ parent =
+ yaffs_FindOrCreateObjectByNumber
+ (dev, oh->parentObjectId,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+
+ fileSize = oh->fileSize;
+ isShrink = oh->isShrink;
+ equivalentObjectId = oh->equivalentObjectId;
+
+ }
+ else {
+ in->variantType = tags.extraObjectType;
+ parent =
+ yaffs_FindOrCreateObjectByNumber
+ (dev, tags.extraParentObjectId,
+ YAFFS_OBJECT_TYPE_DIRECTORY);
+ fileSize = tags.extraFileLength;
+ isShrink = tags.extraIsShrinkHeader;
+ equivalentObjectId = tags.extraEquivalentObjectId;
+ in->lazyLoaded = 1;
+
+ }
+ in->dirty = 0;
+
+ /* directory stuff...
+ * hook up to parent
+ */
+
+ if (parent->variantType ==
+ YAFFS_OBJECT_TYPE_UNKNOWN) {
+ /* Set up as a directory */
+ parent->variantType =
+ YAFFS_OBJECT_TYPE_DIRECTORY;
+ INIT_LIST_HEAD(&parent->variant.
+ directoryVariant.
+ children);
+ } else if (parent->variantType !=
+ YAFFS_OBJECT_TYPE_DIRECTORY)
+ {
+ /* Hoosterman, another problem....
+ * We're trying to use a non-directory as a directory
+ */
+
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("yaffs tragedy: attempting to use non-directory as"
+ " a directory in scan. Put in lost+found."
+ TENDSTR)));
+ parent = dev->lostNFoundDir;
+ }
+
+ yaffs_AddObjectToDirectory(parent, in);
+
+ itsUnlinked = (parent == dev->deletedDir) ||
+ (parent == dev->unlinkedDir);
+
+ if (isShrink) {
+ /* Mark the block as having a shrinkHeader */
+ bi->hasShrinkHeader = 1;
+ }
+
+ /* Note re hardlinks.
+ * Since we might scan a hardlink before its equivalent object is scanned
+ * we put them all in a list.
+ * After scanning is complete, we should have all the objects, so we run
+ * through this list and fix up all the chains.
+ */
+
+ switch (in->variantType) {
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ /* Todo got a problem */
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+
+ if (in->variant.fileVariant.
+ scannedFileSize < fileSize) {
+ /* This covers the case where the file size is greater
+ * than where the data is
+ * This will happen if the file is resized to be larger
+ * than its current data extents.
+ */
+ in->variant.fileVariant.fileSize = fileSize;
+ in->variant.fileVariant.scannedFileSize =
+ in->variant.fileVariant.fileSize;
+ }
+
+ if (isShrink &&
+ in->variant.fileVariant.shrinkSize > fileSize) {
+ in->variant.fileVariant.shrinkSize = fileSize;
+ }
+
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ if(!itsUnlinked) {
+ in->variant.hardLinkVariant.equivalentObjectId =
+ equivalentObjectId;
+ in->hardLinks.next =
+ (struct list_head *) hardList;
+ hardList = in;
+ }
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ /* Do nothing */
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ if(oh)
+ in->variant.symLinkVariant.alias =
+ yaffs_CloneString(oh->
+ alias);
+ break;
+ }
+
+ }
+ }
+ }
+
+ if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+ /* If we got this far while scanning, then the block is fully allocated. */
+ state = YAFFS_BLOCK_STATE_FULL;
+ }
+
+ bi->blockState = state;
+
+ /* Now let's see if it was dirty */
+ if (bi->pagesInUse == 0 &&
+ !bi->hasShrinkHeader &&
+ bi->blockState == YAFFS_BLOCK_STATE_FULL) {
+ yaffs_BlockBecameDirty(dev, blk);
+ }
+
+ }
+
+ if (altBlockIndex)
+ YFREE_ALT(blockIndex);
+ else
+ YFREE(blockIndex);
+
+ /* Ok, we've done all the scanning.
+ * Fix up the hard link chains.
+ * We should now have scanned all the objects, now it's time to add these
+ * hardlinks.
+ */
+ yaffs_HardlinkFixup(dev,hardList);
+
+
+ /*
+ * Sort out state of unlinked and deleted objects.
+ */
+ {
+ struct list_head *i;
+ struct list_head *n;
+
+ yaffs_Object *l;
+
+ /* Soft delete all the unlinked files */
+ list_for_each_safe(i, n,
+ &dev->unlinkedDir->variant.directoryVariant.
+ children) {
+ if (i) {
+ l = list_entry(i, yaffs_Object, siblings);
+ yaffs_DestroyObject(l);
+ }
+ }
+
+ /* Soft delete all the deletedDir files */
+ list_for_each_safe(i, n,
+ &dev->deletedDir->variant.directoryVariant.
+ children) {
+ if (i) {
+ l = list_entry(i, yaffs_Object, siblings);
+ yaffs_DestroyObject(l);
+
+ }
+ }
+ }
+
+ yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
+
+ T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
+
+ return YAFFS_OK;
+}
+
+/*------------------------------ Directory Functions ----------------------------- */
+
+static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj)
+{
+ yaffs_Device *dev = obj->myDev;
+
+ if(dev && dev->removeObjectCallback)
+ dev->removeObjectCallback(obj);
+
+ list_del_init(&obj->siblings);
+ obj->parent = NULL;
+}
+
+
+static void yaffs_AddObjectToDirectory(yaffs_Object * directory,
+ yaffs_Object * obj)
+{
+
+ if (!directory) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("tragedy: Trying to add an object to a null pointer directory"
+ TENDSTR)));
+ YBUG();
+ }
+ if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("tragedy: Trying to add an object to a non-directory"
+ TENDSTR)));
+ YBUG();
+ }
+
+ if (obj->siblings.prev == NULL) {
+ /* Not initialised */
+ INIT_LIST_HEAD(&obj->siblings);
+
+ } else if (!list_empty(&obj->siblings)) {
+ /* If it is holed up somewhere else, un hook it */
+ yaffs_RemoveObjectFromDirectory(obj);
+ }
+ /* Now add it */
+ list_add(&obj->siblings, &directory->variant.directoryVariant.children);
+ obj->parent = directory;
+
+ if (directory == obj->myDev->unlinkedDir
+ || directory == obj->myDev->deletedDir) {
+ obj->unlinked = 1;
+ obj->myDev->nUnlinkedFiles++;
+ obj->renameAllowed = 0;
+ }
+}
+
+yaffs_Object *yaffs_FindObjectByName(yaffs_Object * directory,
+ const YCHAR * name)
+{
+ int sum;
+
+ struct list_head *i;
+ YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
+
+ yaffs_Object *l;
+
+ if (!name) {
+ return NULL;
+ }
+
+ if (!directory) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("tragedy: yaffs_FindObjectByName: null pointer directory"
+ TENDSTR)));
+ YBUG();
+ }
+ if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
+ YBUG();
+ }
+
+ sum = yaffs_CalcNameSum(name);
+
+ list_for_each(i, &directory->variant.directoryVariant.children) {
+ if (i) {
+ l = list_entry(i, yaffs_Object, siblings);
+
+ yaffs_CheckObjectDetailsLoaded(l);
+
+ /* Special case for lost-n-found */
+ if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
+ if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) {
+ return l;
+ }
+ } else if (yaffs_SumCompare(l->sum, sum) || l->chunkId <= 0)
+ {
+ /* LostnFound cunk called Objxxx
+ * Do a real check
+ */
+ yaffs_GetObjectName(l, buffer,
+ YAFFS_MAX_NAME_LENGTH);
+ if (yaffs_strcmp(name, buffer) == 0) {
+ return l;
+ }
+
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+#if 0
+int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir,
+ int (*fn) (yaffs_Object *))
+{
+ struct list_head *i;
+ yaffs_Object *l;
+
+ if (!theDir) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("tragedy: yaffs_FindObjectByName: null pointer directory"
+ TENDSTR)));
+ YBUG();
+ }
+ if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
+ YBUG();
+ }
+
+ list_for_each(i, &theDir->variant.directoryVariant.children) {
+ if (i) {
+ l = list_entry(i, yaffs_Object, siblings);
+ if (l && !fn(l)) {
+ return YAFFS_FAIL;
+ }
+ }
+ }
+
+ return YAFFS_OK;
+
+}
+#endif
+
+/* GetEquivalentObject dereferences any hard links to get to the
+ * actual object.
+ */
+
+yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj)
+{
+ if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
+ /* We want the object id of the equivalent object, not this one */
+ obj = obj->variant.hardLinkVariant.equivalentObject;
+ }
+ return obj;
+
+}
+
+int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize)
+{
+ memset(name, 0, buffSize * sizeof(YCHAR));
+
+ yaffs_CheckObjectDetailsLoaded(obj);
+
+ if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
+ yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
+ } else if (obj->chunkId <= 0) {
+ YCHAR locName[20];
+ /* make up a name */
+ yaffs_sprintf(locName, _Y("%s%d"), YAFFS_LOSTNFOUND_PREFIX,
+ obj->objectId);
+ yaffs_strncpy(name, locName, buffSize - 1);
+
+ }
+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+ else if (obj->shortName[0]) {
+ yaffs_strcpy(name, obj->shortName);
+ }
+#endif
+ else {
+ int result;
+ __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
+
+ yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer;
+
+ memset(buffer, 0, obj->myDev->nDataBytesPerChunk);
+
+ if (obj->chunkId >= 0) {
+ result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev,
+ obj->chunkId, buffer,
+ NULL);
+ }
+ yaffs_strncpy(name, oh->name, buffSize - 1);
+
+ yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
+ }
+
+ return yaffs_strlen(name);
+}
+
+int yaffs_GetObjectFileLength(yaffs_Object * obj)
+{
+
+ /* Dereference any hard linking */
+ obj = yaffs_GetEquivalentObject(obj);
+
+ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
+ return obj->variant.fileVariant.fileSize;
+ }
+ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
+ return yaffs_strlen(obj->variant.symLinkVariant.alias);
+ } else {
+ /* Only a directory should drop through to here */
+ return obj->myDev->nDataBytesPerChunk;
+ }
+}
+
+int yaffs_GetObjectLinkCount(yaffs_Object * obj)
+{
+ int count = 0;
+ struct list_head *i;
+
+ if (!obj->unlinked) {
+ count++; /* the object itself */
+ }
+ list_for_each(i, &obj->hardLinks) {
+ count++; /* add the hard links; */
+ }
+ return count;
+
+}
+
+int yaffs_GetObjectInode(yaffs_Object * obj)
+{
+ obj = yaffs_GetEquivalentObject(obj);
+
+ return obj->objectId;
+}
+
+unsigned yaffs_GetObjectType(yaffs_Object * obj)
+{
+ obj = yaffs_GetEquivalentObject(obj);
+
+ switch (obj->variantType) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ return DT_REG;
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ return DT_DIR;
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ return DT_LNK;
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ return DT_REG;
+ break;
+ case YAFFS_OBJECT_TYPE_SPECIAL:
+ if (S_ISFIFO(obj->yst_mode))
+ return DT_FIFO;
+ if (S_ISCHR(obj->yst_mode))
+ return DT_CHR;
+ if (S_ISBLK(obj->yst_mode))
+ return DT_BLK;
+ if (S_ISSOCK(obj->yst_mode))
+ return DT_SOCK;
+ default:
+ return DT_REG;
+ break;
+ }
+}
+
+YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj)
+{
+ obj = yaffs_GetEquivalentObject(obj);
+ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
+ return yaffs_CloneString(obj->variant.symLinkVariant.alias);
+ } else {
+ return yaffs_CloneString(_Y(""));
+ }
+}
+
+#ifndef CONFIG_YAFFS_WINCE
+
+int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr)
+{
+ unsigned int valid = attr->ia_valid;
+
+ if (valid & ATTR_MODE)
+ obj->yst_mode = attr->ia_mode;
+ if (valid & ATTR_UID)
+ obj->yst_uid = attr->ia_uid;
+ if (valid & ATTR_GID)
+ obj->yst_gid = attr->ia_gid;
+
+ if (valid & ATTR_ATIME)
+ obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
+ if (valid & ATTR_CTIME)
+ obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
+ if (valid & ATTR_MTIME)
+ obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
+
+ if (valid & ATTR_SIZE)
+ yaffs_ResizeFile(obj, attr->ia_size);
+
+ yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
+
+ return YAFFS_OK;
+
+}
+int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr)
+{
+ unsigned int valid = 0;
+
+ attr->ia_mode = obj->yst_mode;
+ valid |= ATTR_MODE;
+ attr->ia_uid = obj->yst_uid;
+ valid |= ATTR_UID;
+ attr->ia_gid = obj->yst_gid;
+ valid |= ATTR_GID;
+
+ Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
+ valid |= ATTR_ATIME;
+ Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
+ valid |= ATTR_CTIME;
+ Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
+ valid |= ATTR_MTIME;
+
+ attr->ia_size = yaffs_GetFileSize(obj);
+ valid |= ATTR_SIZE;
+
+ attr->ia_valid = valid;
+
+ return YAFFS_OK;
+
+}
+
+#endif
+
+#if 0
+int yaffs_DumpObject(yaffs_Object * obj)
+{
+ YCHAR name[257];
+
+ yaffs_GetObjectName(obj, name, 256);
+
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d"
+ " chunk %d type %d size %d\n"
+ TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name,
+ obj->dirty, obj->valid, obj->serial, obj->sum, obj->chunkId,
+ yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
+
+ return YAFFS_OK;
+}
+#endif
+
+/*---------------------------- Initialisation code -------------------------------------- */
+
+static int yaffs_CheckDevFunctions(const yaffs_Device * dev)
+{
+
+ /* Common functions, gotta have */
+ if (!dev->eraseBlockInNAND || !dev->initialiseNAND)
+ return 0;
+
+#ifdef CONFIG_YAFFS_YAFFS2
+
+ /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
+ if (dev->writeChunkWithTagsToNAND &&
+ dev->readChunkWithTagsFromNAND &&
+ !dev->writeChunkToNAND &&
+ !dev->readChunkFromNAND &&
+ dev->markNANDBlockBad && dev->queryNANDBlock)
+ return 1;
+#endif
+
+ /* Can use the "spare" style interface for yaffs1 */
+ if (!dev->isYaffs2 &&
+ !dev->writeChunkWithTagsToNAND &&
+ !dev->readChunkWithTagsFromNAND &&
+ dev->writeChunkToNAND &&
+ dev->readChunkFromNAND &&
+ !dev->markNANDBlockBad && !dev->queryNANDBlock)
+ return 1;
+
+ return 0; /* bad */
+}
+
+
+static void yaffs_CreateInitialDirectories(yaffs_Device *dev)
+{
+ /* Initialise the unlinked, deleted, root and lost and found directories */
+
+ dev->lostNFoundDir = dev->rootDir = NULL;
+ dev->unlinkedDir = dev->deletedDir = NULL;
+
+ dev->unlinkedDir =
+ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
+ dev->deletedDir =
+ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
+
+ dev->rootDir =
+ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT,
+ YAFFS_ROOT_MODE | S_IFDIR);
+ dev->lostNFoundDir =
+ yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND,
+ YAFFS_LOSTNFOUND_MODE | S_IFDIR);
+ yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir);
+}
+
+int yaffs_GutsInitialise(yaffs_Device * dev)
+{
+ unsigned x;
+ int bits;
+
+ T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
+
+ /* Check stuff that must be set */
+
+ if (!dev) {
+ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Need a device" TENDSTR)));
+ return YAFFS_FAIL;
+ }
+
+ dev->internalStartBlock = dev->startBlock;
+ dev->internalEndBlock = dev->endBlock;
+ dev->blockOffset = 0;
+ dev->chunkOffset = 0;
+ dev->nFreeChunks = 0;
+
+ if (dev->startBlock == 0) {
+ dev->internalStartBlock = dev->startBlock + 1;
+ dev->internalEndBlock = dev->endBlock + 1;
+ dev->blockOffset = 1;
+ dev->chunkOffset = dev->nChunksPerBlock;
+ }
+
+ /* Check geometry parameters. */
+
+ if ((dev->isYaffs2 && dev->nDataBytesPerChunk < 1024) ||
+ (!dev->isYaffs2 && dev->nDataBytesPerChunk != 512) ||
+ dev->nChunksPerBlock < 2 ||
+ dev->nReservedBlocks < 2 ||
+ dev->internalStartBlock <= 0 ||
+ dev->internalEndBlock <= 0 ||
+ dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2) // otherwise it is too small
+ ) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s "
+ TENDSTR), dev->nDataBytesPerChunk, dev->isYaffs2 ? "2" : ""));
+ return YAFFS_FAIL;
+ }
+
+ if (yaffs_InitialiseNAND(dev) != YAFFS_OK) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
+ return YAFFS_FAIL;
+ }
+
+ /* Got the right mix of functions? */
+ if (!yaffs_CheckDevFunctions(dev)) {
+ /* Function missing */
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("yaffs: device function(s) missing or wrong\n" TENDSTR)));
+
+ return YAFFS_FAIL;
+ }
+
+ /* This is really a compilation check. */
+ if (!yaffs_CheckStructures()) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
+ return YAFFS_FAIL;
+ }
+
+ if (dev->isMounted) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: device already mounted\n" TENDSTR)));
+ return YAFFS_FAIL;
+ }
+
+ /* Finished with most checks. One or two more checks happen later on too. */
+
+ dev->isMounted = 1;
+
+
+
+ /* OK now calculate a few things for the device */
+
+ /*
+ * Calculate all the chunk size manipulation numbers:
+ */
+ /* Start off assuming it is a power of 2 */
+ dev->chunkShift = ShiftDiv(dev->nDataBytesPerChunk);
+ dev->chunkMask = (1<<dev->chunkShift) - 1;
+
+ if(dev->nDataBytesPerChunk == (dev->chunkMask + 1)){
+ /* Yes it is a power of 2, disable crumbs */
+ dev->crumbMask = 0;
+ dev->crumbShift = 0;
+ dev->crumbsPerChunk = 0;
+ } else {
+ /* Not a power of 2, use crumbs instead */
+ dev->crumbShift = ShiftDiv(sizeof(yaffs_PackedTags2TagsPart));
+ dev->crumbMask = (1<<dev->crumbShift)-1;
+ dev->crumbsPerChunk = dev->nDataBytesPerChunk/(1 << dev->crumbShift);
+ dev->chunkShift = 0;
+ dev->chunkMask = 0;
+ }
+
+
+ /*
+ * Calculate chunkGroupBits.
+ * We need to find the next power of 2 > than internalEndBlock
+ */
+
+ x = dev->nChunksPerBlock * (dev->internalEndBlock + 1);
+
+ bits = ShiftsGE(x);
+
+ /* Set up tnode width if wide tnodes are enabled. */
+ if(!dev->wideTnodesDisabled){
+ /* bits must be even so that we end up with 32-bit words */
+ if(bits & 1)
+ bits++;
+ if(bits < 16)
+ dev->tnodeWidth = 16;
+ else
+ dev->tnodeWidth = bits;
+ }
+ else
+ dev->tnodeWidth = 16;
+
+ dev->tnodeMask = (1<<dev->tnodeWidth)-1;
+
+ /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
+ * so if the bitwidth of the
+ * chunk range we're using is greater than 16 we need
+ * to figure out chunk shift and chunkGroupSize
+ */
+
+ if (bits <= dev->tnodeWidth)
+ dev->chunkGroupBits = 0;
+ else
+ dev->chunkGroupBits = bits - dev->tnodeWidth;
+
+
+ dev->chunkGroupSize = 1 << dev->chunkGroupBits;
+
+ if (dev->nChunksPerBlock < dev->chunkGroupSize) {
+ /* We have a problem because the soft delete won't work if
+ * the chunk group size > chunks per block.
+ * This can be remedied by using larger "virtual blocks".
+ */
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: chunk group too large\n" TENDSTR)));
+
+ return YAFFS_FAIL;
+ }
+
+ /* OK, we've finished verifying the device, lets continue with initialisation */
+
+ /* More device initialisation */
+ dev->garbageCollections = 0;
+ dev->passiveGarbageCollections = 0;
+ dev->currentDirtyChecker = 0;
+ dev->bufferedBlock = -1;
+ dev->doingBufferedBlockRewrite = 0;
+ dev->nDeletedFiles = 0;
+ dev->nBackgroundDeletions = 0;
+ dev->nUnlinkedFiles = 0;
+ dev->eccFixed = 0;
+ dev->eccUnfixed = 0;
+ dev->tagsEccFixed = 0;
+ dev->tagsEccUnfixed = 0;
+ dev->nErasureFailures = 0;
+ dev->nErasedBlocks = 0;
+ dev->isDoingGC = 0;
+ dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */
+
+ /* Initialise temporary buffers and caches. */
+ {
+ int i;
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+ dev->tempBuffer[i].line = 0; /* not in use */
+ dev->tempBuffer[i].buffer =
+ YMALLOC_DMA(dev->nDataBytesPerChunk);
+ }
+ }
+
+ if (dev->nShortOpCaches > 0) {
+ int i;
+
+ if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) {
+ dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
+ }
+
+ dev->srCache =
+ YMALLOC(dev->nShortOpCaches * sizeof(yaffs_ChunkCache));
+
+ for (i = 0; i < dev->nShortOpCaches; i++) {
+ dev->srCache[i].object = NULL;
+ dev->srCache[i].lastUse = 0;
+ dev->srCache[i].dirty = 0;
+ dev->srCache[i].data = YMALLOC_DMA(dev->nDataBytesPerChunk);
+ }
+ dev->srLastUse = 0;
+ }
+
+ dev->cacheHits = 0;
+
+ dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
+
+ if (dev->isYaffs2) {
+ dev->useHeaderFileSize = 1;
+ }
+
+ yaffs_InitialiseBlocks(dev);
+ yaffs_InitialiseTnodes(dev);
+ yaffs_InitialiseObjects(dev);
+
+ yaffs_CreateInitialDirectories(dev);
+
+
+ /* Now scan the flash. */
+ if (dev->isYaffs2) {
+ if(yaffs_CheckpointRestore(dev)) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: restored from checkpoint" TENDSTR)));
+ } else {
+
+ /* Clean up the mess caused by an aborted checkpoint load
+ * and scan backwards.
+ */
+ yaffs_DeinitialiseBlocks(dev);
+ yaffs_DeinitialiseTnodes(dev);
+ yaffs_DeinitialiseObjects(dev);
+ yaffs_InitialiseBlocks(dev);
+ yaffs_InitialiseTnodes(dev);
+ yaffs_InitialiseObjects(dev);
+ yaffs_CreateInitialDirectories(dev);
+
+ yaffs_ScanBackwards(dev);
+ }
+ }else
+ yaffs_Scan(dev);
+
+ /* Zero out stats */
+ dev->nPageReads = 0;
+ dev->nPageWrites = 0;
+ dev->nBlockErasures = 0;
+ dev->nGCCopies = 0;
+ dev->nRetriedWrites = 0;
+
+ dev->nRetiredBlocks = 0;
+
+ yaffs_VerifyFreeChunks(dev);
+ T(YAFFS_TRACE_TRACING,
+ (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
+ return YAFFS_OK;
+
+}
+
+void yaffs_Deinitialise(yaffs_Device * dev)
+{
+ if (dev->isMounted) {
+ int i;
+
+ yaffs_DeinitialiseBlocks(dev);
+ yaffs_DeinitialiseTnodes(dev);
+ yaffs_DeinitialiseObjects(dev);
+ if (dev->nShortOpCaches > 0) {
+
+ for (i = 0; i < dev->nShortOpCaches; i++) {
+ YFREE(dev->srCache[i].data);
+ }
+
+ YFREE(dev->srCache);
+ }
+
+ YFREE(dev->gcCleanupList);
+
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+ YFREE(dev->tempBuffer[i].buffer);
+ }
+
+ dev->isMounted = 0;
+ }
+
+}
+
+static int yaffs_CountFreeChunks(yaffs_Device * dev)
+{
+ int nFree;
+ int b;
+
+ yaffs_BlockInfo *blk;
+
+ for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
+ b++) {
+ blk = yaffs_GetBlockInfo(dev, b);
+
+ switch (blk->blockState) {
+ case YAFFS_BLOCK_STATE_EMPTY:
+ case YAFFS_BLOCK_STATE_ALLOCATING:
+ case YAFFS_BLOCK_STATE_COLLECTING:
+ case YAFFS_BLOCK_STATE_FULL:
+ nFree +=
+ (dev->nChunksPerBlock - blk->pagesInUse +
+ blk->softDeletions);
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ return nFree;
+}
+
+int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev)
+{
+ /* This is what we report to the outside world */
+
+ int nFree;
+ int nDirtyCacheChunks;
+ int blocksForCheckpoint;
+
+#if 1
+ nFree = dev->nFreeChunks;
+#else
+ nFree = yaffs_CountFreeChunks(dev);
+#endif
+
+ nFree += dev->nDeletedFiles;
+
+ /* Now count the number of dirty chunks in the cache and subtract those */
+
+ {
+ int i;
+ for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
+ if (dev->srCache[i].dirty)
+ nDirtyCacheChunks++;
+ }
+ }
+
+ nFree -= nDirtyCacheChunks;
+
+ nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
+
+ /* Now we figure out how much to reserve for the checkpoint and report that... */
+ blocksForCheckpoint = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint;
+ if(blocksForCheckpoint < 0)
+ blocksForCheckpoint = 0;
+
+ nFree -= (blocksForCheckpoint * dev->nChunksPerBlock);
+
+ if (nFree < 0)
+ nFree = 0;
+
+ return nFree;
+
+}
+
+static int yaffs_freeVerificationFailures;
+
+static void yaffs_VerifyFreeChunks(yaffs_Device * dev)
+{
+ int counted = yaffs_CountFreeChunks(dev);
+
+ int difference = dev->nFreeChunks - counted;
+
+ if (difference) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
+ dev->nFreeChunks, counted, difference));
+ yaffs_freeVerificationFailures++;
+ }
+}
+
+/*---------------------------------------- YAFFS test code ----------------------*/
+
+#define yaffs_CheckStruct(structure,syze, name) \
+ if(sizeof(structure) != syze) \
+ { \
+ T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),\
+ name,syze,sizeof(structure))); \
+ return YAFFS_FAIL; \
+ }
+
+static int yaffs_CheckStructures(void)
+{
+/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags") */
+/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion") */
+/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare") */
+#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
+ yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode")
+#endif
+ yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader")
+
+ return YAFFS_OK;
+}
diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h
new file mode 100644
index 00000000000..9ef651d0f44
--- /dev/null
+++ b/fs/yaffs2/yaffs_guts.h
@@ -0,0 +1,889 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_GUTS_H__
+#define __YAFFS_GUTS_H__
+
+#include "devextras.h"
+#include "yportenv.h"
+
+#define YAFFS_OK 1
+#define YAFFS_FAIL 0
+
+/* Give us a Y=0x59,
+ * Give us an A=0x41,
+ * Give us an FF=0xFF
+ * Give us an S=0x53
+ * And what have we got...
+ */
+#define YAFFS_MAGIC 0x5941FF53
+
+#define YAFFS_NTNODES_LEVEL0 16
+#define YAFFS_TNODES_LEVEL0_BITS 4
+#define YAFFS_TNODES_LEVEL0_MASK 0xf
+
+#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
+#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
+#define YAFFS_TNODES_INTERNAL_MASK 0x7
+#define YAFFS_TNODES_MAX_LEVEL 6
+
+#ifndef CONFIG_YAFFS_NO_YAFFS1
+#define YAFFS_BYTES_PER_SPARE 16
+#define YAFFS_BYTES_PER_CHUNK 512
+#define YAFFS_CHUNK_SIZE_SHIFT 9
+#define YAFFS_CHUNKS_PER_BLOCK 32
+#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
+#endif
+
+#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
+#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
+
+#define YAFFS_MAX_CHUNK_ID 0x000FFFFF
+
+#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
+
+#define YAFFS_ALLOCATION_NOBJECTS 100
+#define YAFFS_ALLOCATION_NTNODES 100
+#define YAFFS_ALLOCATION_NLINKS 100
+
+#define YAFFS_NOBJECT_BUCKETS 256
+
+
+#define YAFFS_OBJECT_SPACE 0x40000
+
+#define YAFFS_NCHECKPOINT_OBJECTS 5000
+
+#define YAFFS_CHECKPOINT_VERSION 2
+
+#ifdef CONFIG_YAFFS_UNICODE
+#define YAFFS_MAX_NAME_LENGTH 127
+#define YAFFS_MAX_ALIAS_LENGTH 79
+#else
+#define YAFFS_MAX_NAME_LENGTH 255
+#define YAFFS_MAX_ALIAS_LENGTH 159
+#endif
+
+#define YAFFS_SHORT_NAME_LENGTH 15
+
+/* Some special object ids for pseudo objects */
+#define YAFFS_OBJECTID_ROOT 1
+#define YAFFS_OBJECTID_LOSTNFOUND 2
+#define YAFFS_OBJECTID_UNLINKED 3
+#define YAFFS_OBJECTID_DELETED 4
+
+/* Sseudo object ids for checkpointing */
+#define YAFFS_OBJECTID_SB_HEADER 0x10
+#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
+#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
+
+/* */
+
+#define YAFFS_MAX_SHORT_OP_CACHES 20
+
+#define YAFFS_N_TEMP_BUFFERS 4
+
+/* Sequence numbers are used in YAFFS2 to determine block allocation order.
+ * The range is limited slightly to help distinguish bad numbers from good.
+ * This also allows us to perhaps in the future use special numbers for
+ * special purposes.
+ * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,
+ * and is a larger number than the lifetime of a 2GB device.
+ */
+#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
+#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00
+
+/* ChunkCache is used for short read/write operations.*/
+typedef struct {
+ struct yaffs_ObjectStruct *object;
+ int chunkId;
+ int lastUse;
+ int dirty;
+ int nBytes; /* Only valid if the cache is dirty */
+ int locked; /* Can't push out or flush while locked. */
+#ifdef CONFIG_YAFFS_YAFFS2
+ __u8 *data;
+#else
+ __u8 data[YAFFS_BYTES_PER_CHUNK];
+#endif
+} yaffs_ChunkCache;
+
+
+
+/* Tags structures in RAM
+ * NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
+ * the structure size will get blown out.
+ */
+
+#ifndef CONFIG_YAFFS_NO_YAFFS1
+typedef struct {
+ unsigned chunkId:20;
+ unsigned serialNumber:2;
+ unsigned byteCount:10;
+ unsigned objectId:18;
+ unsigned ecc:12;
+ unsigned unusedStuff:2;
+
+} yaffs_Tags;
+
+typedef union {
+ yaffs_Tags asTags;
+ __u8 asBytes[8];
+} yaffs_TagsUnion;
+
+#endif
+
+/* Stuff used for extended tags in YAFFS2 */
+
+typedef enum {
+ YAFFS_ECC_RESULT_UNKNOWN,
+ YAFFS_ECC_RESULT_NO_ERROR,
+ YAFFS_ECC_RESULT_FIXED,
+ YAFFS_ECC_RESULT_UNFIXED
+} yaffs_ECCResult;
+
+typedef enum {
+ YAFFS_OBJECT_TYPE_UNKNOWN,
+ YAFFS_OBJECT_TYPE_FILE,
+ YAFFS_OBJECT_TYPE_SYMLINK,
+ YAFFS_OBJECT_TYPE_DIRECTORY,
+ YAFFS_OBJECT_TYPE_HARDLINK,
+ YAFFS_OBJECT_TYPE_SPECIAL
+} yaffs_ObjectType;
+
+typedef struct {
+
+ unsigned validMarker0;
+ unsigned chunkUsed; /* Status of the chunk: used or unused */
+ unsigned objectId; /* If 0 then this is not part of an object (unused) */
+ unsigned chunkId; /* If 0 then this is a header, else a data chunk */
+ unsigned byteCount; /* Only valid for data chunks */
+
+ /* The following stuff only has meaning when we read */
+ yaffs_ECCResult eccResult;
+ unsigned blockBad;
+
+ /* YAFFS 1 stuff */
+ unsigned chunkDeleted; /* The chunk is marked deleted */
+ unsigned serialNumber; /* Yaffs1 2-bit serial number */
+
+ /* YAFFS2 stuff */
+ unsigned sequenceNumber; /* The sequence number of this block */
+
+ /* Extra info if this is an object header (YAFFS2 only) */
+
+ unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */
+ unsigned extraParentObjectId; /* The parent object */
+ unsigned extraIsShrinkHeader; /* Is it a shrink header? */
+ unsigned extraShadows; /* Does this shadow another object? */
+
+ yaffs_ObjectType extraObjectType; /* What object type? */
+
+ unsigned extraFileLength; /* Length if it is a file */
+ unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */
+
+ unsigned validMarker1;
+
+} yaffs_ExtendedTags;
+
+/* Spare structure for YAFFS1 */
+typedef struct {
+ __u8 tagByte0;
+ __u8 tagByte1;
+ __u8 tagByte2;
+ __u8 tagByte3;
+ __u8 pageStatus; /* set to 0 to delete the chunk */
+ __u8 blockStatus;
+ __u8 tagByte4;
+ __u8 tagByte5;
+ __u8 ecc1[3];
+ __u8 tagByte6;
+ __u8 tagByte7;
+ __u8 ecc2[3];
+} yaffs_Spare;
+
+/*Special structure for passing through to mtd */
+struct yaffs_NANDSpare {
+ yaffs_Spare spare;
+ int eccres1;
+ int eccres2;
+};
+
+/* Block data in RAM */
+
+typedef enum {
+ YAFFS_BLOCK_STATE_UNKNOWN = 0,
+
+ YAFFS_BLOCK_STATE_SCANNING,
+ YAFFS_BLOCK_STATE_NEEDS_SCANNING,
+ /* The block might have something on it (ie it is allocating or full, perhaps empty)
+ * but it needs to be scanned to determine its true state.
+ * This state is only valid during yaffs_Scan.
+ * NB We tolerate empty because the pre-scanner might be incapable of deciding
+ * However, if this state is returned on a YAFFS2 device, then we expect a sequence number
+ */
+
+ YAFFS_BLOCK_STATE_EMPTY,
+ /* This block is empty */
+
+ YAFFS_BLOCK_STATE_ALLOCATING,
+ /* This block is partially allocated.
+ * At least one page holds valid data.
+ * This is the one currently being used for page
+ * allocation. Should never be more than one of these
+ */
+
+ YAFFS_BLOCK_STATE_FULL,
+ /* All the pages in this block have been allocated.
+ */
+
+ YAFFS_BLOCK_STATE_DIRTY,
+ /* All pages have been allocated and deleted.
+ * Erase me, reuse me.
+ */
+
+ YAFFS_BLOCK_STATE_CHECKPOINT,
+ /* This block is assigned to holding checkpoint data.
+ */
+
+ YAFFS_BLOCK_STATE_COLLECTING,
+ /* This block is being garbage collected */
+
+ YAFFS_BLOCK_STATE_DEAD
+ /* This block has failed and is not in use */
+} yaffs_BlockState;
+
+typedef struct {
+
+ int softDeletions:10; /* number of soft deleted pages */
+ int pagesInUse:10; /* number of pages in use */
+ yaffs_BlockState blockState:4; /* One of the above block states */
+ __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
+ /* and retire the block. */
+ __u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */
+ __u32 gcPrioritise: 1; /* An ECC check or bank check has failed on this block.
+ It should be prioritised for GC */
+ __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
+
+#ifdef CONFIG_YAFFS_YAFFS2
+ __u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
+ __u32 sequenceNumber; /* block sequence number for yaffs2 */
+#endif
+
+} yaffs_BlockInfo;
+
+/* -------------------------- Object structure -------------------------------*/
+/* This is the object structure as stored on NAND */
+
+typedef struct {
+ yaffs_ObjectType type;
+
+ /* Apply to everything */
+ int parentObjectId;
+ __u16 sum__NoLongerUsed; /* checksum of name. No longer used */
+ YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
+
+ /* Thes following apply to directories, files, symlinks - not hard links */
+ __u32 yst_mode; /* protection */
+
+#ifdef CONFIG_YAFFS_WINCE
+ __u32 notForWinCE[5];
+#else
+ __u32 yst_uid;
+ __u32 yst_gid;
+ __u32 yst_atime;
+ __u32 yst_mtime;
+ __u32 yst_ctime;
+#endif
+
+ /* File size applies to files only */
+ int fileSize;
+
+ /* Equivalent object id applies to hard links only. */
+ int equivalentObjectId;
+
+ /* Alias is for symlinks only. */
+ YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
+
+ __u32 yst_rdev; /* device stuff for block and char devices (major/min) */
+
+#ifdef CONFIG_YAFFS_WINCE
+ __u32 win_ctime[2];
+ __u32 win_atime[2];
+ __u32 win_mtime[2];
+ __u32 roomToGrow[4];
+#else
+ __u32 roomToGrow[10];
+#endif
+
+ int shadowsObject; /* This object header shadows the specified object if > 0 */
+
+ /* isShrink applies to object headers written when we shrink the file (ie resize) */
+ __u32 isShrink;
+
+} yaffs_ObjectHeader;
+
+/*--------------------------- Tnode -------------------------- */
+
+union yaffs_Tnode_union {
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+ union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
+#else
+ union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
+#endif
+/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
+
+};
+
+typedef union yaffs_Tnode_union yaffs_Tnode;
+
+struct yaffs_TnodeList_struct {
+ struct yaffs_TnodeList_struct *next;
+ yaffs_Tnode *tnodes;
+};
+
+typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
+
+/*------------------------ Object -----------------------------*/
+/* An object can be one of:
+ * - a directory (no data, has children links
+ * - a regular file (data.... not prunes :->).
+ * - a symlink [symbolic link] (the alias).
+ * - a hard link
+ */
+
+typedef struct {
+ __u32 fileSize;
+ __u32 scannedFileSize;
+ __u32 shrinkSize;
+ int topLevel;
+ yaffs_Tnode *top;
+} yaffs_FileStructure;
+
+typedef struct {
+ struct list_head children; /* list of child links */
+} yaffs_DirectoryStructure;
+
+typedef struct {
+ YCHAR *alias;
+} yaffs_SymLinkStructure;
+
+typedef struct {
+ struct yaffs_ObjectStruct *equivalentObject;
+ __u32 equivalentObjectId;
+} yaffs_HardLinkStructure;
+
+typedef union {
+ yaffs_FileStructure fileVariant;
+ yaffs_DirectoryStructure directoryVariant;
+ yaffs_SymLinkStructure symLinkVariant;
+ yaffs_HardLinkStructure hardLinkVariant;
+} yaffs_ObjectVariant;
+
+struct yaffs_ObjectStruct {
+ __u8 deleted:1; /* This should only apply to unlinked files. */
+ __u8 softDeleted:1; /* it has also been soft deleted */
+ __u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/
+ __u8 fake:1; /* A fake object has no presence on NAND. */
+ __u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */
+ __u8 unlinkAllowed:1;
+ __u8 dirty:1; /* the object needs to be written to flash */
+ __u8 valid:1; /* When the file system is being loaded up, this
+ * object might be created before the data
+ * is available (ie. file data records appear before the header).
+ */
+ __u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */
+
+ __u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is
+ * still in the inode cache. Free of object is defered.
+ * until the inode is released.
+ */
+
+ __u8 serial; /* serial number of chunk in NAND. Cached here */
+ __u16 sum; /* sum of the name to speed searching */
+
+ struct yaffs_DeviceStruct *myDev; /* The device I'm on */
+
+ struct list_head hashLink; /* list of objects in this hash bucket */
+
+ struct list_head hardLinks; /* all the equivalent hard linked objects */
+
+ /* directory structure stuff */
+ /* also used for linking up the free list */
+ struct yaffs_ObjectStruct *parent;
+ struct list_head siblings;
+
+ /* Where's my object header in NAND? */
+ int chunkId;
+
+ int nDataChunks; /* Number of data chunks attached to the file. */
+
+ __u32 objectId; /* the object id value */
+
+ __u32 yst_mode;
+
+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+ YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
+#endif
+
+#ifndef __KERNEL__
+ __u32 inUse;
+#endif
+
+#ifdef CONFIG_YAFFS_WINCE
+ __u32 win_ctime[2];
+ __u32 win_mtime[2];
+ __u32 win_atime[2];
+#else
+ __u32 yst_uid;
+ __u32 yst_gid;
+ __u32 yst_atime;
+ __u32 yst_mtime;
+ __u32 yst_ctime;
+#endif
+
+ __u32 yst_rdev;
+
+#ifdef __KERNEL__
+ struct inode *myInode;
+
+#endif
+
+ yaffs_ObjectType variantType;
+
+ yaffs_ObjectVariant variant;
+
+};
+
+typedef struct yaffs_ObjectStruct yaffs_Object;
+
+struct yaffs_ObjectList_struct {
+ yaffs_Object *objects;
+ struct yaffs_ObjectList_struct *next;
+};
+
+typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
+
+typedef struct {
+ struct list_head list;
+ int count;
+} yaffs_ObjectBucket;
+
+
+/* yaffs_CheckpointObject holds the definition of an object as dumped
+ * by checkpointing.
+ */
+
+typedef struct {
+ int structType;
+ __u32 objectId;
+ __u32 parentId;
+ int chunkId;
+
+ yaffs_ObjectType variantType:3;
+ __u8 deleted:1;
+ __u8 softDeleted:1;
+ __u8 unlinked:1;
+ __u8 fake:1;
+ __u8 renameAllowed:1;
+ __u8 unlinkAllowed:1;
+ __u8 serial;
+
+ int nDataChunks;
+ __u32 fileSizeOrEquivalentObjectId;
+
+}yaffs_CheckpointObject;
+
+/*--------------------- Temporary buffers ----------------
+ *
+ * These are chunk-sized working buffers. Each device has a few
+ */
+
+typedef struct {
+ __u8 *buffer;
+ int line; /* track from whence this buffer was allocated */
+ int maxLine;
+} yaffs_TempBuffer;
+
+/*----------------- Device ---------------------------------*/
+
+struct yaffs_DeviceStruct {
+ struct list_head devList;
+ const char *name;
+
+ /* Entry parameters set up way early. Yaffs sets up the rest.*/
+ int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
+ int nChunksPerBlock; /* does not need to be a power of 2 */
+ int nBytesPerSpare; /* spare area size */
+ int startBlock; /* Start block we're allowed to use */
+ int endBlock; /* End block we're allowed to use */
+ int nReservedBlocks; /* We want this tuneable so that we can reduce */
+ /* reserved blocks on NOR and RAM. */
+
+ /* Stuff used by the partitioned checkpointing mechanism */
+ int checkpointStartBlock;
+ int checkpointEndBlock;
+
+ /* Stuff used by the shared space checkpointing mechanism */
+ /* If this value is zero, then this mechanism is disabled */
+
+ int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */
+
+
+
+
+ int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
+ * the number of short op caches (don't use too many)
+ */
+
+ int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
+
+ int useNANDECC; /* Flag to decide whether or not to use NANDECC */
+
+ void *genericDevice; /* Pointer to device context
+ * On an mtd this holds the mtd pointer.
+ */
+ void *superBlock;
+
+ /* NAND access functions (Must be set before calling YAFFS)*/
+
+ int (*writeChunkToNAND) (struct yaffs_DeviceStruct * dev,
+ int chunkInNAND, const __u8 * data,
+ const yaffs_Spare * spare);
+ int (*readChunkFromNAND) (struct yaffs_DeviceStruct * dev,
+ int chunkInNAND, __u8 * data,
+ yaffs_Spare * spare);
+ int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev,
+ int blockInNAND);
+ int (*initialiseNAND) (struct yaffs_DeviceStruct * dev);
+
+#ifdef CONFIG_YAFFS_YAFFS2
+ int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev,
+ int chunkInNAND, const __u8 * data,
+ const yaffs_ExtendedTags * tags);
+ int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev,
+ int chunkInNAND, __u8 * data,
+ yaffs_ExtendedTags * tags);
+ int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
+ int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,
+ yaffs_BlockState * state, int *sequenceNumber);
+#endif
+
+ int isYaffs2;
+
+ /* The removeObjectCallback function must be supplied by OS flavours that
+ * need it. The Linux kernel does not use this, but yaffs direct does use
+ * it to implement the faster readdir
+ */
+ void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
+
+ /* Callback to mark the superblock dirsty */
+ void (*markSuperBlockDirty)(void * superblock);
+
+ int wideTnodesDisabled; /* Set to disable wide tnodes */
+
+
+ /* End of stuff that must be set before initialisation. */
+
+ /* Runtime parameters. Set up by YAFFS. */
+
+ __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
+ __u16 chunkGroupSize; /* == 2^^chunkGroupBits */
+
+ /* Stuff to support wide tnodes */
+ __u32 tnodeWidth;
+ __u32 tnodeMask;
+
+ /* Stuff to support various file offses to chunk/offset translations */
+ /* "Crumbs" for nDataBytesPerChunk not being a power of 2 */
+ __u32 crumbMask;
+ __u32 crumbShift;
+ __u32 crumbsPerChunk;
+
+ /* Straight shifting for nDataBytesPerChunk being a power of 2 */
+ __u32 chunkShift;
+ __u32 chunkMask;
+
+
+#ifdef __KERNEL__
+
+ struct semaphore sem; /* Semaphore for waiting on erasure.*/
+ struct semaphore grossLock; /* Gross locking semaphore */
+ __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
+ * at compile time so we have to allocate it.
+ */
+ void (*putSuperFunc) (struct super_block * sb);
+#endif
+
+ int isMounted;
+
+ int isCheckpointed;
+
+
+ /* Stuff to support block offsetting to support start block zero */
+ int internalStartBlock;
+ int internalEndBlock;
+ int blockOffset;
+ int chunkOffset;
+
+
+ /* Runtime checkpointing stuff */
+ int checkpointPageSequence; /* running sequence number of checkpoint pages */
+ int checkpointByteCount;
+ int checkpointByteOffset;
+ __u8 *checkpointBuffer;
+ int checkpointOpenForWrite;
+ int blocksInCheckpoint;
+ int checkpointCurrentChunk;
+ int checkpointCurrentBlock;
+ int checkpointNextBlock;
+ int *checkpointBlockList;
+ int checkpointMaxBlocks;
+
+ /* Block Info */
+ yaffs_BlockInfo *blockInfo;
+ __u8 *chunkBits; /* bitmap of chunks in use */
+ unsigned blockInfoAlt:1; /* was allocated using alternative strategy */
+ unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */
+ int chunkBitmapStride; /* Number of bytes of chunkBits per block.
+ * Must be consistent with nChunksPerBlock.
+ */
+
+ int nErasedBlocks;
+ int allocationBlock; /* Current block being allocated off */
+ __u32 allocationPage;
+ int allocationBlockFinder; /* Used to search for next allocation block */
+
+ /* Runtime state */
+ int nTnodesCreated;
+ yaffs_Tnode *freeTnodes;
+ int nFreeTnodes;
+ yaffs_TnodeList *allocatedTnodeList;
+
+ int isDoingGC;
+
+ int nObjectsCreated;
+ yaffs_Object *freeObjects;
+ int nFreeObjects;
+
+ yaffs_ObjectList *allocatedObjectList;
+
+ yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
+
+ int nFreeChunks;
+
+ int currentDirtyChecker; /* Used to find current dirtiest block */
+
+ __u32 *gcCleanupList; /* objects to delete at the end of a GC. */
+
+ /* Statistcs */
+ int nPageWrites;
+ int nPageReads;
+ int nBlockErasures;
+ int nErasureFailures;
+ int nGCCopies;
+ int garbageCollections;
+ int passiveGarbageCollections;
+ int nRetriedWrites;
+ int nRetiredBlocks;
+ int eccFixed;
+ int eccUnfixed;
+ int tagsEccFixed;
+ int tagsEccUnfixed;
+ int nDeletions;
+ int nUnmarkedDeletions;
+
+ int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
+
+ /* Special directories */
+ yaffs_Object *rootDir;
+ yaffs_Object *lostNFoundDir;
+
+ /* Buffer areas for storing data to recover from write failures TODO
+ * __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
+ * yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
+ */
+
+ int bufferedBlock; /* Which block is buffered here? */
+ int doingBufferedBlockRewrite;
+
+ yaffs_ChunkCache *srCache;
+ int srLastUse;
+
+ int cacheHits;
+
+ /* Stuff for background deletion and unlinked files.*/
+ yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
+ yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
+ yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/
+ int nDeletedFiles; /* Count of files awaiting deletion;*/
+ int nUnlinkedFiles; /* Count of unlinked files. */
+ int nBackgroundDeletions; /* Count of background deletions. */
+
+
+ yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
+ int maxTemp;
+ int unmanagedTempAllocations;
+ int unmanagedTempDeallocations;
+
+ /* yaffs2 runtime stuff */
+ unsigned sequenceNumber; /* Sequence number of currently allocating block */
+ unsigned oldestDirtySequence;
+
+};
+
+typedef struct yaffs_DeviceStruct yaffs_Device;
+
+/* The static layout of bllock usage etc is stored in the super block header */
+typedef struct {
+ int StructType;
+ int version;
+ int checkpointStartBlock;
+ int checkpointEndBlock;
+ int startBlock;
+ int endBlock;
+ int rfu[100];
+} yaffs_SuperBlockHeader;
+
+/* The CheckpointDevice structure holds the device information that changes at runtime and
+ * must be preserved over unmount/mount cycles.
+ */
+typedef struct {
+ int structType;
+ int nErasedBlocks;
+ int allocationBlock; /* Current block being allocated off */
+ __u32 allocationPage;
+ int nFreeChunks;
+
+ int nDeletedFiles; /* Count of files awaiting deletion;*/
+ int nUnlinkedFiles; /* Count of unlinked files. */
+ int nBackgroundDeletions; /* Count of background deletions. */
+
+ /* yaffs2 runtime stuff */
+ unsigned sequenceNumber; /* Sequence number of currently allocating block */
+ unsigned oldestDirtySequence;
+
+} yaffs_CheckpointDevice;
+
+
+typedef struct {
+ int structType;
+ __u32 magic;
+ __u32 version;
+ __u32 head;
+} yaffs_CheckpointValidity;
+
+/* Function to manipulate block info */
+static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
+{
+ if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
+ blk));
+ YBUG();
+ }
+ return &dev->blockInfo[blk - dev->internalStartBlock];
+}
+
+/*----------------------- YAFFS Functions -----------------------*/
+
+int yaffs_GutsInitialise(yaffs_Device * dev);
+void yaffs_Deinitialise(yaffs_Device * dev);
+
+int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev);
+
+int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName,
+ yaffs_Object * newDir, const YCHAR * newName);
+
+int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name);
+int yaffs_DeleteFile(yaffs_Object * obj);
+
+int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize);
+int yaffs_GetObjectFileLength(yaffs_Object * obj);
+int yaffs_GetObjectInode(yaffs_Object * obj);
+unsigned yaffs_GetObjectType(yaffs_Object * obj);
+int yaffs_GetObjectLinkCount(yaffs_Object * obj);
+
+int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr);
+int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr);
+
+/* File operations */
+int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, loff_t offset,
+ int nBytes);
+int yaffs_WriteDataToFile(yaffs_Object * obj, const __u8 * buffer, loff_t offset,
+ int nBytes, int writeThrough);
+int yaffs_ResizeFile(yaffs_Object * obj, loff_t newSize);
+
+yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name,
+ __u32 mode, __u32 uid, __u32 gid);
+int yaffs_FlushFile(yaffs_Object * obj, int updateTime);
+
+/* Flushing and checkpointing */
+void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
+
+int yaffs_CheckpointSave(yaffs_Device *dev);
+int yaffs_CheckpointRestore(yaffs_Device *dev);
+
+/* Directory operations */
+yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name,
+ __u32 mode, __u32 uid, __u32 gid);
+yaffs_Object *yaffs_FindObjectByName(yaffs_Object * theDir, const YCHAR * name);
+int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir,
+ int (*fn) (yaffs_Object *));
+
+yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number);
+
+/* Link operations */
+yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name,
+ yaffs_Object * equivalentObject);
+
+yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj);
+
+/* Symlink operations */
+yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name,
+ __u32 mode, __u32 uid, __u32 gid,
+ const YCHAR * alias);
+YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj);
+
+/* Special inodes (fifos, sockets and devices) */
+yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name,
+ __u32 mode, __u32 uid, __u32 gid, __u32 rdev);
+
+/* Special directories */
+yaffs_Object *yaffs_Root(yaffs_Device * dev);
+yaffs_Object *yaffs_LostNFound(yaffs_Device * dev);
+
+#ifdef CONFIG_YAFFS_WINCE
+/* CONFIG_YAFFS_WINCE special stuff */
+void yfsd_WinFileTimeNow(__u32 target[2]);
+#endif
+
+#ifdef __KERNEL__
+
+void yaffs_HandleDeferedFree(yaffs_Object * obj);
+#endif
+
+/* Debug dump */
+int yaffs_DumpObject(yaffs_Object * obj);
+
+void yaffs_GutsTest(yaffs_Device * dev);
+
+/* A few useful functions */
+void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
+void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn);
+int yaffs_CheckFF(__u8 * buffer, int nBytes);
+void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
+
+#endif
diff --git a/fs/yaffs2/yaffs_mtdif.c b/fs/yaffs2/yaffs_mtdif.c
new file mode 100644
index 00000000000..9b50e109efc
--- /dev/null
+++ b/fs/yaffs2/yaffs_mtdif.c
@@ -0,0 +1,248 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+const char *yaffs_mtdif_c_version =
+ "$Id: yaffs_mtdif.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $";
+
+#include "yportenv.h"
+#include "yaffs_mtdif.h"
+#include "linux/mtd/mtd.h"
+#include "linux/types.h"
+#include "linux/time.h"
+#include "linux/mtd/nand.h"
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+static struct nand_oobinfo yaffs_oobinfo = {
+ .useecc = 1,
+ .eccbytes = 6,
+ .eccpos = {8, 9, 10, 13, 14, 15}
+};
+
+static struct nand_oobinfo yaffs_noeccinfo = {
+ .useecc = 0,
+};
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
+{
+ oob[0] = spare->tagByte0;
+ oob[1] = spare->tagByte1;
+ oob[2] = spare->tagByte2;
+ oob[3] = spare->tagByte3;
+ oob[4] = spare->tagByte4;
+ oob[5] = spare->tagByte5 & 0x3f;
+ oob[5] |= spare->blockStatus == 'Y' ? 0: 0x80;
+ oob[5] |= spare->pageStatus == 0 ? 0: 0x40;
+ oob[6] = spare->tagByte6;
+ oob[7] = spare->tagByte7;
+}
+
+static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
+{
+ struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
+
+ spare->tagByte0 = oob[0];
+ spare->tagByte1 = oob[1];
+ spare->tagByte2 = oob[2];
+ spare->tagByte3 = oob[3];
+ spare->tagByte4 = oob[4];
+ spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
+ spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
+ spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
+ spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
+ spare->tagByte6 = oob[6];
+ spare->tagByte7 = oob[7];
+ spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
+
+ nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
+#if 0
+ char i;
+ for (i=0;i<8;i++)
+ printk("oob %d :%x",i,oob[i]);
+#endif
+}
+#endif
+
+int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
+ const __u8 * data, const yaffs_Spare * spare)
+{
+ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ struct mtd_oob_ops ops;
+#endif
+ size_mtd_t dummy;
+ int retval = 0;
+
+ loff_mtd_t addr = ((loff_mtd_t) chunkInNAND) * dev->nDataBytesPerChunk;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ __u8 spareAsBytes[8]; /* OOB */
+
+ if (data && !spare)
+ retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
+ &dummy, data);
+ else if (spare) {
+ if (dev->useNANDECC) {
+ translate_spare2oob(spare, spareAsBytes);
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooblen = 8; /* temp hack */
+ ops.oobbuf = spareAsBytes;
+ } else {
+ ops.mode = MTD_OOB_RAW;
+ ops.ooblen = YAFFS_BYTES_PER_SPARE;
+ ops.oobbuf = (__u8 *)spare;
+ }
+ ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
+ ops.datbuf = (u8 *)data;
+ ops.ooboffs = 0;
+ retval = mtd->write_oob(mtd, addr, &ops);
+ }
+#else
+ __u8 *spareAsBytes = (__u8 *) spare;
+
+ if (data && spare) {
+ if (dev->useNANDECC)
+ retval =
+ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
+ &dummy, data, spareAsBytes,
+ &yaffs_oobinfo);
+ else
+ retval =
+ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
+ &dummy, data, spareAsBytes,
+ &yaffs_noeccinfo);
+ } else {
+ if (data)
+ retval =
+ mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
+ data);
+ if (spare)
+ retval =
+ mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
+ &dummy, spareAsBytes);
+ }
+#endif
+
+ if (retval == 0)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+}
+
+int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
+ yaffs_Spare * spare)
+{
+ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ struct mtd_oob_ops ops;
+#endif
+ size_mtd_t dummy;
+ int retval = 0;
+
+ loff_mtd_t addr = ((loff_mtd_t) chunkInNAND) * dev->nDataBytesPerChunk;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ __u8 spareAsBytes[8]; /* OOB */
+
+ if (data && !spare)
+ retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
+ &dummy, data);
+ else if (spare) {
+ if (dev->useNANDECC) {
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooblen = 8; /* temp hack */
+ ops.oobbuf = spareAsBytes;
+ } else {
+ ops.mode = MTD_OOB_RAW;
+ ops.ooblen = YAFFS_BYTES_PER_SPARE;
+ ops.oobbuf = (__u8 *)spare;
+ }
+ ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
+ ops.datbuf = data;
+ ops.ooboffs = 0;
+ retval = mtd->read_oob(mtd, addr, &ops);
+ if (dev->useNANDECC)
+ translate_oob2spare(spare, spareAsBytes);
+ }
+#else
+ __u8 *spareAsBytes = (__u8 *) spare;
+
+ if (data && spare) {
+ if (dev->useNANDECC) {
+ /* Careful, this call adds 2 ints */
+ /* to the end of the spare data. Calling function */
+ /* should allocate enough memory for spare, */
+ /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
+ retval =
+ mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
+ &dummy, data, spareAsBytes,
+ &yaffs_oobinfo);
+ } else {
+ retval =
+ mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
+ &dummy, data, spareAsBytes,
+ &yaffs_noeccinfo);
+ }
+ } else {
+ if (data)
+ retval =
+ mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
+ data);
+ if (spare)
+ retval =
+ mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
+ &dummy, spareAsBytes);
+ }
+#endif
+
+ if (retval == 0)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+}
+
+int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
+{
+ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+ __u64 addr =
+ ((loff_mtd_t) blockNumber) * dev->nDataBytesPerChunk
+ * dev->nChunksPerBlock;
+ struct erase_info ei;
+ int retval = 0;
+
+ ei.mtd = mtd;
+ ei.addr = addr;
+ ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
+ ei.time = 1000;
+ ei.retries = 2;
+ ei.callback = NULL;
+ ei.priv = (u_long) dev;
+
+ /* Todo finish off the ei if required */
+
+ sema_init(&dev->sem, 0);
+
+ retval = mtd->erase(mtd, &ei);
+
+ if (retval == 0)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+}
+
+int nandmtd_InitialiseNAND(yaffs_Device * dev)
+{
+ return YAFFS_OK;
+}
+
diff --git a/fs/yaffs2/yaffs_mtdif.h b/fs/yaffs2/yaffs_mtdif.h
new file mode 100644
index 00000000000..f75e08c23a4
--- /dev/null
+++ b/fs/yaffs2/yaffs_mtdif.h
@@ -0,0 +1,27 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_MTDIF_H__
+#define __YAFFS_MTDIF_H__
+
+#include "yaffs_guts.h"
+
+int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
+ const __u8 * data, const yaffs_Spare * spare);
+int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
+ yaffs_Spare * spare);
+int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber);
+int nandmtd_InitialiseNAND(yaffs_Device * dev);
+#endif
diff --git a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c
new file mode 100644
index 00000000000..f3a8263dbd7
--- /dev/null
+++ b/fs/yaffs2/yaffs_mtdif2.c
@@ -0,0 +1,369 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* mtd interface for YAFFS2 */
+
+const char *yaffs_mtdif2_c_version =
+ "$Id: yaffs_mtdif2.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $";
+
+#include "yportenv.h"
+#include "yaffs_mtdif2.h"
+#include "linux/mtd/mtd.h"
+#include "linux/types.h"
+#include "linux/time.h"
+
+#include "yaffs_packedtags2.h"
+
+#define PT2_BYTES 25
+
+void nandmtd2_pt2buf(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw)
+{
+ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+ int i, j = 0, k, n;
+ __u8 pt2_byte_buf[PT2_BYTES];
+
+ /* Pack buffer with 0xff */
+ for (i = 0; i < mtd->oobsize; i++)
+ dev->spareBuffer[i] = 0xff;
+
+ if (!is_raw) {
+ *((unsigned int *) &dev->spareBuffer[0]) = pt->t.sequenceNumber;
+ *((unsigned int *) &dev->spareBuffer[4]) = pt->t.objectId;
+ *((unsigned int *) &dev->spareBuffer[8]) = pt->t.chunkId;
+ *((unsigned int *) &dev->spareBuffer[12]) = pt->t.byteCount;
+ dev->spareBuffer[16] = pt->ecc.colParity;
+ dev->spareBuffer[17] = pt->ecc.lineParity & 0xff;
+ dev->spareBuffer[18] = (pt->ecc.lineParity >> 8) & 0xff;
+ dev->spareBuffer[19] = (pt->ecc.lineParity >> 16) & 0xff;
+ dev->spareBuffer[20] = (pt->ecc.lineParity >> 24) & 0xff;
+ dev->spareBuffer[21] = pt->ecc.lineParityPrime & 0xff;
+ dev->spareBuffer[22] = (pt->ecc.lineParityPrime >> 8) & 0xff;
+ dev->spareBuffer[23] = (pt->ecc.lineParityPrime >> 16) & 0xff;
+ dev->spareBuffer[24] = (pt->ecc.lineParityPrime >> 24) & 0xff;
+ } else {
+ *((unsigned int *) &pt2_byte_buf[0]) = pt->t.sequenceNumber;
+ *((unsigned int *) &pt2_byte_buf[4]) = pt->t.objectId;
+ *((unsigned int *) &pt2_byte_buf[8]) = pt->t.chunkId;
+ *((unsigned int *) &pt2_byte_buf[12]) = pt->t.byteCount;
+ pt2_byte_buf[16] = pt->ecc.colParity;
+ pt2_byte_buf[17] = pt->ecc.lineParity & 0xff;
+ pt2_byte_buf[18] = (pt->ecc.lineParity >> 8) & 0xff;
+ pt2_byte_buf[19] = (pt->ecc.lineParity >> 16) & 0xff;
+ pt2_byte_buf[20] = (pt->ecc.lineParity >> 24) & 0xff;
+ pt2_byte_buf[21] = pt->ecc.lineParityPrime & 0xff;
+ pt2_byte_buf[22] = (pt->ecc.lineParityPrime >> 8) & 0xff;
+ pt2_byte_buf[23] = (pt->ecc.lineParityPrime >> 16) & 0xff;
+ pt2_byte_buf[24] = (pt->ecc.lineParityPrime >> 24) & 0xff;
+
+// k = mtd->oobinfo.oobfree[j][0];
+// n = mtd->oobinfo.oobfree[j][1];
+
+ k = mtd->ecclayout->oobfree[j].offset;
+ n = mtd->ecclayout->oobfree[j].length;
+ if (n == 0) {
+ T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR)));
+ YBUG();
+ }
+
+ for (i = 0; i < PT2_BYTES; i++) {
+ if (n == 0) {
+ j++;
+// k = mtd->oobinfo.oobfree[j][0];
+// n = mtd->oobinfo.oobfree[j][1];
+ k = mtd->ecclayout->oobfree[j].offset;
+ n = mtd->ecclayout->oobfree[j].length;
+
+ if (n == 0) {
+ T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR)));
+ YBUG();
+ }
+ }
+ dev->spareBuffer[k++] = pt2_byte_buf[i];
+ n--;
+ }
+ }
+
+}
+
+void nandmtd2_buf2pt(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw)
+{
+ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+ int i, j = 0, k, n;
+ __u8 pt2_byte_buf[PT2_BYTES];
+
+
+ if (!is_raw) {
+ pt->t.sequenceNumber = *((unsigned int *) &dev->spareBuffer[0]);
+ pt->t.objectId = *((unsigned int *) &dev->spareBuffer[4]);
+ pt->t.chunkId = *((unsigned int *) &dev->spareBuffer[8]);
+ pt->t.byteCount = *((unsigned int *) &dev->spareBuffer[12]);
+ pt->ecc.colParity = dev->spareBuffer[16];
+ pt->ecc.lineParity = (dev->spareBuffer[17] & 0x000000ff) |
+ ((dev->spareBuffer[18] << 8) & 0x0000ff00) |
+ ((dev->spareBuffer[19] << 16) & 0x00ff0000) |
+ ((dev->spareBuffer[20] << 24) & 0xff000000);
+ pt->ecc.lineParityPrime = (dev->spareBuffer[21] & 0x000000ff) |
+ ((dev->spareBuffer[22] << 8) & 0x0000ff00) |
+ ((dev->spareBuffer[23] << 16) & 0x00ff0000) |
+ ((dev->spareBuffer[24] << 24) & 0xff000000);
+ } else {
+// k = mtd->oobinfo.oobfree[j][0];
+// n = mtd->oobinfo.oobfree[j][1];
+
+ k = mtd->ecclayout->oobfree[j].offset;
+ n = mtd->ecclayout->oobfree[j].length;
+
+ if (n == 0) {
+ T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR)));
+ YBUG();
+ }
+
+ for (i = 0; i < PT2_BYTES; i++) {
+ if (n == 0) {
+ j++;
+// k = mtd->oobinfo.oobfree[j][0];
+// n = mtd->oobinfo.oobfree[j][1];
+ k = mtd->ecclayout->oobfree[j].offset;
+ n = mtd->ecclayout->oobfree[j].length;
+
+ if (n == 0) {
+ T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR)));
+ YBUG();
+ }
+ }
+ pt2_byte_buf[i] = dev->spareBuffer[k++];
+ n--;
+ }
+ pt->t.sequenceNumber = *((unsigned int *) &pt2_byte_buf[0]);
+ pt->t.objectId = *((unsigned int *) &pt2_byte_buf[4]);
+ pt->t.chunkId = *((unsigned int *) &pt2_byte_buf[8]);
+ pt->t.byteCount = *((unsigned int *) &pt2_byte_buf[12]);
+ pt->ecc.colParity = pt2_byte_buf[16];
+ pt->ecc.lineParity = (pt2_byte_buf[17] & 0x000000ff) |
+ ((pt2_byte_buf[18] << 8) & 0x0000ff00) |
+ ((pt2_byte_buf[19] << 16) & 0x00ff0000) |
+ ((pt2_byte_buf[20] << 24) & 0xff000000);
+ pt->ecc.lineParityPrime = (pt2_byte_buf[21] & 0x000000ff) |
+ ((pt2_byte_buf[22] << 8) & 0x0000ff00) |
+ ((pt2_byte_buf[23] << 16) & 0x00ff0000) |
+ ((pt2_byte_buf[24] << 24) & 0xff000000);
+ }
+}
+
+int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
+ const __u8 * data,
+ const yaffs_ExtendedTags * tags)
+{
+ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ struct mtd_oob_ops ops;
+#else
+ size_t dummy;
+#endif
+ int retval = 0;
+ loff_mtd_t addr = ((loff_mtd_t) chunkInNAND) * dev->nDataBytesPerChunk;
+ yaffs_PackedTags2 pt;
+
+ T(YAFFS_TRACE_MTD,
+ (TSTR
+ ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
+ TENDSTR), chunkInNAND, data, tags));
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ if (tags)
+ yaffs_PackTags2(&pt, tags);
+ else
+ BUG(); /* both tags and data should always be present */
+
+ if (data) {
+ nandmtd2_pt2buf(dev, &pt, 0); //modify
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooblen = sizeof(pt);
+ ops.len = dev->nDataBytesPerChunk;
+ ops.ooboffs = 0;
+ ops.datbuf = (__u8 *)data;
+// ops.oobbuf = (void *)&pt; //modify
+ ops.oobbuf = (void *)dev->spareBuffer; //modify
+ retval = mtd->write_oob(mtd, addr, &ops);
+ } else
+ BUG(); /* both tags and data should always be present */
+#else
+ if (tags) {
+ yaffs_PackTags2(&pt, tags);
+ }
+
+ if (data && tags) {
+ nandmtd2_pt2buf(dev, &pt, 0);
+ if (dev->useNANDECC)
+ retval =
+ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
+ &dummy, data, dev->spareBuffer, NULL);
+ else
+ retval =
+ mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
+ &dummy, data, dev->spareBuffer, NULL);
+ } else {
+ if (data) {
+ retval =
+ mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
+ data);
+ }
+ if (tags) {
+ nandmtd2_pt2buf(dev, &pt, 1);
+ retval =
+ mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
+ dev->spareBuffer);
+ }
+ }
+#endif
+
+ if (retval == 0)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+}
+
+int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
+ __u8 * data, yaffs_ExtendedTags * tags)
+{
+ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ struct mtd_oob_ops ops;
+#endif
+ size_mtd_t dummy;
+ int retval = 0;
+ loff_mtd_t addr = ((loff_mtd_t) chunkInNAND) * dev->nDataBytesPerChunk;
+ yaffs_PackedTags2 pt;
+
+ T(YAFFS_TRACE_MTD,
+ (TSTR
+ ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
+ TENDSTR), chunkInNAND, data, tags));
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+ if (data && !tags)
+ retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
+ &dummy, data);
+ else if (tags) {
+ ops.mode = MTD_OOB_AUTO;
+ ops.ooblen = sizeof(pt);
+ ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
+ ops.ooboffs = 0;
+ ops.datbuf = data;
+ ops.oobbuf = dev->spareBuffer;
+ retval = mtd->read_oob(mtd, addr, &ops);
+ nandmtd2_buf2pt(dev, &pt, 0); //modify by yliu
+ }
+#else
+ if (data && tags) {
+ if (dev->useNANDECC) {
+ retval =
+ mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
+ &dummy, data, dev->spareBuffer,
+ NULL);
+ } else {
+ retval =
+ mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
+ &dummy, data, dev->spareBuffer,
+ NULL);
+ }
+ nandmtd2_buf2pt(dev, &pt, 0);
+ } else {
+ if (data) {
+ retval =
+ mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
+ data);
+ }
+ if (tags) {
+ retval =
+ mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
+ dev->spareBuffer);
+ nandmtd2_buf2pt(dev, &pt, 1);
+ }
+ }
+#endif
+
+ if (tags)
+ yaffs_UnpackTags2(tags, &pt);
+
+ if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
+ tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
+
+ if (retval == 0)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+}
+
+int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
+{
+ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+ int retval;
+ T(YAFFS_TRACE_MTD,
+ (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
+
+ retval =
+ mtd->block_markbad(mtd,
+ (u64)blockNo * dev->nChunksPerBlock *
+ dev->nDataBytesPerChunk);
+
+ if (retval == 0)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+
+}
+
+int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
+ yaffs_BlockState * state, int *sequenceNumber)
+{
+ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+ int retval;
+
+ T(YAFFS_TRACE_MTD,
+ (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
+
+ retval =
+ mtd->block_isbad(mtd,
+ (u64)blockNo * dev->nChunksPerBlock *
+ dev->nDataBytesPerChunk);
+ if (retval) {
+ T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
+
+ *state = YAFFS_BLOCK_STATE_DEAD;
+ *sequenceNumber = 0;
+ } else {
+ yaffs_ExtendedTags t;
+ nandmtd2_ReadChunkWithTagsFromNAND(dev,
+ blockNo *
+ dev->nChunksPerBlock, NULL,
+ &t);
+
+ if (t.chunkUsed) {
+ *sequenceNumber = t.sequenceNumber;
+ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
+ } else {
+ *sequenceNumber = 0;
+ *state = YAFFS_BLOCK_STATE_EMPTY;
+ }
+ }
+ T(YAFFS_TRACE_MTD,
+ (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
+ *state));
+
+ if (retval == 0)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+}
+
diff --git a/fs/yaffs2/yaffs_mtdif2.h b/fs/yaffs2/yaffs_mtdif2.h
new file mode 100644
index 00000000000..e70d751c21e
--- /dev/null
+++ b/fs/yaffs2/yaffs_mtdif2.h
@@ -0,0 +1,29 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_MTDIF2_H__
+#define __YAFFS_MTDIF2_H__
+
+#include "yaffs_guts.h"
+int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
+ const __u8 * data,
+ const yaffs_ExtendedTags * tags);
+int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
+ __u8 * data, yaffs_ExtendedTags * tags);
+int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
+int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
+ yaffs_BlockState * state, int *sequenceNumber);
+
+#endif
diff --git a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c
new file mode 100644
index 00000000000..ef90b4a4ae7
--- /dev/null
+++ b/fs/yaffs2/yaffs_nand.c
@@ -0,0 +1,134 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+const char *yaffs_nand_c_version =
+ "$Id: yaffs_nand.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $";
+
+#include "yaffs_nand.h"
+#include "yaffs_tagscompat.h"
+#include "yaffs_tagsvalidity.h"
+
+
+int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
+ __u8 * buffer,
+ yaffs_ExtendedTags * tags)
+{
+ int result;
+ yaffs_ExtendedTags localTags;
+
+ int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
+
+ /* If there are no tags provided, use local tags to get prioritised gc working */
+ if(!tags)
+ tags = &localTags;
+
+ if (dev->readChunkWithTagsFromNAND)
+ result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
+ tags);
+ else
+ result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
+ realignedChunkInNAND,
+ buffer,
+ tags);
+
+ if(tags &&
+ tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
+ yaffs_HandleChunkError(dev,bi);
+ }
+
+ return result;
+}
+
+int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
+ int chunkInNAND,
+ const __u8 * buffer,
+ yaffs_ExtendedTags * tags)
+{
+ chunkInNAND -= dev->chunkOffset;
+
+
+ if (tags) {
+ tags->sequenceNumber = dev->sequenceNumber;
+ tags->chunkUsed = 1;
+ if (!yaffs_ValidateTags(tags)) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("Writing uninitialised tags" TENDSTR)));
+ YBUG();
+ }
+ T(YAFFS_TRACE_WRITE,
+ (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
+ tags->objectId, tags->chunkId));
+ } else {
+ T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
+ YBUG();
+ }
+
+ if (dev->writeChunkWithTagsToNAND)
+ return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
+ tags);
+ else
+ return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
+ chunkInNAND,
+ buffer,
+ tags);
+}
+
+int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
+{
+ blockNo -= dev->blockOffset;
+
+;
+ if (dev->markNANDBlockBad)
+ return dev->markNANDBlockBad(dev, blockNo);
+ else
+ return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
+}
+
+int yaffs_QueryInitialBlockState(yaffs_Device * dev,
+ int blockNo,
+ yaffs_BlockState * state,
+ unsigned *sequenceNumber)
+{
+ blockNo -= dev->blockOffset;
+
+ if (dev->queryNANDBlock)
+ return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
+ else
+ return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
+ state,
+ sequenceNumber);
+}
+
+
+int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
+ int blockInNAND)
+{
+ int result;
+
+ blockInNAND -= dev->blockOffset;
+
+
+ dev->nBlockErasures++;
+ result = dev->eraseBlockInNAND(dev, blockInNAND);
+
+ return result;
+}
+
+int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
+{
+ return dev->initialiseNAND(dev);
+}
+
+
+
diff --git a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h
new file mode 100644
index 00000000000..8ed1a2d5c4a
--- /dev/null
+++ b/fs/yaffs2/yaffs_nand.h
@@ -0,0 +1,44 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_NAND_H__
+#define __YAFFS_NAND_H__
+#include "yaffs_guts.h"
+
+
+
+int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
+ __u8 * buffer,
+ yaffs_ExtendedTags * tags);
+
+int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
+ int chunkInNAND,
+ const __u8 * buffer,
+ yaffs_ExtendedTags * tags);
+
+int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo);
+
+int yaffs_QueryInitialBlockState(yaffs_Device * dev,
+ int blockNo,
+ yaffs_BlockState * state,
+ unsigned *sequenceNumber);
+
+int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
+ int blockInNAND);
+
+int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
+
+#endif
+
diff --git a/fs/yaffs2/yaffs_nandemul2k.h b/fs/yaffs2/yaffs_nandemul2k.h
new file mode 100644
index 00000000000..13520e10593
--- /dev/null
+++ b/fs/yaffs2/yaffs_nandemul2k.h
@@ -0,0 +1,39 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* Interface to emulated NAND functions (2k page size) */
+
+#ifndef __YAFFS_NANDEMUL2K_H__
+#define __YAFFS_NANDEMUL2K_H__
+
+#include "yaffs_guts.h"
+
+int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
+ int chunkInNAND, const __u8 * data,
+ yaffs_ExtendedTags * tags);
+int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
+ int chunkInNAND, __u8 * data,
+ yaffs_ExtendedTags * tags);
+int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
+int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
+ yaffs_BlockState * state, int *sequenceNumber);
+int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
+ int blockInNAND);
+int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
+int nandemul2k_GetBytesPerChunk(void);
+int nandemul2k_GetChunksPerBlock(void);
+int nandemul2k_GetNumberOfBlocks(void);
+
+#endif
diff --git a/fs/yaffs2/yaffs_packedtags1.c b/fs/yaffs2/yaffs_packedtags1.c
new file mode 100644
index 00000000000..f480bf1df11
--- /dev/null
+++ b/fs/yaffs2/yaffs_packedtags1.c
@@ -0,0 +1,52 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_packedtags1.h"
+#include "yportenv.h"
+
+void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t)
+{
+ pt->chunkId = t->chunkId;
+ pt->serialNumber = t->serialNumber;
+ pt->byteCount = t->byteCount;
+ pt->objectId = t->objectId;
+ pt->ecc = 0;
+ pt->deleted = (t->chunkDeleted) ? 0 : 1;
+ pt->unusedStuff = 0;
+ pt->shouldBeFF = 0xFFFFFFFF;
+
+}
+
+void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt)
+{
+ static const __u8 allFF[] =
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff };
+
+ if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
+ t->blockBad = 0;
+ if (pt->shouldBeFF != 0xFFFFFFFF) {
+ t->blockBad = 1;
+ }
+ t->chunkUsed = 1;
+ t->objectId = pt->objectId;
+ t->chunkId = pt->chunkId;
+ t->byteCount = pt->byteCount;
+ t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+ t->chunkDeleted = (pt->deleted) ? 0 : 1;
+ t->serialNumber = pt->serialNumber;
+ } else {
+ memset(t, 0, sizeof(yaffs_ExtendedTags));
+
+ }
+}
diff --git a/fs/yaffs2/yaffs_packedtags1.h b/fs/yaffs2/yaffs_packedtags1.h
new file mode 100644
index 00000000000..627b2f8f528
--- /dev/null
+++ b/fs/yaffs2/yaffs_packedtags1.h
@@ -0,0 +1,37 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
+
+#ifndef __YAFFS_PACKEDTAGS1_H__
+#define __YAFFS_PACKEDTAGS1_H__
+
+#include "yaffs_guts.h"
+
+typedef struct {
+ unsigned chunkId:20;
+ unsigned serialNumber:2;
+ unsigned byteCount:10;
+ unsigned objectId:18;
+ unsigned ecc:12;
+ unsigned deleted:1;
+ unsigned unusedStuff:1;
+ unsigned shouldBeFF;
+
+} yaffs_PackedTags1;
+
+void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t);
+void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt);
+#endif
diff --git a/fs/yaffs2/yaffs_packedtags2.c b/fs/yaffs2/yaffs_packedtags2.c
new file mode 100644
index 00000000000..23e28862d49
--- /dev/null
+++ b/fs/yaffs2/yaffs_packedtags2.c
@@ -0,0 +1,184 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_packedtags2.h"
+#include "yportenv.h"
+#include "yaffs_tagsvalidity.h"
+
+/* This code packs a set of extended tags into a binary structure for
+ * NAND storage
+ */
+
+/* Some of the information is "extra" struff which can be packed in to
+ * speed scanning
+ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
+ */
+
+/* Extra flags applied to chunkId */
+
+#define EXTRA_HEADER_INFO_FLAG 0x80000000
+#define EXTRA_SHRINK_FLAG 0x40000000
+#define EXTRA_SHADOWS_FLAG 0x20000000
+#define EXTRA_SPARE_FLAGS 0x10000000
+
+#define ALL_EXTRA_FLAGS 0xF0000000
+
+/* Also, the top 4 bits of the object Id are set to the object type. */
+#define EXTRA_OBJECT_TYPE_SHIFT (28)
+#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
+
+static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
+{
+ T(YAFFS_TRACE_MTD,
+// T(YAFFS_TRACE_ALWAYS,
+ (TSTR("packed tags obj %x chunk %x byte %x seq %x" TENDSTR),
+ pt->t.objectId, pt->t.chunkId, pt->t.byteCount,
+ pt->t.sequenceNumber));
+}
+
+static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
+{
+ T(YAFFS_TRACE_MTD,
+// T(YAFFS_TRACE_ALWAYS,
+ (TSTR
+ ("ext.tags eccres %x blkbad %x chused %x obj %x chunk%x byte "
+ "%x del %x ser %x seq %x"
+ TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
+ t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
+ t->sequenceNumber));
+
+}
+
+void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
+{
+ pt->t.chunkId = t->chunkId;
+ pt->t.sequenceNumber = t->sequenceNumber;
+ pt->t.byteCount = t->byteCount;
+ pt->t.objectId = t->objectId;
+
+ if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
+ /* Store the extra header info instead */
+ /* We save the parent object in the chunkId */
+ pt->t.chunkId = EXTRA_HEADER_INFO_FLAG
+ | t->extraParentObjectId;
+ if (t->extraIsShrinkHeader) {
+ pt->t.chunkId |= EXTRA_SHRINK_FLAG;
+ }
+ if (t->extraShadows) {
+ pt->t.chunkId |= EXTRA_SHADOWS_FLAG;
+ }
+
+ pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
+ pt->t.objectId |=
+ (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
+
+ if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
+ pt->t.byteCount = t->extraEquivalentObjectId;
+ } else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
+ pt->t.byteCount = t->extraFileLength;
+ } else {
+ pt->t.byteCount = 0;
+ }
+ }
+
+// yaffs_DumpPackedTags2(pt);
+// yaffs_DumpTags2(t);
+
+#if !defined(YAFFS_IGNORE_TAGS_ECC) && !defined(CONFIG_MTD_HW_BCH_ECC)
+ {
+ yaffs_ECCCalculateOther((unsigned char *)&pt->t,
+ sizeof(yaffs_PackedTags2TagsPart),
+ &pt->ecc);
+ }
+#endif
+}
+
+void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
+{
+ yaffs_InitialiseTags(t);
+
+ if (pt->t.sequenceNumber != 0xFFFFFFFF) {
+ /* Page is in use */
+#if defined(YAFFS_IGNORE_TAGS_ECC) || defined(CONFIG_MTD_HW_BCH_ECC)
+ {
+ t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+ }
+#else
+ {
+ yaffs_ECCOther ecc;
+ int result;
+#if defined(CONFIG_YAFFS_ECC_HAMMING)
+ yaffs_ECCCalculateOther((unsigned char *)&pt->t,
+ sizeof
+ (yaffs_PackedTags2TagsPart),
+ &ecc);
+#endif
+ result =
+ yaffs_ECCCorrectOther((unsigned char *)&pt->t,
+ sizeof
+ (yaffs_PackedTags2TagsPart),
+ &pt->ecc, &ecc);
+
+ switch(result){
+ case 0:
+ t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+ break;
+ case 1:
+ t->eccResult = YAFFS_ECC_RESULT_FIXED;
+ break;
+ case -1:
+ t->eccResult = YAFFS_ECC_RESULT_UNFIXED;
+ break;
+ default:
+ t->eccResult = YAFFS_ECC_RESULT_UNKNOWN;
+ }
+ }
+#endif
+ t->blockBad = 0;
+ t->chunkUsed = 1;
+ t->objectId = pt->t.objectId;
+ t->chunkId = pt->t.chunkId;
+ t->byteCount = pt->t.byteCount;
+ t->chunkDeleted = 0;
+ t->serialNumber = 0;
+ t->sequenceNumber = pt->t.sequenceNumber;
+
+ /* Do extra header info stuff */
+
+ if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) {
+ t->chunkId = 0;
+ t->byteCount = 0;
+
+ t->extraHeaderInfoAvailable = 1;
+ t->extraParentObjectId =
+ pt->t.chunkId & (~(ALL_EXTRA_FLAGS));
+ t->extraIsShrinkHeader =
+ (pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
+ t->extraShadows =
+ (pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
+ t->extraObjectType =
+ pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT;
+ t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
+
+ if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
+ t->extraEquivalentObjectId = pt->t.byteCount;
+ } else {
+ t->extraFileLength = pt->t.byteCount;
+ }
+ }
+ }
+// printk("\n TAG %d",t->chunkUsed);
+ yaffs_DumpPackedTags2(pt);
+ yaffs_DumpTags2(t);
+// printk("\n TAG %d",t->chunkUsed);
+}
diff --git a/fs/yaffs2/yaffs_packedtags2.h b/fs/yaffs2/yaffs_packedtags2.h
new file mode 100644
index 00000000000..7c4a72c483d
--- /dev/null
+++ b/fs/yaffs2/yaffs_packedtags2.h
@@ -0,0 +1,38 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
+
+#ifndef __YAFFS_PACKEDTAGS2_H__
+#define __YAFFS_PACKEDTAGS2_H__
+
+#include "yaffs_guts.h"
+#include "yaffs_ecc.h"
+
+typedef struct {
+ unsigned sequenceNumber;
+ unsigned objectId;
+ unsigned chunkId;
+ unsigned byteCount;
+} yaffs_PackedTags2TagsPart;
+
+typedef struct {
+ yaffs_PackedTags2TagsPart t;
+ yaffs_ECCOther ecc;
+} yaffs_PackedTags2;
+
+void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
+void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt);
+#endif
diff --git a/fs/yaffs2/yaffs_qsort.c b/fs/yaffs2/yaffs_qsort.c
new file mode 100644
index 00000000000..887c7b71458
--- /dev/null
+++ b/fs/yaffs2/yaffs_qsort.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "yportenv.h"
+//#include <linux/string.h>
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) { \
+ long i = (n) / sizeof (TYPE); \
+ register TYPE *pi = (TYPE *) (parmi); \
+ register TYPE *pj = (TYPE *) (parmj); \
+ do { \
+ register TYPE t = *pi; \
+ *pi++ = *pj; \
+ *pj++ = t; \
+ } while (--i > 0); \
+}
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+ es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+static __inline void
+swapfunc(char *a, char *b, int n, int swaptype)
+{
+ if (swaptype <= 1)
+ swapcode(long, a, b, n)
+ else
+ swapcode(char, a, b, n)
+}
+
+#define swap(a, b) \
+ if (swaptype == 0) { \
+ long t = *(long *)(a); \
+ *(long *)(a) = *(long *)(b); \
+ *(long *)(b) = t; \
+ } else \
+ swapfunc(a, b, es, swaptype)
+
+#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+static __inline char *
+med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
+{
+ return cmp(a, b) < 0 ?
+ (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
+ :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
+}
+
+void
+qsort(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *))
+{
+ char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+ int d, r, swaptype, swap_cnt;
+ register char *a = aa;
+
+loop: SWAPINIT(a, es);
+ swap_cnt = 0;
+ if (n < 7) {
+ for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
+ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+ pm = (char *)a + (n / 2) * es;
+ if (n > 7) {
+ pl = (char *)a;
+ pn = (char *)a + (n - 1) * es;
+ if (n > 40) {
+ d = (n / 8) * es;
+ pl = med3(pl, pl + d, pl + 2 * d, cmp);
+ pm = med3(pm - d, pm, pm + d, cmp);
+ pn = med3(pn - 2 * d, pn - d, pn, cmp);
+ }
+ pm = med3(pl, pm, pn, cmp);
+ }
+ swap(a, pm);
+ pa = pb = (char *)a + es;
+
+ pc = pd = (char *)a + (n - 1) * es;
+ for (;;) {
+ while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ swap(pa, pb);
+ pa += es;
+ }
+ pb += es;
+ }
+ while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+ if (r == 0) {
+ swap_cnt = 1;
+ swap(pc, pd);
+ pd -= es;
+ }
+ pc -= es;
+ }
+ if (pb > pc)
+ break;
+ swap(pb, pc);
+ swap_cnt = 1;
+ pb += es;
+ pc -= es;
+ }
+ if (swap_cnt == 0) { /* Switch to insertion sort */
+ for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
+ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+ pl -= es)
+ swap(pl, pl - es);
+ return;
+ }
+
+ pn = (char *)a + n * es;
+ r = min(pa - (char *)a, pb - pa);
+ vecswap(a, pb - r, r);
+ r = min((long)(pd - pc), (long)(pn - pd - es));
+ vecswap(pb, pn - r, r);
+ if ((r = pb - pa) > es)
+ qsort(a, r / es, es, cmp);
+ if ((r = pd - pc) > es) {
+ /* Iterate rather than recurse to save stack space */
+ a = pn - r;
+ n = r / es;
+ goto loop;
+ }
+/* qsort(pn - r, r / es, es, cmp);*/
+}
diff --git a/fs/yaffs2/yaffs_qsort.h b/fs/yaffs2/yaffs_qsort.h
new file mode 100644
index 00000000000..6d3f554c9a0
--- /dev/null
+++ b/fs/yaffs2/yaffs_qsort.h
@@ -0,0 +1,23 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YAFFS_QSORT_H__
+#define __YAFFS_QSORT_H__
+
+extern void qsort (void *const base, size_t total_elems, size_t size,
+ int (*cmp)(const void *, const void *));
+
+#endif
diff --git a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c
new file mode 100644
index 00000000000..d594d619324
--- /dev/null
+++ b/fs/yaffs2/yaffs_tagscompat.c
@@ -0,0 +1,530 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_guts.h"
+#include "yaffs_tagscompat.h"
+#include "yaffs_ecc.h"
+
+static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
+#ifdef NOTYET
+static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND);
+static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
+ const __u8 * data,
+ const yaffs_Spare * spare);
+static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
+ const yaffs_Spare * spare);
+static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);
+#endif
+
+static const char yaffs_countBitsTable[256] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+static int yaffs_CountBits(__u8 x)
+{
+ int retVal;
+ retVal = yaffs_countBitsTable[x];
+ return retVal;
+}
+
+/********** Tags ECC calculations *********/
+
+void yaffs_CalcECC(const __u8 * data, yaffs_Spare * spare)
+{
+ yaffs_ECCCalculate(data, spare->ecc1);
+ yaffs_ECCCalculate(&data[256], spare->ecc2);
+}
+
+void yaffs_CalcTagsECC(yaffs_Tags * tags)
+{
+ /* Calculate an ecc */
+
+ unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
+ unsigned i, j;
+ unsigned ecc = 0;
+ unsigned bit = 0;
+
+ tags->ecc = 0;
+
+ for (i = 0; i < 8; i++) {
+ for (j = 1; j & 0xff; j <<= 1) {
+ bit++;
+ if (b[i] & j) {
+ ecc ^= bit;
+ }
+ }
+ }
+
+ tags->ecc = ecc;
+
+}
+
+int yaffs_CheckECCOnTags(yaffs_Tags * tags)
+{
+ unsigned ecc = tags->ecc;
+
+ yaffs_CalcTagsECC(tags);
+
+ ecc ^= tags->ecc;
+
+ if (ecc && ecc <= 64) {
+ /* TODO: Handle the failure better. Retire? */
+ unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
+
+ ecc--;
+
+ b[ecc / 8] ^= (1 << (ecc & 7));
+
+ /* Now recvalc the ecc */
+ yaffs_CalcTagsECC(tags);
+
+ return 1; /* recovered error */
+ } else if (ecc) {
+ /* Wierd ecc failure value */
+ /* TODO Need to do somethiong here */
+ return -1; /* unrecovered error */
+ }
+
+ return 0;
+}
+
+/********** Tags **********/
+
+static void yaffs_LoadTagsIntoSpare(yaffs_Spare * sparePtr,
+ yaffs_Tags * tagsPtr)
+{
+ yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
+
+ yaffs_CalcTagsECC(tagsPtr);
+
+ sparePtr->tagByte0 = tu->asBytes[0];
+ sparePtr->tagByte1 = tu->asBytes[1];
+ sparePtr->tagByte2 = tu->asBytes[2];
+ sparePtr->tagByte3 = tu->asBytes[3];
+ sparePtr->tagByte4 = tu->asBytes[4];
+ sparePtr->tagByte5 = tu->asBytes[5];
+ sparePtr->tagByte6 = tu->asBytes[6];
+ sparePtr->tagByte7 = tu->asBytes[7];
+}
+
+static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr,
+ yaffs_Tags * tagsPtr)
+{
+ yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
+ int result;
+
+ tu->asBytes[0] = sparePtr->tagByte0;
+ tu->asBytes[1] = sparePtr->tagByte1;
+ tu->asBytes[2] = sparePtr->tagByte2;
+ tu->asBytes[3] = sparePtr->tagByte3;
+ tu->asBytes[4] = sparePtr->tagByte4;
+ tu->asBytes[5] = sparePtr->tagByte5;
+ tu->asBytes[6] = sparePtr->tagByte6;
+ tu->asBytes[7] = sparePtr->tagByte7;
+
+ result = yaffs_CheckECCOnTags(tagsPtr);
+ if (result > 0) {
+ dev->tagsEccFixed++;
+ } else if (result < 0) {
+ dev->tagsEccUnfixed++;
+ }
+}
+
+static void yaffs_SpareInitialise(yaffs_Spare * spare)
+{
+ memset(spare, 0xFF, sizeof(yaffs_Spare));
+}
+
+static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
+ int chunkInNAND, const __u8 * data,
+ yaffs_Spare * spare)
+{
+ if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
+ chunkInNAND));
+ return YAFFS_FAIL;
+ }
+
+ dev->nPageWrites++;
+ return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
+}
+
+static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
+ int chunkInNAND,
+ __u8 * data,
+ yaffs_Spare * spare,
+ yaffs_ECCResult * eccResult,
+ int doErrorCorrection)
+{
+ int retVal;
+ yaffs_Spare localSpare;
+
+ dev->nPageReads++;
+
+ if (!spare && data) {
+ /* If we don't have a real spare, then we use a local one. */
+ /* Need this for the calculation of the ecc */
+ spare = &localSpare;
+ }
+
+ if (!dev->useNANDECC) {
+ retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
+ if (data && doErrorCorrection) {
+ /* Do ECC correction */
+ /* Todo handle any errors */
+ int eccResult1, eccResult2;
+ __u8 calcEcc[3];
+
+ yaffs_ECCCalculate(data, calcEcc);
+ eccResult1 =
+ yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
+ yaffs_ECCCalculate(&data[256], calcEcc);
+ eccResult2 =
+ yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
+
+ if (eccResult1 > 0) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("**>>yaffs ecc error fix performed on chunk %d:0"
+ TENDSTR), chunkInNAND));
+ dev->eccFixed++;
+ } else if (eccResult1 < 0) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("**>>yaffs ecc error unfixed on chunk %d:0"
+ TENDSTR), chunkInNAND));
+ dev->eccUnfixed++;
+ }
+
+ if (eccResult2 > 0) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("**>>yaffs ecc error fix performed on chunk %d:1"
+ TENDSTR), chunkInNAND));
+ dev->eccFixed++;
+ } else if (eccResult2 < 0) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("**>>yaffs ecc error unfixed on chunk %d:1"
+ TENDSTR), chunkInNAND));
+ dev->eccUnfixed++;
+ }
+
+ if (eccResult1 || eccResult2) {
+ /* We had a data problem on this page */
+ yaffs_HandleReadDataError(dev, chunkInNAND);
+ }
+
+ if (eccResult1 < 0 || eccResult2 < 0)
+ *eccResult = YAFFS_ECC_RESULT_UNFIXED;
+ else if (eccResult1 > 0 || eccResult2 > 0)
+ *eccResult = YAFFS_ECC_RESULT_FIXED;
+ else
+ *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+ }
+ } else {
+ /* Must allocate enough memory for spare+2*sizeof(int) */
+ /* for ecc results from device. */
+ struct yaffs_NANDSpare nspare;
+ retVal =
+ dev->readChunkFromNAND(dev, chunkInNAND, data,
+ (yaffs_Spare *) & nspare);
+ memcpy(spare, &nspare, sizeof(yaffs_Spare));
+ if (data && doErrorCorrection) {
+ if (nspare.eccres1 > 0) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("**>>mtd ecc error fix performed on chunk %d:0"
+ TENDSTR), chunkInNAND));
+ } else if (nspare.eccres1 < 0) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("**>>mtd ecc error unfixed on chunk %d:0"
+ TENDSTR), chunkInNAND));
+ }
+
+ if (nspare.eccres2 > 0) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("**>>mtd ecc error fix performed on chunk %d:1"
+ TENDSTR), chunkInNAND));
+ } else if (nspare.eccres2 < 0) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("**>>mtd ecc error unfixed on chunk %d:1"
+ TENDSTR), chunkInNAND));
+ }
+
+ if (nspare.eccres1 || nspare.eccres2) {
+ /* We had a data problem on this page */
+ yaffs_HandleReadDataError(dev, chunkInNAND);
+ }
+
+ if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
+ *eccResult = YAFFS_ECC_RESULT_UNFIXED;
+ else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
+ *eccResult = YAFFS_ECC_RESULT_FIXED;
+ else
+ *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+
+ }
+ }
+ return retVal;
+}
+
+#ifdef NOTYET
+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
+ int chunkInNAND)
+{
+
+ static int init = 0;
+ static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
+ static __u8 data[YAFFS_BYTES_PER_CHUNK];
+ /* Might as well always allocate the larger size for */
+ /* dev->useNANDECC == true; */
+ static __u8 spare[sizeof(struct yaffs_NANDSpare)];
+
+ dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
+
+ if (!init) {
+ memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
+ init = 1;
+ }
+
+ if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
+ return YAFFS_FAIL;
+ if (memcmp(cmpbuf, spare, 16))
+ return YAFFS_FAIL;
+
+ return YAFFS_OK;
+
+}
+#endif
+
+/*
+ * Functions for robustisizing
+ */
+
+static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND)
+{
+ int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
+
+ /* Mark the block for retirement */
+ yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
+ T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+ (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
+
+ /* TODO:
+ * Just do a garbage collection on the affected block
+ * then retire the block
+ * NB recursion
+ */
+}
+
+#ifdef NOTYET
+static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
+{
+}
+
+static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
+ const __u8 * data,
+ const yaffs_Spare * spare)
+{
+}
+
+static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
+ const yaffs_Spare * spare)
+{
+}
+
+static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
+{
+ int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
+
+ /* Mark the block for retirement */
+ yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
+ /* Delete the chunk */
+ yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
+}
+
+static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
+ const yaffs_Spare * s0, const yaffs_Spare * s1)
+{
+
+ if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
+ s0->tagByte0 != s1->tagByte0 ||
+ s0->tagByte1 != s1->tagByte1 ||
+ s0->tagByte2 != s1->tagByte2 ||
+ s0->tagByte3 != s1->tagByte3 ||
+ s0->tagByte4 != s1->tagByte4 ||
+ s0->tagByte5 != s1->tagByte5 ||
+ s0->tagByte6 != s1->tagByte6 ||
+ s0->tagByte7 != s1->tagByte7 ||
+ s0->ecc1[0] != s1->ecc1[0] ||
+ s0->ecc1[1] != s1->ecc1[1] ||
+ s0->ecc1[2] != s1->ecc1[2] ||
+ s0->ecc2[0] != s1->ecc2[0] ||
+ s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
+ return 0;
+ }
+
+ return 1;
+}
+#endif /* NOTYET */
+
+int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
+ int chunkInNAND,
+ const __u8 * data,
+ const yaffs_ExtendedTags *
+ eTags)
+{
+ yaffs_Spare spare;
+ yaffs_Tags tags;
+
+ yaffs_SpareInitialise(&spare);
+
+ if (eTags->chunkDeleted) {
+ spare.pageStatus = 0;
+ } else {
+ tags.objectId = eTags->objectId;
+ tags.chunkId = eTags->chunkId;
+ tags.byteCount = eTags->byteCount;
+ tags.serialNumber = eTags->serialNumber;
+
+ if (!dev->useNANDECC && data) {
+ yaffs_CalcECC(data, &spare);
+ }
+ yaffs_LoadTagsIntoSpare(&spare, &tags);
+
+ }
+
+ return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
+}
+
+int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
+ int chunkInNAND,
+ __u8 * data,
+ yaffs_ExtendedTags * eTags)
+{
+
+ yaffs_Spare spare;
+ yaffs_Tags tags;
+ yaffs_ECCResult eccResult;
+
+ static yaffs_Spare spareFF;
+ static int init;
+
+ if (!init) {
+ memset(&spareFF, 0xFF, sizeof(spareFF));
+ init = 1;
+ }
+
+ if (yaffs_ReadChunkFromNAND
+ (dev, chunkInNAND, data, &spare, &eccResult, 1)) {
+ /* eTags may be NULL */
+ if (eTags) {
+
+ int deleted =
+ (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
+
+ eTags->chunkDeleted = deleted;
+ eTags->eccResult = eccResult;
+ eTags->blockBad = 0; /* We're reading it */
+ /* therefore it is not a bad block */
+ eTags->chunkUsed =
+ (memcmp(&spareFF, &spare, sizeof(spareFF)) !=
+ 0) ? 1 : 0;
+
+ if (eTags->chunkUsed) {
+ yaffs_GetTagsFromSpare(dev, &spare, &tags);
+
+ eTags->objectId = tags.objectId;
+ eTags->chunkId = tags.chunkId;
+ eTags->byteCount = tags.byteCount;
+ eTags->serialNumber = tags.serialNumber;
+ }
+ }
+
+ return YAFFS_OK;
+ } else {
+ return YAFFS_FAIL;
+ }
+}
+
+int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
+ int blockInNAND)
+{
+
+ yaffs_Spare spare;
+
+ memset(&spare, 0xff, sizeof(yaffs_Spare));
+
+ spare.blockStatus = 'Y';
+
+ yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
+ &spare);
+ yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
+ NULL, &spare);
+
+ return YAFFS_OK;
+
+}
+
+int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
+ int blockNo, yaffs_BlockState *
+ state,
+ int *sequenceNumber)
+{
+
+ yaffs_Spare spare0, spare1;
+ static yaffs_Spare spareFF;
+ static int init;
+ yaffs_ECCResult dummy;
+
+ if (!init) {
+ memset(&spareFF, 0xFF, sizeof(spareFF));
+ init = 1;
+ }
+
+ *sequenceNumber = 0;
+
+ yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
+ &spare0, &dummy, 1);
+ yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
+ &spare1, &dummy, 1);
+
+ if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
+ *state = YAFFS_BLOCK_STATE_DEAD;
+ else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
+ *state = YAFFS_BLOCK_STATE_EMPTY;
+ else
+ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
+
+ return YAFFS_OK;
+}
diff --git a/fs/yaffs2/yaffs_tagscompat.h b/fs/yaffs2/yaffs_tagscompat.h
new file mode 100644
index 00000000000..c746ad91d9e
--- /dev/null
+++ b/fs/yaffs2/yaffs_tagscompat.h
@@ -0,0 +1,36 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_TAGSCOMPAT_H__
+#define __YAFFS_TAGSCOMPAT_H__
+
+#include "yaffs_guts.h"
+int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
+ int chunkInNAND,
+ const __u8 * data,
+ const yaffs_ExtendedTags *
+ tags);
+int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
+ int chunkInNAND,
+ __u8 * data,
+ yaffs_ExtendedTags *
+ tags);
+int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
+ int blockNo);
+int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
+ int blockNo, yaffs_BlockState *
+ state, int *sequenceNumber);
+
+#endif
diff --git a/fs/yaffs2/yaffs_tagsvalidity.c b/fs/yaffs2/yaffs_tagsvalidity.c
new file mode 100644
index 00000000000..9e0bd1cf56b
--- /dev/null
+++ b/fs/yaffs2/yaffs_tagsvalidity.c
@@ -0,0 +1,28 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_tagsvalidity.h"
+
+void yaffs_InitialiseTags(yaffs_ExtendedTags * tags)
+{
+ memset(tags, 0, sizeof(yaffs_ExtendedTags));
+ tags->validMarker0 = 0xAAAAAAAA;
+ tags->validMarker1 = 0x55555555;
+}
+
+int yaffs_ValidateTags(yaffs_ExtendedTags * tags)
+{
+ return (tags->validMarker0 == 0xAAAAAAAA &&
+ tags->validMarker1 == 0x55555555);
+
+}
diff --git a/fs/yaffs2/yaffs_tagsvalidity.h b/fs/yaffs2/yaffs_tagsvalidity.h
new file mode 100644
index 00000000000..ba56727fffa
--- /dev/null
+++ b/fs/yaffs2/yaffs_tagsvalidity.h
@@ -0,0 +1,24 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YAFFS_TAGS_VALIDITY_H__
+#define __YAFFS_TAGS_VALIDITY_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
+int yaffs_ValidateTags(yaffs_ExtendedTags * tags);
+#endif
diff --git a/fs/yaffs2/yaffsinterface.h b/fs/yaffs2/yaffsinterface.h
new file mode 100644
index 00000000000..0cfdfcf6baa
--- /dev/null
+++ b/fs/yaffs2/yaffsinterface.h
@@ -0,0 +1,21 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFSINTERFACE_H__
+#define __YAFFSINTERFACE_H__
+
+int yaffs_Initialise(unsigned nBlocks);
+
+#endif
diff --git a/fs/yaffs2/yportenv.h b/fs/yaffs2/yportenv.h
new file mode 100644
index 00000000000..10ad10582ea
--- /dev/null
+++ b/fs/yaffs2/yportenv.h
@@ -0,0 +1,163 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YPORTENV_H__
+#define __YPORTENV_H__
+
+#if defined CONFIG_YAFFS_WINCE
+
+#include "ywinceenv.h"
+
+#elif defined __KERNEL__
+
+#include "moduleconfig.h"
+
+/* Linux kernel */
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+#include <linux/config.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+
+#define YCHAR char
+#define YUCHAR unsigned char
+#define _Y(x) x
+#define yaffs_strcpy(a,b) strcpy(a,b)
+#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
+#define yaffs_strlen(s) strlen(s)
+#define yaffs_sprintf sprintf
+#define yaffs_toupper(a) toupper(a)
+
+#define Y_INLINE inline
+
+#define YAFFS_LOSTNFOUND_NAME "lost+found"
+#define YAFFS_LOSTNFOUND_PREFIX "obj"
+
+/* #define YPRINTF(x) printk x */
+#define YMALLOC(x) kmalloc(x,GFP_KERNEL)
+#define YFREE(x) kfree(x)
+#define YMALLOC_ALT(x) vmalloc(x)
+#define YFREE_ALT(x) vfree(x)
+#define YMALLOC_DMA(x) YMALLOC(x)
+
+// KR - added for use in scan so processes aren't blocked indefinitely.
+#define YYIELD() schedule()
+
+#define YAFFS_ROOT_MODE 0666
+#define YAFFS_LOSTNFOUND_MODE 0666
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
+#define Y_TIME_CONVERT(x) (x).tv_sec
+#else
+#define Y_CURRENT_TIME CURRENT_TIME
+#define Y_TIME_CONVERT(x) (x)
+#endif
+
+#define yaffs_SumCompare(x,y) ((x) == (y))
+#define yaffs_strcmp(a,b) strcmp(a,b)
+
+#define TENDSTR "\n"
+#define TSTR(x) KERN_WARNING x
+#define TOUT(p) printk p
+
+#elif defined CONFIG_YAFFS_DIRECT
+
+/* Direct interface */
+#include "ydirectenv.h"
+
+#elif defined CONFIG_YAFFS_UTIL
+
+/* Stuff for YAFFS utilities */
+
+#include "stdlib.h"
+#include "stdio.h"
+#include "string.h"
+
+#include "devextras.h"
+
+#define YMALLOC(x) malloc(x)
+#define YFREE(x) free(x)
+#define YMALLOC_ALT(x) malloc(x)
+#define YFREE_ALT(x) free(x)
+
+#define YCHAR char
+#define YUCHAR unsigned char
+#define _Y(x) x
+#define yaffs_strcpy(a,b) strcpy(a,b)
+#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
+#define yaffs_strlen(s) strlen(s)
+#define yaffs_sprintf sprintf
+#define yaffs_toupper(a) toupper(a)
+
+#define Y_INLINE inline
+
+/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */
+/* #define YALERT(s) YINFO(s) */
+
+#define TENDSTR "\n"
+#define TSTR(x) x
+#define TOUT(p) printf p
+
+#define YAFFS_LOSTNFOUND_NAME "lost+found"
+#define YAFFS_LOSTNFOUND_PREFIX "obj"
+/* #define YPRINTF(x) printf x */
+
+#define YAFFS_ROOT_MODE 0666
+#define YAFFS_LOSTNFOUND_MODE 0666
+
+#define yaffs_SumCompare(x,y) ((x) == (y))
+#define yaffs_strcmp(a,b) strcmp(a,b)
+
+#else
+/* Should have specified a configuration type */
+#error Unknown configuration
+
+#endif
+
+extern unsigned yaffs_traceMask;
+
+#define YAFFS_TRACE_ERROR 0x00000001
+#define YAFFS_TRACE_OS 0x00000002
+#define YAFFS_TRACE_ALLOCATE 0x00000004
+#define YAFFS_TRACE_SCAN 0x00000008
+#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
+#define YAFFS_TRACE_ERASE 0x00000020
+#define YAFFS_TRACE_GC 0x00000040
+#define YAFFS_TRACE_WRITE 0x00000080
+#define YAFFS_TRACE_TRACING 0x00000100
+#define YAFFS_TRACE_DELETION 0x00000200
+#define YAFFS_TRACE_BUFFERS 0x00000400
+#define YAFFS_TRACE_NANDACCESS 0x00000800
+#define YAFFS_TRACE_GC_DETAIL 0x00001000
+#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
+#define YAFFS_TRACE_MTD 0x00004000
+#define YAFFS_TRACE_CHECKPOINT 0x00008000
+#define YAFFS_TRACE_ALWAYS 0x40000000
+#define YAFFS_TRACE_BUG 0x80000000
+
+#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ERROR)) TOUT(p);} while(0)
+
+#ifndef CONFIG_YAFFS_WINCE
+#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))
+#endif
+
+#endif
diff --git a/include/linux/i2c-dev.h b/include/linux/i2c-dev.h
index fd53bfd2647..606adb4795d 100644
--- a/include/linux/i2c-dev.h
+++ b/include/linux/i2c-dev.h
@@ -50,6 +50,9 @@
#define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */
#define I2C_SMBUS 0x0720 /* SMBus transfer */
+#define I2C_SET_SUB_ADDRESS 0x0730
+#define I2C_SET_CLOCK 0x0731
+
/* This is the structure as used in the I2C_SMBUS ioctl call */
struct i2c_smbus_ioctl_data {
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index f4784c0fe97..58af5dc4fc2 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -47,6 +47,8 @@ struct i2c_driver;
union i2c_smbus_data;
struct i2c_board_info;
+#define EEPROM_DEVICE_NUMBER 0x50 /*eeprom device number.20091027*/
+
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
/*
* The master routines are the ones normally used to transmit data to devices
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 0f32a9b6ff5..3b126666e00 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -92,10 +92,10 @@ typedef enum {
*/
struct mtd_oob_ops {
mtd_oob_mode_t mode;
- size_t len;
- size_t retlen;
- size_t ooblen;
- size_t oobretlen;
+ size_mtd_t len;
+ size_mtd_t retlen;
+ size_mtd_t ooblen;
+ size_mtd_t oobretlen;
uint32_t ooboffs;
uint8_t *datbuf;
uint8_t *oobbuf;
@@ -157,11 +157,11 @@ struct mtd_info {
/* This stuff for eXecute-In-Place */
/* phys is optional and may be set to NULL */
- int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, void **virt, resource_size_t *phys);
+ int (*point) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len,
+ size_mtd_t *retlen, void **virt, resource_size_t *phys);
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
- void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
+ void (*unpoint) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len);
/* Allow NOMMU mmap() to directly map the device (if not NULL)
* - return the address to which the offset maps
@@ -178,8 +178,8 @@ struct mtd_info {
struct backing_dev_info *backing_dev_info;
- int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
- int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
+ int (*read) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, size_mtd_t *retlen, u_char *buf);
+ int (*write) (struct mtd_info *mtd, loff_mtd_t to, size_mtd_t len, size_mtd_t *retlen, const u_char *buf);
/* In blackbox flight recorder like scenarios we want to make successful
writes in interrupt context. panic_write() is only intended to be
@@ -188,11 +188,11 @@ struct mtd_info {
longer, this function can break locks and delay to ensure the write
succeeds (but not sleep). */
- int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
+ int (*panic_write) (struct mtd_info *mtd, loff_mtd_t to, size_mtd_t len, size_mtd_t *retlen, const u_char *buf);
- int (*read_oob) (struct mtd_info *mtd, loff_t from,
+ int (*read_oob) (struct mtd_info *mtd, loff_mtd_t from,
struct mtd_oob_ops *ops);
- int (*write_oob) (struct mtd_info *mtd, loff_t to,
+ int (*write_oob) (struct mtd_info *mtd, loff_mtd_t to,
struct mtd_oob_ops *ops);
/*
@@ -200,33 +200,33 @@ struct mtd_info {
* flash devices. The user data is one time programmable but the
* factory data is read only.
*/
- int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
- int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
- int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
- int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
- int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
- int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
+ int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_mtd_t len);
+ int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, size_mtd_t *retlen, u_char *buf);
+ int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_mtd_t len);
+ int (*read_user_prot_reg) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, size_mtd_t *retlen, u_char *buf);
+ int (*write_user_prot_reg) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, size_mtd_t *retlen, u_char *buf);
+ int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len);
/* kvec-based read/write methods.
NB: The 'count' parameter is the number of _vectors_, each of
which contains an (ofs, len) tuple.
*/
- int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
+ int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_mtd_t to, size_mtd_t *retlen);
/* Sync */
void (*sync) (struct mtd_info *mtd);
/* Chip-supported device locking */
- int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
- int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
+ int (*lock) (struct mtd_info *mtd, loff_mtd_t ofs, loff_mtd_t len);
+ int (*unlock) (struct mtd_info *mtd, loff_mtd_t ofs, loff_mtd_t len);
/* Power Management functions */
int (*suspend) (struct mtd_info *mtd);
void (*resume) (struct mtd_info *mtd);
/* Bad block management functions */
- int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
- int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
+ int (*block_isbad) (struct mtd_info *mtd, loff_mtd_t ofs);
+ int (*block_markbad) (struct mtd_info *mtd, loff_mtd_t ofs);
struct notifier_block reboot_notifier; /* default mode before reboot */
@@ -306,10 +306,10 @@ extern void register_mtd_user (struct mtd_notifier *new);
extern int unregister_mtd_user (struct mtd_notifier *old);
int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t *retlen);
+ unsigned long count, loff_mtd_t to, size_mtd_t *retlen);
int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
- unsigned long count, loff_t from, size_t *retlen);
+ unsigned long count, loff_mtd_t from, size_mtd_t *retlen);
#ifdef CONFIG_MTD_PARTITIONS
void mtd_erase_callback(struct erase_info *instr);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 4030ebada49..fc2619d06cf 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -43,8 +43,8 @@ extern void nand_wait_ready(struct mtd_info *mtd);
* is supported now. If you add a chip with bigger oobsize/page
* adjust this accordingly.
*/
-#define NAND_MAX_OOBSIZE 128
-#define NAND_MAX_PAGESIZE 4096
+#define NAND_MAX_OOBSIZE 256
+#define NAND_MAX_PAGESIZE 8192
/*
* Constants for hardware specific CLE/ALE/NCE function
@@ -53,6 +53,11 @@ extern void nand_wait_ready(struct mtd_info *mtd);
* bits in one go.
*/
/* Select the chip by setting nCE to low */
+#define NAND_NCE1 0x08
+#define NAND_NCE2 0x10
+#define NAND_NCE3 0x20
+#define NAND_NCE4 0x40
+
#define NAND_NCE 0x01
/* Select the command latch by setting CLE to high */
#define NAND_CLE 0x02
@@ -373,8 +378,8 @@ struct nand_chip {
void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
void (*select_chip)(struct mtd_info *mtd, int chip);
- int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
- int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
+ int (*block_bad)(struct mtd_info *mtd, loff_mtd_t ofs, int getchip);
+ int (*block_markbad)(struct mtd_info *mtd, loff_mtd_t ofs);
void (*cmd_ctrl)(struct mtd_info *mtd, int dat,
unsigned int ctrl);
int (*dev_ready)(struct mtd_info *mtd);
@@ -401,6 +406,9 @@ struct nand_chip {
uint8_t cellinfo;
int badblockpos;
+ int realplanenum; /* number of planes the NAND has */
+ int planenum; /* number of planes operating synchronously */
+
nand_state_t state;
uint8_t *oob_poi;
@@ -451,7 +459,7 @@ struct nand_flash_dev {
char *name;
int id;
unsigned long pagesize;
- unsigned long chipsize;
+ u64 chipsize;
unsigned long erasesize;
unsigned long options;
};
@@ -539,13 +547,13 @@ struct nand_bbt_descr {
#define NAND_BBT_SCAN_MAXBLOCKS 4
extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
-extern int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
+extern int nand_update_bbt(struct mtd_info *mtd, loff_mtd_t offs);
extern int nand_default_bbt(struct mtd_info *mtd);
-extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
+extern int nand_isbad_bbt(struct mtd_info *mtd, loff_mtd_t offs, int allowbbt);
extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
int allowbbt);
-extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t * retlen, uint8_t * buf);
+extern int nand_do_read(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len,
+ size_mtd_t * retlen, uint8_t * buf);
/*
* Constants for oob configuration
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index b70313d33ff..4ab9190165f 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -40,6 +40,10 @@ struct mtd_partition {
uint64_t offset; /* offset within the master MTD space */
uint32_t mask_flags; /* master MTD flags to mask out for this partition */
struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/
+
+ char cpu_mode; /* flag to specify whether the partition works with cpu mode, 0: dma mode, 1:cpu mode */
+ char use_planes; /* flag to specify whether multiple planes of NAND is used in the partition, 0:don't use planes, 1: use planes */
+ uint32_t mtdblock_jz_invalid; /* flag to specify whether the partition works over mtdblock-jz, 0: over mtdblock-jz, 1: not over mtdblock-jz */
};
#define MTDPART_OFS_NXTBLK (-2)
diff --git a/include/linux/vt.h b/include/linux/vt.h
index 02c1c028877..edbb787e528 100644
--- a/include/linux/vt.h
+++ b/include/linux/vt.h
@@ -18,10 +18,16 @@ extern int unregister_vt_notifier(struct notifier_block *nb);
* resizing).
*/
#define MIN_NR_CONSOLES 1 /* must be at least 1 */
-#define MAX_NR_CONSOLES 63 /* serial lines start at 64 */
-#define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */
- /* Note: the ioctl VT_GETSTATE does not work for
- consoles 16 and higher (since it returns a short) */
+
+#if defined(CONFIG_JZSOC)
+#define MAX_NR_CONSOLES 2
+#define MAX_NR_USER_CONSOLES 2
+#else
+#define MAX_NR_CONSOLES 63 /* serial lines start at 64 */
+#define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */
+ /* Note: the ioctl VT_GETSTATE does not work for
+ consoles 16 and higher (since it returns a short) */
+#endif
/* 0x56 is 'V', to avoid collision with termios and kd */
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index be51ae2bd0f..1eac18bfffe 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -7,9 +7,16 @@
#include <linux/types.h>
+#ifndef __KERNEL__
+#define __user
+#endif
+
+typedef uint64_t size_mtd_t;
+typedef uint64_t loff_mtd_t;
+
struct erase_info_user {
- __u32 start;
- __u32 length;
+ __u64 start;
+ __u64 length;
};
struct erase_info_user64 {
@@ -30,6 +37,14 @@ struct mtd_oob_buf64 {
__u64 usr_ptr;
};
+struct mtd_page_buf {
+ uint32_t start; //page start address
+ uint32_t ooblength;
+ uint32_t datlength;
+ unsigned char __user *oobptr;
+ unsigned char __user *datptr;
+};
+
#define MTD_ABSENT 0
#define MTD_RAM 1
#define MTD_ROM 2
@@ -43,6 +58,9 @@ struct mtd_oob_buf64 {
#define MTD_NO_ERASE 0x1000 /* No erase necessary */
#define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */
+#define MTD_MTDBLOCK_JZ_INVALID 0x4000 /* Device doesn't works over mtdblock-jz */
+#define MTD_NAND_CPU_MODE 0x8000 /* Using cpu mode for NAND */
+
// Some common devices / combinations of capabilities
#define MTD_CAP_ROM 0
#define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
@@ -64,7 +82,7 @@ struct mtd_oob_buf64 {
struct mtd_info_user {
__u8 type;
__u32 flags;
- __u32 size; // Total size of the MTD
+ __u64 size; // Total size of the MTD
__u32 erasesize;
__u32 writesize;
__u32 oobsize; // Amount of OOB data per block (e.g. 16)
@@ -75,7 +93,7 @@ struct mtd_info_user {
};
struct region_info_user {
- __u32 offset; /* At which this region starts,
+ __u64 offset; /* At which this region starts,
* from the beginning of the MTD */
__u32 erasesize; /* For this region */
__u32 numblocks; /* Number of blocks in this region */
@@ -98,8 +116,8 @@ struct otp_info {
#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
-#define MEMGETBADBLOCK _IOW('M', 11, __kernel_loff_t)
-#define MEMSETBADBLOCK _IOW('M', 12, __kernel_loff_t)
+#define MEMGETBADBLOCK _IOW('M', 11, loff_mtd_t)
+#define MEMSETBADBLOCK _IOW('M', 12, loff_mtd_t)
#define OTPSELECT _IOR('M', 13, int)
#define OTPGETREGIONCOUNT _IOW('M', 14, int)
#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
@@ -110,6 +128,7 @@ struct otp_info {
#define MEMERASE64 _IOW('M', 20, struct erase_info_user64)
#define MEMWRITEOOB64 _IOWR('M', 21, struct mtd_oob_buf64)
#define MEMREADOOB64 _IOWR('M', 22, struct mtd_oob_buf64)
+#define MEMWRITEPAGE _IOWR('M', 23, struct mtd_page_buf)
/*
* Obsolete legacy interface. Keep it in order not to break userspace
@@ -119,7 +138,7 @@ struct nand_oobinfo {
__u32 useecc;
__u32 eccbytes;
__u32 oobfree[8][2];
- __u32 eccpos[32];
+ __u32 eccpos[104];
};
struct nand_oobfree {
@@ -134,7 +153,7 @@ struct nand_oobfree {
*/
struct nand_ecclayout {
__u32 eccbytes;
- __u32 eccpos[64];
+ __u32 eccpos[128];
__u32 oobavail;
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
};
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 23893523dc8..2c0788ea62c 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -113,16 +113,18 @@ struct snd_pcm_ops {
#define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */
#define SNDRV_PCM_RATE_8000 (1<<1) /* 8000Hz */
#define SNDRV_PCM_RATE_11025 (1<<2) /* 11025Hz */
-#define SNDRV_PCM_RATE_16000 (1<<3) /* 16000Hz */
-#define SNDRV_PCM_RATE_22050 (1<<4) /* 22050Hz */
-#define SNDRV_PCM_RATE_32000 (1<<5) /* 32000Hz */
-#define SNDRV_PCM_RATE_44100 (1<<6) /* 44100Hz */
-#define SNDRV_PCM_RATE_48000 (1<<7) /* 48000Hz */
-#define SNDRV_PCM_RATE_64000 (1<<8) /* 64000Hz */
-#define SNDRV_PCM_RATE_88200 (1<<9) /* 88200Hz */
-#define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */
-#define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */
-#define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */
+#define SNDRV_PCM_RATE_12000 (1<<3) /* 12000Hz */
+#define SNDRV_PCM_RATE_16000 (1<<4) /* 16000Hz */
+#define SNDRV_PCM_RATE_22050 (1<<5) /* 22050Hz */
+#define SNDRV_PCM_RATE_24000 (1<<6) /* 24000Hz */
+#define SNDRV_PCM_RATE_32000 (1<<7) /* 32000Hz */
+#define SNDRV_PCM_RATE_44100 (1<<8) /* 44100Hz */
+#define SNDRV_PCM_RATE_48000 (1<<9) /* 48000Hz */
+#define SNDRV_PCM_RATE_64000 (1<<10) /* 64000Hz */
+#define SNDRV_PCM_RATE_88200 (1<<11) /* 88200Hz */
+#define SNDRV_PCM_RATE_96000 (1<<12) /* 96000Hz */
+#define SNDRV_PCM_RATE_176400 (1<<13) /* 176400Hz */
+#define SNDRV_PCM_RATE_192000 (1<<14) /* 192000Hz */
#define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */
#define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 093f6591550..72f119a9e10 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -386,7 +386,8 @@ void __init prepare_namespace(void)
if (saved_root_name[0]) {
root_device_name = saved_root_name;
if (!strncmp(root_device_name, "mtd", 3) ||
- !strncmp(root_device_name, "ubi", 3)) {
+ !strncmp(root_device_name, "ubi", 3) ||
+ !strncmp(root_device_name, "mmc", 3)) {
mount_block_root(root_device_name, root_mountflags);
goto out;
}
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 9db60d831bb..c69dc9dfd0e 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -2053,6 +2053,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
}
+#if 0
snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size)
{
struct snd_pcm_runtime *runtime;
@@ -2068,6 +2069,108 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u
return -EINVAL;
return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
}
+#else
+snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size)
+{
+ struct snd_pcm_runtime *runtime;
+ int nonblock;
+
+ snd_pcm_sframes_t tmp_frames;
+ snd_pcm_sframes_t final_frames;
+ int channels;
+
+ if (snd_BUG_ON(substream != NULL))
+ return -ENXIO;
+
+ runtime = substream->runtime;
+
+ if (snd_BUG_ON(runtime != NULL))
+ return -ENXIO;
+
+ if (snd_BUG_ON(substream->ops->copy != NULL || runtime->dma_area != NULL))
+ return -EINVAL;
+
+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
+ return -EBADFD;
+
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
+ if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
+ return -EINVAL;
+
+ /*
+ * mono capture process for no mono codec
+ * function codec such as ipcood and dlv
+ */
+
+ tmp_frames = snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
+
+ channels = runtime->channels;
+
+ if (channels == 1) {
+ short *tmpbuf = kcalloc(tmp_frames, sizeof(short), GFP_KERNEL);
+ short *src, *dst, *end;
+
+ memcpy(tmpbuf, buf, frames_to_bytes(runtime, tmp_frames));
+
+ src = (short *)buf;
+ dst = (short *)tmpbuf;
+ end = dst + tmp_frames - 1;
+
+ src++;
+ dst++;
+ dst++;
+ final_frames = 1;
+ while (dst <= end) {
+ *src = *dst;
+ final_frames++;
+ src++;
+ dst++;
+ dst++;
+ }
+ tmp_frames = final_frames;
+ kfree(tmpbuf);
+
+#if 0
+ /* when i have time, i will try the code, no kcalloc */
+ if (snd_BUG_ON(runtime->dma_area))
+ return -EFAULT;
+
+ if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
+ return -EFAULT;
+
+ unsigned int up_bytes = frames_to_bytes(runtime, frames);
+
+ int while_cnt = 4;
+ int while_all = up_bytes - 2;
+
+ while (while_cnt <= while_all) {
+ //printk("[%d = %d]\n",(while_cnt/2),while_cnt);
+ buf[(while_cnt/2)] = buf[while_cnt];
+ //printk("[%d = %d]\n",((while_cnt/2)+1),(while_cnt+1));
+ buf[((while_cnt/2)+1)] = buf[(while_cnt+1)];
+ while_cnt += 4;
+#if 0
+ buf[2] = buf[4];
+ buf[3] = buf[5];
+
+ buf[4] = buf[8];
+ buf[5] = buf[9];
+
+ buf[6] = buf[12];
+ buf[7] = buf[13];
+
+ buf[8] = buf[16];
+ buf[9] = buf[17];
+#endif
+ }
+ /* when i have time, i will try the code, no kcalloc */
+#endif
+ }
+
+ return tmp_frames;
+}
+
+#endif
EXPORT_SYMBOL(snd_pcm_lib_read);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index ac2150e0670..2a57ab773da 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1748,12 +1748,13 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
-#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12
+#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 14
#error "Change this table"
#endif
-static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,
- 48000, 64000, 88200, 96000, 176400, 192000 };
+static unsigned int rates[] = { 5512, 8000, 11025, 12000, 16000, 22050, 24000,
+ 32000, 44100, 48000, 64000, 88200, 96000,
+ 176400, 192000 };
const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
.count = ARRAY_SIZE(rates),
@@ -1764,9 +1765,17 @@ static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_pcm_hardware *hw = rule->private;
+#if 0
return snd_interval_list(hw_param_interval(params, rule->var),
snd_pcm_known_rates.count,
snd_pcm_known_rates.list, hw->rates);
+#else
+ //printk("hw->rates=0x%08x\n",hw->rates);//0x3b6
+ hw->rates = 0x3fe;//12KHz and 24KHz bits are all zero,you need set 1
+ return snd_interval_list(hw_param_interval(params, rule->var),
+ snd_pcm_known_rates.count,
+ snd_pcm_known_rates.list, hw->rates);
+#endif
}
static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params,
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index bcf2a0698d5..cc4ecb0b2ec 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -5,6 +5,62 @@
#
# Prompt user for primary drivers.
+config SOUND_JZ_AC97
+ bool "Jz On-Chip AC97 driver"
+ depends on JZSOC
+ help
+ Say Y here if you have want to select the on-chip AC97 driver
+ on Jz4730/Jz4740/Jz5730.
+
+config SOUND_JZ_I2S
+ bool "Jz On-Chip I2S driver"
+ depends on JZSOC
+ help
+ Say Y here if you have want to select the on-chip I2S driver
+ on Jz4730/Jz4740/Jz5730.
+
+config SOUND_JZ_PCM
+ bool "Jz On-Chip PCM driver"
+ depends on SOC_JZ4750
+ help
+ Say Y here if you have want to select the on-chip PCM driver
+ on Jz4750.
+
+choice
+ prompt "I2S codec type"
+ depends on SOUND_JZ_I2S
+
+config I2S_AK4642EN
+ bool "AK4642EN"
+ depends on SOC_JZ4730
+ help
+ Answer Y if you have an external AK4642EN codec.
+
+config I2S_ICODEC
+ bool "Internal On-Chip codec"
+ depends on SOC_JZ4740
+ help
+ Answer Y if you have an internal I2S codec.
+
+config I2S_DLV
+ bool "Internal On-Chip codec on Jz4750 or Jz4750d"
+ depends on SOC_JZ4750 || SOC_JZ4750D || SOC_JZ4750L
+ help
+ Answer Y if you have an internal I2S codec on Jz4750 or Jz4750d, jz4750L.
+
+endchoice
+
+choice
+ prompt "PCM codec type"
+ depends on SOUND_JZ_PCM
+
+config PCM_TLV320AIC1106
+ bool "TLV320AIC1106"
+ help
+ Answer Y if you have an TI tlv320aic 1106 codec.
+
+endchoice
+
config SOUND_BCM_CS4297A
tristate "Crystal Sound CS4297a (for Swarm)"
depends on SIBYTE_SWARM
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index e0ae4d4d6a5..06bc7567b8a 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -8,6 +8,12 @@
obj-$(CONFIG_SOUND_OSS) += sound.o
# Please leave it as is, cause the link order is significant !
+#
+obj-$(CONFIG_SOUND_JZ_AC97) += jz_ac97.o ac97_codec.o
+obj-$(CONFIG_I2S_AK4642EN) += ak4642en.o
+obj-$(CONFIG_I2S_ICODEC) += jzcodec.o jz_i2s.o
+obj-$(CONFIG_I2S_DLV) += jzdlv.o jz_i2s.o
+obj-$(CONFIG_SOUND_JZ_PCM) += jz_pcm_tlv320aic1106_dma.o
obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o
obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o
diff --git a/sound/oss/ak4642en.c b/sound/oss/ak4642en.c
new file mode 100644
index 00000000000..a61eae295cc
--- /dev/null
+++ b/sound/oss/ak4642en.c
@@ -0,0 +1,711 @@
+/*
+ * linux/sound/oss/ak4642en.c
+ *
+ * AKM ak4642en codec chip driver to I2S interface
+ *
+ * Copyright (c) 2005-2007 Ingenic Semiconductor Inc.
+ * Author: <cjfeng@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Because the normal application of AUDIO devices are focused on Little_endian,
+ * then we only perform the little endian data format in driver.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/proc_fs.h>
+#include <linux/soundcard.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <asm/hardirq.h>
+#include <asm/jzsoc.h>
+
+#include "sound_config.h"
+
+extern mixer_info info;
+extern _old_mixer_info old_info;
+extern int abnormal_data_count;
+
+extern void (*clear_codec_mode)(void);
+extern void (*set_codec_gpio_pin)(void);
+extern void (*each_time_init_codec)(void);
+extern void (*set_codec_record)(void);
+extern void (*set_codec_replay)(void);
+extern void (*clear_codec_record)(void);
+extern void (*clear_codec_replay)(void);
+extern void (*set_codec_speed)(int range);
+extern void (*codec_mixer_old_info_id_name)(void);
+extern void (*codec_mixer_info_id_name)(void);
+extern void (*set_codec_volume)(int val);
+extern void (*set_codec_mic)(int val);
+extern void (*i2s_resume_codec)(void);
+extern void (*i2s_suspend_codec)(int wr,int rd);
+extern void (*set_replay_hp_or_speaker)(void);
+
+#define I2S_PDN 68
+#define JACK_PLUG_PIN 83
+#define JACK_PLUG_IRQ (IRQ_GPIO_0 + JACK_PLUG_PIN)
+
+static int jack_plug_level, old_level;
+static unsigned int i2c_addr = 0x26; //AK4642EN device address at I2C bus
+static unsigned int i2c_clk = 100000;//AK4642EN 400kHz max,but 100kHz here
+static unsigned int spk_hp = 0;
+static int codec_volume;
+
+void set_ak4642en_gpio_pin(void);
+void each_time_init_ak4642en(void);
+void set_ak4642en_replay(void);
+void set_ak4642en_record(void);
+void turn_on_ak4642en(void);
+void turn_off_ak4642en(void);
+void set_ak4642en_speed(int rate);
+void reset_ak4642en(void);
+void ak4642en_mixer_old_info_id_name(void);
+void ak4642en_mixer_info_id_name(void);
+void set_ak4642en_bass(int val);
+void set_ak4642en_volume(int val);
+void set_ak4642en_mic(int val);
+void resume_ak4642en(void);
+void suspend_ak4642en(int wr,int rd);
+
+static void write_reg(u8 reg, u8 val)
+{
+ i2c_open();
+ i2c_setclk(i2c_clk);
+ i2c_write((i2c_addr >> 1), &val, reg, 1);
+ i2c_close();
+}
+
+#if 0
+static u8 read_reg(u8 reg)
+{
+ u8 val;
+ i2c_open();
+ i2c_setclk(i2c_clk);
+ i2c_read((i2c_addr >> 1), &val, reg, 1);
+ i2c_close();
+ return val;
+}
+
+static u16 i2s_codec_read(u8 reg)
+{
+ u16 value;
+ value = read_reg(reg);
+ return value;
+}
+#endif
+
+static void i2s_codec_write(u8 reg, u16 data)
+{
+ u8 val = data & 0xff;
+ write_reg(reg, val);
+}
+
+void set_ak4642en_gpio_pin(void)
+{
+ //set AIC pin to I2S slave mode,only GPIO70,71,77,78
+ __gpio_as_output(68);
+ __gpio_clear_pin(68);
+ __gpio_as_output(69);
+ __gpio_clear_pin(69);
+ __gpio_as_output(70);
+ __gpio_clear_pin(70);
+ __gpio_as_input(71);
+ __gpio_clear_pin(71);
+ __gpio_as_input(77);
+ __gpio_clear_pin(77);
+ __gpio_as_input(78);
+ __gpio_clear_pin(78);
+ REG_GPIO_GPALR(2) &= 0xC3FF0CFF;
+ REG_GPIO_GPALR(2) |= 0x14005000;
+ //set SCC clock initialization
+ REG_SCC1_CR(SCC1_BASE) = 0x00000000;
+ udelay(2);
+ REG_SCC1_CR(SCC1_BASE) |= 1 << 31;
+ udelay(2);
+
+ __gpio_as_output(I2S_PDN);
+ __gpio_set_pin(I2S_PDN);
+ udelay(5);
+ __gpio_clear_pin(I2S_PDN);
+ ndelay(300);//>150ns
+ __gpio_set_pin(I2S_PDN);
+ mdelay(1);
+ //set PLL Master mode
+ i2s_codec_write(0x01, 0x0008);//master
+ i2s_codec_write(0x04, 0x006b);//ref:12MHz;BITCLK:64fs;I2S compli
+ i2s_codec_write(0x05, 0x000b);//sync:48KHz;
+ i2s_codec_write(0x00, 0x0040);//PMVCM
+ i2s_codec_write(0x01, 0x0009);//master,PLL enable
+ mdelay(40);
+ jack_plug_level = 10;
+ old_level = 100;
+ spk_hp = 0;
+ __gpio_disable_pull(JACK_PLUG_PIN);
+ udelay(10);
+ __gpio_as_input(JACK_PLUG_PIN);
+ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN);
+ //i suppose jack_plug_lvel is 1 indicate with HPO
+ if (jack_plug_level > 1 || jack_plug_level <0)
+ printk("Audio ak4642en codec Jack plug level is wrong!\n");
+ if (jack_plug_level)
+ __gpio_as_irq_fall_edge(JACK_PLUG_PIN);
+ else
+ __gpio_as_irq_rise_edge(JACK_PLUG_PIN);
+}
+
+void clear_ak4642en_mode(void)
+{
+ spk_hp = 0;
+ i2s_codec_write(0x01, 0x0008);//master,PLL disable
+ //free_irq(JACK_PLUG_IRQ, i2s_controller);
+ __gpio_clear_pin(I2S_PDN);
+ udelay(2);
+ REG_SCC1_CR(SCC1_BASE) &= 0 << 31;
+ udelay(2);
+}
+
+void set_ak4642en_replay(void)
+{
+ //for poll
+ /*jack_plug_level is H for SPK,is L for HP*/
+ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN);
+ if(old_level == jack_plug_level)
+ return;
+ old_level = jack_plug_level;
+ if(spk_hp == 1)
+ {
+ if(jack_plug_level == 1)
+ {
+ //now HeadPhone output,so clear SPK
+ i2s_codec_write(0x02, 0x0020);
+ i2s_codec_write(0x02, 0x0000);
+ i2s_codec_write(0x00, 0x0040);
+ }
+ else
+ {
+ //now Speaker output,so clear HP
+ i2s_codec_write(0x01, 0x0039);
+ i2s_codec_write(0x01, 0x0009);
+ i2s_codec_write(0x00, 0x0040);
+ i2s_codec_write(0x0e, 0x0000);
+ i2s_codec_write(0x0f, 0x0008);
+ }
+ }
+ spk_hp = 1;
+ if(jack_plug_level == 1)
+ {
+ //for HeadPhone output
+ i2s_codec_write(0x00, 0x0060); //
+ i2s_codec_write(0x0f, 0x0009); //5-10
+
+ i2s_codec_write(0x00, 0x0064); //
+ i2s_codec_write(0x09, 0x0091);// volume control 0dB
+ i2s_codec_write(0x0c, 0x0091);// 0dB(right)
+ //eq off
+ i2s_codec_write(0x11, 0x0000);//5-10
+ i2s_codec_write(0x01, 0x0039); //
+
+ i2s_codec_write(0x01, 0x0079); //
+ }
+ else
+ {
+ //for Speaker output
+ i2s_codec_write(0x00, 0x0040);
+ i2s_codec_write(0x02, 0x0020);
+
+ i2s_codec_write(0x03, 0x0018);//5-10
+ i2s_codec_write(0x06, 0x003c);
+
+ i2s_codec_write(0x08, 0x00A1);//5-10
+
+ i2s_codec_write(0x0b, 0x0040); //5-10
+
+ i2s_codec_write(0x07, 0x002d); //5-10
+ i2s_codec_write(0x09, 0x0091);
+ i2s_codec_write(0x0c, 0x0091);
+ //HP volume output value
+
+ i2s_codec_write(0x0a, codec_volume);//5-10
+ i2s_codec_write(0x0d, codec_volume);//5-10
+
+ i2s_codec_write(0x00, 0x0074);
+ i2s_codec_write(0x02, 0x00a0);
+ }
+}
+
+void set_ak4642en_record(void)
+{
+ abnormal_data_count = 0;
+ i2s_codec_write(0x02, 0x0004);
+ i2s_codec_write(0x03, 0x0038);// recording volume add
+ i2s_codec_write(0x06, 0x0000);//for ALC short waiting time
+ i2s_codec_write(0x08, 0x00e1);
+ i2s_codec_write(0x0b, 0x0000);
+ i2s_codec_write(0x07, 0x0021); // ALC on
+
+ i2s_codec_write(0x10, 0x0000);//0x0001
+ //i2s_codec_write(0x10, 0x0001);//0x0001
+ i2s_codec_write(0x01, 0x0039); //for open pop noise
+ i2s_codec_write(0x01, 0x0079);
+ i2s_codec_write(0x00, 0x0065);
+ mdelay(300);
+}
+
+void clear_ak4642en_replay(void)
+{
+ //for poll
+ old_level = 100;
+ spk_hp = 0;
+ if(jack_plug_level == 1)
+ {
+ //for HeadPhone output
+ i2s_codec_write(0x01, 0x0039); // for close pop noise
+ mdelay(300);
+ i2s_codec_write(0x01, 0x0009); //PLL on I2S
+ i2s_codec_write(0x07, 0x0001);
+ i2s_codec_write(0x11, 0x0000);
+ i2s_codec_write(0x00, 0x0040);
+ i2s_codec_write(0x0f, 0x0008); // for open pop noise
+ }
+ else
+ {
+ //for Speaker output
+ i2s_codec_write(0x02, 0x0020);
+ i2s_codec_write(0x07, 0x0001);
+ i2s_codec_write(0x11, 0x0000);
+ i2s_codec_write(0x02, 0x0000);
+ i2s_codec_write(0x00, 0x0040); // for close pop noise
+ }
+}
+
+void clear_ak4642en_record(void)
+{
+ //for Mic input(Stereo)
+ i2s_codec_write(0x02, 0x0001);
+ i2s_codec_write(0x07, 0x0001);
+ i2s_codec_write(0x11, 0x0000);
+}
+
+void each_time_init_ak4642en(void)
+{
+ __i2s_disable();
+ __i2s_as_slave();
+ __i2s_set_sample_size(16);
+}
+
+void set_ak4642en_speed(int rate)
+{
+ //codec work at frequency
+ unsigned short speed = 0;
+ unsigned short val = 0;
+ switch (rate)
+ {
+ case 8000:
+ speed = 0x00;
+ if(jack_plug_level == 1) //speaker
+ {
+ i2s_codec_write(0x16, 0x0000);
+ i2s_codec_write(0x17, 0x0000);
+ i2s_codec_write(0x18, 0x0000);
+ i2s_codec_write(0x19, 0x0000);
+ i2s_codec_write(0x1A, 0x0000);
+ i2s_codec_write(0x1B, 0x0000);
+ i2s_codec_write(0x1C, 0x0027);//800hz
+ i2s_codec_write(0x1D, 0x0018);
+ i2s_codec_write(0x1E, 0x00b2);
+ i2s_codec_write(0x1F, 0x002f);
+ i2s_codec_write(0x11, 0x0010); //eq on
+ }
+ break;
+ case 12000:
+ speed = 0x01;
+ if(jack_plug_level == 1)
+ {
+ i2s_codec_write(0x16, 0x0000);
+ i2s_codec_write(0x17, 0x0000);
+ i2s_codec_write(0x18, 0x0000);
+ i2s_codec_write(0x19, 0x0000);
+ i2s_codec_write(0x1A, 0x0000);
+ i2s_codec_write(0x1B, 0x0000);
+ i2s_codec_write(0x1C, 0x0064);
+ i2s_codec_write(0x1D, 0x001a);
+ i2s_codec_write(0x1E, 0x0038);
+ i2s_codec_write(0x1F, 0x002b);
+ i2s_codec_write(0x11, 0x0010); //eq on
+ }
+ break;
+ case 16000:
+ speed = 0x02;
+ if(jack_plug_level == 1)
+ {
+ i2s_codec_write(0x16, 0x00af);
+ i2s_codec_write(0x17, 0x0020);
+ i2s_codec_write(0x18, 0x0043);
+ i2s_codec_write(0x19, 0x001a);
+ i2s_codec_write(0x1A, 0x00af);
+ i2s_codec_write(0x1B, 0x0020);
+ i2s_codec_write(0x1C, 0x00a0);
+ i2s_codec_write(0x1D, 0x001b);
+ i2s_codec_write(0x1E, 0x00c0);
+ i2s_codec_write(0x1F, 0x0028);
+ i2s_codec_write(0x11, 0x0018); //eq on
+ }
+ break;
+ case 24000:
+ speed = 0x03;
+ if(jack_plug_level == 1)
+ {
+ i2s_codec_write(0x16, 0x0086);
+ i2s_codec_write(0x17, 0x0015);
+ i2s_codec_write(0x18, 0x005d);
+ i2s_codec_write(0x19, 0x0006);
+ i2s_codec_write(0x1A, 0x0086);
+ i2s_codec_write(0x1B, 0x0015);
+ i2s_codec_write(0x1C, 0x00f5);
+ i2s_codec_write(0x1D, 0x001c);
+ i2s_codec_write(0x1E, 0x0016);
+ i2s_codec_write(0x1F, 0x0026);
+ i2s_codec_write(0x11, 0x0018); //eq on
+ }
+ break;
+ case 7350:
+ speed = 0x04;
+ if(jack_plug_level == 1)
+ {
+ i2s_codec_write(0x16, 0x0000);
+ i2s_codec_write(0x17, 0x0000);
+ i2s_codec_write(0x18, 0x0000);
+ i2s_codec_write(0x19, 0x0000);
+ i2s_codec_write(0x1A, 0x0000);
+ i2s_codec_write(0x1B, 0x0000);
+ i2s_codec_write(0x1C, 0x0027);
+ i2s_codec_write(0x1D, 0x0018);
+ i2s_codec_write(0x1E, 0x00b2);
+ i2s_codec_write(0x1F, 0x002f);
+ i2s_codec_write(0x11, 0x0010); //eq on
+ }
+ break;
+ case 11025:
+ speed = 0x05;
+ if(jack_plug_level == 1)
+ {
+ i2s_codec_write(0x16, 0x0059);
+ i2s_codec_write(0x17, 0x000d);
+ i2s_codec_write(0x18, 0x00cb);
+ i2s_codec_write(0x19, 0x0037);
+ i2s_codec_write(0x1A, 0x0059);
+ i2s_codec_write(0x1B, 0x000d);
+ i2s_codec_write(0x1C, 0x0046);
+ i2s_codec_write(0x1D, 0x001e);
+ i2s_codec_write(0x1E, 0x0074);
+ i2s_codec_write(0x1F, 0x0023);
+ i2s_codec_write(0x11, 0x0018); //eq on
+ }
+ break;
+ case 14700:
+ speed = 0x06;
+ if(jack_plug_level == 1)
+ {
+ i2s_codec_write(0x16, 0x0000);
+ i2s_codec_write(0x17, 0x0000);
+ i2s_codec_write(0x18, 0x0000);
+ i2s_codec_write(0x19, 0x0000);
+ i2s_codec_write(0x1A, 0x0000);
+ i2s_codec_write(0x1B, 0x0000);
+ i2s_codec_write(0x1C, 0x004a);
+ i2s_codec_write(0x1D, 0x001b);
+ i2s_codec_write(0x1E, 0x006c);
+ i2s_codec_write(0x1F, 0x0029);
+ i2s_codec_write(0x11, 0x0010); //eq on
+ }
+ break;
+ case 22050:
+ speed = 0x07;
+ if(jack_plug_level == 1)
+ {
+ i2s_codec_write(0x16, 0x002d);
+ i2s_codec_write(0x17, 0x0017);
+ i2s_codec_write(0x18, 0x0050);
+ i2s_codec_write(0x19, 0x0009);
+ i2s_codec_write(0x1A, 0x002d);
+ i2s_codec_write(0x1B, 0x0017);
+ i2s_codec_write(0x1C, 0x00d7);
+ i2s_codec_write(0x1D, 0x001c);
+ i2s_codec_write(0x1E, 0x0093);
+ i2s_codec_write(0x1F, 0x0026);
+ i2s_codec_write(0x11, 0x0018); //eq on
+ }
+ break;
+ case 32000:
+ speed = 0x0a;
+ if(jack_plug_level == 1)
+ {
+ i2s_codec_write(0x16, 0x0012);
+ i2s_codec_write(0x17, 0x0011);
+ i2s_codec_write(0x18, 0x006e);
+ i2s_codec_write(0x19, 0x003e);
+ i2s_codec_write(0x1A, 0x0012);
+ i2s_codec_write(0x1B, 0x0011);
+ i2s_codec_write(0x1C, 0x00aa);
+ i2s_codec_write(0x1D, 0x001d);
+ i2s_codec_write(0x1E, 0x00ab);
+ i2s_codec_write(0x1F, 0x0024);
+ i2s_codec_write(0x11, 0x0018); //eq on
+ }
+ break;
+ case 48000:
+ speed = 0x0b;
+ if(jack_plug_level == 1)
+ {
+ i2s_codec_write(0x16, 0x0082);
+ i2s_codec_write(0x17, 0x000c);
+ i2s_codec_write(0x18, 0x004b);
+ i2s_codec_write(0x19, 0x0036);
+ i2s_codec_write(0x1A, 0x0082);
+ i2s_codec_write(0x1B, 0x000c);
+ i2s_codec_write(0x1C, 0x0068);
+ i2s_codec_write(0x1D, 0x001e);
+ i2s_codec_write(0x1E, 0x0030);
+ i2s_codec_write(0x1F, 0x0023);
+ i2s_codec_write(0x11, 0x0018); //eq on
+ }
+ break;
+ case 29400:
+ speed = 0x0e;
+ if(jack_plug_level == 1)
+ {
+ i2s_codec_write(0x16, 0x003d);
+ i2s_codec_write(0x17, 0x0012);
+ i2s_codec_write(0x18, 0x0083);
+ i2s_codec_write(0x19, 0x0000);
+ i2s_codec_write(0x1A, 0x003d);
+ i2s_codec_write(0x1B, 0x0012);
+ i2s_codec_write(0x1C, 0x0079);
+ i2s_codec_write(0x1D, 0x001d);
+ i2s_codec_write(0x1E, 0x000d);
+ i2s_codec_write(0x1F, 0x0025);
+ i2s_codec_write(0x11, 0x0018); //eq on
+ }
+ break;
+ case 44100:
+ speed = 0x0f;
+ if(jack_plug_level == 1)
+ {
+ i2s_codec_write(0x16, 0x0059);
+ i2s_codec_write(0x17, 0x000d);
+ i2s_codec_write(0x18, 0x00cb);
+ i2s_codec_write(0x19, 0x0037);
+ i2s_codec_write(0x1A, 0x0059);
+ i2s_codec_write(0x1B, 0x000d);
+ i2s_codec_write(0x1C, 0x0046);
+ i2s_codec_write(0x1D, 0x001e);
+ i2s_codec_write(0x1E, 0x0074);
+ i2s_codec_write(0x1F, 0x0023);
+ i2s_codec_write(0x11, 0x0018); //eq on
+ }
+ break;
+ default:
+ break;
+ }
+ val = speed & 0x08;
+ val = val << 2;
+ speed = speed & 0x07;
+ val = val | speed;
+ i2s_codec_write(0x05, val);
+}
+
+void ak4642en_mixer_old_info_id_name(void)
+{
+ strncpy(info.id, "AK4642EN", sizeof(info.id));
+ strncpy(info.name,"AKM AK4642en codec", sizeof(info.name));
+}
+
+void ak4642en_mixer_info_id_name(void)
+{
+ strncpy(old_info.id, "AK4642EN", sizeof(old_info.id));
+ strncpy(old_info.name,"AKM AK4642en codec", sizeof(old_info.name));
+}
+
+void set_ak4642en_volume(int val)
+{
+ if ( val == 0 )
+ codec_volume = 255;
+ else if ( val > 1 && val <= 10)
+ codec_volume = 92;
+ else if ( val > 10 && val <= 20 )
+ codec_volume = 67;
+ else if ( val > 20 && val <= 30 )
+ codec_volume = 50;
+ else if ( val > 30 && val <= 40 )
+ codec_volume = 40;
+ else if ( val > 40 && val <= 50 )
+ codec_volume = 30;
+ else if ( val > 50 && val <= 60 )
+ codec_volume = 22;
+ else if ( val > 60&& val <= 70 )
+ codec_volume = 15;
+ else if ( val > 70 && val <= 80 )
+ codec_volume = 8;
+ else if ( val > 80 && val <= 90 )
+ codec_volume = 4;
+ else if ( val > 90 && val <= 100 )
+ codec_volume = 2;
+
+ i2s_codec_write(0x0a, codec_volume);
+ i2s_codec_write(0x0d, codec_volume);
+}
+
+void set_ak4642en_mic(int val)
+{
+ int mic_gain;
+ mic_gain = 241 * val /100;
+ i2s_codec_write(0x09, mic_gain);
+ i2s_codec_write(0x0c, mic_gain);
+}
+
+void resume_ak4642en(void)
+{
+ __gpio_as_output(17);
+ __gpio_set_pin(17); //enable ak4642
+ __gpio_as_output(68);
+ __gpio_clear_pin(68);
+ __gpio_as_output(69);
+ __gpio_clear_pin(69);
+ __gpio_as_output(70);
+ __gpio_clear_pin(70);
+ __gpio_as_input(71);
+ __gpio_clear_pin(71);
+ __gpio_as_input(77);
+ __gpio_clear_pin(77);
+ __gpio_as_input(78);
+ __gpio_clear_pin(78);
+ REG_GPIO_GPALR(2) &= 0xC3FF0CFF;
+ REG_GPIO_GPALR(2) |= 0x14005000;
+ //set SCC clock initialization
+ REG_SCC1_CR(SCC1_BASE) = 0x00000000;
+ udelay(2);
+ REG_SCC1_CR(SCC1_BASE) |= 1 << 31;
+ udelay(2);
+ __gpio_as_output(I2S_PDN);
+ __gpio_set_pin(I2S_PDN);
+ udelay(5);
+ __gpio_clear_pin(I2S_PDN);
+ ndelay(300);//>150ns
+ __gpio_set_pin(I2S_PDN);
+ mdelay(1);
+ //set PLL Master mode
+ i2s_codec_write(0x01, 0x0008);//master
+ i2s_codec_write(0x04, 0x006b);//ref:12MHz;BITCLK:64fs;I2S compli
+ i2s_codec_write(0x05, 0x000b);//sync:48KHz;
+ i2s_codec_write(0x00, 0x0040);//PMVCM
+ i2s_codec_write(0x01, 0x0009);//master,PLL enable
+ jack_plug_level = 10;
+ old_level = 100;
+ spk_hp = 0;
+ __gpio_as_input(JACK_PLUG_PIN);
+ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN);
+ //i suppose jack_plug_lvel is 1 indicate with HPO
+ if(jack_plug_level > 1 || jack_plug_level <0)
+ printk("Audio ak4642en codec Jack plug level is wrong!\n");
+ if(jack_plug_level)
+ __gpio_as_irq_fall_edge(JACK_PLUG_PIN);
+ else
+ __gpio_as_irq_rise_edge(JACK_PLUG_PIN);
+
+ i2s_codec_write(0x00, 0x0065); //for resume power
+ i2s_codec_write(0x01, 0x0039); //for open pop noise
+ i2s_codec_write(0x01, 0x0079);
+ i2s_codec_write(0x0a, codec_volume);
+ i2s_codec_write(0x0d, codec_volume);
+}
+
+void suspend_ak4642en(int wr,int rd)
+{
+ if(wr) //playing
+ {
+ if(jack_plug_level == 0)
+ {
+ i2s_codec_write(0x01, 0x0039); // for close pop noise
+ mdelay(500);
+ i2s_codec_write(0x01, 0x0009); //PLL on I2S
+ i2s_codec_write(0x07, 0x0001);
+ i2s_codec_write(0x11, 0x0000);
+ i2s_codec_write(0x00, 0x0040);
+ i2s_codec_write(0x0f, 0x0008); // for open pop noise
+
+ }
+ else
+ {
+ //for Speaker output
+ i2s_codec_write(0x02, 0x0020);
+ i2s_codec_write(0x07, 0x0001);
+ i2s_codec_write(0x11, 0x0000);
+ i2s_codec_write(0x02, 0x0000);
+ i2s_codec_write(0x00, 0x0040); // for close pop noise
+ }
+ }
+
+ if(rd) // recording
+ {
+ i2s_codec_write(0x02, 0x0001); // 5-11 a1
+ i2s_codec_write(0x07, 0x0001);
+ i2s_codec_write(0x11, 0x0000);
+ mdelay(300);
+ }
+ __gpio_as_output(17);
+ __gpio_clear_pin(17);//disable ak4642
+ __i2s_disable();
+}
+
+static int __init init_ak4642en(void)
+{
+ set_codec_gpio_pin = set_ak4642en_gpio_pin;
+ each_time_init_codec = each_time_init_ak4642en;
+ clear_codec_mode = clear_ak4642en_mode;
+
+ set_codec_record = set_ak4642en_record;
+ set_codec_replay = set_ak4642en_replay;
+ set_replay_hp_or_speaker = set_ak4642en_replay;
+
+ set_codec_speed = set_ak4642en_speed;
+ clear_codec_record = clear_ak4642en_record;
+ clear_codec_replay = clear_ak4642en_replay;
+
+ codec_mixer_old_info_id_name = ak4642en_mixer_old_info_id_name;
+ codec_mixer_info_id_name = ak4642en_mixer_info_id_name;
+
+ set_codec_volume = set_ak4642en_volume;
+
+ set_codec_mic = set_ak4642en_mic;
+
+ i2s_resume_codec = resume_ak4642en;
+ i2s_suspend_codec = suspend_ak4642en;
+ printk("---> ak4642en initialization!\n");
+ return 0;
+}
+
+static void __exit cleanup_ak4642en(void)
+{
+ spk_hp = 0;
+ i2s_codec_write(0x01, 0x0008);//master,PLL disable
+ //free_irq(JACK_PLUG_IRQ, i2s_controller);
+ __gpio_clear_pin(I2S_PDN);
+ udelay(2);
+ REG_SCC1_CR(SCC1_BASE) &= 0 << 31;
+ udelay(2);
+}
+
+module_init(init_ak4642en);
+module_exit(cleanup_ak4642en);
diff --git a/sound/oss/jz_ac97.c b/sound/oss/jz_ac97.c
new file mode 100644
index 00000000000..698a003f17b
--- /dev/null
+++ b/sound/oss/jz_ac97.c
@@ -0,0 +1,2252 @@
+/*
+ * linux/drivers/sound/jz_ac97.c
+ *
+ * Jz On-Chip AC97 audio driver.
+ *
+ * Copyright (C) 2005 - 2007, Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Because the normal application of AUDIO devices are focused on Little_endian,
+ * then we only perform the little endian data format in driver.
+ *
+ */
+
+#define __NO_VERSION__
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/soundcard.h>
+#include <linux/ac97_codec.h>
+#include <asm/hardirq.h>
+#include <asm/jzsoc.h>
+//#include <asm/mach-jz4730/dma.h>
+#include "sound_config.h"
+
+#define DMA_ID_AC97_TX DMA_ID_AIC_TX
+#define DMA_ID_AC97_RX DMA_ID_AIC_RX
+
+/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
+#define NR_AC97 2
+
+#define STANDARD_SPEED 48000
+#define MAX_RETRY 100
+
+static unsigned int k_8000[] = {
+ 0, 42, 85, 128, 170, 213,
+};
+
+static unsigned int reload_8000[] = {
+ 1, 0, 0, 0, 0, 0,
+};
+
+static unsigned int k_11025[] = {
+ 0, 58, 117, 176, 234, 37, 96, 154,
+ 213, 16, 74, 133, 192, 250, 53, 112,
+ 170, 229, 32, 90, 149, 208, 10, 69,
+ 128, 186, 245, 48, 106, 165, 224, 26,
+ 85, 144, 202, 5, 64, 122, 181, 240,
+ 42, 101, 160, 218, 21, 80, 138, 197,
+};
+
+static unsigned int reload_11025[] = {
+ 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+};
+
+static unsigned int k_16000[] = {
+ 0, 85, 170,
+};
+
+static unsigned int reload_16000[] = {
+ 1, 0, 0,
+};
+
+static unsigned int k_22050[] = {
+ 0, 117, 234, 96, 213, 74, 192, 53,
+ 170, 32, 149, 10, 128, 245, 106, 224,
+ 85, 202, 64, 181, 42, 160, 21, 138,
+};
+
+static unsigned int reload_22050[] = {
+ 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+};
+
+static unsigned int k_24000[] = {
+ 0, 128,
+};
+
+static unsigned int reload_24000[] = {
+ 1, 0,
+};
+
+static unsigned int k_32000[] = {
+ 0, 170, 85,
+};
+
+static unsigned int reload_32000[] = {
+ 1, 0, 1,
+};
+
+static unsigned int k_44100[] = {
+ 0, 234, 213, 192, 170, 149, 128, 106,
+ 85, 64, 42, 21,
+};
+
+static unsigned int reload_44100[] = {
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static unsigned int k_48000[] = {
+ 0,
+};
+
+static unsigned int reload_48000[] = {
+ 1,
+};
+
+
+static unsigned int f_scale_counts[8] = {
+ 6, 48, 3, 24, 2, 3, 12, 1,
+};
+
+static int jz_audio_rate;
+static char jz_audio_format;
+static char jz_audio_channels;
+static int jz_audio_k; /* rate expand multiple */
+static int jz_audio_q; /* rate expand compensate */
+static int jz_audio_count; /* total count of voice data */
+static int last_jz_audio_count;
+
+static int jz_audio_fragments;//unused fragment amount
+static int jz_audio_fragstotal;
+static int jz_audio_fragsize;
+static int jz_audio_dma_tran_count;//bytes count of one DMA transfer
+
+static unsigned int f_scale_count;
+static unsigned int *f_scale_array;
+static unsigned int *f_scale_reload;
+static unsigned int f_scale_idx;
+
+static void (*old_mksound)(unsigned int hz, unsigned int ticks);
+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
+extern void jz_set_dma_block_size(int dmanr, int nbyte);
+extern void jz_set_dma_dest_width(int dmanr, int nbit);
+extern void jz_set_dma_src_width(int dmanr, int nbit);
+
+static void jz_update_filler(int bits, int channels);
+
+static void Init_In_Out_queue(int fragstotal,int fragsize);
+static void Free_In_Out_queue(int fragstotal,int fragsize);
+
+static irqreturn_t
+jz_ac97_replay_dma_irq(int irqnr, void *dev_id);
+static irqreturn_t
+jz_ac97_record_dma_irq(int irqnr, void *dev_id);
+
+static void
+(*replay_filler)(unsigned long src_start, int count, int id);
+static int
+(*record_filler)(unsigned long dst_start, int count, int id);
+
+static struct file_operations jz_ac97_audio_fops;
+
+DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue);
+DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue);
+
+struct jz_ac97_controller_info
+{
+ int io_base;
+ int dma1; /* play */
+ int dma2; /* record */
+
+ char *name;
+
+ int dev_audio;
+ struct ac97_codec *ac97_codec[NR_AC97];
+
+ unsigned short ac97_features;
+
+ int opened1;
+ int opened2;
+
+ unsigned char *tmp1; /* tmp buffer for sample conversions */
+ unsigned char *tmp2;
+
+ spinlock_t lock;
+ spinlock_t ioctllock;
+ wait_queue_head_t dac_wait;
+ wait_queue_head_t adc_wait;
+
+ int nextIn; // byte index to next-in to DMA buffer
+ int nextOut; // byte index to next-out from DMA buffer
+ int count; // current byte count in DMA buffer
+ int finish; // current transfered byte count in DMA buffer
+ unsigned total_bytes; // total bytes written or read
+ unsigned blocks;
+ unsigned error; // over/underrun
+
+ /* We use two devices, because we can do simultaneous play and record.
+ This keeps track of which device is being used for what purpose;
+ these are the actual device numbers. */
+ int dev_for_play;
+ int dev_for_record;
+
+ int playing;
+ int recording;
+ int patched;
+ unsigned long rec_buf_size;
+ unsigned long playback_buf_size;
+
+#ifdef CONFIG_PM
+ struct pm_dev *pm;
+#endif
+};
+
+static struct jz_ac97_controller_info *ac97_controller = NULL;
+
+static int jz_readAC97Reg(struct ac97_codec *dev, u8 reg);
+static int jz_writeAC97Reg(struct ac97_codec *dev, u8 reg, u16 data);
+static u16 ac97_codec_read(struct ac97_codec *codec, u8 reg);
+static void ac97_codec_write(struct ac97_codec *codec, u8 reg, u16 data);
+
+#define QUEUE_MAX 2
+
+typedef struct buffer_queue_s {
+ int count;
+ int *id;
+ spinlock_t lock;
+} buffer_queue_t;
+
+static unsigned long *out_dma_buf = NULL;
+static unsigned long *out_dma_pbuf = NULL;
+static unsigned long *out_dma_buf_data_count = NULL;
+static unsigned long *in_dma_buf = NULL;
+static unsigned long *in_dma_pbuf = NULL;
+static unsigned long *in_dma_buf_data_count = NULL;
+
+static buffer_queue_t out_empty_queue;
+static buffer_queue_t out_full_queue;
+static buffer_queue_t out_busy_queue;
+
+static buffer_queue_t in_empty_queue;
+static buffer_queue_t in_full_queue;
+static buffer_queue_t in_busy_queue;
+
+static int first_record_call = 0;
+
+static inline int get_buffer_id(struct buffer_queue_s *q)
+{
+ int r, i;
+ unsigned long flags;
+ spin_lock_irqsave(&q->lock, flags);
+ if (q->count == 0) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ return -1;
+ }
+ r = *(q->id + 0);
+ for (i=0;i < q->count-1;i++)
+ *(q->id + i) = *(q->id + (i+1));
+ q->count --;
+ spin_unlock_irqrestore(&q->lock, flags);
+ return r;
+}
+
+static inline void put_buffer_id(struct buffer_queue_s *q, int id)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&q->lock, flags);
+ *(q->id + q->count) = id;
+ q->count ++;
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+static inline int elements_in_queue(struct buffer_queue_s *q)
+{
+ int r;
+ unsigned long flags;
+ spin_lock_irqsave(&q->lock, flags);
+ r = q->count;
+ spin_unlock_irqrestore(&q->lock, flags);
+ return r;
+}
+
+/****************************************************************************
+ * Architecture related routines
+ ****************************************************************************/
+static inline
+void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode)
+{
+ unsigned long flags;
+ struct jz_ac97_controller_info * controller =
+ (struct jz_ac97_controller_info *) dev_id;
+ //for DSP_GETOPTR
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ jz_audio_dma_tran_count = count;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ flags = claim_dma_lock();
+ disable_dma(chan);
+ clear_dma_ff(chan);
+ set_dma_mode(chan, mode);
+ set_dma_addr(chan, phyaddr);
+ if (count == 0) {
+ count++;
+ printk(KERN_DEBUG "%s: JzSOC DMA controller can't set dma count zero!\n",
+ __FUNCTION__);
+ }
+ set_dma_count(chan, count);
+ enable_dma(chan);
+ release_dma_lock(flags);
+}
+
+static irqreturn_t
+jz_ac97_record_dma_irq (int irq, void *dev_id)
+{
+ struct jz_ac97_controller_info * controller =
+ (struct jz_ac97_controller_info *) dev_id;
+ int dma = controller->dma2;
+ int id1, id2;
+ unsigned long flags;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+
+ //for DSP_GETIPTR
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ id1 = get_buffer_id(&in_busy_queue);
+ put_buffer_id(&in_full_queue, id1);
+ wake_up(&rx_wait_queue);
+ wake_up(&controller->adc_wait);
+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id2);
+
+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1);
+ audio_start_dma(dma,dev_id,
+ *(in_dma_pbuf + id2),
+ *(in_dma_buf_data_count + id2),
+ DMA_MODE_READ);
+ } else {
+ in_busy_queue.count = 0;
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+jz_ac97_replay_dma_irq (int irq, void *dev_id)
+{
+ struct jz_ac97_controller_info * controller =
+ (struct jz_ac97_controller_info *) dev_id;
+ int dma = controller->dma1, id;
+ unsigned long flags;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+ //for DSP_GETOPTR
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ if ((id = get_buffer_id(&out_busy_queue)) < 0) {
+ printk(KERN_DEBUG "Strange DMA finish interrupt for AC97 module\n");
+ }
+
+ put_buffer_id(&out_empty_queue, id);
+ if ((id = get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ }
+ } else {
+ out_busy_queue.count = 0;
+ }
+ if (elements_in_queue(&out_empty_queue) > 0) {
+ wake_up(&tx_wait_queue);
+ wake_up(&controller->dac_wait);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+/*
+ * Initialize the onchip AC97 controller
+ */
+static void jz_ac97_initHw(struct jz_ac97_controller_info *controller)
+{
+ __ac97_disable();
+ __ac97_reset();
+ __ac97_enable();
+
+ __ac97_cold_reset_codec();
+ /* wait for a long time to let ac97 controller reset completely,
+ * otherwise, registers except ACFR will be clear by reset, can't be
+ * set correctly.
+ */
+ udelay(160);
+
+ __ac97_disable_record();
+ __ac97_disable_replay();
+ __ac97_disable_loopback();
+
+ /* Check the trigger threshold reset value to detect version */
+ if (((REG_AIC_FR & AIC_FR_TFTH_MASK) >> AIC_FR_TFTH_BIT) == 8) {
+ printk("JzAC97: patched controller detected.\n");
+ controller->patched = 1;
+ } else {
+ printk("JzAC97: standard controller detected.\n");
+ controller->patched = 0;
+ }
+
+ /* Set FIFO data size. Which shows valid data bits.
+ *
+ */
+ __ac97_set_oass(8);
+ __ac97_set_iass(8);
+
+ __ac97_set_xs_stereo();
+ __ac97_set_rs_stereo();
+}
+
+/*
+ * Initialize all of in(out)_empty_queue value
+ */
+static void Init_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+ if(out_dma_buf || in_dma_buf)
+ return;
+ in_empty_queue.count = fragstotal;
+ out_empty_queue.count = fragstotal;
+
+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_buf)
+ goto all_mem_err;
+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_pbuf)
+ goto all_mem_err;
+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_buf_data_count)
+ goto all_mem_err;
+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf)
+ goto all_mem_err;
+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_pbuf)
+ goto all_mem_err;
+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf_data_count)
+ goto all_mem_err;
+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_empty_queue.id)
+ goto all_mem_err;
+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_full_queue.id)
+ goto all_mem_err;
+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_busy_queue.id)
+ goto all_mem_err;
+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_empty_queue.id)
+ goto all_mem_err;
+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_full_queue.id)
+ goto all_mem_err;
+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_busy_queue.id)
+ goto all_mem_err;
+
+ for (i=0;i < fragstotal;i++) {
+ *(in_empty_queue.id + i) = i;
+ *(out_empty_queue.id + i) = i;
+ }
+
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ /*alloc DMA buffer*/
+ for (i = 0; i < jz_audio_fragstotal; i++) {
+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(out_dma_buf + i) == 0) {
+ printk(" can't allocate required DMA(OUT) buffers.\n");
+ goto mem_failed_out;
+ }
+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i)));
+ }
+
+ for (i = 0; i < jz_audio_fragstotal; i++) {
+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(in_dma_buf + i) == 0) {
+ printk(" can't allocate required DMA(IN) buffers.\n");
+ goto mem_failed_in;
+ }
+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i)));
+ dma_cache_wback_inv(*(in_dma_buf + i), 4096*8);//fragsize
+ *(in_dma_buf + i) = KSEG1ADDR(*(in_dma_buf + i));
+ }
+ return ;
+
+ all_mem_err:
+ printk("error:allocate memory occur error!\n");
+ return ;
+
+mem_failed_out:
+
+ for (i = 0; i < jz_audio_fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ }
+ return ;
+
+mem_failed_in:
+
+ for (i = 0; i < jz_audio_fragstotal; i++) {
+ if(*(in_dma_buf + i))
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ return ;
+
+}
+static void Free_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+ if(out_dma_buf != NULL)
+ {
+ for (i = 0; i < jz_audio_fragstotal; i++)
+ {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ *(out_dma_buf + i) = 0;
+ }
+ kfree(out_dma_buf);
+ out_dma_buf = NULL;
+ }
+ if(out_dma_pbuf)
+ {
+ kfree(out_dma_pbuf);
+ out_dma_pbuf = NULL;
+ }
+ if(out_dma_buf_data_count)
+ {
+ kfree(out_dma_buf_data_count);
+ out_dma_buf_data_count = NULL;
+ }
+ if(in_dma_buf)
+ {
+ for (i = 0; i < jz_audio_fragstotal; i++)
+ {
+ if(*(in_dma_buf + i))
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ *(in_dma_buf + i) = 0;
+ }
+ kfree(in_dma_buf);
+ in_dma_buf = NULL;
+ }
+ if(in_dma_pbuf)
+ {
+ kfree(in_dma_pbuf);
+ in_dma_pbuf = NULL;
+ }
+ if(in_dma_buf_data_count)
+ {
+ kfree(in_dma_buf_data_count);
+ in_dma_buf_data_count = NULL;
+ }
+ if(in_empty_queue.id)
+ {
+ kfree(in_empty_queue.id);
+ in_empty_queue.id = NULL;
+ }
+ if(in_full_queue.id)
+ {
+ kfree(in_full_queue.id);
+ in_full_queue.id = NULL;
+ }
+ if(in_busy_queue.id)
+ {
+ kfree(in_busy_queue.id);
+ in_busy_queue.id = NULL;
+ }
+ if(out_empty_queue.id)
+ {
+ kfree(out_empty_queue.id);
+ out_empty_queue.id = NULL;
+ }
+ if(out_full_queue.id)
+ {
+ kfree(out_full_queue.id);
+ out_full_queue.id = NULL;
+ }
+ if(out_busy_queue.id)
+ {
+ kfree(out_busy_queue.id);
+ out_busy_queue.id = NULL;
+ }
+
+ in_empty_queue.count = fragstotal;
+ out_empty_queue.count = fragstotal;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ return ;
+}
+
+/*
+ * Reset everything
+ */
+static void
+jz_ac97_full_reset(struct jz_ac97_controller_info *controller)
+{
+ jz_ac97_initHw(controller);
+}
+
+
+static void
+jz_ac97_mksound(unsigned int hz, unsigned int ticks)
+{
+// printk("BEEP - %d %d!\n", hz, ticks);
+}
+
+static int jz_audio_set_speed(int dev, int rate)
+{
+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */
+ u32 dacp;
+ struct ac97_codec *codec=ac97_controller->ac97_codec[0];
+
+ if (rate > 48000)
+ rate = 48000;
+ if (rate < 8000)
+ rate = 8000;
+
+
+ /* Power down the DAC */
+ dacp=ac97_codec_read(codec, AC97_POWER_CONTROL);
+ ac97_codec_write(codec, AC97_POWER_CONTROL, dacp|0x0200);
+ /* Load the rate; only 48Khz playback available, read always zero */
+ if ((ac97_controller->patched) && (ac97_controller->ac97_features & 1))
+ ac97_codec_write(codec, AC97_PCM_FRONT_DAC_RATE, rate);
+ else
+ ac97_codec_write(codec, AC97_PCM_FRONT_DAC_RATE, 48000);
+
+ /* Power it back up */
+ ac97_codec_write(codec, AC97_POWER_CONTROL, dacp);
+
+ jz_audio_rate = rate;
+ jz_audio_k = STANDARD_SPEED / rate;
+ if (rate * jz_audio_k != STANDARD_SPEED)
+ jz_audio_q = rate / ((STANDARD_SPEED / jz_audio_k) - rate );
+ else
+ jz_audio_q = 0x1fffffff; /* a very big value, don't compensate */
+
+ switch (rate) {
+ case 8000:
+ f_scale_count = f_scale_counts[0];
+ f_scale_array = k_8000;
+ f_scale_reload = reload_8000;
+ break;
+ case 11025:
+ f_scale_count = f_scale_counts[1];
+ f_scale_array = k_11025;
+ f_scale_reload = reload_11025;
+ break;
+ case 16000:
+ f_scale_count = f_scale_counts[2];
+ f_scale_array = k_16000;
+ f_scale_reload = reload_16000;
+ break;
+ case 22050:
+ f_scale_count = f_scale_counts[3];
+ f_scale_array = k_22050;
+ f_scale_reload = reload_22050;
+ break;
+ case 24000:
+ f_scale_count = f_scale_counts[4];
+ f_scale_array = k_24000;
+ f_scale_reload = reload_24000;
+ break;
+ case 32000:
+ f_scale_count = f_scale_counts[5];
+ f_scale_array = k_32000;
+ f_scale_reload = reload_32000;
+ break;
+ case 44100:
+ f_scale_count = f_scale_counts[6];
+ f_scale_array = k_44100;
+ f_scale_reload = reload_44100;
+ break;
+ case 48000:
+ f_scale_count = f_scale_counts[7];
+ f_scale_array = k_48000;
+ f_scale_reload = reload_48000;
+ break;
+ }
+ f_scale_idx = 0;
+
+ return jz_audio_rate;
+}
+
+static int record_fill_1x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned char data;
+ volatile unsigned char *s = (unsigned char *)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char *)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ if ((jz_audio_count++ % jz_audio_k) == 0) {
+ cnt++;
+ data = *(s++);
+ *(dp ++) = data + 0x80;
+ s++; /* skip the other channel */
+ } else {
+ s += 2; /* skip the redundancy */
+ }
+ if (jz_audio_count - last_jz_audio_count >= jz_audio_q) {
+ jz_audio_count++;
+ last_jz_audio_count = jz_audio_count;
+ count -= 2;
+ s += 2;
+ }
+ }
+ return cnt;
+}
+
+static int record_fill_2x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned char d1, d2;
+ volatile unsigned char *s = (unsigned char *)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char *)dst_start;
+
+ while (count > 0) {
+ count -= 2;
+ if ((jz_audio_count++ % jz_audio_k) == 0) {
+ cnt += 2;
+ d1 = *(s++);
+ *(dp ++) = d1 + 0x80;
+ d2 = *(s++);
+ *(dp ++) = d2 + 0x80;
+ } else {
+ s += 2; /* skip the redundancy */
+ }
+ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 2) {
+ jz_audio_count += 2;
+ last_jz_audio_count = jz_audio_count;
+ count -= 2;
+ s += 2;
+ }
+ }
+ return cnt;
+}
+
+static int record_fill_1x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned short d1;
+ unsigned short *s = (unsigned short *)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ if ((jz_audio_count++ % jz_audio_k) == 0) {
+ cnt += 2; /* count in byte */
+ d1 = *(s++);
+ *(dp ++) = d1;
+ s++; /* skip the other channel */
+ } else {
+ s += 2; /* skip the redundancy */
+ }
+ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 2) {
+ jz_audio_count += 2;
+ last_jz_audio_count = jz_audio_count;
+ count -= 2;
+ s += 2;
+ }
+ }
+ return cnt;
+}
+
+static int record_fill_2x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned short d1, d2;
+ unsigned short *s = (unsigned short *)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ if ((jz_audio_count++ % jz_audio_k) == 0) {
+ cnt += 4; /* count in byte */
+ d1 = *(s++);
+ *(dp ++) = d1;
+ d2 = *(s++);
+ *(dp ++) = d2;
+ } else
+ s += 2; /* skip the redundancy */
+
+ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 4) {
+ jz_audio_count += 4;
+ last_jz_audio_count = jz_audio_count;
+ count -= 2;
+ s += 2;
+ }
+ }
+ return cnt;
+}
+
+
+static void replay_fill_1x8_u(unsigned long src_start, int count, int id)
+{
+ int i, cnt = 0;
+ unsigned char data;
+ unsigned char *s = (unsigned char *)src_start;
+ unsigned char *dp = (unsigned char *)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count--;
+ jz_audio_count++;
+ cnt += jz_audio_k;
+ data = *(s++) - 0x80;
+ for (i=0;i<jz_audio_k;i++) {
+ *(dp ++) = data;
+ *(dp ++) = data;
+ }
+ }
+ cnt = cnt * 2;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static void replay_fill_2x8_u(unsigned long src_start, int count, int id)
+{
+ int i, cnt = 0;
+ unsigned char d1, d2;
+ unsigned char *s = (unsigned char *)src_start;
+ unsigned char *dp = (unsigned char*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count -= 2;
+ jz_audio_count += 2;
+ cnt += 2 * jz_audio_k;
+ d1 = *(s++) - 0x80;
+ d2 = *(s++) - 0x80;
+ for (i=0;i<jz_audio_k;i++) {
+ *(dp ++) = d1;
+ *(dp ++) = d2;
+ }
+ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 2) {
+ cnt += 2 * jz_audio_k;
+ last_jz_audio_count = jz_audio_count;
+ for (i=0;i<jz_audio_k;i++) {
+ *(dp ++) = d1;
+ *(dp ++) = d2;
+ }
+ }
+ }
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static void replay_fill_1x16_s(unsigned long src_start, int count, int id)
+{
+ int cnt = 0;
+ static short d1, d2, d;
+ short *s = (short *)src_start;
+ short *dp = (short *)(*(out_dma_buf + id));
+
+ d2 = *s++;
+ count -= 2;
+ while (count >= 0) {
+ if (f_scale_reload[f_scale_idx]) {
+ d1 = d2;
+ d2 = *s++;
+ if (!count)
+ break;
+ count -= 2;
+ }
+ d = d1 + (((d2 - d1) * f_scale_array[f_scale_idx]) >> 8);
+ *dp++ = d;
+ *dp++ = d;
+ cnt += 4;
+ f_scale_idx ++;
+ if (f_scale_idx >= f_scale_count)
+ f_scale_idx = 0;
+ }
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static void replay_fill_2x16_s(unsigned long src_start, int count, int id)
+{
+ int cnt = 0;
+ static short d11, d12, d21, d22, d1, d2;
+ short *s = (short *)src_start;
+ short *dp = (short *)(*(out_dma_buf + id));
+
+ d12 = *s++;
+ d22 = *s++;
+ count -= 4;
+ while (count >= 0) {
+ register unsigned int kvalue;
+ kvalue = f_scale_array[f_scale_idx];
+ if (f_scale_reload[f_scale_idx]) {
+ d11 = d12;
+ d12 = *s++;
+ d21 = d22;
+ d22 = *s++;
+ if (!count)
+ break;
+ count -= 4;
+ }
+ d1 = d11 + (((d12 - d11)*kvalue) >> 8);
+ d2 = d21 + (((d22 - d21)*kvalue) >> 8);
+ *dp++ = d1;
+ *dp++ = d2;
+ cnt += 4;
+ f_scale_idx ++;
+ if (f_scale_idx >= f_scale_count)
+ f_scale_idx = 0;
+ }
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static unsigned int jz_audio_set_format(int dev, unsigned int fmt)
+{
+ switch (fmt) {
+ case AFMT_U8:
+ case AFMT_S16_LE:
+ jz_audio_format = fmt;
+ jz_update_filler(fmt, jz_audio_channels);
+ case AFMT_QUERY:
+ break;
+ }
+ return jz_audio_format;
+}
+
+static short jz_audio_set_channels(int dev, short channels)
+{
+ switch (channels) {
+ case 1:
+ __ac97_set_xs_stereo(); // always stereo when recording
+ __ac97_set_rs_stereo(); // always stereo when recording
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+ break;
+ case 2:
+ __ac97_set_xs_stereo();
+ __ac97_set_rs_stereo();
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+ break;
+ case 0:
+ break;
+ }
+ return jz_audio_channels;
+}
+
+
+static void jz_audio_reset(void)
+{
+ __ac97_disable_replay();
+ __ac97_disable_receive_dma();
+ __ac97_disable_record();
+ __ac97_disable_transmit_dma();
+}
+
+static int jz_audio_release(struct inode *inode, struct file *file);
+static int jz_audio_open(struct inode *inode, struct file *file);
+static int jz_audio_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+static unsigned int jz_audio_poll(struct file *file,
+ struct poll_table_struct *wait);
+static ssize_t jz_audio_write(struct file *file, const char *buffer,
+ size_t count, loff_t *ppos);
+static ssize_t jz_audio_read(struct file *file, char *buffer,
+ size_t count, loff_t *ppos);
+
+/* static struct file_operations jz_ac97_audio_fops */
+static struct file_operations jz_ac97_audio_fops =
+{
+ owner: THIS_MODULE,
+ open: jz_audio_open,
+ release: jz_audio_release,
+ write: jz_audio_write,
+ read: jz_audio_read,
+ poll: jz_audio_poll,
+ ioctl: jz_audio_ioctl
+};
+
+/* Read / Write AC97 codec registers */
+static inline int jz_out_command_ready(void)
+{
+ int t2 = 1000;
+ int done = 0;
+
+ while (! done && t2-- > 0) {
+ if (REG32(AC97_ACSR) & AIC_ACSR_CADT) {
+ REG32(AC97_ACSR) &= ~AIC_ACSR_CADT;
+ done = 1;
+ }
+ else
+ udelay (1);
+ }
+ return done;
+}
+
+static inline int jz_in_status_ready(void)
+{
+ int t2 = 1000;
+ int done = 0;
+
+ while (! done && t2-- > 0) {
+ if (REG32(AC97_ACSR) & AIC_ACSR_SADR) {
+ REG32(AC97_ACSR) &= ~AIC_ACSR_SADR;
+ done = 1;
+ }
+ else {
+ if (REG32(AC97_ACSR) & AIC_ACSR_RSTO) {
+ REG32(AC97_ACSR) &= ~AIC_ACSR_RSTO;
+ printk(KERN_DEBUG "%s: RSTO receive status timeout.\n",
+ __FUNCTION__);
+ done = 0;
+ break;
+ }
+ udelay (1);
+ }
+ }
+ return done;
+}
+
+static int jz_readAC97Reg (struct ac97_codec *dev, u8 reg)
+{
+ u16 value;
+
+ if (reg < 128) {
+ u8 ret_reg;
+ __ac97_out_rcmd_addr(reg);//output read addr
+ if (jz_out_command_ready())//judge if send completely?
+ while (jz_in_status_ready()) {//judge if receive completely?
+ ret_reg = __ac97_in_status_addr();//slot1:send addr
+ value = __ac97_in_data();
+ if (ret_reg == reg)
+ return value;
+ else {
+// printk(KERN_DEBUG "%s: index (0x%02x)->(0x%02x) 0x%x\n", __FUNCTION__, reg, ret_reg, value);
+ return -EINVAL;
+ }
+ }
+ }
+ value = __ac97_in_data();
+ printk (KERN_DEBUG "timeout while reading AC97 codec (0x%x)\n", reg);
+ return -EINVAL;
+}
+
+static u16 ac97_codec_read(struct ac97_codec *codec, u8 reg)
+{
+ int res = jz_readAC97Reg(codec, reg);
+ int count = 0;
+ while (res == -EINVAL) {
+ udelay(1000);
+ __ac97_warm_reset_codec();
+ udelay(1000);
+ res = jz_readAC97Reg(codec, reg);
+ count ++;
+ if (count > MAX_RETRY){
+ printk(KERN_WARNING"After try %d when read AC97 codec 0x%x, can't success, give up operate!!\n",
+ MAX_RETRY, reg);
+ break;
+ }
+ }
+ return (u16)res;
+}
+
+static int jz_writeAC97Reg (struct ac97_codec *dev, u8 reg, u16 value)
+{
+ //unsigned long flags;
+ int done = 0;
+
+ //save_and_cli(flags);
+
+ __ac97_out_wcmd_addr(reg);
+ __ac97_out_data(value);
+ if (jz_out_command_ready())
+ done = 1;
+ else
+ printk (KERN_DEBUG "Tiemout AC97 codec write (0x%X<==0x%X)\n", reg, value);
+ //restore_flags(flags);
+ return done;
+}
+static void ac97_codec_write(struct ac97_codec *codec, u8 reg, u16 data)
+{
+ int done = jz_writeAC97Reg(codec, reg, data);
+ int count = 0;
+ while (done == 0) {
+ count ++;
+ udelay (2000);
+ __ac97_warm_reset_codec();
+ udelay(2000);
+ done = jz_writeAC97Reg(codec, reg, data);
+ if ( count > MAX_RETRY ){
+ printk (KERN_DEBUG " After try %d when write AC97 codec (0x%x), can't sucess, give up!! \n",
+ MAX_RETRY, reg);
+ break;
+ }
+ }
+}
+
+/* OSS /dev/mixer file operation methods */
+
+static int jz_ac97_open_mixdev(struct inode *inode, struct file *file)
+{
+ int i;
+ int minor = MINOR(inode->i_rdev);
+ struct jz_ac97_controller_info *controller = ac97_controller;
+
+ for (i = 0; i < NR_AC97; i++)
+ if (controller->ac97_codec[i] != NULL &&
+ controller->ac97_codec[i]->dev_mixer == minor)
+ goto match;
+
+ if (!controller)
+ return -ENODEV;
+
+ match:
+ file->private_data = controller->ac97_codec[i];
+
+ return 0;
+}
+
+static int jz_ac97_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+
+ return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static loff_t jz_ac97_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static /*const*/ struct file_operations jz_ac97_mixer_fops = {
+ owner: THIS_MODULE,
+ llseek: jz_ac97_llseek,
+ ioctl: jz_ac97_ioctl_mixdev,
+ open: jz_ac97_open_mixdev,
+};
+
+/* AC97 codec initialisation. */
+static int __init jz_ac97_codec_init(struct jz_ac97_controller_info *controller)
+{
+ int num_ac97 = 0;
+ int ready_2nd = 0;
+ struct ac97_codec *codec;
+ unsigned short eid;
+ int i = 0;
+
+ if (__ac97_codec_is_low_power_mode()) {
+ printk(KERN_DEBUG "AC97 codec is low power mode, warm reset ...\n");
+ __ac97_warm_reset_codec();
+ udelay(10);
+ }
+ i = 0;
+ while (!__ac97_codec_is_ready()) {
+ i++;
+ if ( i > 100 ) {
+ printk(KERN_WARNING "AC97 codec not ready, failed init ..\n");
+ return -ENODEV;
+ }
+ udelay(10);
+ }
+ i = 0;
+
+ /* Reset the mixer. */
+ for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+ if ((codec = kmalloc(sizeof(struct ac97_codec),
+ GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset(codec, 0, sizeof(struct ac97_codec));
+
+ /* initialize some basic codec information,
+ other fields will be filled
+ in ac97_probe_codec */
+ codec->private_data = controller;
+ codec->id = num_ac97;
+
+ codec->codec_read = ac97_codec_read;
+ codec->codec_write = ac97_codec_write;
+
+ if (ac97_probe_codec(codec) == 0)
+ break;
+
+ eid = ac97_codec_read(codec, AC97_EXTENDED_ID);
+ if (eid == 0xFFFF) {
+ printk(KERN_WARNING "Jz AC97: no codec attached?\n");
+ kfree(codec);
+ break;
+ }
+
+ controller->ac97_features = eid;
+
+ if (!(eid & 0x0001))
+ printk(KERN_WARNING "AC97 codec: only 48Khz playback available.\n");
+ else {
+ printk(KERN_WARNING "AC97 codec: supports variable sample rate.\n");
+ /* Enable HPEN: UCB1400 only */
+ ac97_codec_write(codec, 0x6a,
+ ac97_codec_read(codec, 0x6a) | 0x40);
+
+ /* Enable variable rate mode */
+ ac97_codec_write(codec, AC97_EXTENDED_STATUS, 9);
+ ac97_codec_write(codec,
+ AC97_EXTENDED_STATUS,
+ ac97_codec_read(codec, AC97_EXTENDED_STATUS) | 0xE800);
+ /* power up everything, modify this
+ when implementing power saving */
+ ac97_codec_write(codec,
+ AC97_POWER_CONTROL,
+ ac97_codec_read(codec, AC97_POWER_CONTROL) & ~0x7f00);
+ /* wait for analog ready */
+ for (i=10; i && ((ac97_codec_read(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) {
+// current->state = TASK_UNINTERRUPTIBLE;
+// schedule_timeout(HZ/20);
+ }
+
+ if (!(ac97_codec_read(codec, AC97_EXTENDED_STATUS) & 1)) {
+ printk(KERN_WARNING "Jz AC97: Codec refused to allow VRA, using 48Khz only.\n");
+ controller->ac97_features &= ~1;
+ }
+ }
+
+ if ((codec->dev_mixer =
+ register_sound_mixer(&jz_ac97_mixer_fops, -1)) < 0) {
+ printk(KERN_ERR "Jz AC97: couldn't register mixer!\n");
+ kfree(codec);
+ break;
+ }
+
+ controller->ac97_codec[num_ac97] = codec;
+
+ /* if there is no secondary codec at all, don't probe any more */
+ if (!ready_2nd)
+ return num_ac97+1;
+ }
+ return num_ac97;
+}
+
+static void jz_update_filler(int format, int channels)
+{
+#define TYPE(fmt,ch) (((fmt)<<3) | ((ch)&7)) /* up to 8 chans supported. */
+
+
+ switch (TYPE(format, channels)) {
+ default:
+
+ case TYPE(AFMT_U8, 1):
+ if ((ac97_controller->patched) &&
+ (ac97_controller->ac97_features & 1)) {
+ __aic_enable_mono2stereo();
+ __aic_enable_unsignadj();
+ jz_set_dma_block_size(ac97_controller->dma1, 16);
+ jz_set_dma_block_size(ac97_controller->dma2, 16);
+ } else {
+ __aic_disable_mono2stereo();
+ __aic_disable_unsignadj();
+ jz_set_dma_block_size(ac97_controller->dma1, 4);
+ jz_set_dma_block_size(ac97_controller->dma2, 4);
+ }
+ replay_filler = replay_fill_1x8_u;
+ record_filler = record_fill_1x8_u;
+ __ac97_set_oass(8);
+ __ac97_set_iass(8);
+ jz_set_dma_dest_width(ac97_controller->dma1, 8);
+ jz_set_dma_src_width(ac97_controller->dma2, 8);
+ break;
+ case TYPE(AFMT_U8, 2):
+ if ((ac97_controller->patched) &&
+ (ac97_controller->ac97_features & 1)) {
+ __aic_enable_mono2stereo();
+ __aic_enable_unsignadj();
+ jz_set_dma_block_size(ac97_controller->dma1, 16);
+ jz_set_dma_block_size(ac97_controller->dma2, 16);
+ } else {
+ __aic_disable_mono2stereo();
+ __aic_disable_unsignadj();
+ jz_set_dma_block_size(ac97_controller->dma1, 4);
+ jz_set_dma_block_size(ac97_controller->dma2, 4);
+ }
+ replay_filler = replay_fill_2x8_u;
+ record_filler = record_fill_2x8_u;
+ __ac97_set_oass(8);
+ __ac97_set_iass(8);
+ jz_set_dma_dest_width(ac97_controller->dma1, 8);
+ jz_set_dma_src_width(ac97_controller->dma2, 8);
+ break;
+ case TYPE(AFMT_S16_LE, 1):
+ if ((ac97_controller->patched) &&
+ (ac97_controller->ac97_features & 1)) {
+ __aic_enable_mono2stereo();
+ jz_set_dma_block_size(ac97_controller->dma1, 16);
+ jz_set_dma_block_size(ac97_controller->dma2, 16);
+ } else {
+ __aic_disable_mono2stereo();
+ jz_set_dma_block_size(ac97_controller->dma1, 4);
+ jz_set_dma_block_size(ac97_controller->dma2, 4);
+ }
+ __aic_disable_unsignadj();
+ replay_filler = replay_fill_1x16_s;
+ record_filler = record_fill_1x16_s;
+ __ac97_set_oass(16);
+ __ac97_set_iass(16);
+
+ jz_set_dma_dest_width(ac97_controller->dma1, 16);
+ jz_set_dma_src_width(ac97_controller->dma2, 16);
+
+ break;
+
+ case TYPE(AFMT_S16_LE, 2):
+ if ((ac97_controller->patched) &&
+ (ac97_controller->ac97_features & 1)) {
+ jz_set_dma_block_size(ac97_controller->dma1, 16);
+ jz_set_dma_block_size(ac97_controller->dma2, 16);
+ } else {
+ jz_set_dma_block_size(ac97_controller->dma1, 4);
+ jz_set_dma_block_size(ac97_controller->dma2, 4);
+ }
+ __aic_disable_mono2stereo();
+ __aic_disable_unsignadj();
+ replay_filler = replay_fill_2x16_s;
+ record_filler = record_fill_2x16_s;
+ __ac97_set_oass(16);
+ __ac97_set_iass(16);
+ jz_set_dma_dest_width(ac97_controller->dma1, 16);
+ jz_set_dma_src_width(ac97_controller->dma2, 16);
+ break;
+ }
+}
+
+#ifdef CONFIG_PROC_FS
+
+extern struct proc_dir_entry *proc_jz_root;
+
+static int jz_ac97_init_proc(struct jz_ac97_controller_info *controller)
+{
+ if (!create_proc_read_entry ("ac97", 0, proc_jz_root,
+ ac97_read_proc, controller->ac97_codec[0]))
+ return -EIO;
+
+ return 0;
+}
+
+static void jz_ac97_cleanup_proc(struct jz_ac97_controller_info *controller)
+{
+}
+
+#endif
+
+static void __init attach_jz_ac97(struct jz_ac97_controller_info *controller)
+{
+ char *name;
+ int adev;
+
+ name = controller->name;
+ jz_ac97_initHw(controller);
+
+ /* register /dev/audio ? */
+ adev = register_sound_dsp(&jz_ac97_audio_fops, -1);
+ if (adev < 0)
+ goto audio_failed;
+
+ /* initialize AC97 codec and register /dev/mixer */
+ if (jz_ac97_codec_init(controller) <= 0)
+ goto mixer_failed;
+
+#ifdef CONFIG_PROC_FS
+ if (jz_ac97_init_proc(controller) < 0) {
+ printk(KERN_ERR "%s: can't create AC97 proc filesystem.\n", name);
+ goto proc_failed;
+ }
+#endif
+
+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8);//4
+ if (!controller->tmp1) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp1_failed;
+ }
+
+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8);//4
+ if (!controller->tmp2) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp2_failed;
+ }
+
+ if ((controller->dma1 = jz_request_dma(DMA_ID_AC97_TX, "audio dac",
+ jz_ac97_replay_dma_irq,
+ IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name);
+ goto dma1_failed;
+ }
+ if ((controller->dma2 = jz_request_dma(DMA_ID_AC97_RX, "audio adc",
+ jz_ac97_record_dma_irq,
+ IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name);
+ goto dma2_failed;
+ }
+
+ printk("Jz On-Chip AC97 controller registered (DAC: DMA%d/IRQ%d, ADC: DMA%d/IRQ%d)\n",
+ controller->dma1, get_dma_done_irq(controller->dma1),
+ controller->dma2, get_dma_done_irq(controller->dma2));
+
+ old_mksound = kd_mksound; /* see vt.c */
+ kd_mksound = jz_ac97_mksound;
+ controller->dev_audio = adev;
+ return;
+
+ dma2_failed:
+ jz_free_dma(controller->dma1);
+ dma1_failed:
+ free_pages((unsigned long)controller->tmp2, 8);//4
+ tmp2_failed:
+ free_pages((unsigned long)controller->tmp1, 8);//4
+ tmp1_failed:
+#ifdef CONFIG_PROC_FS
+ jz_ac97_cleanup_proc(controller);
+#endif
+ proc_failed:
+ /* unregister mixer dev */
+ mixer_failed:
+ unregister_sound_dsp(adev);
+ audio_failed:
+ return;
+}
+
+static int __init probe_jz_ac97(struct jz_ac97_controller_info **controller)
+{
+ if ((*controller = kmalloc(sizeof(struct jz_ac97_controller_info),
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_ERR "Jz AC97 Controller: out of memory.\n");
+ return -ENOMEM;
+ }
+ memset( *controller, 0, sizeof(struct jz_ac97_controller_info) );
+ (*controller)->name = "Jz AC97 controller";
+ (*controller)->opened1 = 0;
+ (*controller)->opened2 = 0;
+
+ init_waitqueue_head(&(*controller)->adc_wait);
+ init_waitqueue_head(&(*controller)->dac_wait);
+ spin_lock_init(&(*controller)->lock);
+ init_waitqueue_head(&rx_wait_queue);
+ init_waitqueue_head(&tx_wait_queue);
+
+ return 0;
+}
+
+static void __exit unload_jz_ac97(struct jz_ac97_controller_info *controller)
+{
+ int adev = controller->dev_audio;
+
+ jz_ac97_full_reset (controller);
+
+ controller->dev_audio = -1;
+
+ if (old_mksound)
+ kd_mksound = old_mksound; /* Our driver support bell for kb, see vt.c */
+
+#ifdef CONFIG_PROC_FS
+ jz_ac97_cleanup_proc(controller);
+#endif
+
+ jz_free_dma(controller->dma1);
+ jz_free_dma(controller->dma2);
+
+ free_pages((unsigned long)controller->tmp1, 8);//4
+ free_pages((unsigned long)controller->tmp2, 8);//4
+
+ if (adev >= 0) {
+ //unregister_sound_mixer(audio_devs[adev]->mixer_dev);
+ unregister_sound_dsp(controller->dev_audio);
+ }
+}
+
+#ifdef CONFIG_PM
+
+static int reserve_mastervol, reserve_micvol;
+static int reserve_power1, reserve_power2;
+static int reserve_power3, reserve_power4;
+static int reserve_power5, reserve_power6;
+
+static int jz_ac97_suspend(struct jz_ac97_controller_info *controller, int state)
+{
+ struct ac97_codec *codec = controller->ac97_codec[0];
+
+ /* save codec states */
+ reserve_mastervol = ac97_codec_read(codec, 0x0002);
+ reserve_micvol = ac97_codec_read(codec, 0x000e);
+
+ reserve_power1 = ac97_codec_read(codec, 0x0026);
+ reserve_power2 = ac97_codec_read(codec, 0x006c);
+ reserve_power3 = ac97_codec_read(codec, 0x005c);
+ reserve_power4 = ac97_codec_read(codec, 0x0064);
+ reserve_power5 = ac97_codec_read(codec, 0x0066);
+ reserve_power6 = ac97_codec_read(codec, 0x006a);
+
+ /* put codec into power-saving mode */
+ ac97_codec_write(codec, 0x5c, 0xffff);
+ ac97_codec_write(codec, 0x64, 0x0000);
+ ac97_codec_write(codec, 0x66, 0x0000);
+ ac97_codec_write(codec, 0x6a, 0x0000);
+
+ ac97_codec_write(codec, 0x6c, 0x0030);
+ ac97_codec_write(codec, 0x26, 0x3b00);
+
+ ac97_save_state(codec);
+ __ac97_disable();
+
+ return 0;
+}
+
+static int jz_ac97_resume(struct jz_ac97_controller_info *controller)
+{
+ struct ac97_codec *codec = controller->ac97_codec[0];
+
+ jz_ac97_full_reset(controller);
+ ac97_probe_codec(codec);
+ ac97_restore_state(codec);
+
+ ac97_codec_write(codec, 0x0026, reserve_power1);
+ ac97_codec_write(codec, 0x006c, reserve_power2);
+ ac97_codec_write(codec, 0x005c, reserve_power3);
+ ac97_codec_write(codec, 0x0064, reserve_power4);
+ ac97_codec_write(codec, 0x0066, reserve_power5);
+ ac97_codec_write(codec, 0x006a, reserve_power6);
+
+ ac97_codec_write(codec, 0x0002, reserve_mastervol);
+ ac97_codec_write(codec, 0x000e, reserve_micvol);
+
+ /* Enable variable rate mode */
+ ac97_codec_write(codec, AC97_EXTENDED_STATUS, 9);
+ ac97_codec_write(codec,
+ AC97_EXTENDED_STATUS,
+ ac97_codec_read(codec, AC97_EXTENDED_STATUS) | 0xE800);
+
+ return 0;
+}
+
+static int jz_ac97_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
+{
+ int ret;
+ struct jz_ac97_controller_info *controller = pm_dev->data;
+
+ if (!controller) return -EINVAL;
+
+ switch (req) {
+ case PM_SUSPEND:
+ ret = jz_ac97_suspend(controller, (int)data);
+ break;
+
+ case PM_RESUME:
+ ret = jz_ac97_resume(controller);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+#endif /* CONFIG_PM */
+
+static int __init init_jz_ac97(void)
+{
+ int errno;
+
+ if ((errno = probe_jz_ac97(&ac97_controller)) < 0)
+ return errno;
+ attach_jz_ac97(ac97_controller);
+
+ out_empty_queue.id = NULL;
+ out_full_queue.id = NULL;
+ out_busy_queue.id = NULL;
+
+ in_empty_queue.id = NULL;
+ in_full_queue.id = NULL;
+ in_busy_queue.id = NULL;
+
+#ifdef CONFIG_PM
+ ac97_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN,
+ jz_ac97_pm_callback);
+ if (ac97_controller->pm)
+ ac97_controller->pm->data = ac97_controller;
+#endif
+
+ return 0;
+}
+
+static void __exit cleanup_jz_ac97(void)
+{
+ unload_jz_ac97(ac97_controller);
+}
+
+module_init(init_jz_ac97);
+module_exit(cleanup_jz_ac97);
+
+
+static int drain_adc(struct jz_ac97_controller_info *ctrl, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count;
+ unsigned tmo;
+
+ add_wait_queue(&ctrl->adc_wait, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+
+ if (signal_pending(current))
+ break;
+ if (nonblock) {
+ remove_wait_queue(&ctrl->adc_wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ tmo = (PAGE_SIZE * HZ) / STANDARD_SPEED;
+ tmo *= jz_audio_k * (jz_audio_format == AFMT_S16_LE) ? 2 : 4;
+ tmo /= jz_audio_channels;
+ }
+ remove_wait_queue(&ctrl->adc_wait, &wait);
+ current->state = TASK_RUNNING;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ return 0;
+}
+
+static int drain_dac(struct jz_ac97_controller_info *ctrl, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count;
+ unsigned tmo;
+
+ add_wait_queue(&(ctrl->dac_wait), &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0 && elements_in_queue(&out_full_queue) <= 0)
+ break;
+ if (signal_pending(current))
+ break;
+ if (nonblock) {
+ remove_wait_queue(&ctrl->dac_wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ tmo = (PAGE_SIZE * HZ) / STANDARD_SPEED;
+ tmo *= jz_audio_k * (jz_audio_format == AFMT_S16_LE) ? 2 : 4;
+ tmo /= jz_audio_channels;
+ }
+ remove_wait_queue(&ctrl->dac_wait, &wait);
+ current->state = TASK_RUNNING;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ return 0;
+}
+
+/*
+ * Audio operation routines implementation
+ */
+static int jz_audio_release(struct inode *inode, struct file *file)
+{
+ struct jz_ac97_controller_info *controller =
+ (struct jz_ac97_controller_info *) file->private_data;
+ unsigned long flags;
+
+ if (file->f_mode & FMODE_WRITE) {
+ controller->opened1 = 0;
+ drain_dac(controller, file->f_flags & O_NONBLOCK);
+ disable_dma(controller->dma1);
+ set_dma_count(controller->dma1, 0);
+ __ac97_disable_transmit_dma();
+ __ac97_disable_replay();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ }
+ if (file->f_mode & FMODE_READ) {
+ controller->opened2 = 0;
+ first_record_call = 1;
+ drain_adc(controller, file->f_flags & O_NONBLOCK);
+ disable_dma(controller->dma2);
+ set_dma_count(controller->dma2, 0);
+ __ac97_disable_receive_dma();
+ __ac97_disable_record();
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ }
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ return 0;
+}
+
+static int jz_audio_open(struct inode *inode, struct file *file)
+{
+ struct jz_ac97_controller_info *controller= ac97_controller;
+
+ if (controller == NULL)
+ return -ENODEV;
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (controller->opened1 == 1)
+ return -EBUSY;
+ controller->opened1 = 1;
+ //for ioctl
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+ jz_audio_set_channels(controller->dev_audio, 1);
+ jz_audio_set_format(controller->dev_audio, AFMT_U8);
+ jz_audio_set_speed(controller->dev_audio, 8000);
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ if (controller->opened2 == 1)
+ return -EBUSY;
+ controller->opened2 = 1;
+ first_record_call = 1;
+ printk(KERN_DEBUG "You'd better apply 48000Hz 16-bit Stereo for record.\n");
+ //for ioctl
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+ jz_audio_set_channels(controller->dev_audio, 2);
+ jz_audio_set_format(controller->dev_audio, AFMT_S16_LE);
+ jz_audio_set_speed(controller->dev_audio, 48000);
+ }
+
+ last_jz_audio_count = jz_audio_count = 0;
+ file->private_data = controller;
+
+ jz_audio_fragsize = 8 * PAGE_SIZE;
+ jz_audio_fragstotal = 4;
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ return 0;
+}
+
+static int jz_audio_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct jz_ac97_controller_info *controller =
+ (struct jz_ac97_controller_info *) file->private_data;
+ int val=0,fullc,busyc,unfinish;
+ unsigned int flags;
+ count_info cinfo;
+
+ switch (cmd)
+ {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *)arg);
+
+ case SNDCTL_DSP_RESET:
+ jz_audio_reset();
+ return 0;
+
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ return drain_dac(controller, file->f_flags & O_NONBLOCK);
+ return 0;
+
+ case SNDCTL_DSP_SPEED: /* set smaple rate */
+ {
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val >= 0)
+ jz_audio_set_speed(controller->dev_audio, val);
+ return put_user(val, (int *)arg);
+ }
+
+ case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1);
+ return 0;
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ //return put_user(4*PAGE_SIZE, (int *)arg);
+ return put_user(jz_audio_fragsize , (int *)arg);
+
+ case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg);
+
+ case SNDCTL_DSP_SETFMT: /* Select sample format */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ if (val != AFMT_QUERY) {
+ jz_audio_set_format(controller->dev_audio,val);
+ } else {
+ if (file->f_mode & FMODE_READ)
+ val = (jz_audio_format == 16) ?
+ AFMT_S16_LE : AFMT_U8;
+ else
+ val = (jz_audio_format == 16) ?
+ AFMT_S16_LE : AFMT_U8;
+ }
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_CHANNELS:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ jz_audio_set_channels(controller->dev_audio, val);
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_POST:
+ /* FIXME: the same as RESET ?? */
+ return 0;
+
+ case SNDCTL_DSP_SUBDIVIDE:
+ return 0;
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ if(out_dma_buf || in_dma_buf)
+ return -EBUSY;
+ get_user(val, (long *) arg);
+ jz_audio_fragsize = 1 << (val & 0xFFFF);//16 least bits
+
+ if (jz_audio_fragsize < 4 * PAGE_SIZE)
+ jz_audio_fragsize = 4 * PAGE_SIZE;
+ if (jz_audio_fragsize > (16 * PAGE_SIZE)) //16 PAGE_SIZE
+ jz_audio_fragsize = 16 * PAGE_SIZE;
+ jz_audio_fragstotal = (val >> 16) & 0x7FFF;
+ if (jz_audio_fragstotal < 2)
+ jz_audio_fragstotal = 2;
+ if (jz_audio_fragstotal > 32)
+ jz_audio_fragstotal = 32;
+
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ return 0;
+
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg);
+
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+
+ case SNDCTL_DSP_SETDUPLEX:
+ return -EINVAL;
+
+ case SNDCTL_DSP_GETOSPACE:
+ {
+ audio_buf_info abinfo;
+ int i, bytes = 0;
+
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ //unused fragment amount
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ jz_audio_fragments = elements_in_queue(&out_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+ bytes /= jz_audio_k;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ //bytes /= jz_audio_b;
+ abinfo.fragments = jz_audio_fragments;
+ abinfo.fragstotal = jz_audio_fragstotal;
+ abinfo.fragsize = jz_audio_fragsize;
+ abinfo.bytes = bytes;
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+ }
+
+ case SNDCTL_DSP_GETISPACE:
+ {
+ audio_buf_info abinfo;
+ int i, bytes = 0;
+
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ //unused fragment amount
+ jz_audio_fragments = elements_in_queue(&in_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+
+ abinfo.fragments = jz_audio_fragments;
+ abinfo.fragstotal = jz_audio_fragstotal;
+ abinfo.fragsize = jz_audio_fragsize;
+ abinfo.bytes = bytes;
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+ }
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && in_dma_buf) //record is at working
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && out_dma_buf) //playback is at working
+ val |= PCM_ENABLE_OUTPUT;
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_SETTRIGGER:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ /*if (file->f_mode & FMODE_READ) {
+ if (val & PCM_ENABLE_INPUT) {
+ if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+ return ret;
+ start_adc(state);
+ } else
+ stop_adc(state);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (val & PCM_ENABLE_OUTPUT) {
+ if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+ return ret;
+ start_dac(state);
+ } else
+ stop_dac(state);
+ }*/
+ return 0;
+
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ //controller->total_bytes += get_dma_residue(controller->dma2);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextIn;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ //controller->total_bytes += get_dma_residue(controller->dma1);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextOut;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+ case SNDCTL_DSP_GETODELAY:
+ {
+ int id, i;
+
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ unfinish = 0;
+ fullc = elements_in_queue(&out_full_queue);
+ busyc = elements_in_queue(&out_busy_queue);
+
+ for(i = 0;i < fullc ;i ++)
+ {
+ id = *(out_full_queue.id + i);
+ unfinish += *(out_dma_buf_data_count + id);
+ }
+ for(i = 0;i < busyc ;i ++)
+ {
+ id = *(out_busy_queue.id + i);
+ unfinish += get_dma_residue(controller->dma1);
+ }
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ unfinish /= jz_audio_k;//jz_audio_k is jz_audio_b
+ return put_user(val, (int *)arg);
+ }
+ case SOUND_PCM_READ_RATE:
+ return put_user(jz_audio_rate, (int *)arg);
+ case SOUND_PCM_READ_CHANNELS:
+ return put_user(jz_audio_channels, (int *)arg);
+ case SOUND_PCM_READ_BITS:
+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg);
+ case SNDCTL_DSP_MAPINBUF:
+ case SNDCTL_DSP_MAPOUTBUF:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_WRITE_FILTER:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+static unsigned int jz_audio_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct jz_ac97_controller_info *controller =
+ (struct jz_ac97_controller_info *) file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ return POLLOUT | POLLWRNORM;
+ poll_wait(file, &controller->dac_wait, wait);
+ }
+ if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ return POLLIN | POLLRDNORM;
+ poll_wait(file, &controller->adc_wait, wait);
+ }
+ spin_lock_irqsave(&controller->lock, flags);
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ mask |= POLLOUT | POLLWRNORM;
+ }
+ else if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ spin_unlock_irqrestore(&controller->lock, flags);
+ return mask;
+}
+
+static ssize_t jz_audio_read(struct file *file, char *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct jz_ac97_controller_info *controller =
+ (struct jz_ac97_controller_info *) file->private_data;
+ int id, ret = 0, left_count, copy_count, cnt = 0;
+ unsigned long flags;
+
+ if (count < 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextIn = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+
+ if (count < 2*PAGE_SIZE / jz_audio_k) {
+ copy_count = count * 16 / (jz_audio_channels * jz_audio_format);
+ } else
+ copy_count = ((2*PAGE_SIZE / jz_audio_k + 3) / 4) * 4;
+ left_count = count;
+
+ if (first_record_call) {
+ first_record_call = 0;
+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ *(in_dma_buf_data_count + id) = copy_count * (jz_audio_format/8);
+ __ac97_enable_receive_dma();
+ __ac97_enable_record();
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ interruptible_sleep_on(&rx_wait_queue);
+ } else
+ BUG();
+ }
+
+ while (left_count > 0) {
+ if (elements_in_queue(&in_full_queue) <= 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ else
+ interruptible_sleep_on(&rx_wait_queue);
+ }
+ if (signal_pending(current))
+ return ret ? ret: -ERESTARTSYS;
+
+ if ((id = get_buffer_id(&in_full_queue)) >= 0) {
+ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id);
+ put_buffer_id(&in_empty_queue, id);
+ } else
+ BUG();
+
+ if (elements_in_queue(&in_busy_queue) == 0) {
+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ *(in_dma_buf_data_count + id) = copy_count * (jz_audio_format/8);
+ __ac97_enable_receive_dma();
+ __ac97_enable_record();
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ }
+ }
+
+ if (ret + cnt > count)
+ cnt = count - ret;
+
+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt))
+ return ret ? ret : -EFAULT;
+
+ ret += cnt;
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextIn += ret;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ left_count -= cnt;
+ }
+ if (ret != count)
+ printk(KERN_DEBUG "%s: count=%d ret=%d jz_audio_count=%d\n",
+ __FUNCTION__, count, ret, jz_audio_count);
+ return ret;
+}
+
+static ssize_t jz_audio_write(struct file *file, const char *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct jz_ac97_controller_info *controller =
+ (struct jz_ac97_controller_info *) file->private_data;
+ int id, ret = 0, left_count, copy_count;
+ unsigned int flags;
+
+ if (count <= 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+
+ /* The data buffer size of the user space is always a PAGE_SIZE
+ * scale, so the process can be simplified.
+ */
+
+ if ((ac97_controller->patched) && (ac97_controller->ac97_features & 1))
+ copy_count = count;
+ else {
+ if (count < 2*PAGE_SIZE / jz_audio_k)
+ copy_count = count;
+ else
+ copy_count = ((2*PAGE_SIZE / jz_audio_k + 3) / 4) * 4;
+ }
+ left_count = count;
+
+ if (!(ac97_controller->patched) || !(ac97_controller->ac97_features & 1)) {
+ if (copy_from_user(controller->tmp1, buffer, count)) {
+ printk(KERN_DEBUG "%s: copy_from_user failed.\n", __FUNCTION__);
+ return ret ? ret : -EFAULT;
+ }
+ }
+
+ while (left_count > 0) {
+ if (elements_in_queue(&out_empty_queue) == 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret;
+ else
+ interruptible_sleep_on(&tx_wait_queue);
+ }
+
+ if (signal_pending(current))
+ return ret ? ret : -ERESTARTSYS;
+
+ /* the end fragment size in this write */
+ if (ret + copy_count > count)
+ copy_count = count - ret;
+
+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) {
+ if ((ac97_controller->patched) &&
+ (ac97_controller->ac97_features & 1)) {
+ if (copy_from_user((char *)(*(out_dma_buf + id)), buffer+ret, copy_count)) {
+ printk(KERN_DEBUG "%s: copy_from_user failed.\n", __FUNCTION__);
+ return ret ? ret : -EFAULT;
+ }
+ *(out_dma_buf_data_count + id) = copy_count;
+ } else
+ replay_filler(
+ (unsigned long)controller->tmp1 + ret,
+ copy_count, id);
+ //when 0,kernel will panic
+ if(*(out_dma_buf_data_count + id) > 0) {
+ put_buffer_id(&out_full_queue, id);
+ dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id));
+ } else {//when 0,i need refill in empty queue
+ put_buffer_id(&out_empty_queue, id);
+ }
+ } else
+ BUG();
+ left_count = left_count - copy_count;
+ ret += copy_count;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextOut += ret;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ if (elements_in_queue(&out_busy_queue) == 0) {
+ if ((id=get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id);
+
+ __ac97_enable_transmit_dma();
+ __ac97_enable_replay();
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(controller->dma1,file->private_data,
+ *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ }
+ }
+ }
+ }
+
+ if (ret != count)
+ printk(KERN_DEBUG "%s: count=%d ret=%d jz_audio_count=%d\n",
+ __FUNCTION__, count, ret, jz_audio_count);
+ return ret;
+}
+
+/* this function for the other codec function */
+struct ac97_codec * find_ac97_codec(void)
+{
+ if ( ac97_controller )
+ return ac97_controller->ac97_codec[0];
+ return 0;
+
+}
+
diff --git a/sound/oss/jz_i2s.c b/sound/oss/jz_i2s.c
new file mode 100644
index 00000000000..5bfbabcd2c8
--- /dev/null
+++ b/sound/oss/jz_i2s.c
@@ -0,0 +1,2895 @@
+/*
+ * linux/drivers/sound/Jz_i2s.c
+ *
+ * JzSOC On-Chip I2S audio driver.
+ *
+ * Copyright (C) 2005 by Junzheng Corp.
+ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using
+ * dma channel 4&3,noah is tested.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Because the normal application of AUDIO devices are focused on Little_endian,
+ * then we only perform the little endian data format in driver.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/proc_fs.h>
+#include <linux/soundcard.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <asm/hardirq.h>
+#include <asm/jzsoc.h>
+#include "sound_config.h"
+
+#if defined(CONFIG_I2S_DLV)
+#include "jzdlv.h"
+#endif
+
+#define DPRINTK(args...) printk(args)
+#define DMA_ID_I2S_TX DMA_ID_AIC_TX
+#define DMA_ID_I2S_RX DMA_ID_AIC_RX
+#define NR_I2S 2
+#define JZCODEC_RW_BUFFER_SIZE 5
+#define JZCODEC_RW_BUFFER_TOTAL 4
+
+#define USE_NONE 1
+#define USE_MIC 2
+#define USE_LINEIN 3
+
+typedef struct hpvol_shift_s
+{
+ int hpvol;
+ int shift;
+} hpvol_shift_t;
+
+mixer_info info;
+_old_mixer_info old_info;
+int codec_volue_shift;
+hpvol_shift_t hpvol_shift_table[72];
+int abnormal_data_count;
+unsigned long i2s_clk;
+
+void (*set_codec_mode)(void) = NULL;
+void (*clear_codec_mode)(void) = NULL;
+void (*set_codec_gpio_pin)(void) = NULL;
+void (*each_time_init_codec)(void) = NULL;
+int (*set_codec_startup_param)(void) = NULL;
+void (*set_codec_volume_table)(void) = NULL;
+void (*set_codec_record)(int mode) = NULL;
+void (*set_codec_replay)(void) = NULL;
+void (*set_codec_replay_record)(int mode) = NULL;
+void (*turn_on_codec)(void) = NULL;
+void (*turn_off_codec)(void) = NULL;
+void (*set_codec_speed)(int rate) = NULL;
+void (*reset_codec)(void) = NULL;
+void (*codec_mixer_old_info_id_name)(void) = NULL;
+void (*codec_mixer_info_id_name)(void) = NULL;
+void (*set_codec_bass)(int val) = NULL;
+void (*set_codec_volume)(int val) = NULL;
+void (*set_codec_mic)(int val) = NULL;
+void (*set_codec_line)(int val) = NULL;
+void (*i2s_resume_codec)(void) = NULL;
+void (*i2s_suspend_codec)(int wr,int rd) = NULL;
+void (*init_codec_pin)(void) = NULL;
+void (*set_codec_some_func)(void) = NULL;
+void (*clear_codec_record)(void) = NULL;
+void (*clear_codec_replay)(void) = NULL;
+void (*set_replay_hp_or_speaker)(void) = NULL;
+void (*set_codec_direct_mode)(void) = NULL;
+void (*clear_codec_direct_mode)(void) = NULL;
+void (*set_codec_linein2hp)(void) = NULL;
+void (*clear_codec_linein2hp)(void) = NULL;
+
+static int jz_audio_rate;
+static int jz_audio_format;
+static int jz_audio_volume;
+static int jz_audio_channels;
+static int jz_audio_b; /* bits expand multiple */
+static int jz_audio_fragments; /* unused fragment amount */
+static int jz_audio_fragstotal;
+static int jz_audio_fragsize;
+static int jz_audio_speed;
+
+static int codec_bass_gain;
+static int audio_mix_modcnt;
+static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */
+#if defined(CONFIG_I2S_DLV)
+int jz_mic_only = 1;
+static int jz_codec_config = 0;
+static unsigned long ramp_up_start;
+static unsigned long ramp_up_end;
+static unsigned long gain_up_start;
+static unsigned long gain_up_end;
+static unsigned long ramp_down_start;
+static unsigned long ramp_down_end;
+static unsigned long gain_down_start;
+static unsigned long gain_down_end;
+#endif
+
+static int codec_mic_gain;
+static int pop_dma_flag;
+static int last_dma_buffer_id;
+static int drain_flag;
+static int use_mic_line_flag;
+
+static void (*old_mksound)(unsigned int hz, unsigned int ticks);
+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
+static void jz_update_filler(int bits, int channels);
+
+static int Init_In_Out_queue(int fragstotal,int fragsize);
+static int Free_In_Out_queue(int fragstotal,int fragsize);
+static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref);
+static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref);
+static void (*replay_filler)(signed long src_start, int count, int id);
+static int (*record_filler)(unsigned long dst_start, int count, int id);
+#if defined(CONFIG_I2S_ICODEC)
+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample);
+#endif
+static void jz_audio_reset(void);
+static struct file_operations jz_i2s_audio_fops;
+
+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue);
+
+struct jz_i2s_controller_info
+{
+ int io_base;
+ int dma1; /* for play */
+ int dma2; /* for record */
+ char *name;
+ int dev_audio;
+ struct i2s_codec *i2s_codec[NR_I2S];
+ int opened1;
+ int opened2;
+ unsigned char *tmp1; /* tmp buffer for sample conversions */
+ unsigned char *tmp2;
+ spinlock_t lock;
+ spinlock_t ioctllock;
+
+ wait_queue_head_t dac_wait;
+ wait_queue_head_t adc_wait;
+ int nextIn; /* byte index to next-in to DMA buffer */
+ int nextOut; /* byte index to next-out from DMA buffer */
+ int count; /* current byte count in DMA buffer */
+ int finish; /* current transfered byte count in DMA buffer */
+ unsigned total_bytes; /* total bytes written or read */
+ unsigned blocks;
+ unsigned error; /* over/underrun */
+#ifdef CONFIG_PM
+ struct pm_dev *pm;
+#endif
+};
+
+
+static struct jz_i2s_controller_info *i2s_controller = NULL;
+struct i2s_codec
+{
+ /* I2S controller connected with */
+ void *private_data;
+ char *name;
+ int id;
+ int dev_mixer;
+ /* controller specific lower leverl i2s accessing routines */
+ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */
+ void (*codec_write) (u8 reg, u16 val);
+ /* Wait for codec-ready */
+ void (*codec_wait) (struct i2s_codec *codec);
+ /* OSS mixer masks */
+ int modcnt;
+ int supported_mixers;
+ int stereo_mixers;
+ int record_sources;
+ int bit_resolution;
+ /* OSS mixer interface */
+ int (*read_mixer) (struct i2s_codec *codec, int oss_channel);
+ void (*write_mixer)(struct i2s_codec *codec, int oss_channel,
+ unsigned int left, unsigned int right);
+ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask);
+ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg);
+ /* saved OSS mixer states */
+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+};
+
+
+typedef struct buffer_queue_s
+{
+ int count;
+ int *id;
+ int lock;
+} buffer_queue_t;
+
+typedef struct left_right_sample_s
+{
+ signed long left;
+ signed long right;
+} left_right_sample_t;
+
+static unsigned long pop_turn_onoff_buf;
+static unsigned long pop_turn_onoff_pbuf;
+
+static unsigned long *out_dma_buf = NULL;
+static unsigned long *out_dma_pbuf = NULL;
+static unsigned long *out_dma_buf_data_count = NULL;
+static unsigned long *in_dma_buf = NULL;
+static unsigned long *in_dma_pbuf = NULL;
+static unsigned long *in_dma_buf_data_count = NULL;
+
+static buffer_queue_t out_empty_queue;
+static buffer_queue_t out_full_queue;
+static buffer_queue_t out_busy_queue;
+static buffer_queue_t in_empty_queue;
+static buffer_queue_t in_full_queue;
+static buffer_queue_t in_busy_queue;
+static int first_record_call = 0;
+
+static left_right_sample_t save_last_samples[64];
+
+static inline int get_buffer_id(struct buffer_queue_s *q)
+{
+ int r;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&q->lock, flags);
+ if (q->count == 0) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ return -1;
+ }
+ r = *(q->id + 0);
+ for (i=0;i < q->count-1;i++)
+ *(q->id + i) = *(q->id + (i+1));
+ q->count --;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return r;
+}
+
+static inline void put_buffer_id(struct buffer_queue_s *q, int id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ *(q->id + q->count) = id;
+ q->count ++;
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+static inline int elements_in_queue(struct buffer_queue_s *q)
+{
+ int r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ r = q->count;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return r;
+}
+
+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode)
+{
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ jz_audio_dma_tran_count = count / jz_audio_b;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ flags = claim_dma_lock();
+ disable_dma(chan);
+ clear_dma_ff(chan);
+#if 1
+ jz_set_oss_dma(chan, mode, jz_audio_format);
+#else
+ set_dma_mode(chan, mode);
+#endif
+ set_dma_addr(chan, phyaddr);
+ if (count == 0) {
+ count++;
+ printk("JzSOC DMA controller can't set dma 0 count!\n");
+ }
+ set_dma_count(chan, count);
+ enable_dma(chan);
+ release_dma_lock(flags);
+}
+
+static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id)
+{
+ int id1, id2;
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+ int dma = controller->dma2;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+
+ if(drain_flag == 1)
+ wake_up(&drain_wait_queue);
+ /* for DSP_GETIPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ id1 = get_buffer_id(&in_busy_queue);
+ put_buffer_id(&in_full_queue, id1);
+
+ wake_up(&rx_wait_queue);
+ wake_up(&controller->adc_wait);
+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id2);
+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1);
+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2));
+ audio_start_dma(dma,dev_id,
+ *(in_dma_pbuf + id2),
+ *(in_dma_buf_data_count + id2),
+ DMA_MODE_READ);
+ } else
+ in_busy_queue.count = 0;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id)
+{
+ int id;
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+ int dma = controller->dma1;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+
+ if(pop_dma_flag == 1) {
+ pop_dma_flag = 0;
+ wake_up(&pop_wait_queue);
+ } else {
+ if(drain_flag == 1) {
+ /* Is replay dma buffer over ? */
+ if(elements_in_queue(&out_full_queue) <= 0) {
+ drain_flag = 0;
+ wake_up(&drain_wait_queue);
+ }
+ }
+
+ /* for DSP_GETOPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ if ((id = get_buffer_id(&out_busy_queue)) < 0)
+ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n");
+ put_buffer_id(&out_empty_queue, id);
+ if ((id = get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ last_dma_buffer_id = id;
+ }
+ } else
+ out_busy_queue.count = 0;
+
+ if (elements_in_queue(&out_empty_queue) > 0) {
+ wake_up(&tx_wait_queue);
+ wake_up(&controller->dac_wait);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void jz_i2s_initHw(int set)
+{
+#if defined(CONFIG_MIPS_JZ_URANUS)
+ i2s_clk = 48000000;
+#else
+ i2s_clk = __cpm_get_i2sclk();
+#endif
+ __i2s_disable();
+ if(set)
+ __i2s_reset();
+ schedule_timeout(5);
+ if(each_time_init_codec)
+ each_time_init_codec();
+ __i2s_disable_record();
+ __i2s_disable_replay();
+ __i2s_disable_loopback();
+ __i2s_set_transmit_trigger(4);
+ __i2s_set_receive_trigger(3);
+}
+
+static int Init_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+
+ /* recording */
+ in_empty_queue.count = fragstotal;
+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf)
+ goto all_mem_err;
+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_pbuf)
+ goto all_mem_err;
+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf_data_count)
+ goto all_mem_err;
+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_empty_queue.id)
+ goto all_mem_err;
+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_full_queue.id)
+ goto all_mem_err;
+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_busy_queue.id)
+ goto all_mem_err;
+
+ for (i=0;i < fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+
+ for (i = 0; i < fragstotal; i++) {
+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(in_dma_buf + i) == 0)
+ goto mem_failed_in;
+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i)));
+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
+ }
+
+ /* playing */
+ out_empty_queue.count = fragstotal;
+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_buf)
+ goto all_mem_err;
+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_pbuf)
+ goto all_mem_err;
+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+
+ if (!out_dma_buf_data_count)
+ goto all_mem_err;
+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_empty_queue.id)
+ goto all_mem_err;
+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_full_queue.id)
+ goto all_mem_err;
+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_busy_queue.id)
+ goto all_mem_err;
+ for (i=0;i < fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ /* alloc DMA buffer */
+ for (i = 0; i < fragstotal; i++) {
+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(out_dma_buf + i) == 0) {
+ printk(" can't allocate required DMA(OUT) buffers.\n");
+ goto mem_failed_out;
+ }
+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i)));
+ }
+
+ return 1;
+all_mem_err:
+ printk("error:allocate memory occur error 1!\n");
+ return 0;
+mem_failed_out:
+ printk("error:allocate memory occur error 2!\n");
+ for (i = 0; i < fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ }
+
+ return 0;
+mem_failed_in:
+ printk("error:allocate memory occur error 3!\n");
+ for (i = 0; i < fragstotal; i++) {
+ if(*(in_dma_buf + i))
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ return 0;
+}
+
+static int Free_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+ /* playing */
+ if(out_dma_buf != NULL) {
+ for (i = 0; i < fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ *(out_dma_buf + i) = 0;
+ }
+ kfree(out_dma_buf);
+ out_dma_buf = NULL;
+ }
+ if(out_dma_pbuf) {
+ kfree(out_dma_pbuf);
+ out_dma_pbuf = NULL;
+ }
+ if(out_dma_buf_data_count) {
+ kfree(out_dma_buf_data_count);
+ out_dma_buf_data_count = NULL;
+ }
+ if(out_empty_queue.id) {
+ kfree(out_empty_queue.id);
+ out_empty_queue.id = NULL;
+ }
+ if(out_full_queue.id) {
+ kfree(out_full_queue.id);
+ out_full_queue.id = NULL;
+ }
+ if(out_busy_queue.id) {
+ kfree(out_busy_queue.id);
+ out_busy_queue.id = NULL;
+ }
+ out_empty_queue.count = fragstotal;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+
+ /* recording */
+ if(in_dma_buf) {
+ for (i = 0; i < fragstotal; i++) {
+ if(*(in_dma_buf + i)) {
+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ *(in_dma_buf + i) = 0;
+ }
+ kfree(in_dma_buf);
+ in_dma_buf = NULL;
+ }
+ if(in_dma_pbuf) {
+ kfree(in_dma_pbuf);
+ in_dma_pbuf = NULL;
+ }
+ if(in_dma_buf_data_count) {
+ kfree(in_dma_buf_data_count);
+ in_dma_buf_data_count = NULL;
+ }
+ if(in_empty_queue.id) {
+ kfree(in_empty_queue.id);
+ in_empty_queue.id = NULL;
+ }
+ if(in_full_queue.id) {
+ kfree(in_full_queue.id);
+ in_full_queue.id = NULL;
+ }
+ if(in_busy_queue.id) {
+ kfree(in_busy_queue.id);
+ in_busy_queue.id = NULL;
+ }
+
+ in_empty_queue.count = fragstotal;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+
+ return 1;
+}
+
+static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller)
+{
+ jz_i2s_initHw(0);
+}
+
+static int jz_audio_set_speed(int dev, int rate)
+{
+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */
+ jz_audio_speed = rate;
+#if defined(CONFIG_I2S_DLV)
+ if (rate > 96000)
+ rate = 96000;
+#else
+ if (rate > 48000)
+ rate = 48000;
+#endif
+ if (rate < 8000)
+ rate = 8000;
+ jz_audio_rate = rate;
+
+ if(set_codec_speed)
+ set_codec_speed(rate);
+
+ return jz_audio_rate;
+}
+
+
+static int record_fill_1x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long data;
+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char*)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt++;
+ data = *(s++);
+ *(dp ++) = ((data << 16) >> 24) + 0x80;
+ s++; /* skip the other channel */
+ }
+
+ return cnt;
+}
+
+
+static int record_fill_2x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1, d2;
+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char*)dst_start;
+
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+ *(dp ++) = ((d1 << 16) >> 24) + 0x80;
+ d2 = *(s++);
+ *(dp ++) = ((d2 << 16) >> 24) + 0x80;
+ }
+
+ return cnt;
+}
+
+
+static int record_fill_1x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1;
+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt += 2; /* count in byte */
+ d1 = *(s++);
+ *(dp ++) = (d1 << 16) >> 16;
+ s++; /* skip the other channel */
+ }
+
+ return cnt;
+}
+
+
+static int record_fill_2x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1, d2;
+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt += 4; /* count in byte */
+ d1 = *(s++);
+ d2 = *(s++);
+ if(abnormal_data_count > 0) {
+ d1 = d2 = 0;
+ abnormal_data_count --;
+ }
+ *(dp ++) = (d1 << 16) >> 16;
+ *(dp ++) = (d2 << 16) >> 16;
+ }
+
+ return cnt;
+}
+
+static void replay_fill_1x8_u(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned char data;
+ unsigned long ddata;
+ volatile unsigned char *s = (unsigned char *)src_start;
+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count--;
+ cnt += 1;
+ data = *(s++) - 0x80;
+ ddata = (unsigned long) data << 8;
+ *(dp ++) = ddata;
+ *(dp ++) = ddata;
+
+ /* save last left and right */
+ if(count == 1) {
+ save_last_samples[id].left = ddata;
+ save_last_samples[id].right = ddata;
+ }
+ }
+ cnt = cnt * 2 * jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+
+static void replay_fill_2x8_u(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned char d1;
+ unsigned long dd1;
+ volatile unsigned char *s = (unsigned char *)src_start;
+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count -= 1;
+ cnt += 1 ;
+ d1 = *(s++) - 0x80;
+ dd1 = (unsigned long) d1 << 8;
+ *(dp ++) = dd1;
+ /* save last left */
+ if(count == 2)
+ save_last_samples[id].left = dd1;
+ /* save last right */
+ if(count == 1)
+ save_last_samples[id].right = dd1;
+ }
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+
+static void replay_fill_1x16_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed short d1;
+ signed long l1;
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count -= 2;
+ cnt += 2 ;
+ d1 = *(s++);
+ l1 = (signed long)d1;
+#if defined(CONFIG_I2S_ICODEC)
+ l1 >>= codec_volue_shift;
+#endif
+ *(dp ++) = l1;
+ *(dp ++) = l1;
+
+ /* save last left and right */
+ if(count == 1) {
+ save_last_samples[id].left = l1;
+ save_last_samples[id].right = l1;
+ }
+ }
+ cnt = cnt * 2 * jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static void replay_fill_2x16_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed short d1;
+ signed long l1;
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+#if defined(CONFIG_I2S_ICODEC)
+ int mute_cnt = 0;
+ signed long tmp1,tmp2;
+ volatile signed long *before_dp;
+ int sam_rate = jz_audio_rate / 20;
+
+ tmp1 = tmp2 = 0;
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+
+ l1 = (signed long)d1;
+ l1 >>= codec_volue_shift;
+
+ if(l1 == 0) {
+ mute_cnt ++;
+ if(mute_cnt >= sam_rate) {
+ before_dp = dp - 10;
+ *(before_dp) = (signed long)1;
+ before_dp = dp - 11;
+ *(before_dp) = (signed long)1;
+ mute_cnt = 0;
+ }
+ } else
+ mute_cnt = 0;
+
+ *(dp ++) = l1;
+
+ tmp1 = tmp2;
+ tmp2 = l1;
+ }
+
+ /* save last left */
+ save_last_samples[id].left = tmp1;
+ /* save last right */
+ save_last_samples[id].right = tmp2;
+#endif
+#if defined(CONFIG_I2S_DLV)
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+
+ l1 = (signed long)d1;
+
+ *(dp ++) = l1;
+ }
+#endif
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static void replay_fill_2x18_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed long d1;
+ signed long l1;
+ volatile signed long *s = (signed long *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+ while (count > 0) {
+ count -= 4;
+ cnt += 4;
+ d1 = *(s++);
+ l1 = (signed long)d1;
+ *(dp ++) = l1;
+ }
+
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static unsigned int jz_audio_set_format(int dev, unsigned int fmt)
+{
+ switch (fmt) {
+ case AFMT_U8:
+ __i2s_set_oss_sample_size(8);
+ __i2s_set_iss_sample_size(8);
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format,jz_audio_channels);
+ break;
+ case AFMT_S16_LE:
+#if defined(CONFIG_I2S_DLV)
+ /* DAC path and ADC path */
+ write_codec_file(2, 0x00);
+ //write_codec_file(2, 0x60);
+#endif
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format,jz_audio_channels);
+ __i2s_set_oss_sample_size(16);
+ __i2s_set_iss_sample_size(16);
+ break;
+ case 18:
+ __i2s_set_oss_sample_size(18);
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format,jz_audio_channels);
+ break;
+ case AFMT_QUERY:
+ break;
+ }
+
+ return jz_audio_format;
+}
+
+
+static short jz_audio_set_channels(int dev, short channels)
+{
+ switch (channels) {
+ case 1:
+ if(set_codec_some_func)
+ set_codec_some_func();
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono
+#endif
+ break;
+ case 2:
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo
+#endif
+ break;
+ case 0:
+ break;
+ }
+
+ return jz_audio_channels;
+}
+
+static void init_codec(void)
+{
+ /* inititalize internal I2S codec */
+ if(init_codec_pin)
+ init_codec_pin();
+
+#if defined(CONFIG_I2S_ICDC)
+ /* initialize AIC but not reset it */
+ jz_i2s_initHw(0);
+#endif
+ if(reset_codec)
+ reset_codec();
+}
+
+static void jz_audio_reset(void)
+{
+ __i2s_disable_replay();
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+ __i2s_disable_transmit_dma();
+#if defined(CONFIG_I2S_DLV)
+ REG_AIC_I2SCR = 0x10;
+#endif
+ init_codec();
+}
+
+static int jz_audio_release(struct inode *inode, struct file *file);
+static int jz_audio_open(struct inode *inode, struct file *file);
+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg);
+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait);
+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos);
+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos);
+
+/* static struct file_operations jz_i2s_audio_fops */
+static struct file_operations jz_i2s_audio_fops =
+{
+ owner: THIS_MODULE,
+ open: jz_audio_open,
+ release: jz_audio_release,
+ write: jz_audio_write,
+ read: jz_audio_read,
+ poll: jz_audio_poll,
+ ioctl: jz_audio_ioctl
+};
+
+static int jz_i2s_open_mixdev(struct inode *inode, struct file *file)
+{
+ int i;
+ int minor = MINOR(inode->i_rdev);
+ struct jz_i2s_controller_info *controller = i2s_controller;
+
+ for (i = 0; i < NR_I2S; i++)
+ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor)
+ goto match;
+
+ if (!controller)
+ return -ENODEV;
+match:
+ file->private_data = controller->i2s_codec[i];
+
+ return 0;
+}
+
+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data;
+ return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static struct file_operations jz_i2s_mixer_fops =
+{
+ owner: THIS_MODULE,
+ llseek: jz_i2s_llseek,
+ ioctl: jz_i2s_ioctl_mixdev,
+ open: jz_i2s_open_mixdev,
+};
+
+static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ long val = 0;
+ switch (cmd) {
+ case SOUND_MIXER_INFO:
+
+ if(codec_mixer_info_id_name)
+ codec_mixer_info_id_name();
+ info.modify_counter = audio_mix_modcnt;
+
+ return copy_to_user((void *)arg, &info, sizeof(info));
+ case SOUND_OLD_MIXER_INFO:
+
+ if(codec_mixer_old_info_id_name)
+ codec_mixer_old_info_id_name();
+
+ return copy_to_user((void *)arg, &old_info, sizeof(info));
+ case SOUND_MIXER_READ_STEREODEVS:
+
+ return put_user(0, (long *) arg);
+ case SOUND_MIXER_READ_CAPS:
+
+ val = SOUND_CAP_EXCL_INPUT;
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_READ_DEVMASK:
+ break;
+ case SOUND_MIXER_READ_RECMASK:
+ break;
+ case SOUND_MIXER_READ_RECSRC:
+ break;
+ case SOUND_MIXER_WRITE_SPEAKER:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ switch(val) {
+ case 100:
+ if(set_codec_direct_mode)
+ set_codec_direct_mode();
+ break;
+ case 0:
+ if(clear_codec_direct_mode)
+ clear_codec_direct_mode();
+ break;
+ }
+ break;
+ case SOUND_MIXER_WRITE_BASS:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ codec_bass_gain = val;
+ if(set_codec_bass)
+ set_codec_bass(val);
+
+ return 0;
+ case SOUND_MIXER_READ_BASS:
+
+ val = codec_bass_gain;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_WRITE_VOLUME:
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+
+ jz_audio_volume = val;
+ if(set_codec_volume)
+ set_codec_volume(val);
+
+ return 0;
+ case SOUND_MIXER_READ_VOLUME:
+
+ val = jz_audio_volume;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+
+ case SOUND_MIXER_WRITE_MIC:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ codec_mic_gain = val;
+ use_mic_line_flag = USE_MIC;
+ if(set_codec_mic)
+ set_codec_mic(val);
+
+ return 0;
+ case SOUND_MIXER_READ_MIC:
+
+ val = codec_mic_gain;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+
+ case SOUND_MIXER_WRITE_LINE:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ use_mic_line_flag = USE_LINEIN;
+ codec_mic_gain = val;
+ if(set_codec_line)
+ set_codec_line(val);
+
+ return 0;
+ case SOUND_MIXER_READ_LINE:
+
+ val = codec_mic_gain;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+ default:
+ return -ENOSYS;
+ }
+ audio_mix_modcnt ++;
+ return 0;
+}
+
+
+int i2s_probe_codec(struct i2s_codec *codec)
+{
+ /* generic OSS to I2S wrapper */
+ codec->mixer_ioctl = i2s_mixer_ioctl;
+ return 1;
+}
+
+
+/* I2S codec initialisation. */
+static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller)
+{
+ int num_i2s = 0;
+ struct i2s_codec *codec;
+
+ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) {
+ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset(codec, 0, sizeof(struct i2s_codec));
+ codec->private_data = controller;
+ codec->id = num_i2s;
+
+ if (i2s_probe_codec(codec) == 0)
+ break;
+ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) {
+ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n");
+ kfree(codec);
+ break;
+ }
+ controller->i2s_codec[num_i2s] = codec;
+ }
+ return num_i2s;
+}
+
+
+static void jz_update_filler(int format, int channels)
+{
+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
+
+ switch (TYPE(format, channels))
+ {
+
+ case TYPE(AFMT_U8, 1):
+ jz_audio_b = 4; /* 4bytes * 8bits =32bits */
+ replay_filler = replay_fill_1x8_u;
+ record_filler = record_fill_1x8_u;
+ break;
+ case TYPE(AFMT_U8, 2):
+ jz_audio_b = 4;
+ replay_filler = replay_fill_2x8_u;
+ record_filler = record_fill_2x8_u;
+ break;
+ case TYPE(AFMT_S16_LE, 1):
+ jz_audio_b = 2; /* 2bytes * 16bits =32bits */
+ replay_filler = replay_fill_1x16_s;
+ record_filler = record_fill_1x16_s;
+ break;
+ case TYPE(AFMT_S16_LE, 2):
+ jz_audio_b = 2;
+ replay_filler = replay_fill_2x16_s;
+ record_filler = record_fill_2x16_s;
+ break;
+ case TYPE(18, 2):
+ jz_audio_b = 1;
+ replay_filler = replay_fill_2x18_s;
+ record_filler = record_fill_2x16_s;
+ break;
+ default:
+ ;
+ }
+}
+
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry *proc_jz_root;
+int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ return 0;
+}
+
+static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller)
+{
+ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0]))
+ return -EIO;
+ return 0;
+}
+
+static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller)
+{
+}
+#endif
+
+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller)
+{
+ char *name;
+ int adev; /* No of Audio device. */
+
+ name = controller->name;
+ /* initialize AIC controller and reset it */
+ jz_i2s_initHw(1);
+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1);
+ if (adev < 0)
+ goto audio_failed;
+ /* initialize I2S codec and register /dev/mixer */
+ if (jz_i2s_codec_init(controller) <= 0)
+ goto mixer_failed;
+
+#ifdef CONFIG_PROC_FS
+ if (jz_i2s_init_proc(controller) < 0) {
+ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name);
+ goto proc_failed;
+ }
+#endif
+
+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8);
+ if (!controller->tmp1) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp1_failed;
+ }
+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8);
+ if (!controller->tmp2) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp2_failed;
+ }
+ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name);
+ goto dma2_failed;
+ }
+ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name);
+ goto dma1_failed;
+ }
+ printk(JZ_SOC_NAME": On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2));
+
+ controller->dev_audio = adev;
+ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8);
+ if(!pop_turn_onoff_buf)
+ printk("pop_turn_onoff_buf alloc is wrong!\n");
+ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf);
+
+ return;
+dma2_failed:
+ jz_free_dma(controller->dma1);
+dma1_failed:
+ free_pages((unsigned long)controller->tmp2, 8);
+tmp2_failed:
+ free_pages((unsigned long)controller->tmp1, 8);
+tmp1_failed:
+
+#ifdef CONFIG_PROC_FS
+ jz_i2s_cleanup_proc(controller);
+#endif
+proc_failed:
+ /* unregister mixer dev */
+mixer_failed:
+ unregister_sound_dsp(adev);
+audio_failed:
+ return;
+}
+
+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller)
+{
+ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info),
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n");
+ return -ENOMEM;
+ }
+ (*controller)->name = "Jz I2S controller";
+ (*controller)->opened1 = 0;
+ (*controller)->opened2 = 0;
+ init_waitqueue_head(&(*controller)->adc_wait);
+ init_waitqueue_head(&(*controller)->dac_wait);
+ spin_lock_init(&(*controller)->lock);
+ init_waitqueue_head(&rx_wait_queue);
+ init_waitqueue_head(&tx_wait_queue);
+ init_waitqueue_head(&pop_wait_queue);
+ init_waitqueue_head(&drain_wait_queue);
+
+ return 0;
+}
+
+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller)
+{
+ int adev = controller->dev_audio;
+
+ jz_i2s_full_reset(controller);
+ controller->dev_audio = -1;
+ if (old_mksound)
+ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */
+
+#ifdef CONFIG_PROC_FS
+ jz_i2s_cleanup_proc(controller);
+#endif
+
+ jz_free_dma(controller->dma1);
+ jz_free_dma(controller->dma2);
+ free_pages((unsigned long)controller->tmp1, 8);
+ free_pages((unsigned long)controller->tmp2, 8);
+ free_pages((unsigned long)pop_turn_onoff_buf, 8);
+
+ if (adev >= 0) {
+ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */
+ unregister_sound_dsp(controller->dev_audio);
+ }
+}
+
+#if 0 /* Deprecated PM API */
+//#if CONFIG_PM
+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state)
+{
+ if(i2s_suspend_codec)
+ i2s_suspend_codec(controller->opened1,controller->opened2);
+ printk("Aic and codec are suspended!\n");
+ return 0;
+}
+
+static int jz_i2s_resume(struct jz_i2s_controller_info *controller)
+{
+ if(i2s_resume_codec)
+ i2s_resume_codec();
+
+#if defined(CONFIG_I2S_AK4642EN)
+ jz_i2s_initHw(0);
+ jz_audio_reset();
+ __i2s_enable();
+ jz_audio_set_speed(controller->dev_audio,jz_audio_speed);
+ /* playing */
+ if(controller->opened1) {
+ if(set_codec_replay)
+ set_codec_replay();
+ int dma = controller->dma1;
+ int id;
+ unsigned long flags;
+ disable_dma(dma);
+ if(__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if(__dmac_channel_transmit_end_detected(dma))
+ __dmac_channel_clear_transmit_end(dma);
+
+ /* for DSP_GETOPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ while((id = get_buffer_id(&out_busy_queue)) >= 0)
+ put_buffer_id(&out_empty_queue, id);
+
+ out_busy_queue.count=0;
+ if((id = get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_empty_queue, id);
+ }
+ if (elements_in_queue(&out_empty_queue) > 0) {
+ wake_up(&tx_wait_queue);
+ wake_up(&controller->dac_wait);
+ } else
+ printk("pm out_empty_queue empty");
+ }
+
+ /* recording */
+ if(controller->opened2) {
+ if(set_codec_record)
+ set_codec_record(use_mic_line_flag);
+ int dma = controller->dma2;
+ int id1, id2;
+ unsigned long flags;
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+ }
+ /* for DSP_GETIPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ id1 = get_buffer_id(&in_busy_queue);
+ put_buffer_id(&in_full_queue, id1);
+ wake_up(&rx_wait_queue);
+ wake_up(&controller->adc_wait);
+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_full_queue, id2);
+ }
+ in_busy_queue.count = 0;
+ }
+#endif
+
+ return 0;
+}
+
+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
+{
+ int ret;
+ struct jz_i2s_controller_info *controller = pm_dev->data;
+
+ if (!controller) return -EINVAL;
+
+ switch (req) {
+ case PM_SUSPEND:
+ ret = jz_i2s_suspend(controller, (int)data);
+ break;
+ case PM_RESUME:
+ ret = jz_i2s_resume(controller);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+#endif /* CONFIG_PM */
+
+#if defined(CONFIG_I2S_DLV)
+static irqreturn_t aic_codec_irq(int irq, void *dev_id)
+{
+ u8 file_9 = read_codec_file(9);
+ u8 file_8 = read_codec_file(8);
+
+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9);
+ if ((file_9 & 0x1f) == 0x10) {
+
+ write_codec_file(8, 0x3f);
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ mdelay(300);
+ while ((read_codec_file(9) & 0x4) != 0x4);
+ while ((read_codec_file(9) & 0x10) == 0x10) {
+ write_codec_file(9, 0x10);
+ }
+ write_codec_file_bit(5, 0, 6);//SB_OUT->0
+ mdelay(300);
+ while ((read_codec_file(9) & 0x8) != 0x8);
+ write_codec_file(9, file_9);
+ write_codec_file(8, file_8);
+
+ return IRQ_HANDLED;
+ }
+
+ if (file_9 & 0x8)
+ ramp_up_end = jiffies;
+ else if (file_9 & 0x4)
+ ramp_down_end = jiffies;
+ else if (file_9 & 0x2)
+ gain_up_end = jiffies;
+ else if (file_9 & 0x1)
+ gain_down_end = jiffies;
+
+ write_codec_file(9, file_9);
+ if (file_9 & 0xf)
+ wake_up(&pop_wait_queue);
+ while (REG_ICDC_RGDATA & 0x100);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+static int __init init_jz_i2s(void)
+{
+ int errno;
+#if defined(CONFIG_I2S_DLV)
+ int retval;
+ ramp_up_start = 0;
+ ramp_up_end = 0;
+ gain_up_start = 0;
+ gain_up_end = 0;
+ ramp_down_start = 0;
+ ramp_down_end = 0;
+ gain_down_start = 0;
+ gain_down_end = 0;
+#endif
+ use_mic_line_flag = USE_NONE;
+ abnormal_data_count = 0;
+ if(set_codec_mode)
+ set_codec_mode();
+
+ drain_flag = 0;
+ if ((errno = probe_jz_i2s(&i2s_controller)) < 0)
+ return errno;
+ if(set_codec_gpio_pin)
+ set_codec_gpio_pin();
+
+ attach_jz_i2s(i2s_controller);
+ if(set_codec_startup_param)
+ set_codec_startup_param();
+ if(set_codec_volume_table)
+ set_codec_volume_table();
+
+#if defined(CONFIG_I2S_DLV)
+ jz_codec_config = 0;
+ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL);
+ if (retval) {
+ printk("Could not get aic codec irq %d\n", IRQ_AIC);
+ return retval;
+ }
+#endif
+
+ out_empty_queue.id = NULL;
+ out_full_queue.id = NULL;
+ out_busy_queue.id = NULL;
+ in_empty_queue.id = NULL;
+ in_full_queue.id = NULL;
+ in_busy_queue.id = NULL;
+
+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE;
+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ;
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+
+#if 0 /* Deprecated PM API */
+//#ifdef CONFIG_PM
+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN,
+ jz_i2s_pm_callback);
+ if (i2s_controller->pm)
+ i2s_controller->pm->data = i2s_controller;
+#endif
+
+ printk(JZ_SOC_NAME ": I2S OSS audio driver initialized.\n");
+
+ return 0;
+}
+
+static void __exit cleanup_jz_i2s(void)
+{
+#ifdef CONFIG_PM
+ /* pm_unregister(i2s_controller->pm); */
+#endif
+#if defined(CONFIG_I2S_DLV)
+ free_irq(IRQ_AIC, NULL);
+#endif
+ unload_jz_i2s(i2s_controller);
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ if(clear_codec_mode)
+ clear_codec_mode();
+}
+
+module_init(init_jz_i2s);
+module_exit(cleanup_jz_i2s);
+
+#if defined(CONFIG_SOC_JZ4730)
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count,con;
+
+ if(elements_in_queue(&in_busy_queue) > 0) {
+ if (nonblock)
+ return -EBUSY;
+ drain_flag = 1;
+ sleep_on(&drain_wait_queue);
+ drain_flag = 0;
+ } else {
+ add_wait_queue(&ctrl->adc_wait, &wait);
+ for (con = 0; con < 1000; con ++) {
+ udelay(1);
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ if (nonblock) {
+ remove_wait_queue(&ctrl->adc_wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ remove_wait_queue(&ctrl->adc_wait, &wait);
+ current->state = TASK_RUNNING;
+ }
+ return 0;
+}
+
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count;
+
+ if(elements_in_queue(&out_full_queue) > 0) {
+ if (nonblock)
+ return -EBUSY;
+
+ drain_flag = 1;
+ sleep_on(&drain_wait_queue);
+ drain_flag = 0;
+ } else {
+ add_wait_queue(&(ctrl->dac_wait), &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if(elements_in_queue(&out_full_queue) <= 0) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if(count <= 0)
+ break;
+ }
+ if (nonblock) {
+ remove_wait_queue(&ctrl->dac_wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ remove_wait_queue(&ctrl->dac_wait, &wait);
+ current->state = TASK_RUNNING;
+ }
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SOC_JZ4740)
+#define MAXDELAY 50000
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ int count,ele,i=0;
+ int tfl;
+
+ for (;;) {
+ if(!nonblock) {//blocked
+ if ( i < MAXDELAY ) {
+ udelay(10);
+ i++;
+ } else
+ break;
+
+ ele = elements_in_queue(&out_full_queue);
+ if(ele <= 0) {
+ udelay(10);
+ spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+ }
+ } else {//non-blocked
+ mdelay(100);
+ ele = elements_in_queue(&out_full_queue);
+
+ if(ele <= 0) {
+ mdelay(100);
+
+ spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+ }
+ }
+ }
+
+ /* wait for TX fifo */
+ while (1) {
+ tfl = __aic_get_transmit_resident();
+ if (tfl == 0)
+ break;
+ udelay(2);
+ }
+
+ return 0;
+}
+
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ int count,i=0;
+
+ for (;;) {
+ if ( i < MAXDELAY )
+ {
+ udelay(10);
+ i++;
+ }
+ else
+ break;
+ spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+
+ if (nonblock) {
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) || defined(CONFIG_SOC_JZ4750L)
+#define MAXDELAY 50000
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ //DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count,i=0;
+
+ //add_wait_queue(&ctrl->adc_wait, &wait);
+ for (;;) {
+ if (i < MAXDELAY) {
+ udelay(10);
+ i++;
+ } else
+ break;
+ //set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&ctrl->lock, flags);
+ //spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ //spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+
+ /*if (signal_pending(current))
+ break;*/
+ if (nonblock) {
+ //remove_wait_queue(&ctrl->adc_wait, &wait);
+ //current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ //remove_wait_queue(&ctrl->adc_wait, &wait);
+ //current->state = TASK_RUNNING;
+ /*if (signal_pending(current))
+ return -ERESTARTSYS;*/
+ return 0;
+}
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ unsigned long flags;
+ int count,ele,busyele,emptyele,i=0;
+
+ for (;;) {
+ if(!nonblock) {//blocked
+ if (i < MAXDELAY) {
+ udelay(10);
+ i++;
+ } else
+ break;
+
+ ele = elements_in_queue(&out_full_queue);
+ if(ele <= 0) {
+ udelay(200);
+
+ busyele = elements_in_queue(&out_busy_queue);
+ emptyele = elements_in_queue(&out_empty_queue);
+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ }
+ }
+ } else {//non-blocked
+ //mdelay(100);
+ ele = elements_in_queue(&out_full_queue);
+
+ if(ele <= 0) {
+ //mdelay(100);
+ busyele = elements_in_queue(&out_busy_queue);
+ emptyele = elements_in_queue(&out_empty_queue);
+
+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static int jz_audio_release(struct inode *inode, struct file *file)
+{
+ unsigned long flags;
+#if defined(CONFIG_I2S_DLV)
+ unsigned long tfl;
+#endif
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+#if defined(CONFIG_I2S_DLV)
+ jz_codec_config = 0;
+#endif
+ if (controller == NULL)
+ return -ENODEV;
+
+ pop_dma_flag = 0;
+
+ if (controller->opened1 == 1 && controller->opened2 == 1) {
+ controller->opened1 = 0;
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+ drain_dac(controller, file->f_flags & O_NONBLOCK);
+#if defined(CONFIG_I2S_DLV)
+ /* wait for fifo empty */
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ gain_down_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //gain_down_end = jiffies;
+ /*while (1) {
+ tfl = REG_AIC_SR & 0x00003f00;
+ if (tfl == 0) {
+ udelay(500);
+ break;
+ }
+ mdelay(2);
+ }*/
+ mdelay(100);
+#endif
+ disable_dma(controller->dma1);
+ set_dma_count(controller->dma1, 0);
+ __i2s_disable_transmit_dma();
+ __i2s_disable_replay();
+
+#if defined(CONFIG_I2S_ICODEC)
+ if(clear_codec_replay)
+ clear_codec_replay();
+#endif
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ controller->opened2 = 0;
+ first_record_call = 1;
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ drain_adc(controller, file->f_flags & O_NONBLOCK);
+ disable_dma(controller->dma2);
+ set_dma_count(controller->dma2, 0);
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+#if defined(CONFIG_I2S_ICODEC)
+ if(clear_codec_record)
+ clear_codec_record();
+#endif
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ ramp_down_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //ramp_down_end = jiffies;
+ if (use_mic_line_flag == USE_LINEIN) {
+ unset_record_line_input_audio_with_audio_data_replay();
+ //printk("3 use_mic_line_flag=%d\n",use_mic_line_flag);
+ }
+ if (use_mic_line_flag == USE_MIC) {
+ unset_record_mic_input_audio_with_audio_data_replay();
+ //printk("4 use_mic_line_flag=%d\n",use_mic_line_flag);
+ }
+
+#if 0
+ unset_record_playing_audio_mixed_with_mic_input_audio();
+#endif
+#endif
+ __i2s_disable();
+ if(turn_off_codec)
+ turn_off_codec();
+ abnormal_data_count = 0;
+ } else if (controller->opened1 == 1) {
+ //controller->opened1 = 0;
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+ drain_dac(controller, file->f_flags & O_NONBLOCK);
+ /* add some mute to anti-pop */
+#if defined(CONFIG_I2S_ICODEC)
+ //write_mute_to_dma_buffer(save_last_samples[last_dma_buffer_id].left,save_last_samples[last_dma_buffer_id].right);
+#endif
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ gain_down_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //gain_down_end = jiffies;
+ while (1) {
+ tfl = REG_AIC_SR & 0x00003f00;
+ if (tfl == 0) {
+ udelay(500);
+ break;
+ }
+ mdelay(2);
+ }
+#endif
+ disable_dma(controller->dma1);
+ set_dma_count(controller->dma1, 0);
+ __i2s_disable_transmit_dma();
+ __i2s_disable_replay();
+#if defined(CONFIG_I2S_ICODEC)
+ if(clear_codec_replay)
+ clear_codec_replay();
+#endif
+// __aic_flush_fifo();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ ramp_down_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //ramp_down_end = jiffies;
+ unset_audio_data_replay();
+#endif
+ __i2s_disable();
+#if defined(CONFIG_I2S_ICODEC)
+ if(turn_off_codec)
+ turn_off_codec();
+#endif
+ } else if (controller->opened2 == 1) {
+ controller->opened2 = 0;
+ first_record_call = 1;
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ drain_adc(controller, file->f_flags & O_NONBLOCK);
+ disable_dma(controller->dma2);
+ set_dma_count(controller->dma2, 0);
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+#if defined(CONFIG_I2S_ICODEC)
+ if(clear_codec_record)
+ clear_codec_record();
+#endif
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+#if defined(CONFIG_I2S_DLV)
+#if 0
+ /* unset Record MIC input audio with direct playback */
+ unset_record_mic_input_audio_with_direct_playback();
+#endif
+#if 0
+ /* unset Record MIC input audio without playback */
+ unset_record_mic_input_audio_without_playback();
+#endif
+#if 1
+ unset_playback_line_input_audio_direct_only();
+#endif
+#if 0
+ /* tested */
+ /* unset Record LINE input audio without playback */
+ unset_record_line_input_audio_without_playback();
+#endif
+#endif
+ __i2s_disable();
+#if defined(CONFIG_I2S_ICODEC)
+ if(turn_off_codec)
+ turn_off_codec();
+#endif
+ abnormal_data_count = 0;
+ }
+
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+/* __cpm_stop_idct();
+ __cpm_stop_db();
+ __cpm_stop_me();
+ __cpm_stop_mc();
+ __cpm_stop_ipu();*/
+#endif
+
+ if (controller->opened1 == 1 && controller->opened2 == 1) {
+ controller->opened1 = 0;
+ controller->opened2 = 0;
+ //print_pop_duration();
+ //__dmac_disable_module(0);
+ } else if ( controller->opened1 == 1 ) {
+ controller->opened1 = 0;
+ //print_pop_duration();
+ } else if ( controller->opened2 == 1 ) {
+ controller->opened2 = 0;
+ }
+
+ return 0;
+}
+
+static int jz_audio_open(struct inode *inode, struct file *file)
+{
+ int i;
+ struct jz_i2s_controller_info *controller = i2s_controller;
+#if defined(CONFIG_I2S_DLV)
+ jz_codec_config = 0;
+#endif
+ if (controller == NULL)
+ return -ENODEV;
+
+ mdelay(2);
+#if defined(CONFIG_I2S_DLV)
+ REG_DMAC_DMACKE(0) = 0x3f;
+#endif
+ pop_dma_flag = 0;
+ if (controller->opened1 == 1 || controller->opened2 == 1 ) {
+ printk("\naudio is busy!\n");
+ return -EBUSY;
+ }
+
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ if (controller->opened1 == 1)
+ return -EBUSY;
+ controller->opened1 = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+
+ for(i=0;i < 64;i++) {
+ save_last_samples[i].left = 0;
+ save_last_samples[i].right = 0;
+ }
+
+ out_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ last_dma_buffer_id = 0;
+
+ if (controller->opened2 == 1)
+ return -EBUSY;
+
+ controller->opened2 = 1;
+ first_record_call = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+
+ in_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+ } else if (file->f_mode & FMODE_WRITE) {
+ if (controller->opened1 == 1)
+ return -EBUSY;
+
+ controller->opened1 = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+
+ for(i=0;i < 64;i++) {
+ save_last_samples[i].left = 0;
+ save_last_samples[i].right = 0;
+ }
+
+ out_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ last_dma_buffer_id = 0;
+ } else if (file->f_mode & FMODE_READ) {
+ if (controller->opened2 == 1)
+ return -EBUSY;
+
+ controller->opened2 = 1;
+ first_record_call = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+
+ in_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+ }
+
+ file->private_data = controller;
+ jz_audio_reset();
+ REG_AIC_FR |= (1 << 6);
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+#if defined(CONFIG_I2S_ICODEC)
+ if (set_codec_replay_record)
+ set_codec_replay_record(use_mic_line_flag);
+#endif
+#if defined(CONFIG_I2S_DLV)
+ if (use_mic_line_flag == USE_NONE) {
+ printk("you select mic or line recording please.or use mic recording!\n");
+ use_mic_line_flag = USE_MIC;
+ }
+ if (use_mic_line_flag == USE_LINEIN) {
+ /* Record LINE input audio with Audio data replay (full duplex for linein) */
+ /* codec_test_line */
+ set_record_line_input_audio_with_audio_data_replay();
+
+ }
+ if (use_mic_line_flag == USE_MIC) {
+ /* Record MIC input audio with Audio data replay (full duplex) */
+ /* codec_test_mic */
+ set_record_mic_input_audio_with_audio_data_replay();
+ }
+#if 0
+ /* Record playing audio mixed with MIC input audio */
+ set_record_playing_audio_mixed_with_mic_input_audio();
+#endif
+
+#endif
+ } else if (file->f_mode & FMODE_WRITE) {
+#if defined(CONFIG_I2S_ICODEC)
+ if(set_codec_replay)
+ set_codec_replay();
+#endif
+#if defined(CONFIG_I2S_DLV)
+ //mdelay(10);
+ /* Audio data replay */
+ set_audio_data_replay();
+#endif
+ } else if (file->f_mode & FMODE_READ) {
+#if defined(CONFIG_I2S_ICODEC)
+ abnormal_data_count = 0;
+ if(set_codec_record)
+ set_codec_record(use_mic_line_flag);
+#endif
+#if defined(CONFIG_I2S_DLV)
+#if 0
+ /* Record MIC input audio with direct playback */
+ set_record_mic_input_audio_with_direct_playback();
+#endif
+
+#if 0
+ /* set Record MIC input audio without playback */
+ set_record_mic_input_audio_without_playback();
+#endif
+#if 1
+ /* set Playback LINE input audio direct only */
+ set_playback_line_input_audio_direct_only();
+#endif
+#if 0
+ /* tested */
+ /* set Record LINE input audio without playback */
+ set_record_line_input_audio_without_playback();
+#endif
+ mdelay(1);
+#endif
+ }
+
+#if defined(CONFIG_I2S_DLV)
+ __aic_reset();
+
+ mdelay(10);
+ REG_AIC_I2SCR = 0x10;
+ mdelay(20);
+// __aic_flush_fifo();
+#endif
+
+ __i2s_enable();
+
+#if defined(CONFIG_I2S_DLV)
+ ndelay(100);
+
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+#if defined(CONFIG_I2S_DLV)
+ //set SB_ADC or SB_DAC
+ __dmac_enable_module(0);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ ramp_up_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //ramp_up_end = jiffies;
+#endif
+ } else if (file->f_mode & FMODE_WRITE) {
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ ramp_up_start = jiffies;
+ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_RCR = 0x1;
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_RGR = 1;*/
+ sleep_on(&pop_wait_queue);
+ //ramp_up_end = jiffies;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+#endif
+ } else if (file->f_mode & FMODE_READ) {
+#if defined(CONFIG_I2S_DLV)
+ if (jz_mic_only)
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ else
+ write_codec_file_bit(5, 0, 7);//SB_DAC->0
+ mdelay(500);
+#endif
+ }
+#endif
+ return 0;
+}
+
+
+static int jz_audio_ioctl(struct inode *inode, struct file *file,
+unsigned int cmd, unsigned long arg)
+{
+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize;
+ unsigned long flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ count_info cinfo;
+ audio_buf_info abinfo;
+ int id, i;
+
+ val = 0;
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *)arg);
+ case SNDCTL_DSP_RESET:
+#if 0
+ jz_audio_reset();
+ __i2s_disable_replay();
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+ __i2s_disable_transmit_dma();
+#endif
+ return 0;
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ return drain_dac(controller, file->f_flags & O_NONBLOCK);
+ return 0;
+ case SNDCTL_DSP_SPEED:
+ /* set smaple rate */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val >= 0)
+ jz_audio_set_speed(controller->dev_audio, val);
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_STEREO:
+ /* set stereo or mono channel */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1);
+
+ return 0;
+ case SNDCTL_DSP_GETBLKSIZE:
+ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg);
+ return put_user(jz_audio_fragsize, (int *)arg);
+ case SNDCTL_DSP_GETFMTS:
+ /* Returns a mask of supported sample format*/
+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg);
+ case SNDCTL_DSP_SETFMT:
+ /* Select sample format */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val != AFMT_QUERY)
+ jz_audio_set_format(controller->dev_audio,val);
+ else {
+ if (file->f_mode & FMODE_READ)
+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+ else
+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+ }
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_CHANNELS:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ jz_audio_set_channels(controller->dev_audio, val);
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_POST:
+ /* FIXME: the same as RESET ?? */
+ return 0;
+ case SNDCTL_DSP_SUBDIVIDE:
+ return 0;
+ case SNDCTL_DSP_SETFRAGMENT:
+ get_user(val, (long *) arg);
+ newfragsize = 1 << (val & 0xFFFF);
+ if (newfragsize < 4 * PAGE_SIZE)
+ newfragsize = 4 * PAGE_SIZE;
+ if (newfragsize > (16 * PAGE_SIZE))
+ newfragsize = 16 * PAGE_SIZE;
+
+ newfragstotal = (val >> 16) & 0x7FFF;
+ if (newfragstotal < 2)
+ newfragstotal = 2;
+ if (newfragstotal > 32)
+ newfragstotal = 32;
+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize))
+ return 0;
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ mdelay(500);
+ jz_audio_fragstotal = newfragstotal;
+ jz_audio_fragsize = newfragsize;
+
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ mdelay(10);
+
+ return 0;
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg);
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+ case SNDCTL_DSP_SETDUPLEX:
+ return -EINVAL;
+ case SNDCTL_DSP_GETOSPACE:
+ {
+ int i;
+ unsigned long bytes = 0;
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ jz_audio_fragments = elements_in_queue(&out_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+
+ if (jz_audio_channels == 2)
+ bytes /= jz_audio_b;
+ else if (jz_audio_channels == 1)
+ bytes /= 4;
+ else
+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n");
+
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ /* unused fragment amount */
+ abinfo.fragments = jz_audio_fragments;
+ /* amount of fragments */
+ abinfo.fragstotal = jz_audio_fragstotal;
+ /* fragment size in bytes */
+ if (jz_audio_channels == 2)
+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b;
+ else if (jz_audio_channels == 1)
+ abinfo.fragsize = jz_audio_fragsize / 4;
+ else
+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n");
+
+ /* write size count without blocking in bytes */
+ abinfo.bytes = (int)bytes;
+
+ return copy_to_user((void *)arg, &abinfo,
+ sizeof(abinfo)) ? -EFAULT : 0;
+ }
+ case SNDCTL_DSP_GETISPACE:
+ {
+ int i;
+ unsigned long bytes = 0;
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ jz_audio_fragments = elements_in_queue(&in_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+
+ if (jz_audio_channels == 2)
+ bytes /= jz_audio_b;
+ else if (jz_audio_channels == 1)
+ bytes /= 4;
+ else
+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n");
+
+ abinfo.fragments = jz_audio_fragments;
+ abinfo.fragstotal = jz_audio_fragstotal;
+
+ if (jz_audio_channels == 2)
+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b;
+ else if (jz_audio_channels == 1)
+ abinfo.fragsize = jz_audio_fragsize / 4;
+ else
+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n");
+
+ abinfo.bytes = (int)bytes;
+
+ return copy_to_user((void *)arg, &abinfo,
+ sizeof(abinfo)) ? -EFAULT : 0;
+ }
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && in_dma_buf)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && out_dma_buf)
+ val |= PCM_ENABLE_OUTPUT;
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_SETTRIGGER:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ return 0;
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextIn;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextOut;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ unfinish = 0;
+ fullc = elements_in_queue(&out_full_queue);
+ busyc = elements_in_queue(&out_busy_queue);
+ for(i = 0;i < fullc ;i ++) {
+ id = *(out_full_queue.id + i);
+ unfinish += *(out_dma_buf_data_count + id);
+ }
+ for(i = 0;i < busyc ;i ++) {
+ id = *(out_busy_queue.id + i);
+ unfinish += get_dma_residue(controller->dma1);
+ }
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ if (jz_audio_channels == 2)
+ unfinish /= jz_audio_b;
+ else if (jz_audio_channels == 1)
+ unfinish /= 4;
+ else
+ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n");
+
+ return put_user(unfinish, (int *) arg);
+ case SOUND_PCM_READ_RATE:
+ return put_user(jz_audio_rate, (int *)arg);
+ case SOUND_PCM_READ_CHANNELS:
+ return put_user(jz_audio_channels, (int *)arg);
+ case SOUND_PCM_READ_BITS:
+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg);
+ case SNDCTL_DSP_MAPINBUF:
+ case SNDCTL_DSP_MAPOUTBUF:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_WRITE_FILTER:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+
+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait)
+{
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ return POLLOUT | POLLWRNORM;
+
+ poll_wait(file, &controller->dac_wait, wait);
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ return POLLIN | POLLRDNORM;
+
+ poll_wait(file, &controller->adc_wait, wait);
+ }
+
+ spin_lock_irqsave(&controller->lock, flags);
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ mask |= POLLOUT | POLLWRNORM;
+ } else if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ return mask;
+}
+
+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ int id, ret = 0, left_count, copy_count, cnt = 0;
+ unsigned long flags;
+
+ if (count < 0)
+ return -EINVAL;
+
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextIn = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ copy_count = jz_audio_fragsize / 4;
+
+ left_count = count;
+ if (first_record_call) {
+ first_record_call = 0;
+ audio_read_back_first:
+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ spin_lock(&controller->lock);
+ *(in_dma_buf_data_count + id) = copy_count * 4;
+
+ spin_unlock(&controller->lock);
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id));
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ sleep_on(&rx_wait_queue);
+ } else
+ goto audio_read_back_first;
+ }
+
+ while (left_count > 0) {
+ audio_read_back_second:
+ if (elements_in_queue(&in_full_queue) <= 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ else
+ sleep_on(&rx_wait_queue);
+ }
+
+ if ((id = get_buffer_id(&in_full_queue)) >= 0) {
+ spin_lock(&controller->lock);
+ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id);
+ spin_unlock(&controller->lock);
+ put_buffer_id(&in_empty_queue, id);
+ } else
+ goto audio_read_back_second;
+
+ if (elements_in_queue(&in_busy_queue) == 0) {
+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ spin_lock(&controller->lock);
+ *(in_dma_buf_data_count + id) = copy_count * 4;
+ spin_unlock(&controller->lock);
+
+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id));
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ }
+ }
+ if (ret + cnt > count) {
+ spin_lock(&controller->lock);
+ cnt = count - ret;
+ spin_unlock(&controller->lock);
+ }
+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt))
+ return ret ? ret : -EFAULT;
+
+ spin_lock(&controller->lock);
+ ret += cnt;
+ spin_unlock(&controller->lock);
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextIn += ret;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ spin_lock(&controller->lock);
+ left_count -= cnt;
+ spin_unlock(&controller->lock);
+ }
+ return ret;
+}
+
+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ int id, ret = 0, left_count, copy_count = 0;
+ unsigned long flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+
+ if (count <= 0)
+ return -EINVAL;
+
+ if(set_replay_hp_or_speaker)
+ set_replay_hp_or_speaker();
+
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ if (jz_audio_channels == 2)
+ copy_count = jz_audio_fragsize / jz_audio_b;
+ else if(jz_audio_channels == 1)
+ copy_count = jz_audio_fragsize / 4;
+ left_count = count;
+ if (copy_from_user(controller->tmp1, buffer, count)) {
+ printk("copy_from_user failed:%d",ret);
+ return ret ? ret : -EFAULT;
+ }
+
+ while (left_count > 0) {
+ audio_write_back:
+ if (file->f_flags & O_NONBLOCK)
+ udelay(2);
+ if (elements_in_queue(&out_empty_queue) == 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret;
+ else
+ sleep_on(&tx_wait_queue);
+ }
+ /* the end fragment size in this write */
+ if (ret + copy_count > count)
+ copy_count = count - ret;
+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) {
+ replay_filler((signed long)controller->tmp1 + ret, copy_count, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ put_buffer_id(&out_full_queue, id);
+ dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id));
+ } else
+ put_buffer_id(&out_empty_queue, id);
+ } else
+ goto audio_write_back;
+
+ left_count = left_count - copy_count;
+ ret += copy_count;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextOut += ret;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ if (elements_in_queue(&out_busy_queue) == 0) {
+ if ((id=get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(controller->dma1,
+ file->private_data,
+ *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ last_dma_buffer_id = id;
+#if defined(CONFIG_I2S_DLV)
+ if (jz_codec_config == 0) {
+ write_codec_file_bit(1, 0, 5);
+ gain_up_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //gain_up_end = jiffies;
+ jz_codec_config = 1;
+ //SB_ADC->1
+ //write_codec_file_bit(5, 1, 4);
+ //while(1);
+ }
+#endif
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+#if defined(CONFIG_I2S_ICODEC)
+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample)
+{
+ int i,step_len;
+ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf;
+ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19;
+ unsigned long l_sample_count,r_sample_count,sample_count;
+ struct jz_i2s_controller_info *controller = i2s_controller;
+ signed int left_sam=0,right_sam=0,l_val,r_val;
+
+ switch (sample_oss) {
+ case 0x0:
+ break;
+ case 0x1:
+ left_sam = (signed int)l_sample;
+ right_sam = (signed int)r_sample;
+ break;
+ case 0x2:
+ break;
+ case 0x3:
+ break;
+ case 0x4:
+ break;
+ }
+
+ if(left_sam == 0 && right_sam == 0)
+ return;
+
+ switch (sample_oss) {
+ case 0x0:
+ break;
+ case 0x1:
+ step_len = jz_audio_speed / 10 * 3;
+ step_len = step_len / 2;
+ step_len = 0x7fff / step_len + 1;
+
+ l_sample_count = 0;
+ l_val = left_sam;
+
+ while(1) {
+ if(l_val > 0) {
+ if(l_val >= step_len) {
+ l_val -= step_len;
+ l_sample_count ++;
+ } else
+ break;
+ }
+
+ if(l_val < 0) {
+ if(l_val <= -step_len) {
+ l_val += step_len;
+ l_sample_count ++;
+ } else
+ break;
+ }
+
+ if(l_val == 0)
+ break;
+ }
+
+ r_sample_count = 0;
+ r_val = right_sam;
+ while(1) {
+ if(r_val > 0) {
+ if(r_val >= step_len) {
+ r_val -= step_len;
+ r_sample_count ++;
+ } else
+ break;
+ }
+
+ if(r_val < 0) {
+ if(r_val <= -step_len) {
+ r_val += step_len;
+ r_sample_count ++;
+ } else
+ break;
+ }
+
+ if(r_val == 0)
+ break;
+ }
+ /* fill up */
+ if(l_sample_count > r_sample_count)
+ sample_count = l_sample_count;
+ else
+ sample_count = r_sample_count;
+
+ l_val = left_sam;
+ r_val = right_sam;
+ for(i=0;i <= sample_count;i++) {
+
+ *pop_buf = (unsigned long)l_val;
+ pop_buf ++;
+
+ if(l_val > step_len)
+ l_val -= step_len;
+ else if(l_val < -step_len)
+ l_val += step_len;
+ else if(l_val >= -step_len && l_val <= step_len)
+ l_val = 0;
+
+ *pop_buf = (unsigned long)r_val;
+ pop_buf ++;
+ if(r_val > step_len)
+ r_val -= step_len;
+ else if(r_val < -step_len)
+ r_val += step_len;
+ else if(r_val >= -step_len && r_val <= step_len)
+ r_val = 0;
+ }
+
+ *pop_buf = 0;
+ pop_buf ++;
+ *pop_buf = 0;
+
+ pop_buf ++;
+ sample_count += 2;
+ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8);
+
+ pop_dma_flag = 1;
+ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE);
+ sleep_on(&pop_wait_queue);
+ pop_dma_flag = 0;
+ break;
+ case 0x2:
+ break;
+ case 0x3:
+ break;
+ case 0x4:
+ break;
+ }
+}
+#endif
diff --git a/sound/oss/jz_i2s_4750.c b/sound/oss/jz_i2s_4750.c
new file mode 100644
index 00000000000..b18270f313d
--- /dev/null
+++ b/sound/oss/jz_i2s_4750.c
@@ -0,0 +1,3010 @@
+/*
+ * linux/drivers/sound/Jz_i2s.c
+ *
+ * JzSOC On-Chip I2S audio driver.
+ *
+ * Copyright (C) 2005 by Junzheng Corp.
+ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using
+ * dma channel 4&3,noah is tested.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Because the normal application of AUDIO devices are focused on Little_endian,
+ * then we only perform the little endian data format in driver.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/pm_legacy.h>
+#include <sound/driver.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/proc_fs.h>
+#include <linux/soundcard.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <asm/hardirq.h>
+#include <asm/jzsoc.h>
+#include "sound_config.h"
+
+#define DPRINTK(args...) printk(args)
+#define DMA_ID_I2S_TX DMA_ID_AIC_TX
+#define DMA_ID_I2S_RX DMA_ID_AIC_RX
+#define NR_I2S 2
+#define MAXDELAY 50000
+#define JZCODEC_RW_BUFFER_SIZE 2
+#define JZCODEC_RW_BUFFER_TOTAL 6
+
+typedef struct hpvol_shift_s
+{
+ int hpvol;
+ int shift;
+} hpvol_shift_t;
+
+mixer_info info;
+_old_mixer_info old_info;
+int codec_volue_shift;
+hpvol_shift_t hpvol_shift_table[72];
+int abnormal_data_count;
+unsigned long i2s_clk;
+
+void (*set_codec_mode)(void) = NULL;
+void (*clear_codec_mode)(void) = NULL;
+void (*set_codec_gpio_pin)(void) = NULL;
+void (*each_time_init_codec)(void) = NULL;
+int (*set_codec_startup_param)(void) = NULL;
+void (*set_codec_volume_table)(void) = NULL;
+void (*set_codec_record)(void) = NULL;
+void (*set_codec_replay)(void) = NULL;
+void (*set_codec_replay_record)(void);
+void (*turn_on_codec)(void) = NULL;
+void (*turn_off_codec)(void) = NULL;
+void (*set_codec_speed)(int rate) = NULL;
+void (*reset_codec)(void) = NULL;
+void (*codec_mixer_old_info_id_name)(void) = NULL;
+void (*codec_mixer_info_id_name)(void) = NULL;
+void (*set_codec_bass)(int val) = NULL;
+void (*set_codec_volume)(int val) = NULL;
+void (*set_codec_mic)(int val) = NULL;
+void (*i2s_resume_codec)(void) = NULL;
+void (*i2s_suspend_codec)(int wr,int rd) = NULL;
+void (*init_codec_pin)(void) = NULL;
+void (*set_codec_some_func)(void) = NULL;
+void (*clear_codec_record)(void) = NULL;
+void (*clear_codec_replay)(void) = NULL;
+void (*set_replay_hp_or_speaker)(void) = NULL;
+void (*set_codec_direct_mode)(void) = NULL;
+void (*clear_codec_direct_mode)(void) = NULL;
+
+static int jz_audio_rate;
+static int jz_audio_format;
+static int jz_audio_volume;
+static int jz_audio_channels;
+static int jz_audio_b; /* bits expand multiple */
+static int jz_audio_fragments; /* unused fragment amount */
+static int jz_audio_fragstotal;
+static int jz_audio_fragsize;
+static int jz_audio_speed;
+
+static int codec_bass_gain;
+static int audio_mix_modcnt;
+static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */
+static int jz_mic_only = 1;
+static int jz_codec_config = 0;
+static unsigned long ramp_up_start;
+static unsigned long ramp_up_end;
+static unsigned long gain_up_start;
+static unsigned long gain_up_end;
+static unsigned long ramp_down_start;
+static unsigned long ramp_down_end;
+static unsigned long gain_down_start;
+static unsigned long gain_down_end;
+
+static int codec_mic_gain;
+static int pop_dma_flag;
+static int last_dma_buffer_id;
+static int drain_flag;
+
+static void (*old_mksound)(unsigned int hz, unsigned int ticks);
+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
+static void jz_update_filler(int bits, int channels);
+
+static int Init_In_Out_queue(int fragstotal,int fragsize);
+static int Free_In_Out_queue(int fragstotal,int fragsize);
+static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref);
+static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref);
+static void (*replay_filler)(signed long src_start, int count, int id);
+static int (*record_filler)(unsigned long dst_start, int count, int id);
+#if defined(CONFIG_I2S_ICODEC)
+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample);
+#endif
+static void jz_audio_reset(void);
+static struct file_operations jz_i2s_audio_fops;
+
+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue);
+
+struct jz_i2s_controller_info
+{
+ int io_base;
+ int dma1; /* for play */
+ int dma2; /* for record */
+ char *name;
+ int dev_audio;
+ struct i2s_codec *i2s_codec[NR_I2S];
+ int opened1;
+ int opened2;
+ unsigned char *tmp1; /* tmp buffer for sample conversions */
+ unsigned char *tmp2;
+ spinlock_t lock;
+ spinlock_t ioctllock;
+
+ wait_queue_head_t dac_wait;
+ wait_queue_head_t adc_wait;
+ int nextIn; /* byte index to next-in to DMA buffer */
+ int nextOut; /* byte index to next-out from DMA buffer */
+ int count; /* current byte count in DMA buffer */
+ int finish; /* current transfered byte count in DMA buffer */
+ unsigned total_bytes; /* total bytes written or read */
+ unsigned blocks;
+ unsigned error; /* over/underrun */
+#ifdef CONFIG_PM
+ struct pm_dev *pm;
+#endif
+};
+
+
+static struct jz_i2s_controller_info *i2s_controller = NULL;
+struct i2s_codec
+{
+ /* I2S controller connected with */
+ void *private_data;
+ char *name;
+ int id;
+ int dev_mixer;
+ /* controller specific lower leverl i2s accessing routines */
+ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */
+ void (*codec_write) (u8 reg, u16 val);
+ /* Wait for codec-ready */
+ void (*codec_wait) (struct i2s_codec *codec);
+ /* OSS mixer masks */
+ int modcnt;
+ int supported_mixers;
+ int stereo_mixers;
+ int record_sources;
+ int bit_resolution;
+ /* OSS mixer interface */
+ int (*read_mixer) (struct i2s_codec *codec, int oss_channel);
+ void (*write_mixer)(struct i2s_codec *codec, int oss_channel,
+ unsigned int left, unsigned int right);
+ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask);
+ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg);
+ /* saved OSS mixer states */
+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+};
+
+
+typedef struct buffer_queue_s
+{
+ int count;
+ int *id;
+ int lock;
+} buffer_queue_t;
+
+typedef struct left_right_sample_s
+{
+ signed long left;
+ signed long right;
+} left_right_sample_t;
+
+static unsigned long pop_turn_onoff_buf;
+static unsigned long pop_turn_onoff_pbuf;
+
+static unsigned long *out_dma_buf = NULL;
+static unsigned long *out_dma_pbuf = NULL;
+static unsigned long *out_dma_buf_data_count = NULL;
+static unsigned long *in_dma_buf = NULL;
+static unsigned long *in_dma_pbuf = NULL;
+static unsigned long *in_dma_buf_data_count = NULL;
+
+static buffer_queue_t out_empty_queue;
+static buffer_queue_t out_full_queue;
+static buffer_queue_t out_busy_queue;
+static buffer_queue_t in_empty_queue;
+static buffer_queue_t in_full_queue;
+static buffer_queue_t in_busy_queue;
+static int first_record_call = 0;
+
+static left_right_sample_t save_last_samples[64];
+static int read_codec_file(int addr)
+{
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ mdelay(1);
+ return(__icdc_get_value());
+}
+
+#if 0 /* mask warning */
+static void printk_codec_files(void)
+{
+ int cnt;
+
+ printk("\n");
+
+ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR);
+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR);
+ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR);
+ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR);
+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR);
+ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR);
+ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR);
+ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA);
+
+ for (cnt = 0; cnt <= 27 ; cnt++) {
+ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt));
+ }
+ printk("\n");
+}
+#endif
+
+static void write_codec_file(int addr, int val)
+{
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ __icdc_set_cmd(val); /* write */
+ mdelay(1);
+ __icdc_set_rgwr();
+ mdelay(1);
+}
+
+static int write_codec_file_bit(int addr, int bitval, int mask_bit)
+{
+ int val;
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ mdelay(1);
+ val = __icdc_get_value(); /* read */
+
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ val &= ~(1 << mask_bit);
+ if (bitval == 1)
+ val |= 1 << mask_bit;
+
+ __icdc_set_cmd(val); /* write */
+ mdelay(1);
+ __icdc_set_rgwr();
+ mdelay(1);
+
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ val = __icdc_get_value(); /* read */
+
+ if (((val >> mask_bit) & bitval) == bitval)
+ return 1;
+ else
+ return 0;
+}
+
+#if 0 /* mask warning */
+/* set Audio data replay */
+static void set_audio_data_replay(void)
+{
+ /* DAC path */
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ mdelay(10);
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ //mdelay(100);
+ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //mdelay(300);
+}
+#endif
+
+/* unset Audio data replay */
+static void unset_audio_data_replay(void)
+{
+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ //mdelay(800);
+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ //mdelay(800);
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 4);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+#if 0 /* mask warning */
+/* set Record MIC input audio without playback */
+static void set_record_mic_input_audio_without_playback(void)
+{
+ /* ADC path for MIC IN */
+ jz_mic_only = 1;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ mdelay(10);
+ write_codec_file_bit(1, 1, 2);
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+
+ write_codec_file(22, 0x40);//mic 1
+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ //write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file(1, 0x4);
+}
+#endif
+
+#if 0 /* mask warning */
+/* unset Record MIC input audio without playback */
+static void unset_record_mic_input_audio_without_playback(void)
+{
+ /* ADC path for MIC IN */
+ jz_mic_only = 0;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 0 /* mask warning */
+/* set Record LINE input audio without playback */
+static void set_record_line_input_audio_without_playback(void)
+{
+ /* ADC path for LINE IN */
+ jz_mic_only = 1;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+ write_codec_file(22, 0xf6);//line in 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1
+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ mdelay(10);
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file(1, 0x4);
+}
+#endif
+
+#if 0 /* mask warning */
+/* unset Record LINE input audio without playback */
+static void unset_record_line_input_audio_without_playback(void)
+{
+ /* ADC path for LINE IN */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1
+
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 0 /* mask warning */
+/* set Playback LINE input audio direct only */
+static void set_playback_line_input_audio_direct_only(void)
+{
+ jz_audio_reset();//or init_codec()
+ REG_AIC_I2SCR = 0x10;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+ write_codec_file(22, 0xf6);//line in 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ mdelay(10);
+ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1
+ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1
+}
+#endif
+
+#if 0 /* mask warning */
+/* unset Playback LINE input audio direct only */
+static void unset_playback_line_input_audio_direct_only(void)
+{
+ write_codec_file_bit(6, 0, 3);//GIM->0
+ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ mdelay(100);
+ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 0 /* mask warning */
+/* set Record MIC input audio with direct playback */
+static void set_record_mic_input_audio_with_direct_playback(void)
+{
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ jz_mic_only = 0;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+
+ write_codec_file(22, 0x60);//mic 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ //write_codec_file(1, 0x4);
+}
+#endif
+
+#if 0 /* mask warning */
+/* unset Record MIC input audio with direct playback */
+static void unset_record_mic_input_audio_with_direct_playback(void)
+{
+ /* ADC path for MIC IN */
+ jz_mic_only = 0;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 0 /* mask warning */
+/* set Record playing audio mixed with MIC input audio */
+static void set_record_playing_audio_mixed_with_mic_input_audio(void)
+{
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ mdelay(10);
+
+ write_codec_file(22, 0x63);//mic 1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0
+}
+#endif
+
+#if 0 /* mask warning */
+/* unset Record playing audio mixed with MIC input audio */
+static void unset_record_playing_audio_mixed_with_mic_input_audio(void)
+{
+ /* ADC path */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 5);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 0 /* mask warning */
+/* set Record MIC input audio with Audio data replay (full duplex) */
+static void set_record_mic_input_audio_with_audio_data_replay(void)
+{
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+}
+#endif
+
+#if 0 /* mask warning */
+/* unset Record MIC input audio with Audio data replay (full duplex) */
+static void unset_record_mic_input_audio_with_audio_data_replay(void)
+{
+ /* ADC path */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 5);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 0 /* mask warning */
+/* set Record LINE input audio with Audio data replay (full duplex for linein) */
+static void set_record_line_input_audio_with_audio_data_replay(void)
+{
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+
+
+ //jz_mic_only = 1;
+ write_codec_file(22, 0xc6);//line in 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+}
+#endif
+
+#if 0 /* mask warning */
+/* unset Record LINE input audio with Audio data replay (full duplex for linein) */
+static void unset_record_line_input_audio_with_audio_data_replay(void)
+{
+ /* ADC path */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 5);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+static inline int get_buffer_id(struct buffer_queue_s *q)
+{
+ int r;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&q->lock, flags);
+ if (q->count == 0) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ return -1;
+ }
+ r = *(q->id + 0);
+ for (i=0;i < q->count-1;i++)
+ *(q->id + i) = *(q->id + (i+1));
+ q->count --;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return r;
+}
+
+static inline void put_buffer_id(struct buffer_queue_s *q, int id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ *(q->id + q->count) = id;
+ q->count ++;
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+static inline int elements_in_queue(struct buffer_queue_s *q)
+{
+ int r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ r = q->count;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return r;
+}
+
+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode)
+{
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ jz_audio_dma_tran_count = count / jz_audio_b;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ flags = claim_dma_lock();
+ disable_dma(chan);
+ clear_dma_ff(chan);
+ //set_dma_mode(chan, mode);
+ jz_set_oss_dma(chan, mode, jz_audio_format);
+ set_dma_addr(chan, phyaddr);
+ if (count == 0) {
+ count++;
+ printk("JzSOC DMA controller can't set dma 0 count!\n");
+ }
+ set_dma_count(chan, count);
+ enable_dma(chan);
+ release_dma_lock(flags);
+}
+
+static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id)
+{
+ int id1, id2;
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+ int dma = controller->dma2;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+
+ if(drain_flag == 1)
+ wake_up(&drain_wait_queue);
+ /* for DSP_GETIPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ id1 = get_buffer_id(&in_busy_queue);
+ put_buffer_id(&in_full_queue, id1);
+
+ wake_up(&rx_wait_queue);
+ wake_up(&controller->adc_wait);
+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id2);
+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1);
+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2));
+ audio_start_dma(dma,dev_id,
+ *(in_dma_pbuf + id2),
+ *(in_dma_buf_data_count + id2),
+ DMA_MODE_READ);
+ } else
+ in_busy_queue.count = 0;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id)
+{
+ int id;
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+ int dma = controller->dma1;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+
+ if(pop_dma_flag == 1) {
+ pop_dma_flag = 0;
+ wake_up(&pop_wait_queue);
+ } else {
+ if(drain_flag == 1) {
+ /* Is replay dma buffer over ? */
+ if(elements_in_queue(&out_full_queue) <= 0) {
+ drain_flag = 0;
+ wake_up(&drain_wait_queue);
+ }
+ }
+
+ /* for DSP_GETOPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ if ((id = get_buffer_id(&out_busy_queue)) < 0)
+ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n");
+ put_buffer_id(&out_empty_queue, id);
+ if ((id = get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ last_dma_buffer_id = id;
+ }
+ } else
+ out_busy_queue.count = 0;
+
+ if (elements_in_queue(&out_empty_queue) > 0) {
+ wake_up(&tx_wait_queue);
+ wake_up(&controller->dac_wait);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void jz_i2s_initHw(int set)
+{
+#if defined(CONFIG_MIPS_JZ_URANUS)
+ i2s_clk = 48000000;
+#else
+ i2s_clk = __cpm_get_i2sclk();
+#endif
+ __i2s_disable();
+ if(set)
+ __i2s_reset();
+ schedule_timeout(5);
+ if(each_time_init_codec)
+ each_time_init_codec();
+ __i2s_disable_record();
+ __i2s_disable_replay();
+ __i2s_disable_loopback();
+ __i2s_set_transmit_trigger(4);
+ __i2s_set_receive_trigger(3);
+}
+
+static int Init_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+
+ /* recording */
+ in_empty_queue.count = fragstotal;
+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf)
+ goto all_mem_err;
+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_pbuf)
+ goto all_mem_err;
+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf_data_count)
+ goto all_mem_err;
+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_empty_queue.id)
+ goto all_mem_err;
+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_full_queue.id)
+ goto all_mem_err;
+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_busy_queue.id)
+ goto all_mem_err;
+
+ for (i=0;i < fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+
+ for (i = 0; i < fragstotal; i++) {
+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(in_dma_buf + i) == 0)
+ goto mem_failed_in;
+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i)));
+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
+ }
+
+ /* playing */
+ out_empty_queue.count = fragstotal;
+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_buf)
+ goto all_mem_err;
+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_pbuf)
+ goto all_mem_err;
+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+
+ if (!out_dma_buf_data_count)
+ goto all_mem_err;
+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_empty_queue.id)
+ goto all_mem_err;
+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_full_queue.id)
+ goto all_mem_err;
+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_busy_queue.id)
+ goto all_mem_err;
+ for (i=0;i < fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ /* alloc DMA buffer */
+ for (i = 0; i < fragstotal; i++) {
+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(out_dma_buf + i) == 0) {
+ printk(" can't allocate required DMA(OUT) buffers.\n");
+ goto mem_failed_out;
+ }
+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i)));
+ }
+
+ return 1;
+all_mem_err:
+ printk("error:allocate memory occur error 1!\n");
+ return 0;
+mem_failed_out:
+ printk("error:allocate memory occur error 2!\n");
+ for (i = 0; i < fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ }
+
+ return 0;
+mem_failed_in:
+ printk("error:allocate memory occur error 3!\n");
+ for (i = 0; i < fragstotal; i++) {
+ if(*(in_dma_buf + i))
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ return 0;
+}
+
+static int Free_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+ /* playing */
+ if(out_dma_buf != NULL) {
+ for (i = 0; i < fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ *(out_dma_buf + i) = 0;
+ }
+ kfree(out_dma_buf);
+ out_dma_buf = NULL;
+ }
+ if(out_dma_pbuf) {
+ kfree(out_dma_pbuf);
+ out_dma_pbuf = NULL;
+ }
+ if(out_dma_buf_data_count) {
+ kfree(out_dma_buf_data_count);
+ out_dma_buf_data_count = NULL;
+ }
+ if(out_empty_queue.id) {
+ kfree(out_empty_queue.id);
+ out_empty_queue.id = NULL;
+ }
+ if(out_full_queue.id) {
+ kfree(out_full_queue.id);
+ out_full_queue.id = NULL;
+ }
+ if(out_busy_queue.id) {
+ kfree(out_busy_queue.id);
+ out_busy_queue.id = NULL;
+ }
+ out_empty_queue.count = fragstotal;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+
+ /* recording */
+ if(in_dma_buf) {
+ for (i = 0; i < fragstotal; i++) {
+ if(*(in_dma_buf + i)) {
+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ *(in_dma_buf + i) = 0;
+ }
+ kfree(in_dma_buf);
+ in_dma_buf = NULL;
+ }
+ if(in_dma_pbuf) {
+ kfree(in_dma_pbuf);
+ in_dma_pbuf = NULL;
+ }
+ if(in_dma_buf_data_count) {
+ kfree(in_dma_buf_data_count);
+ in_dma_buf_data_count = NULL;
+ }
+ if(in_empty_queue.id) {
+ kfree(in_empty_queue.id);
+ in_empty_queue.id = NULL;
+ }
+ if(in_full_queue.id) {
+ kfree(in_full_queue.id);
+ in_full_queue.id = NULL;
+ }
+ if(in_busy_queue.id) {
+ kfree(in_busy_queue.id);
+ in_busy_queue.id = NULL;
+ }
+
+ in_empty_queue.count = fragstotal;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+
+ return 1;
+}
+
+static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller)
+{
+ jz_i2s_initHw(0);
+}
+
+static int jz_audio_set_speed(int dev, int rate)
+{
+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */
+ jz_audio_speed = rate;
+ if (rate > 48000)
+ rate = 48000;
+ if (rate < 8000)
+ rate = 8000;
+ jz_audio_rate = rate;
+
+ if(set_codec_speed)
+ set_codec_speed(rate);
+
+ return jz_audio_rate;
+}
+
+
+static int record_fill_1x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long data;
+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char*)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt++;
+ data = *(s++);
+ *(dp ++) = ((data << 16) >> 24) + 0x80;
+ s++; /* skip the other channel */
+ }
+
+ return cnt;
+}
+
+
+static int record_fill_2x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1, d2;
+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char*)dst_start;
+
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+ *(dp ++) = ((d1 << 16) >> 24) + 0x80;
+ d2 = *(s++);
+ *(dp ++) = ((d2 << 16) >> 24) + 0x80;
+ }
+
+ return cnt;
+}
+
+
+static int record_fill_1x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1;
+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt += 2; /* count in byte */
+ d1 = *(s++);
+ *(dp ++) = (d1 << 16) >> 16;
+ s++; /* skip the other channel */
+ }
+
+ return cnt;
+}
+
+
+static int record_fill_2x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1, d2;
+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt += 4; /* count in byte */
+ d1 = *(s++);
+ d2 = *(s++);
+ if(abnormal_data_count > 0) {
+ d1 = d2 = 0;
+ abnormal_data_count --;
+ }
+ *(dp ++) = (d1 << 16) >> 16;
+ *(dp ++) = (d2 << 16) >> 16;
+ }
+
+ return cnt;
+}
+
+static void replay_fill_1x8_u(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned char data;
+ unsigned long ddata;
+ volatile unsigned char *s = (unsigned char *)src_start;
+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count--;
+ cnt += 1;
+ data = *(s++) - 0x80;
+ ddata = (unsigned long) data << 8;
+ *(dp ++) = ddata;
+ *(dp ++) = ddata;
+
+ /* save last left and right */
+ if(count == 1) {
+ save_last_samples[id].left = ddata;
+ save_last_samples[id].right = ddata;
+ }
+ }
+ cnt = cnt * 2 * jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+
+static void replay_fill_2x8_u(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned char d1;
+ unsigned long dd1;
+ volatile unsigned char *s = (unsigned char *)src_start;
+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count -= 1;
+ cnt += 1 ;
+ d1 = *(s++) - 0x80;
+ dd1 = (unsigned long) d1 << 8;
+ *(dp ++) = dd1;
+ /* save last left */
+ if(count == 2)
+ save_last_samples[id].left = dd1;
+ /* save last right */
+ if(count == 1)
+ save_last_samples[id].right = dd1;
+ }
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+
+static void replay_fill_1x16_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed short d1;
+ signed long l1;
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count -= 2;
+ cnt += 2 ;
+ d1 = *(s++);
+ l1 = (signed long)d1;
+ *(dp ++) = l1;
+ *(dp ++) = l1;
+
+ /* save last left and right */
+ if(count == 1) {
+ save_last_samples[id].left = l1;
+ save_last_samples[id].right = l1;
+ }
+ }
+ cnt = cnt * 2 * jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+#if 0
+static void replay_fill_2x16_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed short d1;
+ signed long l1;
+ int mute_cnt = 0;
+ signed long tmp1,tmp2;
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+#if defined(CONFIG_I2S_ICDC)
+ volatile signed long *before_dp;
+ int sam_rate = jz_audio_rate / 20;
+
+ tmp1 = tmp2 = 0;
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+
+ l1 = (signed long)d1;
+ l1 >>= codec_volue_shift;
+
+ if(l1 == 0) {
+ mute_cnt ++;
+ if(mute_cnt >= sam_rate) {
+ before_dp = dp - 10;
+ *(before_dp) = (signed long)1;
+ before_dp = dp - 11;
+ *(before_dp) = (signed long)1;
+ mute_cnt = 0;
+ }
+ } else
+ mute_cnt = 0;
+
+ *(dp ++) = l1;
+
+ tmp1 = tmp2;
+ tmp2 = l1;
+ }
+
+ /* save last left */
+ save_last_samples[id].left = tmp1;
+ /* save last right */
+ save_last_samples[id].right = tmp2;
+#endif
+#if defined(CONFIG_I2S_DLV)
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+
+ l1 = (signed long)d1;
+
+ *(dp ++) = l1;
+ }
+#endif
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+#else
+static void replay_fill_2x16_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed short d1;
+ signed long l1;
+
+#if 0
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed short *dp = (signed short*)(*(out_dma_buf + id));
+ memcpy((char*)dp, (char*)s, count);
+ *(out_dma_buf_data_count + id) = count;
+#else
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+
+ l1 = (signed long)d1;
+
+ *(dp ++) = l1;
+ }
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+#endif
+}
+#endif
+
+
+static unsigned int jz_audio_set_format(int dev, unsigned int fmt)
+{
+ switch (fmt) {
+ case AFMT_U8:
+ __i2s_set_oss_sample_size(8);
+ __i2s_set_iss_sample_size(8);
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+ break;
+ case AFMT_S16_LE:
+#if defined(CONFIG_I2S_DLV)
+ /* DAC path and ADC path */
+ write_codec_file(2, 0x00);
+ //write_codec_file(2, 0x60);
+#endif
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format,jz_audio_channels);
+ /* print all files */
+ __i2s_set_oss_sample_size(16);
+ __i2s_set_iss_sample_size(16);
+ break;
+
+ case AFMT_QUERY:
+ break;
+ }
+
+ return jz_audio_format;
+}
+
+
+static short jz_audio_set_channels(int dev, short channels)
+{
+ switch (channels) {
+ case 1:
+ if(set_codec_some_func)
+ set_codec_some_func();
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono
+#endif
+ break;
+ case 2:
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo
+#endif
+ break;
+ case 0:
+ break;
+ }
+
+ return jz_audio_channels;
+}
+
+static void init_codec(void)
+{
+ /* inititalize internal I2S codec */
+ if(init_codec_pin)
+ init_codec_pin();
+
+#if defined(CONFIG_I2S_ICDC)
+ /* initialize AIC but not reset it */
+ jz_i2s_initHw(0);
+#endif
+ if(reset_codec)
+ reset_codec();
+}
+
+static void jz_audio_reset(void)
+{
+ __i2s_disable_replay();
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+ __i2s_disable_transmit_dma();
+#if defined(CONFIG_I2S_DLV)
+ REG_AIC_I2SCR = 0x10;
+#endif
+ init_codec();
+}
+
+static int jz_audio_release(struct inode *inode, struct file *file);
+static int jz_audio_open(struct inode *inode, struct file *file);
+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg);
+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait);
+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos);
+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos);
+
+/* static struct file_operations jz_i2s_audio_fops */
+static struct file_operations jz_i2s_audio_fops =
+{
+ owner: THIS_MODULE,
+ open: jz_audio_open,
+ release: jz_audio_release,
+ write: jz_audio_write,
+ read: jz_audio_read,
+ poll: jz_audio_poll,
+ ioctl: jz_audio_ioctl
+};
+
+static int jz_i2s_open_mixdev(struct inode *inode, struct file *file)
+{
+ int i;
+ int minor = MINOR(inode->i_rdev);
+ struct jz_i2s_controller_info *controller = i2s_controller;
+
+ for (i = 0; i < NR_I2S; i++)
+ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor)
+ goto match;
+
+ if (!controller)
+ return -ENODEV;
+match:
+ file->private_data = controller->i2s_codec[i];
+
+ return 0;
+}
+
+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data;
+ return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static struct file_operations jz_i2s_mixer_fops =
+{
+ owner: THIS_MODULE,
+ llseek: jz_i2s_llseek,
+ ioctl: jz_i2s_ioctl_mixdev,
+ open: jz_i2s_open_mixdev,
+};
+
+static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ long val = 0;
+ switch (cmd) {
+ case SOUND_MIXER_INFO:
+
+ if(codec_mixer_info_id_name)
+ codec_mixer_info_id_name();
+ info.modify_counter = audio_mix_modcnt;
+
+ return copy_to_user((void *)arg, &info, sizeof(info));
+ case SOUND_OLD_MIXER_INFO:
+
+ if(codec_mixer_old_info_id_name)
+ codec_mixer_old_info_id_name();
+
+ return copy_to_user((void *)arg, &old_info, sizeof(info));
+ case SOUND_MIXER_READ_STEREODEVS:
+
+ return put_user(0, (long *) arg);
+ case SOUND_MIXER_READ_CAPS:
+
+ val = SOUND_CAP_EXCL_INPUT;
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_READ_DEVMASK:
+ break;
+ case SOUND_MIXER_READ_RECMASK:
+ break;
+ case SOUND_MIXER_READ_RECSRC:
+ break;
+ case SOUND_MIXER_WRITE_SPEAKER:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ switch(val) {
+ case 100:
+ if(set_codec_direct_mode)
+ set_codec_direct_mode();
+ break;
+ case 0:
+ if(clear_codec_direct_mode)
+ clear_codec_direct_mode();
+ break;
+ }
+ break;
+ case SOUND_MIXER_WRITE_BASS:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ codec_bass_gain = val;
+ if(set_codec_bass)
+ set_codec_bass(val);
+
+ return 0;
+ case SOUND_MIXER_READ_BASS:
+
+ val = codec_bass_gain;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_WRITE_VOLUME:
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ if (val > 31)
+ val = 31;
+ jz_audio_volume = val;
+
+ if(set_codec_volume)
+ set_codec_volume(val);
+ return 0;
+ case SOUND_MIXER_READ_VOLUME:
+
+ val = jz_audio_volume;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_WRITE_MIC:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ codec_mic_gain = val;
+ if(set_codec_mic)
+ set_codec_mic(val);
+
+ return 0;
+ case SOUND_MIXER_READ_MIC:
+
+ val = codec_mic_gain;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+ default:
+ return -ENOSYS;
+ }
+ audio_mix_modcnt ++;
+ return 0;
+}
+
+
+int i2s_probe_codec(struct i2s_codec *codec)
+{
+ /* generic OSS to I2S wrapper */
+ codec->mixer_ioctl = i2s_mixer_ioctl;
+ return 1;
+}
+
+
+/* I2S codec initialisation. */
+static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller)
+{
+ int num_i2s = 0;
+ struct i2s_codec *codec;
+
+ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) {
+ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset(codec, 0, sizeof(struct i2s_codec));
+ codec->private_data = controller;
+ codec->id = num_i2s;
+
+ if (i2s_probe_codec(codec) == 0)
+ break;
+ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) {
+ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n");
+ kfree(codec);
+ break;
+ }
+ controller->i2s_codec[num_i2s] = codec;
+ }
+ return num_i2s;
+}
+
+
+static void jz_update_filler(int format, int channels)
+{
+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
+
+ switch (TYPE(format, channels))
+ {
+
+ case TYPE(AFMT_U8, 1):
+ jz_audio_b = 4; /* 4bytes * 8bits =32bits */
+ replay_filler = replay_fill_1x8_u;
+ record_filler = record_fill_1x8_u;
+ break;
+ case TYPE(AFMT_U8, 2):
+ jz_audio_b = 4;
+ replay_filler = replay_fill_2x8_u;
+ record_filler = record_fill_2x8_u;
+ break;
+ case TYPE(AFMT_S16_LE, 1):
+ jz_audio_b = 2; /* 2bytes * 16bits =32bits */
+ replay_filler = replay_fill_1x16_s;
+ record_filler = record_fill_1x16_s;
+ break;
+ case TYPE(AFMT_S16_LE, 2):
+ jz_audio_b = 2;
+ replay_filler = replay_fill_2x16_s;
+ record_filler = record_fill_2x16_s;
+ break;
+ default:
+ ;
+ }
+}
+
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry *proc_jz_root;
+int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ return 0;
+}
+
+static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller)
+{
+ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0]))
+ return -EIO;
+ return 0;
+}
+
+static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller)
+{
+}
+#endif
+
+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller)
+{
+ char *name;
+ int adev; /* No of Audio device. */
+
+ name = controller->name;
+ /* initialize AIC controller and reset it */
+ jz_i2s_initHw(1);
+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1);
+ if (adev < 0)
+ goto audio_failed;
+ /* initialize I2S codec and register /dev/mixer */
+ if (jz_i2s_codec_init(controller) <= 0)
+ goto mixer_failed;
+
+#ifdef CONFIG_PROC_FS
+ if (jz_i2s_init_proc(controller) < 0) {
+ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name);
+ goto proc_failed;
+ }
+#endif
+
+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8);
+ if (!controller->tmp1) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp1_failed;
+ }
+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8);
+ if (!controller->tmp2) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp2_failed;
+ }
+ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name);
+ goto dma2_failed;
+ }
+ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name);
+ goto dma1_failed;
+ }
+ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2));
+
+ controller->dev_audio = adev;
+ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8);
+ if(!pop_turn_onoff_buf)
+ printk("pop_turn_onoff_buf alloc is wrong!\n");
+ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf);
+
+ return;
+dma2_failed:
+ jz_free_dma(controller->dma1);
+dma1_failed:
+ free_pages((unsigned long)controller->tmp2, 8);
+tmp2_failed:
+ free_pages((unsigned long)controller->tmp1, 8);
+tmp1_failed:
+
+#ifdef CONFIG_PROC_FS
+ jz_i2s_cleanup_proc(controller);
+#endif
+proc_failed:
+ /* unregister mixer dev */
+mixer_failed:
+ unregister_sound_dsp(adev);
+audio_failed:
+ return;
+}
+
+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller)
+{
+ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info),
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n");
+ return -ENOMEM;
+ }
+ (*controller)->name = "Jz I2S controller";
+ (*controller)->opened1 = 0;
+ (*controller)->opened2 = 0;
+ init_waitqueue_head(&(*controller)->adc_wait);
+ init_waitqueue_head(&(*controller)->dac_wait);
+ spin_lock_init(&(*controller)->lock);
+ init_waitqueue_head(&rx_wait_queue);
+ init_waitqueue_head(&tx_wait_queue);
+ init_waitqueue_head(&pop_wait_queue);
+ init_waitqueue_head(&drain_wait_queue);
+
+ return 0;
+}
+
+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller)
+{
+ int adev = controller->dev_audio;
+
+ jz_i2s_full_reset(controller);
+ controller->dev_audio = -1;
+ if (old_mksound)
+ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */
+
+#ifdef CONFIG_PROC_FS
+ jz_i2s_cleanup_proc(controller);
+#endif
+
+ jz_free_dma(controller->dma1);
+ jz_free_dma(controller->dma2);
+ free_pages((unsigned long)controller->tmp1, 8);
+ free_pages((unsigned long)controller->tmp2, 8);
+ free_pages((unsigned long)pop_turn_onoff_buf, 8);
+
+ if (adev >= 0) {
+ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */
+ unregister_sound_dsp(controller->dev_audio);
+ }
+}
+
+#ifdef CONFIG_PM
+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state)
+{
+ if(i2s_suspend_codec)
+ i2s_suspend_codec(controller->opened1,controller->opened2);
+ printk("Aic and codec are suspended!\n");
+ return 0;
+}
+
+static int jz_i2s_resume(struct jz_i2s_controller_info *controller)
+{
+ if(i2s_resume_codec)
+ i2s_resume_codec();
+
+#if defined(CONFIG_I2S_AK4642EN)
+ jz_i2s_initHw(0);
+ jz_audio_reset();
+ __i2s_enable();
+ jz_audio_set_speed(controller->dev_audio,jz_audio_speed);
+ /* playing */
+ if(controller->opened1) {
+ if(set_codec_replay)
+ set_codec_replay();
+ int dma = controller->dma1;
+ int id;
+ unsigned long flags;
+ disable_dma(dma);
+ if(__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if(__dmac_channel_transmit_end_detected(dma))
+ __dmac_channel_clear_transmit_end(dma);
+
+ /* for DSP_GETOPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ while((id = get_buffer_id(&out_busy_queue)) >= 0)
+ put_buffer_id(&out_empty_queue, id);
+
+ out_busy_queue.count=0;
+ if((id = get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_empty_queue, id);
+ }
+ if (elements_in_queue(&out_empty_queue) > 0) {
+ wake_up(&tx_wait_queue);
+ wake_up(&controller->dac_wait);
+ } else
+ printk("pm out_empty_queue empty");
+ }
+
+ /* recording */
+ if(controller->opened2) {
+ if(set_codec_record)
+ set_codec_record();
+ int dma = controller->dma2;
+ int id1, id2;
+ unsigned long flags;
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+ }
+ /* for DSP_GETIPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ id1 = get_buffer_id(&in_busy_queue);
+ put_buffer_id(&in_full_queue, id1);
+ wake_up(&rx_wait_queue);
+ wake_up(&controller->adc_wait);
+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_full_queue, id2);
+ }
+ in_busy_queue.count = 0;
+ }
+#endif
+
+ return 0;
+}
+
+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
+{
+ int ret;
+ struct jz_i2s_controller_info *controller = pm_dev->data;
+
+ if (!controller) return -EINVAL;
+
+ switch (req) {
+ case PM_SUSPEND:
+ ret = jz_i2s_suspend(controller, (int)data);
+ break;
+ case PM_RESUME:
+ ret = jz_i2s_resume(controller);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+#endif /* CONFIG_PM */
+static irqreturn_t aic_codec_irq(int irq, void *dev_id)
+{
+ u8 file_9 = read_codec_file(9);
+ u8 file_8 = read_codec_file(8);
+
+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9);
+ if ((file_9 & 0x1f) == 0x10) {
+
+ write_codec_file(8, 0x3f);
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ mdelay(300);
+ while ((read_codec_file(9) & 0x4) != 0x4);
+ while ((read_codec_file(9) & 0x10) == 0x10) {
+ write_codec_file(9, 0x10);
+ }
+ write_codec_file_bit(5, 0, 6);//SB_OUT->0
+ mdelay(300);
+ while ((read_codec_file(9) & 0x8) != 0x8);
+ write_codec_file(9, file_9);
+ write_codec_file(8, file_8);
+
+ return IRQ_HANDLED;
+ }
+
+ if (file_9 & 0x8)
+ ramp_up_end = jiffies;
+ else if (file_9 & 0x4)
+ ramp_down_end = jiffies;
+ else if (file_9 & 0x2)
+ gain_up_end = jiffies;
+ else if (file_9 & 0x1)
+ gain_down_end = jiffies;
+
+ write_codec_file(9, file_9);
+ if (file_9 & 0xf)
+ wake_up(&pop_wait_queue);
+ while (REG_ICDC_RGDATA & 0x100);
+
+ return IRQ_HANDLED;
+}
+
+static int __init init_jz_i2s(void)
+{
+ int errno, retval;
+#if defined(CONFIG_I2S_DLV)
+
+ ramp_up_start = 0;
+ ramp_up_end = 0;
+ gain_up_start = 0;
+ gain_up_end = 0;
+ ramp_down_start = 0;
+ ramp_down_end = 0;
+ gain_down_start = 0;
+ gain_down_end = 0;
+#endif
+
+ abnormal_data_count = 0;
+ if(set_codec_mode)
+ set_codec_mode();
+
+ drain_flag = 0;
+ if ((errno = probe_jz_i2s(&i2s_controller)) < 0)
+ return errno;
+ if(set_codec_gpio_pin)
+ set_codec_gpio_pin();
+
+ attach_jz_i2s(i2s_controller);
+ if(set_codec_startup_param)
+ set_codec_startup_param();
+#if defined(CONFIG_I2S_DLV)
+ jz_codec_config = 0;
+ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL);
+ if (retval) {
+ printk("Could not get aic codec irq %d\n", IRQ_AIC);
+ return retval;
+ }
+#endif
+ if(set_codec_volume_table)
+ set_codec_volume_table();
+
+ out_empty_queue.id = NULL;
+ out_full_queue.id = NULL;
+ out_busy_queue.id = NULL;
+ in_empty_queue.id = NULL;
+ in_full_queue.id = NULL;
+ in_busy_queue.id = NULL;
+
+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE;
+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ;
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+
+#ifdef CONFIG_PM
+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN,
+ jz_i2s_pm_callback);
+ if (i2s_controller->pm)
+ i2s_controller->pm->data = i2s_controller;
+#endif
+
+#if defined(CONFIG_I2S_DLV)
+ __cpm_start_idct();
+ __cpm_start_db();
+ __cpm_start_me();
+ __cpm_start_mc();
+ __cpm_start_ipu();
+#endif
+
+ printk("JZ I2S OSS audio driver initialized\n");
+
+ return 0;
+}
+
+static void __exit cleanup_jz_i2s(void)
+{
+#ifdef CONFIG_PM
+ /* pm_unregister(i2s_controller->pm); */
+#endif
+#if defined(CONFIG_I2S_DLV)
+ free_irq(IRQ_AIC, NULL);
+#endif
+ unload_jz_i2s(i2s_controller);
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ if(clear_codec_mode)
+ clear_codec_mode();
+}
+
+module_init(init_jz_i2s);
+module_exit(cleanup_jz_i2s);
+
+#if defined(CONFIG_SOC_JZ4730)
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count,con;
+
+ if(elements_in_queue(&in_busy_queue) > 0) {
+ if (nonblock)
+ return -EBUSY;
+ drain_flag = 1;
+ sleep_on(&drain_wait_queue);
+ drain_flag = 0;
+ } else {
+ add_wait_queue(&ctrl->adc_wait, &wait);
+ for (con = 0; con < 1000; con ++) {
+ udelay(1);
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ if (nonblock) {
+ remove_wait_queue(&ctrl->adc_wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ remove_wait_queue(&ctrl->adc_wait, &wait);
+ current->state = TASK_RUNNING;
+ }
+ return 0;
+}
+
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count;
+
+ if(elements_in_queue(&out_full_queue) > 0) {
+ if (nonblock)
+ return -EBUSY;
+
+ drain_flag = 1;
+ sleep_on(&drain_wait_queue);
+ drain_flag = 0;
+ } else {
+ add_wait_queue(&(ctrl->dac_wait), &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if(elements_in_queue(&out_full_queue) <= 0) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if(count <= 0)
+ break;
+ }
+ if (nonblock) {
+ remove_wait_queue(&ctrl->dac_wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ remove_wait_queue(&ctrl->dac_wait, &wait);
+ current->state = TASK_RUNNING;
+ }
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D)
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ //DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count,i=0;
+
+ //add_wait_queue(&ctrl->adc_wait, &wait);
+ for (;;) {
+ if (i < MAXDELAY) {
+ udelay(10);
+ i++;
+ } else
+ break;
+ //set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&ctrl->lock, flags);
+ //spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ //spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+
+ /*if (signal_pending(current))
+ break;*/
+ if (nonblock) {
+ //remove_wait_queue(&ctrl->adc_wait, &wait);
+ //current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ //remove_wait_queue(&ctrl->adc_wait, &wait);
+ //current->state = TASK_RUNNING;
+ /*if (signal_pending(current))
+ return -ERESTARTSYS;*/
+ return 0;
+}
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ unsigned long flags;
+ int count,ele,busyele,emptyele,i=0;
+
+ for (;;) {
+ if(!nonblock) {//blocked
+ if (i < MAXDELAY) {
+ udelay(10);
+ i++;
+ } else
+ break;
+
+ ele = elements_in_queue(&out_full_queue);
+ if(ele <= 0) {
+ udelay(200);
+
+ busyele = elements_in_queue(&out_busy_queue);
+ emptyele = elements_in_queue(&out_empty_queue);
+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ }
+ }
+ } else {//non-blocked
+ //mdelay(100);
+ ele = elements_in_queue(&out_full_queue);
+
+ if(ele <= 0) {
+ //mdelay(100);
+ busyele = elements_in_queue(&out_busy_queue);
+ emptyele = elements_in_queue(&out_empty_queue);
+
+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SOC_JZ4740)
+#define MAXDELAY 50000
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ int count,ele,i=0;
+
+ for (;;) {
+ if(!nonblock) {//blocked
+ if ( i < MAXDELAY ) {
+ udelay(10);
+ i++;
+ } else
+ break;
+
+ ele = elements_in_queue(&out_full_queue);
+ if(ele <= 0) {
+ udelay(10);
+ spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+ }
+ } else {//non-blocked
+ mdelay(100);
+ ele = elements_in_queue(&out_full_queue);
+
+ if(ele <= 0) {
+ mdelay(100);
+
+ spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ int count,i=0;
+
+ for (;;) {
+ if ( i < MAXDELAY )
+ {
+ udelay(10);
+ i++;
+ }
+ else
+ break;
+ spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+
+ if (nonblock) {
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static int jz_audio_release(struct inode *inode, struct file *file)
+{
+ unsigned long flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ unsigned long tfl;
+
+ if (controller == NULL)
+ return -ENODEV;
+
+ pop_dma_flag = 0;
+ if (controller->opened1 == 1) {
+ controller->opened1 = 0;
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+ drain_dac(controller, file->f_flags & O_NONBLOCK);
+ /* add some mute to anti-pop */
+#if defined(CONFIG_I2S_DLV)
+ /* wait for fifo empty */
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ gain_down_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //gain_down_end = jiffies;
+ while (1) {
+ tfl = REG_AIC_SR & 0x00003f00;
+ if (tfl == 0) {
+ udelay(500);
+ break;
+ }
+ mdelay(2);
+ }
+#endif
+ disable_dma(controller->dma1);
+ set_dma_count(controller->dma1, 0);
+ __i2s_disable_transmit_dma();
+ __i2s_disable_replay();
+ __aic_flush_fifo();
+ if(clear_codec_replay)
+ clear_codec_replay();
+ __aic_flush_fifo();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ ramp_down_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //ramp_down_end = jiffies;
+ unset_audio_data_replay();
+#endif
+ __i2s_disable();
+ if(turn_off_codec)
+ turn_off_codec();
+ }
+
+ if (controller->opened2 == 1) {
+ controller->opened2 = 0;
+ first_record_call = 1;
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ drain_adc(controller, file->f_flags & O_NONBLOCK);
+ disable_dma(controller->dma2);
+ set_dma_count(controller->dma2, 0);
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+
+ if(clear_codec_record)
+ clear_codec_record();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ __i2s_disable();
+ if(turn_off_codec)
+ turn_off_codec();
+ abnormal_data_count = 0;
+ }
+
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+#endif
+ return 0;
+}
+
+static int jz_audio_open(struct inode *inode, struct file *file)
+{
+ int i;
+ struct jz_i2s_controller_info *controller = i2s_controller;
+
+ if (controller == NULL)
+ return -ENODEV;
+
+ mdelay(2);
+ REG_DMAC_DMACKE(0) = 0x3f;
+ pop_dma_flag = 0;
+ if (controller->opened1 == 1 || controller->opened2 == 1 ) {
+ printk("\naudio is busy!\n");
+ return -EBUSY;
+ }
+ jz_codec_config = 0;
+
+ ramp_up_start = 0;
+ ramp_up_end = 0;
+ gain_up_start = 0;
+ gain_up_end = 0;
+ ramp_down_start = 0;
+ ramp_down_end = 0;
+ gain_down_start = 0;
+ gain_down_end = 0;
+ if (file->f_mode & FMODE_WRITE) {
+ if (controller->opened1 == 1)
+ return -EBUSY;
+
+ controller->opened1 = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+
+ for(i=0;i < 64;i++) {
+ save_last_samples[i].left = 0;
+ save_last_samples[i].right = 0;
+ }
+
+ out_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ last_dma_buffer_id = 0;
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ if (controller->opened2 == 1)
+ return -EBUSY;
+
+ controller->opened2 = 1;
+ first_record_call = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+
+ in_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+ }
+
+ file->private_data = controller;
+ jz_audio_reset();
+ REG_AIC_FR |= (1 << 6);
+
+ if (file->f_mode & FMODE_WRITE) {
+ if(set_codec_replay)
+ set_codec_replay();
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ abnormal_data_count = 0;
+ if(set_codec_record)
+ set_codec_record();
+ }
+
+#if defined(CONFIG_I2S_DLV)
+ __aic_reset();
+
+ mdelay(10);
+ REG_AIC_I2SCR = 0x10;
+ mdelay(20);
+ __aic_flush_fifo();
+#endif
+
+ __i2s_enable();
+
+#if defined(CONFIG_I2S_DLV)
+ if (file->f_mode & FMODE_WRITE) {
+
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ ramp_up_start = jiffies;
+ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_RCR = 0x1;
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_RGR = 1;*/
+ sleep_on(&pop_wait_queue);
+ //ramp_up_end = jiffies;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ } else if (file->f_mode & FMODE_READ) {
+ if (jz_mic_only)
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ else
+ write_codec_file_bit(5, 0, 7);//SB_DAC->0
+ mdelay(500);
+ }
+
+#endif
+
+ return 0;
+}
+
+
+static int jz_audio_ioctl(struct inode *inode, struct file *file,
+unsigned int cmd, unsigned long arg)
+{
+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize;
+ unsigned int flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ count_info cinfo;
+ audio_buf_info abinfo;
+ int id, i;
+
+ val = 0;
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *)arg);
+ case SNDCTL_DSP_RESET:
+#if 0
+ jz_audio_reset();
+ __i2s_disable_replay();
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+ __i2s_disable_transmit_dma();
+#endif
+ return 0;
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ return drain_dac(controller, file->f_flags & O_NONBLOCK);
+ return 0;
+ case SNDCTL_DSP_SPEED:
+ /* set smaple rate */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val >= 0)
+ jz_audio_set_speed(controller->dev_audio, val);
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_STEREO:
+ /* set stereo or mono channel */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1);
+
+ return 0;
+ case SNDCTL_DSP_GETBLKSIZE:
+ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg);
+ return put_user(jz_audio_fragsize, (int *)arg);
+ case SNDCTL_DSP_GETFMTS:
+ /* Returns a mask of supported sample format*/
+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg);
+ case SNDCTL_DSP_SETFMT:
+ /* Select sample format */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val != AFMT_QUERY)
+ jz_audio_set_format(controller->dev_audio,val);
+ else {
+ if (file->f_mode & FMODE_READ)
+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+ else
+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+ }
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_CHANNELS:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ jz_audio_set_channels(controller->dev_audio, val);
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_POST:
+ /* FIXME: the same as RESET ?? */
+ return 0;
+ case SNDCTL_DSP_SUBDIVIDE:
+ return 0;
+ case SNDCTL_DSP_SETFRAGMENT:
+ get_user(val, (long *) arg);
+ newfragsize = 1 << (val & 0xFFFF);
+ if (newfragsize < 4 * PAGE_SIZE)
+ newfragsize = 4 * PAGE_SIZE;
+ if (newfragsize > (16 * PAGE_SIZE))
+ newfragsize = 16 * PAGE_SIZE;
+
+ newfragstotal = (val >> 16) & 0x7FFF;
+ if (newfragstotal < 2)
+ newfragstotal = 2;
+ if (newfragstotal > 32)
+ newfragstotal = 32;
+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize))
+ return 0;
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ mdelay(500);
+ jz_audio_fragstotal = newfragstotal;
+ jz_audio_fragsize = newfragsize;
+
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ mdelay(10);
+
+ return 0;
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg);
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+ case SNDCTL_DSP_SETDUPLEX:
+ return -EINVAL;
+ case SNDCTL_DSP_GETOSPACE:
+ {
+ int i, bytes = 0;
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ jz_audio_fragments = elements_in_queue(&out_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+
+ if (jz_audio_channels == 2)
+ bytes /= jz_audio_b;
+ else if (jz_audio_channels == 1)
+ bytes /= 4;
+ else
+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n");
+
+
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ /* unused fragment amount */
+ abinfo.fragments = jz_audio_fragments;
+ /* amount of fragments */
+ abinfo.fragstotal = jz_audio_fragstotal;
+ /* fragment size in bytes */
+ if (jz_audio_channels == 2)
+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b;
+ else if (jz_audio_channels == 1)
+ abinfo.fragsize = jz_audio_fragsize / 4;
+ else
+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n");
+
+ /* write size count without blocking in bytes */
+ abinfo.bytes = bytes;
+
+ return copy_to_user((void *)arg, &abinfo,
+ sizeof(abinfo)) ? -EFAULT : 0;
+ }
+ case SNDCTL_DSP_GETISPACE:
+ {
+ int i, bytes = 0;
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ jz_audio_fragments = elements_in_queue(&in_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+
+ if (jz_audio_channels == 2)
+ bytes /= jz_audio_b;
+ else if (jz_audio_channels == 1)
+ bytes /= 4;
+ else
+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n");
+
+ abinfo.fragments = jz_audio_fragments;
+ abinfo.fragstotal = jz_audio_fragstotal;
+
+ if (jz_audio_channels == 2)
+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b;
+ else if (jz_audio_channels == 1)
+ abinfo.fragsize = jz_audio_fragsize / 4;
+ else
+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n");
+
+ abinfo.bytes = bytes;
+
+ return copy_to_user((void *)arg, &abinfo,
+ sizeof(abinfo)) ? -EFAULT : 0;
+ }
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && in_dma_buf)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && out_dma_buf)
+ val |= PCM_ENABLE_OUTPUT;
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_SETTRIGGER:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ return 0;
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextIn;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextOut;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ unfinish = 0;
+ fullc = elements_in_queue(&out_full_queue);
+ busyc = elements_in_queue(&out_busy_queue);
+ for(i = 0;i < fullc ;i ++) {
+ id = *(out_full_queue.id + i);
+ unfinish += *(out_dma_buf_data_count + id);
+ }
+ for(i = 0;i < busyc ;i ++) {
+ id = *(out_busy_queue.id + i);
+ unfinish += get_dma_residue(controller->dma1);
+ }
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ if (jz_audio_channels == 2)
+ unfinish /= jz_audio_b;
+ else if (jz_audio_channels == 1)
+ unfinish /= 4;
+ else
+ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n");
+
+ return put_user(unfinish, (int *) arg);
+ case SOUND_PCM_READ_RATE:
+ return put_user(jz_audio_rate, (int *)arg);
+ case SOUND_PCM_READ_CHANNELS:
+ return put_user(jz_audio_channels, (int *)arg);
+ case SOUND_PCM_READ_BITS:
+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg);
+ case SNDCTL_DSP_MAPINBUF:
+ case SNDCTL_DSP_MAPOUTBUF:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_WRITE_FILTER:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+
+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait)
+{
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ return POLLOUT | POLLWRNORM;
+
+ poll_wait(file, &controller->dac_wait, wait);
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ return POLLIN | POLLRDNORM;
+
+ poll_wait(file, &controller->adc_wait, wait);
+ }
+
+ spin_lock_irqsave(&controller->lock, flags);
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ mask |= POLLOUT | POLLWRNORM;
+ } else if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ return mask;
+}
+
+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ int id, ret = 0, left_count, copy_count, cnt = 0;
+ unsigned long flags;
+
+ if (count < 0)
+ return -EINVAL;
+
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextIn = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ copy_count = jz_audio_fragsize / 4;
+
+ left_count = count;
+ if (first_record_call) {
+ first_record_call = 0;
+ audio_read_back_first:
+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ spin_lock(&controller->lock);
+ *(in_dma_buf_data_count + id) = copy_count * 4;
+
+ spin_unlock(&controller->lock);
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id));
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ sleep_on(&rx_wait_queue);
+ } else
+ goto audio_read_back_first;
+ }
+
+ while (left_count > 0) {
+ audio_read_back_second:
+ if (elements_in_queue(&in_full_queue) <= 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ else
+ sleep_on(&rx_wait_queue);
+ }
+
+ if ((id = get_buffer_id(&in_full_queue)) >= 0) {
+ spin_lock(&controller->lock);
+ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id);
+ spin_unlock(&controller->lock);
+ put_buffer_id(&in_empty_queue, id);
+ } else
+ goto audio_read_back_second;
+
+ if (elements_in_queue(&in_busy_queue) == 0) {
+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ spin_lock(&controller->lock);
+ *(in_dma_buf_data_count + id) = copy_count * 4;
+ spin_unlock(&controller->lock);
+
+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id));
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ }
+ }
+ if (ret + cnt > count) {
+ spin_lock(&controller->lock);
+ cnt = count - ret;
+ spin_unlock(&controller->lock);
+ }
+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt))
+ return ret ? ret : -EFAULT;
+
+ spin_lock(&controller->lock);
+ ret += cnt;
+ spin_unlock(&controller->lock);
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextIn += ret;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ spin_lock(&controller->lock);
+ left_count -= cnt;
+ spin_unlock(&controller->lock);
+ }
+ return ret;
+}
+
+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ int id, ret = 0, left_count, copy_count = 0;
+ unsigned int flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+
+ if (count <= 0)
+ return -EINVAL;
+
+ if(set_replay_hp_or_speaker)
+ set_replay_hp_or_speaker();
+
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ if (jz_audio_channels == 2)
+ copy_count = jz_audio_fragsize / jz_audio_b;
+ else if(jz_audio_channels == 1)
+ copy_count = jz_audio_fragsize / 4;
+ left_count = count;
+ if (copy_from_user(controller->tmp1, buffer, count)) {
+ printk("copy_from_user failed:%d",ret);
+ return ret ? ret : -EFAULT;
+ }
+
+ while (left_count > 0) {
+ audio_write_back:
+ /*if (file->f_flags & O_NONBLOCK)
+ udelay(2);*/
+ if (elements_in_queue(&out_empty_queue) == 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret;
+ else
+ sleep_on(&tx_wait_queue);
+ }
+ /* the end fragment size in this write */
+ if (ret + copy_count > count)
+ copy_count = count - ret;
+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) {
+ replay_filler((signed long)controller->tmp1 + ret, copy_count, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ put_buffer_id(&out_full_queue, id);
+ dma_cache_wback_inv(*(out_dma_buf + id),
+ *(out_dma_buf_data_count + id));
+ } else
+ put_buffer_id(&out_empty_queue, id);
+ } else
+ goto audio_write_back;
+
+ left_count = left_count - copy_count;
+ ret += copy_count;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextOut += ret;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ if (elements_in_queue(&out_busy_queue) == 0) {
+ if ((id=get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id);
+
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(controller->dma1,
+ file->private_data,
+ *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ last_dma_buffer_id = id;
+ if (jz_codec_config == 0) {
+ write_codec_file_bit(1, 0, 5);
+ gain_up_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //gain_up_end = jiffies;
+ jz_codec_config = 1;
+ //SB_ADC->1
+ //write_codec_file_bit(5, 1, 4);
+ //while(1);
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+#if defined(CONFIG_I2S_ICODEC)
+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample)
+{
+ int i,step_len;
+ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf;
+ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19;
+ unsigned long l_sample_count,r_sample_count,sample_count;
+ struct jz_i2s_controller_info *controller = i2s_controller;
+ signed int left_sam=0,right_sam=0,l_val,r_val;
+
+ switch (sample_oss) {
+ case 0x0:
+ break;
+ case 0x1:
+ left_sam = (signed int)l_sample;
+ right_sam = (signed int)r_sample;
+ break;
+ case 0x2:
+ break;
+ case 0x3:
+ break;
+ case 0x4:
+ break;
+ }
+
+ if(left_sam == 0 && right_sam == 0)
+ return;
+
+ switch (sample_oss) {
+ case 0x0:
+ break;
+ case 0x1:
+ step_len = jz_audio_speed / 10 * 3;
+ step_len = step_len / 2;
+ step_len = 0x7fff / step_len + 1;
+
+ l_sample_count = 0;
+ l_val = left_sam;
+
+ while(1) {
+ if(l_val > 0) {
+ if(l_val >= step_len) {
+ l_val -= step_len;
+ l_sample_count ++;
+ } else
+ break;
+ }
+
+ if(l_val < 0) {
+ if(l_val <= -step_len) {
+ l_val += step_len;
+ l_sample_count ++;
+ } else
+ break;
+ }
+
+ if(l_val == 0)
+ break;
+ }
+
+ r_sample_count = 0;
+ r_val = right_sam;
+ while(1) {
+ if(r_val > 0) {
+ if(r_val >= step_len) {
+ r_val -= step_len;
+ r_sample_count ++;
+ } else
+ break;
+ }
+
+ if(r_val < 0) {
+ if(r_val <= -step_len) {
+ r_val += step_len;
+ r_sample_count ++;
+ } else
+ break;
+ }
+
+ if(r_val == 0)
+ break;
+ }
+ /* fill up */
+ if(l_sample_count > r_sample_count)
+ sample_count = l_sample_count;
+ else
+ sample_count = r_sample_count;
+
+ l_val = left_sam;
+ r_val = right_sam;
+ for(i=0;i <= sample_count;i++) {
+
+ *pop_buf = (unsigned long)l_val;
+ pop_buf ++;
+
+ if(l_val > step_len)
+ l_val -= step_len;
+ else if(l_val < -step_len)
+ l_val += step_len;
+ else if(l_val >= -step_len && l_val <= step_len)
+ l_val = 0;
+
+ *pop_buf = (unsigned long)r_val;
+ pop_buf ++;
+ if(r_val > step_len)
+ r_val -= step_len;
+ else if(r_val < -step_len)
+ r_val += step_len;
+ else if(r_val >= -step_len && r_val <= step_len)
+ r_val = 0;
+ }
+
+ *pop_buf = 0;
+ pop_buf ++;
+ *pop_buf = 0;
+
+ pop_buf ++;
+ sample_count += 2;
+ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8);
+
+ pop_dma_flag = 1;
+ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE);
+ sleep_on(&pop_wait_queue);
+ pop_dma_flag = 0;
+ break;
+ case 0x2:
+ break;
+ case 0x3:
+ break;
+ case 0x4:
+ break;
+ }
+}
+#endif
diff --git a/sound/oss/jz_i2s_dlv_dma_test.c b/sound/oss/jz_i2s_dlv_dma_test.c
new file mode 100644
index 00000000000..49a64a2f55f
--- /dev/null
+++ b/sound/oss/jz_i2s_dlv_dma_test.c
@@ -0,0 +1,2808 @@
+/*
+ * linux/drivers/sound/jz_i2s_dlv.c
+ *
+ * JzSOC On-Chip I2S audio driver.
+ *
+ * Copyright (C) 2005 by Junzheng Corp.
+ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using
+ * dma channel 4&3,noah is tested.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Because the normal application of AUDIO devices are focused on Little_endian,
+ * then we only perform the little endian data format in driver.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/pm_legacy.h>
+#include <sound/driver.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/proc_fs.h>
+#include <linux/soundcard.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <asm/hardirq.h>
+#include <asm/jzsoc.h>
+#include "sound_config.h"
+
+#define DPRINTK(args...) printk(args)
+#define DMA_ID_I2S_TX DMA_ID_AIC_TX
+#define DMA_ID_I2S_RX DMA_ID_AIC_RX
+
+#define NR_I2S 2
+#define MAXDELAY 50000
+#define JZCODEC_RW_BUFFER_SIZE 3
+#define JZCODEC_RW_BUFFER_TOTAL 3
+#define JZCODEC_USER_BUFFER 6
+
+#define USE_NONE 1
+#define USE_MIC 2
+#define USE_LINEIN 3
+
+static int jz_audio_rate;
+static char jz_audio_format;
+static char jz_audio_volume;
+static char jz_audio_channels;
+static int jz_audio_b; /* bits expand multiple */
+static int jz_audio_fragments;//unused fragment amount
+static int jz_audio_fragstotal;
+static int jz_audio_fragsize;
+static int jz_audio_speed;
+static int audio_mix_modcnt;
+static int codec_volue_shift;
+static int jz_audio_dma_tran_count;//bytes count of one DMA transfer
+static int jz_mic_only = 1;
+static int jz_codec_config = 0;
+static int use_mic_line_flag;
+static unsigned long ramp_up_start;
+static unsigned long ramp_up_end;
+static unsigned long gain_up_start;
+static unsigned long gain_up_end;
+static unsigned long ramp_down_start;
+static unsigned long ramp_down_end;
+static unsigned long gain_down_start;
+static unsigned long gain_down_end;
+
+
+static void jz_update_filler(int bits, int channels);
+static int Init_In_Out_queue(int fragstotal,int fragsize);
+static int Free_In_Out_queue(int fragstotal,int fragsize);
+static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref);
+static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref);
+static void (*replay_filler)(signed long src_start, int count, int id);
+static int (*record_filler)(unsigned long dst_start, int count, int id);
+static void jz_audio_reset(void);
+
+static struct file_operations jz_i2s_audio_fops;
+
+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue);
+
+struct jz_i2s_controller_info
+{
+ int io_base;
+ int dma1; /* play */
+ int dma2; /* record */
+ char *name;
+ int dev_audio;
+ struct i2s_codec *i2s_codec[NR_I2S];
+ int opened1;
+ int opened2;
+ unsigned char *tmp1; /* tmp buffer for sample conversions */
+ unsigned char *tmp2;
+ spinlock_t lock;
+ spinlock_t ioctllock;
+
+ wait_queue_head_t dac_wait;
+ wait_queue_head_t adc_wait;
+ int nextIn; // byte index to next-in to DMA buffer
+ int nextOut; // byte index to next-out from DMA buffer
+ int count; // current byte count in DMA buffer
+ int finish; // current transfered byte count in DMA buffer
+ unsigned total_bytes; // total bytes written or read
+ unsigned blocks;
+ unsigned error; // over/underrun
+#ifdef CONFIG_PM
+ struct pm_dev *pm;
+#endif
+};
+
+
+static struct jz_i2s_controller_info *i2s_controller = NULL;
+struct i2s_codec
+{
+ /* I2S controller connected with */
+ void *private_data;
+ char *name;
+ int id;
+ int dev_mixer;
+ /* controller specific lower leverl i2s accessing routines */
+ u16 (*codec_read) (u8 reg);//the function accessing Codec REGs fcj add
+ void (*codec_write) (u8 reg, u16 val);//to AK4642EN,val is 8bit
+ /* Wait for codec-ready. Ok to sleep here. */
+ void (*codec_wait) (struct i2s_codec *codec);
+ /* OSS mixer masks */
+ int modcnt;
+ int supported_mixers;
+ int stereo_mixers;
+ int record_sources;
+ int bit_resolution;
+ /* OSS mixer interface */
+ int (*read_mixer) (struct i2s_codec *codec, int oss_channel);
+ void (*write_mixer)(struct i2s_codec *codec, int oss_channel,
+ unsigned int left, unsigned int right);
+ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask);
+ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg);
+ /* saved OSS mixer states */
+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+};
+
+
+typedef struct buffer_queue_s
+{
+ int count;
+ int *id;
+ int lock;
+} buffer_queue_t;
+
+typedef struct left_right_sample_s
+{
+ signed long left;
+ signed long right;
+} left_right_sample_t;
+
+typedef struct hpvol_shift_s
+{
+ int hpvol;
+ int shift;
+} hpvol_shift_t;
+
+static unsigned long *out_dma_buf = NULL;
+static unsigned long *out_dma_pbuf = NULL;
+static unsigned long *out_dma_buf_data_count = NULL;
+static unsigned long *in_dma_buf = NULL;
+static unsigned long *in_dma_pbuf = NULL;
+static unsigned long *in_dma_buf_data_count = NULL;
+
+static buffer_queue_t out_empty_queue;
+static buffer_queue_t out_full_queue;
+static buffer_queue_t out_busy_queue;
+static buffer_queue_t in_empty_queue;
+static buffer_queue_t in_full_queue;
+static buffer_queue_t in_busy_queue;
+static int first_record_call = 0;
+
+static int read_codec_file(int addr)
+{
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ mdelay(1);
+ return(__icdc_get_value());
+}
+
+static void printk_codec_files(void)
+{
+ int cnt;
+
+ printk("\n");
+
+ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR);
+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR);
+ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR);
+ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR);
+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR);
+ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR);
+ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR);
+ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA);
+
+ for (cnt = 0; cnt <= 27 ; cnt++) {
+ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt));
+ }
+ printk("\n");
+}
+
+static void write_codec_file(int addr, int val)
+{
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ __icdc_set_cmd(val); /* write */
+ mdelay(1);
+ __icdc_set_rgwr();
+ mdelay(1);
+}
+
+static int write_codec_file_bit(int addr, int bitval, int mask_bit)
+{
+ int val;
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ mdelay(1);
+ val = __icdc_get_value(); /* read */
+
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ val &= ~(1 << mask_bit);
+ if (bitval == 1)
+ val |= 1 << mask_bit;
+
+ __icdc_set_cmd(val); /* write */
+ mdelay(1);
+ __icdc_set_rgwr();
+ mdelay(1);
+
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ val = __icdc_get_value(); /* read */
+
+ if (((val >> mask_bit) & bitval) == bitval)
+ return 1;
+ else
+ return 0;
+}
+
+/* set Audio data replay */
+static void set_audio_data_replay()
+{
+ /* DAC path */
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ mdelay(10);
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ //mdelay(100);
+ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //mdelay(300);
+}
+
+/* unset Audio data replay */
+static void unset_audio_data_replay(void)
+{
+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ //mdelay(800);
+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ //mdelay(800);
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 4);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/* set Record MIC input audio without playback */
+static void set_record_mic_input_audio_without_playback(void)
+{
+ /* ADC path for MIC IN */
+ jz_mic_only = 1;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ mdelay(10);
+ write_codec_file_bit(1, 1, 2);
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+
+ write_codec_file(22, 0x40);//mic 1
+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ //write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file(1, 0x4);
+}
+
+/* unset Record MIC input audio without playback */
+static void unset_record_mic_input_audio_without_playback(void)
+{
+ /* ADC path for MIC IN */
+ jz_mic_only = 0;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/* set Record LINE input audio without playback */
+static void set_record_line_input_audio_without_playback(void)
+{
+ /* ADC path for LINE IN */
+ jz_mic_only = 1;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+ write_codec_file(22, 0xf6);//line in 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1
+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ mdelay(10);
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file(1, 0x4);
+}
+
+/* unset Record LINE input audio without playback */
+static void unset_record_line_input_audio_without_playback(void)
+{
+ /* ADC path for LINE IN */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1
+
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/* set Playback LINE input audio direct only */
+static void set_playback_line_input_audio_direct_only()
+{
+ jz_audio_reset();//or init_codec()
+ REG_AIC_I2SCR = 0x10;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+ write_codec_file(22, 0xf6);//line in 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ mdelay(10);
+ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1
+ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1
+}
+
+/* unset Playback LINE input audio direct only */
+static void unset_playback_line_input_audio_direct_only()
+{
+ write_codec_file_bit(6, 0, 3);//GIM->0
+ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ mdelay(100);
+ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/* set Record MIC input audio with direct playback */
+static void set_record_mic_input_audio_with_direct_playback(void)
+{
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ jz_mic_only = 0;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+
+ write_codec_file(22, 0x60);//mic 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ //write_codec_file(1, 0x4);
+}
+
+/* unset Record MIC input audio with direct playback */
+static void unset_record_mic_input_audio_with_direct_playback(void)
+{
+ /* ADC path for MIC IN */
+ jz_mic_only = 0;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/* set Record playing audio mixed with MIC input audio */
+static void set_record_playing_audio_mixed_with_mic_input_audio(void)
+{
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ mdelay(10);
+
+ write_codec_file(22, 0x63);//mic 1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0
+}
+
+/* unset Record playing audio mixed with MIC input audio */
+static void unset_record_playing_audio_mixed_with_mic_input_audio(void)
+{
+ /* ADC path */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 5);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/* set Record MIC input audio with Audio data replay (full duplex) */
+static void set_record_mic_input_audio_with_audio_data_replay(void)
+{
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+}
+
+/* unset Record MIC input audio with Audio data replay (full duplex) */
+static void unset_record_mic_input_audio_with_audio_data_replay(void)
+{
+ /* ADC path */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 5);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/////////
+/* set Record LINE input audio with Audio data replay (full duplex for linein) */
+static void set_record_line_input_audio_with_audio_data_replay(void)
+{
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+
+
+ //jz_mic_only = 1;
+ write_codec_file(22, 0xc6);//line in 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+}
+
+/* unset Record LINE input audio with Audio data replay (full duplex for linein) */
+static void unset_record_line_input_audio_with_audio_data_replay(void)
+{
+ /* ADC path */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 5);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+/////////
+
+static inline int get_buffer_id(struct buffer_queue_s *q)
+{
+ int r;
+ unsigned long flags;
+ int i;
+ spin_lock_irqsave(&q->lock, flags);
+ //spin_lock(&q->lock);
+ if (q->count == 0) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ //spin_unlock(&q->lock);
+ return -1;
+ }
+ r = *(q->id + 0);
+ for (i=0;i < q->count-1;i++)
+ *(q->id + i) = *(q->id + (i+1));
+ q->count --;
+ spin_unlock_irqrestore(&q->lock, flags);
+ //spin_unlock(&q->lock);
+ return r;
+}
+
+static inline void put_buffer_id(struct buffer_queue_s *q, int id)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&q->lock, flags);
+ //spin_lock(&q->lock);
+ *(q->id + q->count) = id;
+ q->count ++;
+ spin_unlock_irqrestore(&q->lock, flags);
+ //spin_unlock(&q->lock);
+}
+
+static inline int elements_in_queue(struct buffer_queue_s *q)
+{
+ int r;
+ unsigned long flags;
+ spin_lock_irqsave(&q->lock, flags);
+ //spin_lock(&q->lock);
+ r = q->count;
+ spin_unlock_irqrestore(&q->lock, flags);
+ //spin_unlock(&q->lock);
+ return r;
+}
+
+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode)
+{
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+ //for DSP_GETOPTR
+ //spin_lock_irqsave(&controller->ioctllock, flags);
+ spin_lock(&controller->ioctllock);
+ jz_audio_dma_tran_count = count;
+ //spin_unlock_irqrestore(&controller->ioctllock, flags);
+ spin_unlock(&controller->ioctllock);
+ flags = claim_dma_lock();
+ //__dmac_disable_module(0);
+ disable_dma(chan);
+ clear_dma_ff(chan);
+
+ set_dma_mode(chan, mode);
+ set_dma_addr(chan, phyaddr);
+ if (count == 0)
+ {
+ count++;
+ printk("JzSOC DMA controller can't set dma 0 count!\n");
+ }
+
+ set_dma_count(chan, count);
+ enable_dma(chan);
+ //__dmac_enable_module(0);
+ release_dma_lock(flags);
+ //dump_jz_dma_channel(chan);
+
+ //printk_codec_files();
+}
+
+static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id)
+{
+ int id1, id2;
+
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+ int dma = controller->dma2;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+ //for DSP_GETIPTR
+ //spin_lock_irqsave(&controller->ioctllock, flags);
+ spin_lock(&controller->ioctllock);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ //spin_unlock_irqrestore(&controller->ioctllock, flags);
+ spin_unlock(&controller->ioctllock);
+ id1 = get_buffer_id(&in_busy_queue);
+ put_buffer_id(&in_full_queue, id1);
+
+ wake_up(&rx_wait_queue);
+ wake_up(&controller->adc_wait);
+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id2);
+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1);
+ //write back
+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2));
+ audio_start_dma(dma,dev_id,
+ *(in_dma_pbuf + id2),
+ *(in_dma_buf_data_count + id2),
+ DMA_MODE_READ);
+ }
+ else
+ in_busy_queue.count = 0;
+ }
+ return IRQ_HANDLED;
+
+}
+
+static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id)
+{
+ int id;
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+ int dma = controller->dma1;
+ disable_dma(dma);
+
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+
+
+ //for DSP_GETOPTR
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ //spin_lock(&controller->ioctllock);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ //spin_unlock(&controller->ioctllock);
+ if ((id = get_buffer_id(&out_busy_queue)) < 0)
+ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n");
+ put_buffer_id(&out_empty_queue, id);
+ if ((id = get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id); //very busy
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ }
+ } else
+ out_busy_queue.count = 0;
+
+ if (elements_in_queue(&out_empty_queue) > 0) {
+ wake_up(&tx_wait_queue);
+ wake_up(&controller->dac_wait);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static void jz_i2s_initHw(int set)
+{
+ __i2s_disable();
+ //schedule_timeout(5);
+
+#if defined(CONFIG_I2S_DLV)
+ __i2s_disable();
+ __i2s_as_slave();
+ __aic_internal_codec();
+ //__i2s_set_oss_sample_size(16);
+ //__i2s_set_iss_sample_size(16);
+
+#endif
+ __i2s_disable_record();
+ __i2s_disable_replay();
+ __i2s_disable_loopback();
+ __i2s_set_transmit_trigger(7);
+ __i2s_set_receive_trigger(8);
+}
+
+static int Init_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+ // recording
+ in_empty_queue.count = fragstotal;
+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf)
+ goto all_mem_err;
+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_pbuf)
+ goto all_mem_err;
+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf_data_count)
+ goto all_mem_err;
+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_empty_queue.id)
+ goto all_mem_err;
+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_full_queue.id)
+ goto all_mem_err;
+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_busy_queue.id)
+ goto all_mem_err;
+
+ for (i=0;i < fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+
+ for (i = 0; i < fragstotal; i++) {
+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(in_dma_buf + i) == 0)
+ goto mem_failed_in;
+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i)));
+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
+ }
+
+ //playing
+ out_empty_queue.count = fragstotal;
+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_buf)
+ goto all_mem_err;
+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_pbuf)
+ goto all_mem_err;
+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+
+ if (!out_dma_buf_data_count)
+ goto all_mem_err;
+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_empty_queue.id)
+ goto all_mem_err;
+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_full_queue.id)
+ goto all_mem_err;
+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_busy_queue.id)
+ goto all_mem_err;
+ for (i=0;i < fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ /*alloc DMA buffer*/
+ for (i = 0; i < fragstotal; i++) {
+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(out_dma_buf + i) == 0) {
+ printk(" can't allocate required DMA(OUT) buffers.\n");
+ goto mem_failed_out;
+ }
+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i)));
+ }
+
+ return 1;
+all_mem_err:
+ printk("error:allocate memory occur error 1!\n");
+ return 0;
+mem_failed_out:
+ printk("error:allocate memory occur error 2!\n");
+ for (i = 0; i < fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ }
+
+ return 0;
+mem_failed_in:
+ printk("error:allocate memory occur error 3!\n");
+ for (i = 0; i < fragstotal; i++) {
+ if(*(in_dma_buf + i))
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ return 0;
+}
+
+static int Free_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+ //playing
+ if(out_dma_buf != NULL) {
+ for (i = 0; i < fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ *(out_dma_buf + i) = 0; //release page error
+ }
+ kfree(out_dma_buf);
+ out_dma_buf = NULL;
+ }
+ if(out_dma_pbuf) {
+ kfree(out_dma_pbuf);
+ out_dma_pbuf = NULL;
+ }
+ if(out_dma_buf_data_count) {
+ kfree(out_dma_buf_data_count);
+ out_dma_buf_data_count = NULL;
+ }
+ if(out_empty_queue.id) {
+ kfree(out_empty_queue.id);
+ out_empty_queue.id = NULL;
+ }
+ if(out_full_queue.id) {
+ kfree(out_full_queue.id);
+ out_full_queue.id = NULL;
+ }
+ if(out_busy_queue.id) {
+ kfree(out_busy_queue.id);
+ out_busy_queue.id = NULL;
+ }
+ out_empty_queue.count = fragstotal;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+
+ // recording
+ if(in_dma_buf) {
+ for (i = 0; i < fragstotal; i++) {
+ if(*(in_dma_buf + i)) {
+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ *(in_dma_buf + i) = 0; //release page error
+ }
+ kfree(in_dma_buf);
+ in_dma_buf = NULL;
+ }
+ if(in_dma_pbuf) {
+ kfree(in_dma_pbuf);
+ in_dma_pbuf = NULL;
+ }
+ if(in_dma_buf_data_count) {
+ kfree(in_dma_buf_data_count);
+ in_dma_buf_data_count = NULL;
+ }
+ if(in_empty_queue.id) {
+ kfree(in_empty_queue.id);
+ in_empty_queue.id = NULL;
+ }
+ if(in_full_queue.id) {
+ kfree(in_full_queue.id);
+ in_full_queue.id = NULL;
+ }
+ if(in_busy_queue.id) {
+ kfree(in_busy_queue.id);
+ in_busy_queue.id = NULL;
+ }
+
+ in_empty_queue.count = fragstotal;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+
+ return 1;
+}
+
+static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller)
+{
+ jz_i2s_initHw(0);
+}
+
+static int jz_audio_set_speed(int dev, int rate)
+{
+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */
+ int speed = 0, val;
+
+ jz_audio_speed = rate;
+ if (rate > 96000)
+ rate = 96000;
+ if (rate < 8000)
+ rate = 8000;
+ jz_audio_rate = rate;
+
+#if defined(CONFIG_I2S_DLV)
+ speed = 0;
+ switch (rate) {
+ case 8000:
+ speed = 10;
+ break;
+ case 9600:
+ speed = 9;
+ break;
+ case 11025:
+ speed = 8;
+ break;
+ case 12000:
+ speed = 7;
+ break;
+ case 16000:
+ speed = 6;
+ break;
+ case 22050:
+ speed = 5;
+ break;
+ case 24000:
+ speed = 4;
+ break;
+ case 32000:
+ speed = 3;
+ break;
+ case 44100:
+ speed = 2;
+ break;
+ case 48000:
+ speed = 1;
+ break;
+ case 96000:
+ speed = 0;
+ break;
+ default:
+ break;
+ }
+
+ val = read_codec_file(4);
+ val = (speed << 4) | speed;
+ write_codec_file(4, val);
+
+#if 0
+ for (i = 0; i <= 27 ; i++) {
+ printk(" ( CCC %d : 0x%x ) ",i ,read_codec_file(i));
+ }
+#endif
+
+#endif
+ return jz_audio_rate;
+}
+
+static int record_fill_1x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long data;
+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char*)dst_start;
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt++;
+ data = *(s++);
+ *(dp ++) = ((data << 16) >> 24) + 0x80;
+ s++; /* skip the other channel */
+ }
+ return cnt;
+}
+
+static int record_fill_2x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1, d2;
+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char*)dst_start;
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+ *(dp ++) = ((d1 << 16) >> 24) + 0x80;
+ d2 = *(s++);
+ *(dp ++) = ((d2 << 16) >> 24) + 0x80;
+ }
+ return cnt;
+}
+
+static int record_fill_1x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1;
+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt += 2; /* count in byte */
+ d1 = *(s++);
+ *(dp ++) = (d1 << 16) >> 16;
+ s++; /* skip the other channel */
+ }
+ return cnt;
+}
+
+
+static int record_fill_2x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1, d2;
+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt += 4; /* count in byte */
+ d1 = *(s++);
+ *(dp ++) = (d1 << 16) >> 16;
+ d2 = *(s++);
+ *(dp ++) = (d2 << 16) >> 16;
+ }
+ return cnt;
+}
+
+static int record_fill_2x24_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1, d2;
+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+
+ while (count > 0) {
+ count -= 4; /* count in dword */
+ cnt += 4; /* count in byte */
+ d1 = *(s++);
+ *(dp ++) = (d1 << 24) >> 24;
+ d2 = *(s++);
+ *(dp ++) = (d2 << 24) >> 24;
+ }
+ //printk("--- rec 24 ---\n");
+ return cnt;
+}
+
+static void replay_fill_1x8_u(unsigned long src_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned char data;
+ unsigned long ddata;
+ volatile unsigned char *s = (unsigned char *)src_start;
+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id));
+ while (count > 0) {
+ count--;
+ cnt += 1;
+ data = *(s++) - 0x80;
+ ddata = (unsigned long) data << 8;
+ *(dp ++) = ddata;
+ *(dp ++) = ddata;
+ }
+ cnt = cnt * 2 * jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static void replay_fill_2x8_u(unsigned long src_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned char d1;
+ unsigned long dd1;
+ volatile unsigned char *s = (unsigned char *)src_start;
+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id));
+ while (count > 0) {
+ count -= 1;
+ cnt += 1 ;
+ d1 = *(s++) - 0x80;
+ dd1 = (unsigned long) d1 << 8;
+ *(dp ++) = dd1;
+ }
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static void replay_fill_1x16_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed short d1;
+ signed long l1;
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count -= 2;
+ cnt += 2 ;
+ d1 = *(s++);
+ l1 = (unsigned long)d1;
+ *(dp ++) = l1;
+ *(dp ++) = l1;
+ }
+ cnt = cnt * 2 * jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static void replay_fill_2x16_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed short d1;
+ signed long l1;
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+
+ l1 = (signed long)d1;
+
+ *(dp ++) = l1;
+ }
+
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static unsigned int jz_audio_set_format(int dev, unsigned int fmt)
+{
+ switch (fmt) {
+ case AFMT_U8:
+ __i2s_set_oss_sample_size(8);
+ __i2s_set_iss_sample_size(8);
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+ break;
+ case AFMT_S16_LE:
+ /* DAC path and ADC path */
+ write_codec_file(2, 0x00);
+ //write_codec_file(2, 0x60);
+
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+
+ /* print all files */
+ __i2s_set_oss_sample_size(16);
+ __i2s_set_iss_sample_size(16);
+ break;
+ case 18:
+ /* DAC path and ADC path */
+ write_codec_file(2, 0x28);
+ //write_codec_file(2, 0x60);
+ __i2s_set_oss_sample_size(18);
+ __i2s_set_iss_sample_size(16);
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format,jz_audio_channels);
+ break;
+ case 24:
+ /* DAC path and ADC path */
+ write_codec_file(2, 0x78);
+ //write_codec_file(2, 0x60);
+ __i2s_set_oss_sample_size(24);
+ __i2s_set_iss_sample_size(24);
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format,jz_audio_channels);
+ break;
+ case AFMT_QUERY:
+ break;
+ }
+ return jz_audio_format;
+}
+
+static short jz_audio_set_channels(int dev, short channels)
+{
+ switch (channels) {
+ case 1:
+ /* print all files */
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono
+ break;
+ case 2:
+ /* print all files */
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo
+ break;
+ case 0:
+ break;
+ }
+ return jz_audio_channels;
+}
+
+static void init_codec(void)
+{
+#if defined(CONFIG_I2S_DLV)
+ /* reset DLV codec. from hibernate mode to sleep mode */
+ write_codec_file(0, 0xf);
+ write_codec_file_bit(6, 0, 0);
+ write_codec_file_bit(6, 0, 1);
+ mdelay(200);
+ //write_codec_file(0, 0xf);
+ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
+ write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0
+ mdelay(10);//wait for stability
+#endif
+}
+
+static void jz_audio_reset(void)
+{
+ __i2s_disable_replay();
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+ __i2s_disable_transmit_dma();
+ REG_AIC_I2SCR = 0x10;
+ init_codec();
+}
+
+static int jz_audio_release(struct inode *inode, struct file *file);
+static int jz_audio_open(struct inode *inode, struct file *file);
+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg);
+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait);
+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos);
+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos);
+/* static struct file_operations jz_i2s_audio_fops */
+static struct file_operations jz_i2s_audio_fops =
+{
+ owner: THIS_MODULE,
+ open: jz_audio_open,
+ release: jz_audio_release,
+ write: jz_audio_write,
+ read: jz_audio_read,
+ poll: jz_audio_poll,
+ ioctl: jz_audio_ioctl
+};
+
+static int jz_i2s_open_mixdev(struct inode *inode, struct file *file)
+{
+ int i;
+ int minor = MINOR(inode->i_rdev);
+ struct jz_i2s_controller_info *controller = i2s_controller;
+
+ for (i = 0; i < NR_I2S; i++)
+ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor)
+ goto match;
+
+ if (!controller)
+ return -ENODEV;
+match:
+ file->private_data = controller->i2s_codec[i];
+ return 0;
+}
+
+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data;
+ return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static struct file_operations jz_i2s_mixer_fops =
+{
+ owner: THIS_MODULE,
+ llseek: jz_i2s_llseek,
+ ioctl: jz_i2s_ioctl_mixdev,
+ open: jz_i2s_open_mixdev,
+};
+
+static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ u8 cur_vol;
+ long val = 0;
+
+ switch (cmd) {
+ case SOUND_MIXER_INFO:
+ {
+ mixer_info info;
+#if defined(CONFIG_I2S_DLV)
+ strncpy(info.id, "DLV", sizeof(info.id));
+ strncpy(info.name,"Jz4750 internal codec", sizeof(info.name));
+#endif
+
+ info.modify_counter = audio_mix_modcnt;
+ return copy_to_user((void *)arg, &info, sizeof(info));
+ }
+ case SOUND_OLD_MIXER_INFO:
+ {
+ _old_mixer_info info;
+#if defined(CONFIG_I2S_DLV)
+ strncpy(info.id, "DLV", sizeof(info.id));
+ strncpy(info.name,"Jz4750 internal codec", sizeof(info.name));
+#endif
+
+ return copy_to_user((void *)arg, &info, sizeof(info));
+ }
+ case SOUND_MIXER_READ_STEREODEVS:
+ return put_user(0, (long *) arg);
+ case SOUND_MIXER_READ_CAPS:
+ val = SOUND_CAP_EXCL_INPUT;
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_READ_DEVMASK:
+ break;
+ case SOUND_MIXER_READ_RECMASK:
+ break;
+ case SOUND_MIXER_READ_RECSRC:
+ break;
+ case SOUND_MIXER_WRITE_SPEAKER:
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+
+ REG_CPM_I2SCDR = val;
+ printk_codec_files();
+ break;
+ case SOUND_MIXER_WRITE_BASS:
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+#if defined(CONFIG_I2S_DLV)
+#endif
+ return 0;
+
+ case SOUND_MIXER_READ_BASS:
+#if defined(CONFIG_I2S_DLV)
+#endif
+ return put_user(val, (long *) arg);
+
+ case SOUND_MIXER_WRITE_VOLUME:
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val == 100) {
+ //REG_CPM_CLKGR |= 0x60;
+ printk("gate clock : 0x%08x\n", REG_CPM_CLKGR);
+ return 100;
+ }
+ if(val == 99) {
+ REG_CPM_CLKGR &= ~0x60;
+ return 99;
+ }
+ if(val == 98) {
+ REG_CPM_CPCCR |= 0x80400000;
+ return 98;
+ }
+ if(val == 97) {
+ REG_CPM_CPCCR &= ~0x8000000;
+ REG_CPM_CPCCR |= 0x0040000;
+ return 97;
+ }
+ if(val > 31)
+ val = 31;
+
+ jz_audio_volume = val;
+ //printk("\njz_audio_volume=%d\n",jz_audio_volume);
+#if defined(CONFIG_I2S_DLV)
+ cur_vol = val;
+ write_codec_file(17, cur_vol | 0xc0);
+ write_codec_file(18, cur_vol);
+#endif
+ return 0;
+ case SOUND_MIXER_READ_VOLUME:
+#if defined(CONFIG_I2S_DLV)
+ val = jz_audio_volume | jz_audio_volume << 8;
+#endif
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_WRITE_LINE:
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if (val == 100) {
+ printk("Playback LINE input audio direct only is starting...\n");
+ printk_codec_files();
+ set_playback_line_input_audio_direct_only();
+ printk_codec_files();
+ return 100;
+ }
+ if (val == 99) {
+ printk("Playback LINE input audio direct only is end\n");
+ unset_playback_line_input_audio_direct_only();
+ printk_codec_files();
+ return 99;
+ }
+
+ if(val > 31)
+ val = 31;
+#if defined(CONFIG_I2S_DLV)
+ use_mic_line_flag = USE_LINEIN;
+ /* set gain */
+ cur_vol = val;
+ cur_vol &= 0x1f;
+ write_codec_file(11, cur_vol);//GO1L
+ write_codec_file(12, cur_vol);//GO1R
+#endif
+ return 0;
+ break;
+ case SOUND_MIXER_WRITE_MIC:
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+
+ if(val > 0xf)
+ val = 0xf;
+#if defined(CONFIG_I2S_DLV)
+ use_mic_line_flag = USE_MIC;
+ /* set gain */
+ //write_codec_file_bit(6, 1, 3);//GIM
+ cur_vol = val;
+ cur_vol |= cur_vol << 4;
+ write_codec_file(19, cur_vol);//GIL,GIR
+#endif
+ return 0;
+
+ case SOUND_MIXER_READ_MIC:
+#if defined(CONFIG_I2S_DLV)
+#endif
+
+ return put_user(val, (long *) arg);
+ default:
+ return -ENOSYS;
+ }
+ audio_mix_modcnt ++;
+
+ return 0;
+}
+
+int i2s_probe_codec(struct i2s_codec *codec)
+{
+ /* generic OSS to I2S wrapper */
+ codec->mixer_ioctl = i2s_mixer_ioctl;
+ return 1;
+}
+
+
+/* I2S codec initialisation. */
+static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller)
+{
+ int num_i2s = 0;
+ struct i2s_codec *codec;
+
+ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) {
+ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset(codec, 0, sizeof(struct i2s_codec));
+ codec->private_data = controller;
+ codec->id = num_i2s;
+
+ if (i2s_probe_codec(codec) == 0)
+ break;
+ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) {
+ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n");
+ kfree(codec);
+ break;
+ }
+ controller->i2s_codec[num_i2s] = codec;
+ }
+ return num_i2s;
+}
+
+static void replay_fill_2x18_s(unsigned long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed long d1;
+ signed long l1;
+ volatile signed long *s = (signed long *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+ while (count > 0) {
+ count -= 4;
+ cnt += 4;
+ d1 = *(s++);
+ l1 = (signed long)d1;
+ *(dp ++) = l1;
+ }
+
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static void replay_fill_2x24_s(unsigned long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed long d1;
+ signed long l1;
+ volatile signed long *s = (signed long *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+ while (count > 0) {
+ count -= 4;
+ cnt += 4;
+ d1 = *(s++);
+ l1 = (signed long)d1;
+ *(dp ++) = l1;
+ }
+
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+ //printk("--- play 24 ---\n");
+}
+
+static void jz_update_filler(int format, int channels)
+{
+ #define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
+
+ switch (TYPE(format, channels))
+ {
+ default:
+ case TYPE(AFMT_U8, 1):
+ jz_audio_b = 4;//4bytes * 8bits =32bits
+ replay_filler = replay_fill_1x8_u;
+ record_filler = record_fill_1x8_u;
+ break;
+ case TYPE(AFMT_U8, 2):
+ jz_audio_b = 4;
+ replay_filler = replay_fill_2x8_u;
+ record_filler = record_fill_2x8_u;
+ break;
+ case TYPE(AFMT_S16_LE, 1):
+ //2bytes * 16bits =32bits
+ jz_audio_b = 2;
+ replay_filler = replay_fill_1x16_s;
+ record_filler = record_fill_1x16_s;
+ break;
+ case TYPE(AFMT_S16_LE, 2):
+ jz_audio_b = 2;
+ replay_filler = replay_fill_2x16_s;
+ record_filler = record_fill_2x16_s;
+ break;
+ case TYPE(18, 2):
+ jz_audio_b = 1;
+ replay_filler = replay_fill_2x18_s;
+ record_filler = record_fill_2x16_s;
+ break;
+ case TYPE(24, 2):
+ jz_audio_b = 1;
+ replay_filler = replay_fill_2x24_s;
+ record_filler = record_fill_2x24_s;
+ //printk("--- 24 ---\n");
+ break;
+ }
+}
+
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry *proc_jz_root;
+
+int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ return 0;
+}
+
+static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller)
+{
+ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0]))
+ return -EIO;
+ return 0;
+}
+
+static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller)
+{
+ ;
+}
+#endif
+
+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller)
+{
+ char *name;
+ int adev;//No of Audio device.
+ name = controller->name;
+ jz_i2s_initHw(1);//initialize AIC controller and reset it
+ /* register /dev/audio */
+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1);
+ if (adev < 0)
+ goto audio_failed;
+ /* initialize I2S codec and register /dev/mixer */
+ if (jz_i2s_codec_init(controller) <= 0)
+ goto mixer_failed;
+
+#ifdef CONFIG_PROC_FS
+ if (jz_i2s_init_proc(controller) < 0) {
+ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name);
+ goto proc_failed;
+ }
+#endif
+
+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, JZCODEC_USER_BUFFER);
+ if (!controller->tmp1) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp1_failed;
+ }
+
+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, JZCODEC_USER_BUFFER);
+ if (!controller->tmp2) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp2_failed;
+ }
+
+ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name);
+ goto dma1_failed;
+ }
+ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name);
+ goto dma2_failed;
+ }
+ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2));
+
+ controller->dev_audio = adev;
+
+ return;
+dma2_failed:
+ jz_free_dma(controller->dma2);
+dma1_failed:
+ jz_free_dma(controller->dma1);
+ free_pages((unsigned long)controller->tmp2, JZCODEC_USER_BUFFER);
+tmp2_failed:
+tmp1_failed:
+ free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER);
+
+#ifdef CONFIG_PROC_FS
+ jz_i2s_cleanup_proc(controller);
+#endif
+proc_failed:
+ /* unregister mixer dev */
+mixer_failed:
+ unregister_sound_dsp(adev);
+audio_failed:
+ return;
+}
+
+
+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller)
+{
+ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info),
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n");
+ return -ENOMEM;
+ }
+ (*controller)->name = "Jz I2S controller";
+ (*controller)->opened1 = 0;
+ (*controller)->opened2 = 0;
+ init_waitqueue_head(&(*controller)->adc_wait);
+ init_waitqueue_head(&(*controller)->dac_wait);
+ spin_lock_init(&(*controller)->lock);
+ init_waitqueue_head(&rx_wait_queue);
+ init_waitqueue_head(&tx_wait_queue);
+ init_waitqueue_head(&pop_wait_queue);
+
+ return 0;
+}
+
+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller)
+{
+ int adev = controller->dev_audio;
+ jz_i2s_full_reset (controller);
+ controller->dev_audio = -1;
+
+#ifdef CONFIG_PROC_FS
+ jz_i2s_cleanup_proc(controller);
+#endif
+
+ jz_free_dma(controller->dma1);
+ jz_free_dma(controller->dma2);
+ free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER);
+ free_pages((unsigned long)controller->tmp2, JZCODEC_USER_BUFFER);
+ if (adev >= 0) {
+ //unregister_sound_mixer(audio_devs[adev]->mixer_dev);
+ unregister_sound_dsp(controller->dev_audio);
+ }
+}
+
+
+#ifdef CONFIG_PM
+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state)
+{
+ return 0;
+}
+
+static int jz_i2s_resume(struct jz_i2s_controller_info *controller)
+{
+ return 0;
+}
+
+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
+{
+ int ret;
+ struct jz_i2s_controller_info *controller = pm_dev->data;
+
+ if (!controller) return -EINVAL;
+
+ switch (req) {
+ case PM_SUSPEND:
+ ret = jz_i2s_suspend(controller, (int)data);
+ break;
+
+ case PM_RESUME:
+ ret = jz_i2s_resume(controller);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+#endif /* CONFIG_PM */
+
+
+static irqreturn_t aic_codec_irq(int irq, void *dev_id)
+{
+ u8 file_9 = read_codec_file(9);
+ u8 file_8 = read_codec_file(8);
+
+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9);
+ if ((file_9 & 0x1f) == 0x10) {
+
+ write_codec_file(8, 0x3f);
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ mdelay(300);
+ while ((read_codec_file(9) & 0x4) != 0x4);
+ while ((read_codec_file(9) & 0x10) == 0x10) {
+ write_codec_file(9, 0x10);
+ }
+ write_codec_file_bit(5, 0, 6);//SB_OUT->0
+ mdelay(300);
+ while ((read_codec_file(9) & 0x8) != 0x8);
+ write_codec_file(9, file_9);
+ write_codec_file(8, file_8);
+
+ return IRQ_HANDLED;
+ }
+
+ if (file_9 & 0x8)
+ ramp_up_end = jiffies;
+ else if (file_9 & 0x4)
+ ramp_down_end = jiffies;
+ else if (file_9 & 0x2)
+ gain_up_end = jiffies;
+ else if (file_9 & 0x1)
+ gain_down_end = jiffies;
+
+ write_codec_file(9, file_9);
+ if (file_9 & 0xf)
+ wake_up(&pop_wait_queue);
+ while (REG_ICDC_RGDATA & 0x100);
+
+ return IRQ_HANDLED;
+}
+
+static int __init init_jz_i2s(void)
+{
+ int errno, retval;
+
+#if defined(CONFIG_I2S_DLV)
+ ramp_up_start = 0;
+ ramp_up_end = 0;
+ gain_up_start = 0;
+ gain_up_end = 0;
+ ramp_down_start = 0;
+ ramp_down_end = 0;
+ gain_down_start = 0;
+ gain_down_end = 0;
+
+ //REG_CPM_CPCCR &= ~(1 << 31);
+ //REG_CPM_CPCCR &= ~(1 << 30);
+ use_mic_line_flag = USE_NONE;
+ write_codec_file(0, 0xf);
+
+ REG_AIC_I2SCR = 0x10;
+ __i2s_internal_codec();
+ __i2s_as_slave();
+ __i2s_select_i2s();
+ __aic_select_i2s();
+ __aic_reset();
+ mdelay(10);
+ REG_AIC_I2SCR = 0x10;
+ mdelay(20);
+
+ /* power on DLV */
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+#endif
+
+ if ((errno = probe_jz_i2s(&i2s_controller)) < 0)
+ return errno;
+ attach_jz_i2s(i2s_controller);
+#if defined(CONFIG_I2S_DLV)
+ __i2s_disable_transmit_intr();
+ __i2s_disable_receive_intr();
+ jz_codec_config = 0;
+ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL);
+ if (retval) {
+ printk("Could not get aic codec irq %d\n", IRQ_AIC);
+ return retval;
+ }
+#endif
+
+ out_empty_queue.id = NULL;
+ out_full_queue.id = NULL;
+ out_busy_queue.id = NULL;
+ in_empty_queue.id = NULL;
+ in_full_queue.id = NULL;
+ in_busy_queue.id = NULL;
+
+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE;
+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ;
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+
+#ifdef CONFIG_PM
+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN,
+ jz_i2s_pm_callback);
+ if (i2s_controller->pm)
+ i2s_controller->pm->data = i2s_controller;
+#endif
+
+ __cpm_start_idct();
+ __cpm_start_db();
+ __cpm_start_me();
+ __cpm_start_mc();
+ __cpm_start_ipu();
+
+ return 0;
+}
+
+
+static void __exit cleanup_jz_i2s(void)
+{
+ unload_jz_i2s(i2s_controller);
+#if defined(CONFIG_I2S_DLV)
+ free_irq(IRQ_AIC, NULL);
+#endif
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+}
+
+module_init(init_jz_i2s);
+module_exit(cleanup_jz_i2s);
+
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ //DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count,i=0;
+
+ //add_wait_queue(&ctrl->adc_wait, &wait);
+ for (;;) {
+ if (i < MAXDELAY) {
+ udelay(10);
+ i++;
+ } else
+ break;
+ //set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&ctrl->lock, flags);
+ //spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ //spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+
+ /*if (signal_pending(current))
+ break;*/
+ if (nonblock) {
+ //remove_wait_queue(&ctrl->adc_wait, &wait);
+ //current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ //remove_wait_queue(&ctrl->adc_wait, &wait);
+ //current->state = TASK_RUNNING;
+ /*if (signal_pending(current))
+ return -ERESTARTSYS;*/
+ return 0;
+}
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ unsigned long flags;
+ int count,ele,busyele,emptyele,i=0;
+
+ for (;;) {
+ if(!nonblock) {//blocked
+ if (i < MAXDELAY) {
+ udelay(10);
+ i++;
+ } else
+ break;
+
+ ele = elements_in_queue(&out_full_queue);
+ if(ele <= 0) {
+ udelay(200);
+
+ busyele = elements_in_queue(&out_busy_queue);
+ emptyele = elements_in_queue(&out_empty_queue);
+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ }
+ }
+ } else {//non-blocked
+ mdelay(100);
+ ele = elements_in_queue(&out_full_queue);
+
+ if(ele <= 0) {
+ mdelay(100);
+ busyele = elements_in_queue(&out_busy_queue);
+ emptyele = elements_in_queue(&out_empty_queue);
+
+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void print_pop_duration(void)
+{
+ long diff;
+#if 0
+ printk(" ramp_up_start=0x%x\n",ramp_up_start);
+ printk(" ramp_up_end =0x%x\n",ramp_up_end);
+ printk(" gain_up_start=0x%x\n",gain_up_start);
+ printk(" gain_up_end =0x%x\n",gain_up_end);
+
+ printk("ramp_down_start=0x%x\n",ramp_down_start);
+ printk("ramp_down_end =0x%x\n",ramp_down_end);
+ printk("gain_down_start=0x%x\n",gain_down_start);
+ printk("gain_down_end =0x%x\n",gain_down_end);
+#endif
+
+ diff = (long)ramp_up_end - (long)ramp_up_start;
+ printk("ramp up duration: %d ms\n",diff * 1000 / HZ);
+ diff = (long)gain_up_end - (long)gain_up_start;
+ printk("gain up duration: %d ms\n",diff * 1000 / HZ);
+ diff = (long)gain_down_end - (long)gain_down_start;
+ printk("gain down duration: %d ms\n",diff);
+ diff = (long)ramp_down_end - (long)ramp_down_start;
+ printk("ramp down duration: %d ms\n",diff * 1000 / HZ);
+}
+
+static int jz_audio_release(struct inode *inode, struct file *file)
+{
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ unsigned long tfl;
+
+ jz_codec_config = 0;
+ if (controller == NULL)
+ return -ENODEV;
+
+ if (controller->opened1 == 1 && controller->opened2 == 1) {
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+
+ drain_dac(controller, file->f_flags & O_NONBLOCK);
+ /* wait for fifo empty */
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ gain_down_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //gain_down_end = jiffies;
+ /*while (1) {
+ tfl = REG_AIC_SR & 0x00003f00;
+ if (tfl == 0) {
+ udelay(500);
+ break;
+ }
+ mdelay(2);
+ }*/
+ mdelay(100);
+ disable_dma(controller->dma1);
+ set_dma_count(controller->dma1, 0);
+
+ __i2s_disable_transmit_dma();
+ __i2s_disable_replay();
+
+ //spin_lock_irqsave(&controller->ioctllock, flags);
+ spin_lock(&controller->ioctllock);
+ controller->total_bytes = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+ //spin_unlock_irqrestore(&controller->ioctllock, flags);
+ spin_unlock(&controller->ioctllock);
+
+ /////////////////////////
+ first_record_call = 1;
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ drain_adc(controller, file->f_flags & O_NONBLOCK);
+ disable_dma(controller->dma2);
+ set_dma_count(controller->dma2, 0);
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+ //__aic_flush_fifo();
+ //spin_lock_irqsave(&controller->ioctllock, flags);
+ spin_lock(&controller->ioctllock);
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+ //spin_unlock_irqrestore(&controller->ioctllock, flags);
+ spin_unlock(&controller->ioctllock);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ ramp_down_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //ramp_down_end = jiffies;
+ if (use_mic_line_flag == USE_LINEIN) {
+ unset_record_line_input_audio_with_audio_data_replay();
+ //printk("3 use_mic_line_flag=%d\n",use_mic_line_flag);
+ }
+ if (use_mic_line_flag == USE_MIC) {
+ unset_record_mic_input_audio_with_audio_data_replay();
+ //printk("4 use_mic_line_flag=%d\n",use_mic_line_flag);
+ }
+
+#if 0
+ unset_record_playing_audio_mixed_with_mic_input_audio();
+#endif
+ __i2s_disable();
+#endif
+ } else if ( controller->opened1 == 1 ) {
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+ drain_dac(controller, file->f_flags & O_NONBLOCK);
+ /* wait for fifo empty */
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ gain_down_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //gain_down_end = jiffies;
+ while (1) {
+ tfl = REG_AIC_SR & 0x00003f00;
+ if (tfl == 0) {
+ udelay(500);
+ break;
+ }
+ mdelay(2);
+ }
+ disable_dma(controller->dma1);
+ set_dma_count(controller->dma1, 0);
+
+ __i2s_disable_transmit_dma();
+ __i2s_disable_replay();
+
+ __aic_flush_fifo();
+
+ //spin_lock_irqsave(&controller->ioctllock, flags);
+ spin_lock(&controller->ioctllock);
+ controller->total_bytes = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+ //spin_unlock_irqrestore(&controller->ioctllock, flags);
+ spin_unlock(&controller->ioctllock);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ ramp_down_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //ramp_down_end = jiffies;
+ unset_audio_data_replay();
+#endif
+ __i2s_disable();
+ } else if ( controller->opened2 == 1 ) {
+ //controller->opened2 = 0;
+ first_record_call = 1;
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ drain_adc(controller, file->f_flags & O_NONBLOCK);
+ disable_dma(controller->dma2);
+ set_dma_count(controller->dma2, 0);
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+
+ //spin_lock_irqsave(&controller->ioctllock, flags);
+ spin_lock(&controller->ioctllock);
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+ //spin_unlock_irqrestore(&controller->ioctllock, flags);
+ spin_unlock(&controller->ioctllock);
+#if defined(CONFIG_I2S_DLV)
+#if 0
+ /* unset Record MIC input audio with direct playback */
+ unset_record_mic_input_audio_with_direct_playback();
+#endif
+#if 1
+ /* unset Record MIC input audio without playback */
+ unset_record_mic_input_audio_without_playback();
+#endif
+#if 0
+ /* tested */
+ /* unset Record LINE input audio without playback */
+ unset_record_line_input_audio_without_playback();
+#endif
+#endif
+ __i2s_disable();
+ }
+
+ if (controller->opened1 == 1 && controller->opened2 == 1) {
+ controller->opened1 = 0;
+ controller->opened2 = 0;
+ print_pop_duration();
+ //__dmac_disable_module(0);
+ } else if ( controller->opened1 == 1 ) {
+ controller->opened1 = 0;
+ print_pop_duration();
+ } else if ( controller->opened2 == 1 ) {
+ controller->opened2 = 0;
+ }
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+
+/* __cpm_stop_idct();
+ __cpm_stop_db();
+ __cpm_stop_me();
+ __cpm_stop_mc();
+ __cpm_stop_ipu();*/
+ printk("close audio and clear ipu gate : 0x%08x\n", REG_CPM_CLKGR);
+ return 0;
+}
+
+static int jz_audio_open(struct inode *inode, struct file *file)
+{
+ int i;
+ struct jz_i2s_controller_info *controller = i2s_controller;
+ if (controller == NULL)
+ return -ENODEV;
+ mdelay(2);
+ REG_DMAC_DMACKE(0) = 0x3f;
+ if (controller->opened1 == 1 || controller->opened2 == 1 ) {
+ printk("\naudio is busy!\n");
+ return -EBUSY;
+ }
+ jz_codec_config = 0;
+
+ ramp_up_start = 0;
+ ramp_up_end = 0;
+ gain_up_start = 0;
+ gain_up_end = 0;
+ ramp_down_start = 0;
+ ramp_down_end = 0;
+ gain_down_start = 0;
+ gain_down_end = 0;
+
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ if (controller->opened1 == 1)
+ return -EBUSY;
+ controller->opened1 = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+
+ out_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+
+ if (controller->opened2 == 1)
+ return -EBUSY;
+
+ controller->opened2 = 1;
+ first_record_call = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+
+ in_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+ } else if (file->f_mode & FMODE_WRITE) {
+ if (controller->opened1 == 1)
+ return -EBUSY;
+ controller->opened1 = 1;
+ //for ioctl
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+
+ out_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ } else if (file->f_mode & FMODE_READ) {
+ if (controller->opened2 == 1)
+ return -EBUSY;
+
+ controller->opened2 = 1;
+ first_record_call = 1;
+ //for ioctl
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+
+ in_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+ }
+
+ file->private_data = controller;
+ jz_audio_reset();//11.2
+
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+#if defined(CONFIG_I2S_DLV)
+
+ if (use_mic_line_flag == USE_LINEIN) {
+ /* Record LINE input audio with Audio data replay (full duplex for linein) */
+ /* codec_test_line */
+ set_record_line_input_audio_with_audio_data_replay();
+
+ }
+ if (use_mic_line_flag == USE_MIC) {
+ /* Record MIC input audio with Audio data replay (full duplex) */
+ /* codec_test_mic */
+ set_record_mic_input_audio_with_audio_data_replay();
+ }
+#if 0
+ /* Record playing audio mixed with MIC input audio */
+ set_record_playing_audio_mixed_with_mic_input_audio();
+#endif
+
+#endif
+ } else if (file->f_mode & FMODE_WRITE) {
+#if defined(CONFIG_I2S_DLV)
+ //mdelay(10);
+ /* Audio data replay */
+ set_audio_data_replay();
+#endif
+ } else if (file->f_mode & FMODE_READ) {
+#if defined(CONFIG_I2S_DLV)
+#if 0
+ /* Record MIC input audio with direct playback */
+ set_record_mic_input_audio_with_direct_playback();
+#endif
+
+#if 1
+ /* set Record MIC input audio without playback */
+ set_record_mic_input_audio_without_playback();
+#endif
+#if 0
+ /* tested */
+ /* set Record LINE input audio without playback */
+ set_record_line_input_audio_without_playback();
+#endif
+ mdelay(1);
+#endif
+ }
+
+ __aic_reset();
+
+ mdelay(10);
+ REG_AIC_I2SCR = 0x10;
+ mdelay(20);
+ __aic_flush_fifo();
+ __i2s_enable();
+ ndelay(100);
+
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+#if defined(CONFIG_I2S_DLV)
+ //set SB_ADC or SB_DAC
+ __dmac_enable_module(0);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ ramp_up_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //ramp_up_end = jiffies;
+#endif
+ } else if (file->f_mode & FMODE_WRITE) {
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ ramp_up_start = jiffies;
+ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_RCR = 0x1;
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_RGR = 1;*/
+ sleep_on(&pop_wait_queue);
+ //ramp_up_end = jiffies;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+#endif
+ } else if (file->f_mode & FMODE_READ) {
+#if defined(CONFIG_I2S_DLV)
+ if (jz_mic_only)
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ else
+ write_codec_file_bit(5, 0, 7);//SB_DAC->0
+ mdelay(500);
+#endif
+ }
+
+
+ printk("open audio and set ipu gate : 0x%08x\n", REG_CPM_CLKGR);
+ return 0;
+}
+
+
+static int jz_audio_ioctl(struct inode *inode, struct file *file,
+unsigned int cmd, unsigned long arg)
+{
+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize;
+ unsigned int flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+
+ audio_buf_info abinfo;
+ int i, bytes, id;
+ count_info cinfo;
+ val = 0;
+ bytes = 0;
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *)arg);
+ case SNDCTL_DSP_RESET:
+ return 0;
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ drain_dac(controller, file->f_flags & O_NONBLOCK);
+ return 0;
+ case SNDCTL_DSP_SPEED:
+ /* set smaple rate */
+ {
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val >= 0)
+ jz_audio_set_speed(controller->dev_audio, val);
+ return put_user(val, (int *)arg);
+ }
+ case SNDCTL_DSP_STEREO:
+ /* set stereo or mono channel */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1);
+ return 0;
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ //return put_user(4*PAGE_SIZE, (int *)arg);
+ return put_user(jz_audio_fragsize , (int *)arg);
+ case SNDCTL_DSP_GETFMTS:
+ /* Returns a mask of supported sample format*/
+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg);
+
+ case SNDCTL_DSP_SETFMT:
+ /* Select sample format */
+ {
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val != AFMT_QUERY) {
+ jz_audio_set_format(controller->dev_audio,val);
+ } else {
+ if (file->f_mode & FMODE_READ)
+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+ else
+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+
+ }
+ return put_user(val, (int *)arg);
+ }
+
+ case SNDCTL_DSP_CHANNELS:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ jz_audio_set_channels(controller->dev_audio, val);
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_POST:
+ /* FIXME: the same as RESET ?? */
+ return 0;
+
+ case SNDCTL_DSP_SUBDIVIDE:
+ return 0;
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ get_user(val, (long *) arg);
+ newfragsize = 1 << (val & 0xFFFF);//16 least bits
+
+ if (newfragsize < 4 * PAGE_SIZE)
+ newfragsize = 4 * PAGE_SIZE;
+ if (newfragsize > (16 * PAGE_SIZE)) //16 PAGE_SIZE
+ newfragsize = 16 * PAGE_SIZE;
+
+ newfragstotal = (val >> 16) & 0x7FFF;
+ if (newfragstotal < 2)
+ newfragstotal = 2;
+ if (newfragstotal > 32)
+ newfragstotal = 32;
+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize))
+ return 0;
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ mdelay(500);
+ jz_audio_fragstotal = newfragstotal;
+ jz_audio_fragsize = newfragsize;
+
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ mdelay(10);
+
+ return 0;
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg);
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+ case SNDCTL_DSP_SETDUPLEX:
+ return -EINVAL;
+ case SNDCTL_DSP_GETOSPACE:
+ {
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ //unused fragment amount
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ jz_audio_fragments = elements_in_queue(&out_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+ bytes /= jz_audio_b;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ abinfo.fragments = jz_audio_fragments;
+ abinfo.fragstotal = jz_audio_fragstotal;
+ abinfo.fragsize = jz_audio_fragsize;
+ abinfo.bytes = bytes;
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+ }
+ case SNDCTL_DSP_GETISPACE:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+
+ bytes = 0;
+ //unused fragment amount
+ jz_audio_fragments = elements_in_queue(&in_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+ bytes /= jz_audio_b;
+ abinfo.fragments = jz_audio_fragments;
+ abinfo.fragstotal = jz_audio_fragstotal;
+ abinfo.fragsize = jz_audio_fragsize;
+ abinfo.bytes = bytes;
+ return copy_to_user((void *)arg, &abinfo,
+ sizeof(abinfo)) ? -EFAULT : 0;
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && in_dma_buf)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && out_dma_buf)
+ val |= PCM_ENABLE_OUTPUT;
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_SETTRIGGER:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ return 0;
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ //controller->total_bytes += get_dma_residue(controller->dma2);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextIn;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ //controller->total_bytes += get_dma_residue(controller->dma1);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextOut;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ unfinish = 0;
+ fullc = elements_in_queue(&out_full_queue);
+ busyc = elements_in_queue(&out_busy_queue);
+ for(i = 0;i < fullc ;i ++) {
+ id = *(out_full_queue.id + i);
+ unfinish += *(out_dma_buf_data_count + id);
+ }
+ for(i = 0;i < busyc ;i ++) {
+ id = *(out_busy_queue.id + i);
+ unfinish += get_dma_residue(controller->dma1);
+ }
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ unfinish /= jz_audio_b;
+ return put_user(unfinish, (int *) arg);
+ case SOUND_PCM_READ_RATE:
+ return put_user(jz_audio_rate, (int *)arg);
+ case SOUND_PCM_READ_CHANNELS:
+ return put_user(jz_audio_channels, (int *)arg);
+ case SOUND_PCM_READ_BITS:
+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16,
+ (int *)arg);
+ case SNDCTL_DSP_MAPINBUF:
+ case SNDCTL_DSP_MAPOUTBUF:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_WRITE_FILTER:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+
+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait)
+{
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ return POLLOUT | POLLWRNORM;
+ poll_wait(file, &controller->dac_wait, wait);
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ return POLLIN | POLLRDNORM;
+ poll_wait(file, &controller->adc_wait, wait);
+ }
+ spin_lock_irqsave(&controller->lock, flags);
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ mask |= POLLOUT | POLLWRNORM;
+ } else if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ spin_unlock_irqrestore(&controller->lock, flags);
+ return mask;
+}
+
+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ int id, ret = 0, left_count, copy_count, cnt = 0;
+
+ if (count < 0)
+ return -EINVAL;
+
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ //spin_lock_irqsave(&controller->ioctllock, flags);
+ spin_lock(&controller->ioctllock);
+ controller->nextIn = 0;
+ //spin_unlock_irqrestore(&controller->ioctllock, flags);
+ spin_unlock(&controller->ioctllock);
+
+ spin_lock(&controller->lock);
+
+ copy_count = jz_audio_fragsize / 4;
+
+ left_count = count;
+ spin_unlock(&controller->lock);
+
+ if (first_record_call) {
+ first_record_call = 0;
+ audio_read_back_first:
+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ spin_lock(&controller->lock);
+ *(in_dma_buf_data_count + id) = copy_count * 4;
+ spin_unlock(&controller->lock);
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+
+ //write back
+ dma_cache_wback_inv(*(in_dma_buf + id),
+ *(in_dma_buf_data_count + id));
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ //interruptible_sleep_on(&rx_wait_queue);
+ sleep_on(&rx_wait_queue);
+ } else
+ goto audio_read_back_first;
+ }
+
+ while (left_count > 0) {
+ audio_read_back_second:
+ if (elements_in_queue(&in_full_queue) <= 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ else
+ sleep_on(&rx_wait_queue);
+ }
+ /*if (signal_pending(current))
+ return ret ? ret: -ERESTARTSYS; */
+ if ((id = get_buffer_id(&in_full_queue)) >= 0) {
+ spin_lock(&controller->lock);
+ cnt = record_filler((unsigned long)controller->tmp2+ret,
+ copy_count, id);
+ spin_unlock(&controller->lock);
+ put_buffer_id(&in_empty_queue, id);
+ } else
+ goto audio_read_back_second;
+
+ if (elements_in_queue(&in_busy_queue) == 0) {
+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ spin_lock(&controller->lock);
+ *(in_dma_buf_data_count + id) = copy_count * 4;
+ spin_unlock(&controller->lock);
+ //write back
+ dma_cache_wback_inv(*(in_dma_buf + id),
+ *(in_dma_buf_data_count + id));
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ }
+ }
+ if (ret + cnt > count) {
+ spin_lock(&controller->lock);
+ cnt = count - ret;
+ spin_unlock(&controller->lock);
+ }
+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt))
+ return ret ? ret : -EFAULT;
+ spin_lock(&controller->lock);
+ ret += cnt;
+ spin_unlock(&controller->lock);
+ //spin_lock_irqsave(&controller->ioctllock, flags);
+ spin_lock(&controller->ioctllock);
+ controller->nextIn += ret;
+ //spin_unlock_irqrestore(&controller->ioctllock, flags);
+ spin_unlock(&controller->ioctllock);
+ spin_lock(&controller->lock);
+ left_count -= cnt;
+ spin_unlock(&controller->lock);
+ }//while (left_count > 0)
+ return ret;
+}
+
+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ int id, ret = 0, left_count, copy_count = 0, val;
+ unsigned int flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+
+ if (count <= 0)
+ return -EINVAL;
+
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ //spin_lock(&controller->ioctllock);
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ //spin_unlock(&controller->ioctllock);
+ if (jz_audio_channels == 2)
+ copy_count = jz_audio_fragsize / jz_audio_b;
+ else if(jz_audio_channels == 1)
+ copy_count = jz_audio_fragsize / 4;
+
+ left_count = count;
+ if (copy_from_user(controller->tmp1, buffer, count)) {
+ printk("copy_from_user failed:%d",ret);
+ return ret ? ret : -EFAULT;
+ }
+
+ while (left_count > 0) {
+ audio_write_back:
+ if (file->f_flags & O_NONBLOCK)
+ udelay(2);
+ if (elements_in_queue(&out_empty_queue) == 0) {
+ // all are full
+ if (file->f_flags & O_NONBLOCK)
+ return ret;//no waiting,no block
+ else {
+ sleep_on(&tx_wait_queue);//blocked
+ }
+ }
+ /*if (signal_pending(current))
+ return ret ? ret : -ERESTARTSYS;*/
+ /* the end fragment size in this write */
+ if (ret + copy_count > count)
+ copy_count = count - ret;
+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) {
+ //replay_filler((unsigned long)controller->tmp1 + ret, copy_count, id);
+ replay_filler((signed long)controller->tmp1 + ret, copy_count, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ put_buffer_id(&out_full_queue, id); //busy in
+ dma_cache_wback_inv(*(out_dma_buf + id),
+ *(out_dma_buf_data_count + id));
+ } else
+ put_buffer_id(&out_empty_queue, id); //spare
+ } else
+ goto audio_write_back;
+
+ left_count = left_count - copy_count;
+ ret += copy_count;
+ //spin_lock_irqsave(&controller->ioctllock, flags);
+ spin_lock(&controller->ioctllock);
+ controller->nextOut += ret;
+ //spin_unlock_irqrestore(&controller->ioctllock, flags);
+ spin_unlock(&controller->ioctllock);
+ if (elements_in_queue(&out_busy_queue) == 0) {
+ if ((id = get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id); //first once,next spare
+
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(controller->dma1,
+ file->private_data,
+ *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ if (jz_codec_config == 0) {
+ write_codec_file_bit(1, 0, 5);
+ gain_up_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //gain_up_end = jiffies;
+ jz_codec_config = 1;
+ //SB_ADC->1
+ //write_codec_file_bit(5, 1, 4);
+ //while(1);
+ }
+ }
+ }
+ }
+ }
+ return ret;
+}
diff --git a/sound/oss/jz_i2s_for_4750.c b/sound/oss/jz_i2s_for_4750.c
new file mode 100644
index 00000000000..f492295af3a
--- /dev/null
+++ b/sound/oss/jz_i2s_for_4750.c
@@ -0,0 +1,2981 @@
+/*
+ * linux/drivers/sound/Jz_i2s.c
+ *
+ * JzSOC On-Chip I2S audio driver.
+ *
+ * Copyright (C) 2005 by Junzheng Corp.
+ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using
+ * dma channel 4&3,noah is tested.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Because the normal application of AUDIO devices are focused on Little_endian,
+ * then we only perform the little endian data format in driver.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/pm_legacy.h>
+#include <sound/driver.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/proc_fs.h>
+#include <linux/soundcard.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <asm/hardirq.h>
+#include <asm/jzsoc.h>
+#include "sound_config.h"
+
+#define DPRINTK(args...) printk(args)
+#define DMA_ID_I2S_TX DMA_ID_AIC_TX
+#define DMA_ID_I2S_RX DMA_ID_AIC_RX
+#define NR_I2S 2
+#define MAXDELAY 50000
+#define JZCODEC_RW_BUFFER_SIZE 2
+#define JZCODEC_RW_BUFFER_TOTAL 6
+
+typedef struct hpvol_shift_s
+{
+ int hpvol;
+ int shift;
+} hpvol_shift_t;
+
+mixer_info info;
+_old_mixer_info old_info;
+int codec_volue_shift;
+hpvol_shift_t hpvol_shift_table[72];
+int abnormal_data_count;
+unsigned long i2s_clk;
+
+void (*set_codec_mode)(void) = NULL;
+void (*clear_codec_mode)(void) = NULL;
+void (*set_codec_gpio_pin)(void) = NULL;
+void (*each_time_init_codec)(void) = NULL;
+int (*set_codec_startup_param)(void) = NULL;
+void (*set_codec_volume_table)(void) = NULL;
+void (*set_codec_record)(void) = NULL;
+void (*set_codec_replay)(void) = NULL;
+void (*set_codec_replay_record)(void);
+void (*turn_on_codec)(void) = NULL;
+void (*turn_off_codec)(void) = NULL;
+void (*set_codec_speed)(int rate) = NULL;
+void (*reset_codec)(void) = NULL;
+void (*codec_mixer_old_info_id_name)(void) = NULL;
+void (*codec_mixer_info_id_name)(void) = NULL;
+void (*set_codec_bass)(int val) = NULL;
+void (*set_codec_volume)(int val) = NULL;
+void (*set_codec_mic)(int val) = NULL;
+void (*i2s_resume_codec)(void) = NULL;
+void (*i2s_suspend_codec)(int wr,int rd) = NULL;
+void (*init_codec_pin)(void) = NULL;
+void (*set_codec_some_func)(void) = NULL;
+void (*clear_codec_record)(void) = NULL;
+void (*clear_codec_replay)(void) = NULL;
+void (*set_replay_hp_or_speaker)(void) = NULL;
+void (*set_codec_direct_mode)(void) = NULL;
+void (*clear_codec_direct_mode)(void) = NULL;
+
+static int jz_audio_rate;
+static int jz_audio_format;
+static int jz_audio_volume;
+static int jz_audio_channels;
+static int jz_audio_b; /* bits expand multiple */
+static int jz_audio_fragments; /* unused fragment amount */
+static int jz_audio_fragstotal;
+static int jz_audio_fragsize;
+static int jz_audio_speed;
+
+static int codec_bass_gain;
+static int audio_mix_modcnt;
+static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */
+static int jz_mic_only = 1;
+static int jz_codec_config = 0;
+static unsigned long ramp_up_start;
+static unsigned long ramp_up_end;
+static unsigned long gain_up_start;
+static unsigned long gain_up_end;
+static unsigned long ramp_down_start;
+static unsigned long ramp_down_end;
+static unsigned long gain_down_start;
+static unsigned long gain_down_end;
+
+static int codec_mic_gain;
+static int pop_dma_flag;
+static int last_dma_buffer_id;
+static int drain_flag;
+
+static void (*old_mksound)(unsigned int hz, unsigned int ticks);
+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
+static void jz_update_filler(int bits, int channels);
+
+static int Init_In_Out_queue(int fragstotal,int fragsize);
+static int Free_In_Out_queue(int fragstotal,int fragsize);
+static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref);
+static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref);
+static void (*replay_filler)(signed long src_start, int count, int id);
+static int (*record_filler)(unsigned long dst_start, int count, int id);
+#if defined(CONFIG_I2S_ICODEC)
+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample);
+#endif
+static void jz_audio_reset(void);
+static struct file_operations jz_i2s_audio_fops;
+
+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue);
+
+struct jz_i2s_controller_info
+{
+ int io_base;
+ int dma1; /* for play */
+ int dma2; /* for record */
+ char *name;
+ int dev_audio;
+ struct i2s_codec *i2s_codec[NR_I2S];
+ int opened1;
+ int opened2;
+ unsigned char *tmp1; /* tmp buffer for sample conversions */
+ unsigned char *tmp2;
+ spinlock_t lock;
+ spinlock_t ioctllock;
+
+ wait_queue_head_t dac_wait;
+ wait_queue_head_t adc_wait;
+ int nextIn; /* byte index to next-in to DMA buffer */
+ int nextOut; /* byte index to next-out from DMA buffer */
+ int count; /* current byte count in DMA buffer */
+ int finish; /* current transfered byte count in DMA buffer */
+ unsigned total_bytes; /* total bytes written or read */
+ unsigned blocks;
+ unsigned error; /* over/underrun */
+#ifdef CONFIG_PM
+ struct pm_dev *pm;
+#endif
+};
+
+
+static struct jz_i2s_controller_info *i2s_controller = NULL;
+struct i2s_codec
+{
+ /* I2S controller connected with */
+ void *private_data;
+ char *name;
+ int id;
+ int dev_mixer;
+ /* controller specific lower leverl i2s accessing routines */
+ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */
+ void (*codec_write) (u8 reg, u16 val);
+ /* Wait for codec-ready */
+ void (*codec_wait) (struct i2s_codec *codec);
+ /* OSS mixer masks */
+ int modcnt;
+ int supported_mixers;
+ int stereo_mixers;
+ int record_sources;
+ int bit_resolution;
+ /* OSS mixer interface */
+ int (*read_mixer) (struct i2s_codec *codec, int oss_channel);
+ void (*write_mixer)(struct i2s_codec *codec, int oss_channel,
+ unsigned int left, unsigned int right);
+ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask);
+ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg);
+ /* saved OSS mixer states */
+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+};
+
+
+typedef struct buffer_queue_s
+{
+ int count;
+ int *id;
+ int lock;
+} buffer_queue_t;
+
+typedef struct left_right_sample_s
+{
+ signed long left;
+ signed long right;
+} left_right_sample_t;
+
+static unsigned long pop_turn_onoff_buf;
+static unsigned long pop_turn_onoff_pbuf;
+
+static unsigned long *out_dma_buf = NULL;
+static unsigned long *out_dma_pbuf = NULL;
+static unsigned long *out_dma_buf_data_count = NULL;
+static unsigned long *in_dma_buf = NULL;
+static unsigned long *in_dma_pbuf = NULL;
+static unsigned long *in_dma_buf_data_count = NULL;
+
+static buffer_queue_t out_empty_queue;
+static buffer_queue_t out_full_queue;
+static buffer_queue_t out_busy_queue;
+static buffer_queue_t in_empty_queue;
+static buffer_queue_t in_full_queue;
+static buffer_queue_t in_busy_queue;
+static int first_record_call = 0;
+
+static left_right_sample_t save_last_samples[64];
+static int read_codec_file(int addr)
+{
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ mdelay(1);
+ return(__icdc_get_value());
+}
+
+static void printk_codec_files(void)
+{
+ int cnt;
+
+ printk("\n");
+
+ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR);
+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR);
+ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR);
+ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR);
+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR);
+ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR);
+ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR);
+ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA);
+
+ for (cnt = 0; cnt <= 27 ; cnt++) {
+ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt));
+ }
+ printk("\n");
+}
+
+static void write_codec_file(int addr, int val)
+{
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ __icdc_set_cmd(val); /* write */
+ mdelay(1);
+ __icdc_set_rgwr();
+ mdelay(1);
+}
+
+static int write_codec_file_bit(int addr, int bitval, int mask_bit)
+{
+ int val;
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ mdelay(1);
+ val = __icdc_get_value(); /* read */
+
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ val &= ~(1 << mask_bit);
+ if (bitval == 1)
+ val |= 1 << mask_bit;
+
+ __icdc_set_cmd(val); /* write */
+ mdelay(1);
+ __icdc_set_rgwr();
+ mdelay(1);
+
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ val = __icdc_get_value(); /* read */
+
+ if (((val >> mask_bit) & bitval) == bitval)
+ return 1;
+ else
+ return 0;
+}
+
+/* set Audio data replay */
+static void set_audio_data_replay()
+{
+ /* DAC path */
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ mdelay(10);
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ //mdelay(100);
+ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //mdelay(300);
+}
+
+/* unset Audio data replay */
+static void unset_audio_data_replay(void)
+{
+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ //mdelay(800);
+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ //mdelay(800);
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 4);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/* set Record MIC input audio without playback */
+static void set_record_mic_input_audio_without_playback(void)
+{
+ /* ADC path for MIC IN */
+ jz_mic_only = 1;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ mdelay(10);
+ write_codec_file_bit(1, 1, 2);
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+
+ write_codec_file(22, 0x40);//mic 1
+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ //write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file(1, 0x4);
+}
+
+/* unset Record MIC input audio without playback */
+static void unset_record_mic_input_audio_without_playback(void)
+{
+ /* ADC path for MIC IN */
+ jz_mic_only = 0;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/* set Record LINE input audio without playback */
+static void set_record_line_input_audio_without_playback(void)
+{
+ /* ADC path for LINE IN */
+ jz_mic_only = 1;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+ write_codec_file(22, 0xf6);//line in 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1
+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ mdelay(10);
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file(1, 0x4);
+}
+
+/* unset Record LINE input audio without playback */
+static void unset_record_line_input_audio_without_playback(void)
+{
+ /* ADC path for LINE IN */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1
+
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/* set Playback LINE input audio direct only */
+static void set_playback_line_input_audio_direct_only()
+{
+ jz_audio_reset();//or init_codec()
+ REG_AIC_I2SCR = 0x10;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+ write_codec_file(22, 0xf6);//line in 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ mdelay(10);
+ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1
+ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1
+}
+
+/* unset Playback LINE input audio direct only */
+static void unset_playback_line_input_audio_direct_only()
+{
+ write_codec_file_bit(6, 0, 3);//GIM->0
+ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ mdelay(100);
+ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/* set Record MIC input audio with direct playback */
+static void set_record_mic_input_audio_with_direct_playback(void)
+{
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ jz_mic_only = 0;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+
+ write_codec_file(22, 0x60);//mic 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ //write_codec_file(1, 0x4);
+}
+
+/* unset Record MIC input audio with direct playback */
+static void unset_record_mic_input_audio_with_direct_playback(void)
+{
+ /* ADC path for MIC IN */
+ jz_mic_only = 0;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/* set Record playing audio mixed with MIC input audio */
+static void set_record_playing_audio_mixed_with_mic_input_audio(void)
+{
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ mdelay(10);
+
+ write_codec_file(22, 0x63);//mic 1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0
+}
+
+/* unset Record playing audio mixed with MIC input audio */
+static void unset_record_playing_audio_mixed_with_mic_input_audio(void)
+{
+ /* ADC path */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 5);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/* set Record MIC input audio with Audio data replay (full duplex) */
+static void set_record_mic_input_audio_with_audio_data_replay(void)
+{
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+}
+
+/* unset Record MIC input audio with Audio data replay (full duplex) */
+static void unset_record_mic_input_audio_with_audio_data_replay(void)
+{
+ /* ADC path */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 5);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+
+/////////
+/* set Record LINE input audio with Audio data replay (full duplex for linein) */
+static void set_record_line_input_audio_with_audio_data_replay(void)
+{
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+
+
+ //jz_mic_only = 1;
+ write_codec_file(22, 0xc6);//line in 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+}
+
+/* unset Record LINE input audio with Audio data replay (full duplex for linein) */
+static void unset_record_line_input_audio_with_audio_data_replay(void)
+{
+ /* ADC path */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 5);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+/////////
+static inline int get_buffer_id(struct buffer_queue_s *q)
+{
+ int r;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&q->lock, flags);
+ if (q->count == 0) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ return -1;
+ }
+ r = *(q->id + 0);
+ for (i=0;i < q->count-1;i++)
+ *(q->id + i) = *(q->id + (i+1));
+ q->count --;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return r;
+}
+
+static inline void put_buffer_id(struct buffer_queue_s *q, int id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ *(q->id + q->count) = id;
+ q->count ++;
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+static inline int elements_in_queue(struct buffer_queue_s *q)
+{
+ int r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ r = q->count;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return r;
+}
+
+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode)
+{
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ jz_audio_dma_tran_count = count / jz_audio_b;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ flags = claim_dma_lock();
+ disable_dma(chan);
+ clear_dma_ff(chan);
+ //set_dma_mode(chan, mode);
+ jz_set_oss_dma(chan, mode, jz_audio_format);
+ set_dma_addr(chan, phyaddr);
+ if (count == 0) {
+ count++;
+ printk("JzSOC DMA controller can't set dma 0 count!\n");
+ }
+ set_dma_count(chan, count);
+ enable_dma(chan);
+ release_dma_lock(flags);
+}
+
+static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id)
+{
+ int id1, id2;
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+ int dma = controller->dma2;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+
+ if(drain_flag == 1)
+ wake_up(&drain_wait_queue);
+ /* for DSP_GETIPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ id1 = get_buffer_id(&in_busy_queue);
+ put_buffer_id(&in_full_queue, id1);
+
+ wake_up(&rx_wait_queue);
+ wake_up(&controller->adc_wait);
+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id2);
+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1);
+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2));
+ audio_start_dma(dma,dev_id,
+ *(in_dma_pbuf + id2),
+ *(in_dma_buf_data_count + id2),
+ DMA_MODE_READ);
+ } else
+ in_busy_queue.count = 0;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id)
+{
+ int id;
+ unsigned long flags;
+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id;
+ int dma = controller->dma1;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+
+ if(pop_dma_flag == 1) {
+ pop_dma_flag = 0;
+ wake_up(&pop_wait_queue);
+ } else {
+ if(drain_flag == 1) {
+ /* Is replay dma buffer over ? */
+ if(elements_in_queue(&out_full_queue) <= 0) {
+ drain_flag = 0;
+ wake_up(&drain_wait_queue);
+ }
+ }
+
+ /* for DSP_GETOPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ if ((id = get_buffer_id(&out_busy_queue)) < 0)
+ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n");
+ put_buffer_id(&out_empty_queue, id);
+ if ((id = get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ last_dma_buffer_id = id;
+ }
+ } else
+ out_busy_queue.count = 0;
+
+ if (elements_in_queue(&out_empty_queue) > 0) {
+ wake_up(&tx_wait_queue);
+ wake_up(&controller->dac_wait);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void jz_i2s_initHw(int set)
+{
+#if defined(CONFIG_MIPS_JZ_URANUS)
+ i2s_clk = 48000000;
+#else
+ i2s_clk = __cpm_get_i2sclk();
+#endif
+ __i2s_disable();
+ if(set)
+ __i2s_reset();
+ schedule_timeout(5);
+ if(each_time_init_codec)
+ each_time_init_codec();
+ __i2s_disable_record();
+ __i2s_disable_replay();
+ __i2s_disable_loopback();
+ __i2s_set_transmit_trigger(4);
+ __i2s_set_receive_trigger(3);
+}
+
+static int Init_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+
+ /* recording */
+ in_empty_queue.count = fragstotal;
+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf)
+ goto all_mem_err;
+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_pbuf)
+ goto all_mem_err;
+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf_data_count)
+ goto all_mem_err;
+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_empty_queue.id)
+ goto all_mem_err;
+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_full_queue.id)
+ goto all_mem_err;
+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_busy_queue.id)
+ goto all_mem_err;
+
+ for (i=0;i < fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+
+ for (i = 0; i < fragstotal; i++) {
+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(in_dma_buf + i) == 0)
+ goto mem_failed_in;
+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i)));
+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
+ }
+
+ /* playing */
+ out_empty_queue.count = fragstotal;
+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_buf)
+ goto all_mem_err;
+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_pbuf)
+ goto all_mem_err;
+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+
+ if (!out_dma_buf_data_count)
+ goto all_mem_err;
+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_empty_queue.id)
+ goto all_mem_err;
+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_full_queue.id)
+ goto all_mem_err;
+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_busy_queue.id)
+ goto all_mem_err;
+ for (i=0;i < fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ /* alloc DMA buffer */
+ for (i = 0; i < fragstotal; i++) {
+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(out_dma_buf + i) == 0) {
+ printk(" can't allocate required DMA(OUT) buffers.\n");
+ goto mem_failed_out;
+ }
+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i)));
+ }
+
+ return 1;
+all_mem_err:
+ printk("error:allocate memory occur error 1!\n");
+ return 0;
+mem_failed_out:
+ printk("error:allocate memory occur error 2!\n");
+ for (i = 0; i < fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ }
+
+ return 0;
+mem_failed_in:
+ printk("error:allocate memory occur error 3!\n");
+ for (i = 0; i < fragstotal; i++) {
+ if(*(in_dma_buf + i))
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ return 0;
+}
+
+static int Free_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+ /* playing */
+ if(out_dma_buf != NULL) {
+ for (i = 0; i < fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ *(out_dma_buf + i) = 0;
+ }
+ kfree(out_dma_buf);
+ out_dma_buf = NULL;
+ }
+ if(out_dma_pbuf) {
+ kfree(out_dma_pbuf);
+ out_dma_pbuf = NULL;
+ }
+ if(out_dma_buf_data_count) {
+ kfree(out_dma_buf_data_count);
+ out_dma_buf_data_count = NULL;
+ }
+ if(out_empty_queue.id) {
+ kfree(out_empty_queue.id);
+ out_empty_queue.id = NULL;
+ }
+ if(out_full_queue.id) {
+ kfree(out_full_queue.id);
+ out_full_queue.id = NULL;
+ }
+ if(out_busy_queue.id) {
+ kfree(out_busy_queue.id);
+ out_busy_queue.id = NULL;
+ }
+ out_empty_queue.count = fragstotal;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+
+ /* recording */
+ if(in_dma_buf) {
+ for (i = 0; i < fragstotal; i++) {
+ if(*(in_dma_buf + i)) {
+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ *(in_dma_buf + i) = 0;
+ }
+ kfree(in_dma_buf);
+ in_dma_buf = NULL;
+ }
+ if(in_dma_pbuf) {
+ kfree(in_dma_pbuf);
+ in_dma_pbuf = NULL;
+ }
+ if(in_dma_buf_data_count) {
+ kfree(in_dma_buf_data_count);
+ in_dma_buf_data_count = NULL;
+ }
+ if(in_empty_queue.id) {
+ kfree(in_empty_queue.id);
+ in_empty_queue.id = NULL;
+ }
+ if(in_full_queue.id) {
+ kfree(in_full_queue.id);
+ in_full_queue.id = NULL;
+ }
+ if(in_busy_queue.id) {
+ kfree(in_busy_queue.id);
+ in_busy_queue.id = NULL;
+ }
+
+ in_empty_queue.count = fragstotal;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+
+ return 1;
+}
+
+static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller)
+{
+ jz_i2s_initHw(0);
+}
+
+static int jz_audio_set_speed(int dev, int rate)
+{
+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */
+ jz_audio_speed = rate;
+ if (rate > 48000)
+ rate = 48000;
+ if (rate < 8000)
+ rate = 8000;
+ jz_audio_rate = rate;
+
+ if(set_codec_speed)
+ set_codec_speed(rate);
+
+ return jz_audio_rate;
+}
+
+
+static int record_fill_1x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long data;
+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char*)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt++;
+ data = *(s++);
+ *(dp ++) = ((data << 16) >> 24) + 0x80;
+ s++; /* skip the other channel */
+ }
+
+ return cnt;
+}
+
+
+static int record_fill_2x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1, d2;
+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char*)dst_start;
+
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+ *(dp ++) = ((d1 << 16) >> 24) + 0x80;
+ d2 = *(s++);
+ *(dp ++) = ((d2 << 16) >> 24) + 0x80;
+ }
+
+ return cnt;
+}
+
+
+static int record_fill_1x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1;
+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt += 2; /* count in byte */
+ d1 = *(s++);
+ *(dp ++) = (d1 << 16) >> 16;
+ s++; /* skip the other channel */
+ }
+
+ return cnt;
+}
+
+
+static int record_fill_2x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned long d1, d2;
+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+ while (count > 0) {
+ count -= 2; /* count in dword */
+ cnt += 4; /* count in byte */
+ d1 = *(s++);
+ d2 = *(s++);
+ if(abnormal_data_count > 0) {
+ d1 = d2 = 0;
+ abnormal_data_count --;
+ }
+ *(dp ++) = (d1 << 16) >> 16;
+ *(dp ++) = (d2 << 16) >> 16;
+ }
+
+ return cnt;
+}
+
+static void replay_fill_1x8_u(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned char data;
+ unsigned long ddata;
+ volatile unsigned char *s = (unsigned char *)src_start;
+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count--;
+ cnt += 1;
+ data = *(s++) - 0x80;
+ ddata = (unsigned long) data << 8;
+ *(dp ++) = ddata;
+ *(dp ++) = ddata;
+
+ /* save last left and right */
+ if(count == 1) {
+ save_last_samples[id].left = ddata;
+ save_last_samples[id].right = ddata;
+ }
+ }
+ cnt = cnt * 2 * jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+
+static void replay_fill_2x8_u(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned char d1;
+ unsigned long dd1;
+ volatile unsigned char *s = (unsigned char *)src_start;
+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count -= 1;
+ cnt += 1 ;
+ d1 = *(s++) - 0x80;
+ dd1 = (unsigned long) d1 << 8;
+ *(dp ++) = dd1;
+ /* save last left */
+ if(count == 2)
+ save_last_samples[id].left = dd1;
+ /* save last right */
+ if(count == 1)
+ save_last_samples[id].right = dd1;
+ }
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+
+static void replay_fill_1x16_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed short d1;
+ signed long l1;
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ count -= 2;
+ cnt += 2 ;
+ d1 = *(s++);
+ l1 = (signed long)d1;
+ *(dp ++) = l1;
+ *(dp ++) = l1;
+
+ /* save last left and right */
+ if(count == 1) {
+ save_last_samples[id].left = l1;
+ save_last_samples[id].right = l1;
+ }
+ }
+ cnt = cnt * 2 * jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+#if 0
+static void replay_fill_2x16_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed short d1;
+ signed long l1;
+ int mute_cnt = 0;
+ signed long tmp1,tmp2;
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+#if defined(CONFIG_I2S_ICDC)
+ volatile signed long *before_dp;
+ int sam_rate = jz_audio_rate / 20;
+
+ tmp1 = tmp2 = 0;
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+
+ l1 = (signed long)d1;
+ l1 >>= codec_volue_shift;
+
+ if(l1 == 0) {
+ mute_cnt ++;
+ if(mute_cnt >= sam_rate) {
+ before_dp = dp - 10;
+ *(before_dp) = (signed long)1;
+ before_dp = dp - 11;
+ *(before_dp) = (signed long)1;
+ mute_cnt = 0;
+ }
+ } else
+ mute_cnt = 0;
+
+ *(dp ++) = l1;
+
+ tmp1 = tmp2;
+ tmp2 = l1;
+ }
+
+ /* save last left */
+ save_last_samples[id].left = tmp1;
+ /* save last right */
+ save_last_samples[id].right = tmp2;
+#endif
+#if defined(CONFIG_I2S_DLV)
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+
+ l1 = (signed long)d1;
+
+ *(dp ++) = l1;
+ }
+#endif
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+}
+#else
+static void replay_fill_2x16_s(signed long src_start, int count, int id)
+{
+ int cnt = 0;
+ signed short d1;
+ signed long l1;
+ int mute_cnt = 0;
+ signed long tmp1,tmp2;
+
+#if 0
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed short *dp = (signed short*)(*(out_dma_buf + id));
+ memcpy((char*)dp, (char*)s, count);
+ *(out_dma_buf_data_count + id) = count;
+#else
+ volatile signed short *s = (signed short *)src_start;
+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id));
+ while (count > 0) {
+ count -= 2;
+ cnt += 2;
+ d1 = *(s++);
+
+ l1 = (signed long)d1;
+
+ *(dp ++) = l1;
+ }
+ cnt *= jz_audio_b;
+ *(out_dma_buf_data_count + id) = cnt;
+#endif
+}
+#endif
+
+
+static unsigned int jz_audio_set_format(int dev, unsigned int fmt)
+{
+ switch (fmt) {
+ case AFMT_U8:
+ __i2s_set_oss_sample_size(8);
+ __i2s_set_iss_sample_size(8);
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+ break;
+ case AFMT_S16_LE:
+#if defined(CONFIG_I2S_DLV)
+ /* DAC path and ADC path */
+ write_codec_file(2, 0x00);
+ //write_codec_file(2, 0x60);
+#endif
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format,jz_audio_channels);
+ /* print all files */
+ __i2s_set_oss_sample_size(16);
+ __i2s_set_iss_sample_size(16);
+ break;
+
+ case AFMT_QUERY:
+ break;
+ }
+
+ return jz_audio_format;
+}
+
+
+static short jz_audio_set_channels(int dev, short channels)
+{
+ switch (channels) {
+ case 1:
+ if(set_codec_some_func)
+ set_codec_some_func();
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono
+#endif
+ break;
+ case 2:
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo
+#endif
+ break;
+ case 0:
+ break;
+ }
+
+ return jz_audio_channels;
+}
+
+static void init_codec(void)
+{
+ /* inititalize internal I2S codec */
+ if(init_codec_pin)
+ init_codec_pin();
+
+#if defined(CONFIG_I2S_ICDC)
+ /* initialize AIC but not reset it */
+ jz_i2s_initHw(0);
+#endif
+ if(reset_codec)
+ reset_codec();
+}
+
+static void jz_audio_reset(void)
+{
+ __i2s_disable_replay();
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+ __i2s_disable_transmit_dma();
+#if defined(CONFIG_I2S_DLV)
+ REG_AIC_I2SCR = 0x10;
+#endif
+ init_codec();
+}
+
+static int jz_audio_release(struct inode *inode, struct file *file);
+static int jz_audio_open(struct inode *inode, struct file *file);
+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg);
+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait);
+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos);
+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos);
+
+/* static struct file_operations jz_i2s_audio_fops */
+static struct file_operations jz_i2s_audio_fops =
+{
+ owner: THIS_MODULE,
+ open: jz_audio_open,
+ release: jz_audio_release,
+ write: jz_audio_write,
+ read: jz_audio_read,
+ poll: jz_audio_poll,
+ ioctl: jz_audio_ioctl
+};
+
+static int jz_i2s_open_mixdev(struct inode *inode, struct file *file)
+{
+ int i;
+ int minor = MINOR(inode->i_rdev);
+ struct jz_i2s_controller_info *controller = i2s_controller;
+
+ for (i = 0; i < NR_I2S; i++)
+ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor)
+ goto match;
+
+ if (!controller)
+ return -ENODEV;
+match:
+ file->private_data = controller->i2s_codec[i];
+
+ return 0;
+}
+
+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data;
+ return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static struct file_operations jz_i2s_mixer_fops =
+{
+ owner: THIS_MODULE,
+ llseek: jz_i2s_llseek,
+ ioctl: jz_i2s_ioctl_mixdev,
+ open: jz_i2s_open_mixdev,
+};
+
+static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ long val = 0;
+ switch (cmd) {
+ case SOUND_MIXER_INFO:
+
+ if(codec_mixer_info_id_name)
+ codec_mixer_info_id_name();
+ info.modify_counter = audio_mix_modcnt;
+
+ return copy_to_user((void *)arg, &info, sizeof(info));
+ case SOUND_OLD_MIXER_INFO:
+
+ if(codec_mixer_old_info_id_name)
+ codec_mixer_old_info_id_name();
+
+ return copy_to_user((void *)arg, &old_info, sizeof(info));
+ case SOUND_MIXER_READ_STEREODEVS:
+
+ return put_user(0, (long *) arg);
+ case SOUND_MIXER_READ_CAPS:
+
+ val = SOUND_CAP_EXCL_INPUT;
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_READ_DEVMASK:
+ break;
+ case SOUND_MIXER_READ_RECMASK:
+ break;
+ case SOUND_MIXER_READ_RECSRC:
+ break;
+ case SOUND_MIXER_WRITE_SPEAKER:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ switch(val) {
+ case 100:
+ if(set_codec_direct_mode)
+ set_codec_direct_mode();
+ break;
+ case 0:
+ if(clear_codec_direct_mode)
+ clear_codec_direct_mode();
+ break;
+ }
+ break;
+ case SOUND_MIXER_WRITE_BASS:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ codec_bass_gain = val;
+ if(set_codec_bass)
+ set_codec_bass(val);
+
+ return 0;
+ case SOUND_MIXER_READ_BASS:
+
+ val = codec_bass_gain;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_WRITE_VOLUME:
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ if (val > 31)
+ val = 31;
+ jz_audio_volume = val;
+
+ if(set_codec_volume)
+ set_codec_volume(val);
+ return 0;
+ case SOUND_MIXER_READ_VOLUME:
+
+ val = jz_audio_volume;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_WRITE_MIC:
+
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ codec_mic_gain = val;
+ if(set_codec_mic)
+ set_codec_mic(val);
+
+ return 0;
+ case SOUND_MIXER_READ_MIC:
+
+ val = codec_mic_gain;
+ ret = val << 8;
+ val = val | ret;
+
+ return put_user(val, (long *) arg);
+ default:
+ return -ENOSYS;
+ }
+ audio_mix_modcnt ++;
+ return 0;
+}
+
+
+int i2s_probe_codec(struct i2s_codec *codec)
+{
+ /* generic OSS to I2S wrapper */
+ codec->mixer_ioctl = i2s_mixer_ioctl;
+ return 1;
+}
+
+
+/* I2S codec initialisation. */
+static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller)
+{
+ int num_i2s = 0;
+ struct i2s_codec *codec;
+
+ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) {
+ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset(codec, 0, sizeof(struct i2s_codec));
+ codec->private_data = controller;
+ codec->id = num_i2s;
+
+ if (i2s_probe_codec(codec) == 0)
+ break;
+ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) {
+ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n");
+ kfree(codec);
+ break;
+ }
+ controller->i2s_codec[num_i2s] = codec;
+ }
+ return num_i2s;
+}
+
+
+static void jz_update_filler(int format, int channels)
+{
+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
+
+ switch (TYPE(format, channels))
+ {
+
+ case TYPE(AFMT_U8, 1):
+ jz_audio_b = 4; /* 4bytes * 8bits =32bits */
+ replay_filler = replay_fill_1x8_u;
+ record_filler = record_fill_1x8_u;
+ break;
+ case TYPE(AFMT_U8, 2):
+ jz_audio_b = 4;
+ replay_filler = replay_fill_2x8_u;
+ record_filler = record_fill_2x8_u;
+ break;
+ case TYPE(AFMT_S16_LE, 1):
+ jz_audio_b = 2; /* 2bytes * 16bits =32bits */
+ replay_filler = replay_fill_1x16_s;
+ record_filler = record_fill_1x16_s;
+ break;
+ case TYPE(AFMT_S16_LE, 2):
+ jz_audio_b = 2;
+ replay_filler = replay_fill_2x16_s;
+ record_filler = record_fill_2x16_s;
+ break;
+ default:
+ ;
+ }
+}
+
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry *proc_jz_root;
+int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ return 0;
+}
+
+static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller)
+{
+ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0]))
+ return -EIO;
+ return 0;
+}
+
+static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller)
+{
+}
+#endif
+
+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller)
+{
+ char *name;
+ int adev; /* No of Audio device. */
+
+ name = controller->name;
+ /* initialize AIC controller and reset it */
+ jz_i2s_initHw(1);
+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1);
+ if (adev < 0)
+ goto audio_failed;
+ /* initialize I2S codec and register /dev/mixer */
+ if (jz_i2s_codec_init(controller) <= 0)
+ goto mixer_failed;
+
+#ifdef CONFIG_PROC_FS
+ if (jz_i2s_init_proc(controller) < 0) {
+ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name);
+ goto proc_failed;
+ }
+#endif
+
+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8);
+ if (!controller->tmp1) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp1_failed;
+ }
+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8);
+ if (!controller->tmp2) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp2_failed;
+ }
+ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name);
+ goto dma2_failed;
+ }
+ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name);
+ goto dma1_failed;
+ }
+ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2));
+
+ controller->dev_audio = adev;
+ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8);
+ if(!pop_turn_onoff_buf)
+ printk("pop_turn_onoff_buf alloc is wrong!\n");
+ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf);
+
+ return;
+dma2_failed:
+ jz_free_dma(controller->dma1);
+dma1_failed:
+ free_pages((unsigned long)controller->tmp2, 8);
+tmp2_failed:
+ free_pages((unsigned long)controller->tmp1, 8);
+tmp1_failed:
+
+#ifdef CONFIG_PROC_FS
+ jz_i2s_cleanup_proc(controller);
+#endif
+proc_failed:
+ /* unregister mixer dev */
+mixer_failed:
+ unregister_sound_dsp(adev);
+audio_failed:
+ return;
+}
+
+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller)
+{
+ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info),
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n");
+ return -ENOMEM;
+ }
+ (*controller)->name = "Jz I2S controller";
+ (*controller)->opened1 = 0;
+ (*controller)->opened2 = 0;
+ init_waitqueue_head(&(*controller)->adc_wait);
+ init_waitqueue_head(&(*controller)->dac_wait);
+ spin_lock_init(&(*controller)->lock);
+ init_waitqueue_head(&rx_wait_queue);
+ init_waitqueue_head(&tx_wait_queue);
+ init_waitqueue_head(&pop_wait_queue);
+ init_waitqueue_head(&drain_wait_queue);
+
+ return 0;
+}
+
+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller)
+{
+ int adev = controller->dev_audio;
+
+ jz_i2s_full_reset(controller);
+ controller->dev_audio = -1;
+ if (old_mksound)
+ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */
+
+#ifdef CONFIG_PROC_FS
+ jz_i2s_cleanup_proc(controller);
+#endif
+
+ jz_free_dma(controller->dma1);
+ jz_free_dma(controller->dma2);
+ free_pages((unsigned long)controller->tmp1, 8);
+ free_pages((unsigned long)controller->tmp2, 8);
+ free_pages((unsigned long)pop_turn_onoff_buf, 8);
+
+ if (adev >= 0) {
+ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */
+ unregister_sound_dsp(controller->dev_audio);
+ }
+}
+
+#ifdef CONFIG_PM
+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state)
+{
+ if(i2s_suspend_codec)
+ i2s_suspend_codec(controller->opened1,controller->opened2);
+ printk("Aic and codec are suspended!\n");
+ return 0;
+}
+
+static int jz_i2s_resume(struct jz_i2s_controller_info *controller)
+{
+ if(i2s_resume_codec)
+ i2s_resume_codec();
+
+#if defined(CONFIG_I2S_AK4642EN)
+ jz_i2s_initHw(0);
+ jz_audio_reset();
+ __i2s_enable();
+ jz_audio_set_speed(controller->dev_audio,jz_audio_speed);
+ /* playing */
+ if(controller->opened1) {
+ if(set_codec_replay)
+ set_codec_replay();
+ int dma = controller->dma1;
+ int id;
+ unsigned long flags;
+ disable_dma(dma);
+ if(__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if(__dmac_channel_transmit_end_detected(dma))
+ __dmac_channel_clear_transmit_end(dma);
+
+ /* for DSP_GETOPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ while((id = get_buffer_id(&out_busy_queue)) >= 0)
+ put_buffer_id(&out_empty_queue, id);
+
+ out_busy_queue.count=0;
+ if((id = get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_empty_queue, id);
+ }
+ if (elements_in_queue(&out_empty_queue) > 0) {
+ wake_up(&tx_wait_queue);
+ wake_up(&controller->dac_wait);
+ } else
+ printk("pm out_empty_queue empty");
+ }
+
+ /* recording */
+ if(controller->opened2) {
+ if(set_codec_record)
+ set_codec_record();
+ int dma = controller->dma2;
+ int id1, id2;
+ unsigned long flags;
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+ }
+ /* for DSP_GETIPTR */
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ id1 = get_buffer_id(&in_busy_queue);
+ put_buffer_id(&in_full_queue, id1);
+ wake_up(&rx_wait_queue);
+ wake_up(&controller->adc_wait);
+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_full_queue, id2);
+ }
+ in_busy_queue.count = 0;
+ }
+#endif
+
+ return 0;
+}
+
+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
+{
+ int ret;
+ struct jz_i2s_controller_info *controller = pm_dev->data;
+
+ if (!controller) return -EINVAL;
+
+ switch (req) {
+ case PM_SUSPEND:
+ ret = jz_i2s_suspend(controller, (int)data);
+ break;
+ case PM_RESUME:
+ ret = jz_i2s_resume(controller);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+#endif /* CONFIG_PM */
+static irqreturn_t aic_codec_irq(int irq, void *dev_id)
+{
+ u8 file_9 = read_codec_file(9);
+ u8 file_8 = read_codec_file(8);
+
+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9);
+ if ((file_9 & 0x1f) == 0x10) {
+
+ write_codec_file(8, 0x3f);
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ mdelay(300);
+ while ((read_codec_file(9) & 0x4) != 0x4);
+ while ((read_codec_file(9) & 0x10) == 0x10) {
+ write_codec_file(9, 0x10);
+ }
+ write_codec_file_bit(5, 0, 6);//SB_OUT->0
+ mdelay(300);
+ while ((read_codec_file(9) & 0x8) != 0x8);
+ write_codec_file(9, file_9);
+ write_codec_file(8, file_8);
+
+ return IRQ_HANDLED;
+ }
+
+ if (file_9 & 0x8)
+ ramp_up_end = jiffies;
+ else if (file_9 & 0x4)
+ ramp_down_end = jiffies;
+ else if (file_9 & 0x2)
+ gain_up_end = jiffies;
+ else if (file_9 & 0x1)
+ gain_down_end = jiffies;
+
+ write_codec_file(9, file_9);
+ if (file_9 & 0xf)
+ wake_up(&pop_wait_queue);
+ while (REG_ICDC_RGDATA & 0x100);
+
+ return IRQ_HANDLED;
+}
+
+static int __init init_jz_i2s(void)
+{
+ int errno, retval;
+#if defined(CONFIG_I2S_DLV)
+
+ ramp_up_start = 0;
+ ramp_up_end = 0;
+ gain_up_start = 0;
+ gain_up_end = 0;
+ ramp_down_start = 0;
+ ramp_down_end = 0;
+ gain_down_start = 0;
+ gain_down_end = 0;
+#endif
+
+ abnormal_data_count = 0;
+ if(set_codec_mode)
+ set_codec_mode();
+
+ drain_flag = 0;
+ if ((errno = probe_jz_i2s(&i2s_controller)) < 0)
+ return errno;
+ if(set_codec_gpio_pin)
+ set_codec_gpio_pin();
+
+ attach_jz_i2s(i2s_controller);
+ if(set_codec_startup_param)
+ set_codec_startup_param();
+#if defined(CONFIG_I2S_DLV)
+ jz_codec_config = 0;
+ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL);
+ if (retval) {
+ printk("Could not get aic codec irq %d\n", IRQ_AIC);
+ return retval;
+ }
+#endif
+ if(set_codec_volume_table)
+ set_codec_volume_table();
+
+ out_empty_queue.id = NULL;
+ out_full_queue.id = NULL;
+ out_busy_queue.id = NULL;
+ in_empty_queue.id = NULL;
+ in_full_queue.id = NULL;
+ in_busy_queue.id = NULL;
+
+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE;
+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ;
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+
+#ifdef CONFIG_PM
+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN,
+ jz_i2s_pm_callback);
+ if (i2s_controller->pm)
+ i2s_controller->pm->data = i2s_controller;
+#endif
+
+#if defined(CONFIG_I2S_DLV)
+ __cpm_start_idct();
+ __cpm_start_db();
+ __cpm_start_me();
+ __cpm_start_mc();
+ __cpm_start_ipu();
+#endif
+
+ printk("JZ I2S OSS audio driver initialized\n");
+
+ return 0;
+}
+
+static void __exit cleanup_jz_i2s(void)
+{
+#ifdef CONFIG_PM
+ /* pm_unregister(i2s_controller->pm); */
+#endif
+#if defined(CONFIG_I2S_DLV)
+ free_irq(IRQ_AIC, NULL);
+#endif
+ unload_jz_i2s(i2s_controller);
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ if(clear_codec_mode)
+ clear_codec_mode();
+}
+
+module_init(init_jz_i2s);
+module_exit(cleanup_jz_i2s);
+
+#if defined(CONFIG_SOC_JZ4730)
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count,con;
+
+ if(elements_in_queue(&in_busy_queue) > 0) {
+ if (nonblock)
+ return -EBUSY;
+ drain_flag = 1;
+ sleep_on(&drain_wait_queue);
+ drain_flag = 0;
+ } else {
+ add_wait_queue(&ctrl->adc_wait, &wait);
+ for (con = 0; con < 1000; con ++) {
+ udelay(1);
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ if (nonblock) {
+ remove_wait_queue(&ctrl->adc_wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ remove_wait_queue(&ctrl->adc_wait, &wait);
+ current->state = TASK_RUNNING;
+ }
+ return 0;
+}
+
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count;
+
+ if(elements_in_queue(&out_full_queue) > 0) {
+ if (nonblock)
+ return -EBUSY;
+
+ drain_flag = 1;
+ sleep_on(&drain_wait_queue);
+ drain_flag = 0;
+ } else {
+ add_wait_queue(&(ctrl->dac_wait), &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if(elements_in_queue(&out_full_queue) <= 0) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if(count <= 0)
+ break;
+ }
+ if (nonblock) {
+ remove_wait_queue(&ctrl->dac_wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ remove_wait_queue(&ctrl->dac_wait, &wait);
+ current->state = TASK_RUNNING;
+ }
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SOC_JZ4750)
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ //DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count,i=0;
+
+ //add_wait_queue(&ctrl->adc_wait, &wait);
+ for (;;) {
+ if (i < MAXDELAY) {
+ udelay(10);
+ i++;
+ } else
+ break;
+ //set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&ctrl->lock, flags);
+ //spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ //spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+
+ /*if (signal_pending(current))
+ break;*/
+ if (nonblock) {
+ //remove_wait_queue(&ctrl->adc_wait, &wait);
+ //current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ }
+ //remove_wait_queue(&ctrl->adc_wait, &wait);
+ //current->state = TASK_RUNNING;
+ /*if (signal_pending(current))
+ return -ERESTARTSYS;*/
+ return 0;
+}
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ unsigned long flags;
+ int count,ele,busyele,emptyele,i=0;
+
+ for (;;) {
+ if(!nonblock) {//blocked
+ if (i < MAXDELAY) {
+ udelay(10);
+ i++;
+ } else
+ break;
+
+ ele = elements_in_queue(&out_full_queue);
+ if(ele <= 0) {
+ udelay(200);
+
+ busyele = elements_in_queue(&out_busy_queue);
+ emptyele = elements_in_queue(&out_empty_queue);
+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ }
+ }
+ } else {//non-blocked
+ //mdelay(100);
+ ele = elements_in_queue(&out_full_queue);
+
+ if(ele <= 0) {
+ //mdelay(100);
+ busyele = elements_in_queue(&out_busy_queue);
+ emptyele = elements_in_queue(&out_empty_queue);
+
+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) {
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SOC_JZ4740)
+#define MAXDELAY 50000
+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ int count,ele,i=0;
+
+ for (;;) {
+ if(!nonblock) {//blocked
+ if ( i < MAXDELAY ) {
+ udelay(10);
+ i++;
+ } else
+ break;
+
+ ele = elements_in_queue(&out_full_queue);
+ if(ele <= 0) {
+ udelay(10);
+ spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+ }
+ } else {//non-blocked
+ mdelay(100);
+ ele = elements_in_queue(&out_full_queue);
+
+ if(ele <= 0) {
+ mdelay(100);
+
+ spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock)
+{
+ int count,i=0;
+
+ for (;;) {
+ if ( i < MAXDELAY )
+ {
+ udelay(10);
+ i++;
+ }
+ else
+ break;
+ spin_lock(&ctrl->lock);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock(&ctrl->lock);
+ if (count <= 0)
+ break;
+
+ if (nonblock) {
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static int jz_audio_release(struct inode *inode, struct file *file)
+{
+ unsigned long flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ unsigned long tfl;
+
+ if (controller == NULL)
+ return -ENODEV;
+
+ pop_dma_flag = 0;
+ if (controller->opened1 == 1) {
+ controller->opened1 = 0;
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+ drain_dac(controller, file->f_flags & O_NONBLOCK);
+ /* add some mute to anti-pop */
+#if defined(CONFIG_I2S_DLV)
+ /* wait for fifo empty */
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ gain_down_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //gain_down_end = jiffies;
+ while (1) {
+ tfl = REG_AIC_SR & 0x00003f00;
+ if (tfl == 0) {
+ udelay(500);
+ break;
+ }
+ mdelay(2);
+ }
+#endif
+ disable_dma(controller->dma1);
+ set_dma_count(controller->dma1, 0);
+ __i2s_disable_transmit_dma();
+ __i2s_disable_replay();
+ __aic_flush_fifo();
+ if(clear_codec_replay)
+ clear_codec_replay();
+ __aic_flush_fifo();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ ramp_down_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //ramp_down_end = jiffies;
+ unset_audio_data_replay();
+#endif
+ __i2s_disable();
+ if(turn_off_codec)
+ turn_off_codec();
+ }
+
+ if (controller->opened2 == 1) {
+ controller->opened2 = 0;
+ first_record_call = 1;
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ drain_adc(controller, file->f_flags & O_NONBLOCK);
+ disable_dma(controller->dma2);
+ set_dma_count(controller->dma2, 0);
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+
+ if(clear_codec_record)
+ clear_codec_record();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ __i2s_disable();
+ if(turn_off_codec)
+ turn_off_codec();
+ abnormal_data_count = 0;
+ }
+
+#if defined(CONFIG_I2S_DLV)
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+#endif
+ return 0;
+}
+
+static int jz_audio_open(struct inode *inode, struct file *file)
+{
+ int i;
+ struct jz_i2s_controller_info *controller = i2s_controller;
+
+ if (controller == NULL)
+ return -ENODEV;
+
+ mdelay(2);
+ REG_DMAC_DMACKE(0) = 0x3f;
+ pop_dma_flag = 0;
+ if (controller->opened1 == 1 || controller->opened2 == 1 ) {
+ printk("\naudio is busy!\n");
+ return -EBUSY;
+ }
+ jz_codec_config = 0;
+
+ ramp_up_start = 0;
+ ramp_up_end = 0;
+ gain_up_start = 0;
+ gain_up_end = 0;
+ ramp_down_start = 0;
+ ramp_down_end = 0;
+ gain_down_start = 0;
+ gain_down_end = 0;
+ if (file->f_mode & FMODE_WRITE) {
+ if (controller->opened1 == 1)
+ return -EBUSY;
+
+ controller->opened1 = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+
+ for(i=0;i < 64;i++) {
+ save_last_samples[i].left = 0;
+ save_last_samples[i].right = 0;
+ }
+
+ out_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ last_dma_buffer_id = 0;
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ if (controller->opened2 == 1)
+ return -EBUSY;
+
+ controller->opened2 = 1;
+ first_record_call = 1;
+ /* for ioctl */
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+
+ in_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+ }
+
+ file->private_data = controller;
+ jz_audio_reset();
+ REG_AIC_FR |= (1 << 6);
+
+ if (file->f_mode & FMODE_WRITE) {
+ if(set_codec_replay)
+ set_codec_replay();
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ abnormal_data_count = 0;
+ if(set_codec_record)
+ set_codec_record();
+ }
+
+#if defined(CONFIG_I2S_DLV)
+ __aic_reset();
+
+ mdelay(10);
+ REG_AIC_I2SCR = 0x10;
+ mdelay(20);
+ __aic_flush_fifo();
+#endif
+
+ __i2s_enable();
+
+#if defined(CONFIG_I2S_DLV)
+ if (file->f_mode & FMODE_WRITE) {
+
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ ramp_up_start = jiffies;
+ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_RCR = 0x1;
+ while (!(REG_RTC_RCR & RTC_RCR_WRDY));
+ REG_RTC_RGR = 1;*/
+ sleep_on(&pop_wait_queue);
+ //ramp_up_end = jiffies;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ } else if (file->f_mode & FMODE_READ) {
+ if (jz_mic_only)
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ else
+ write_codec_file_bit(5, 0, 7);//SB_DAC->0
+ mdelay(500);
+ }
+
+#endif
+
+ return 0;
+}
+
+
+static int jz_audio_ioctl(struct inode *inode, struct file *file,
+unsigned int cmd, unsigned long arg)
+{
+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize;
+ unsigned int flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ count_info cinfo;
+ audio_buf_info abinfo;
+ int id, i;
+
+ val = 0;
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *)arg);
+ case SNDCTL_DSP_RESET:
+#if 0
+ jz_audio_reset();
+ __i2s_disable_replay();
+ __i2s_disable_receive_dma();
+ __i2s_disable_record();
+ __i2s_disable_transmit_dma();
+#endif
+ return 0;
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ return drain_dac(controller, file->f_flags & O_NONBLOCK);
+ return 0;
+ case SNDCTL_DSP_SPEED:
+ /* set smaple rate */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val >= 0)
+ jz_audio_set_speed(controller->dev_audio, val);
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_STEREO:
+ /* set stereo or mono channel */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1);
+
+ return 0;
+ case SNDCTL_DSP_GETBLKSIZE:
+ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg);
+ return put_user(jz_audio_fragsize, (int *)arg);
+ case SNDCTL_DSP_GETFMTS:
+ /* Returns a mask of supported sample format*/
+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg);
+ case SNDCTL_DSP_SETFMT:
+ /* Select sample format */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val != AFMT_QUERY)
+ jz_audio_set_format(controller->dev_audio,val);
+ else {
+ if (file->f_mode & FMODE_READ)
+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+ else
+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+ }
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_CHANNELS:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ jz_audio_set_channels(controller->dev_audio, val);
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_POST:
+ /* FIXME: the same as RESET ?? */
+ return 0;
+ case SNDCTL_DSP_SUBDIVIDE:
+ return 0;
+ case SNDCTL_DSP_SETFRAGMENT:
+ get_user(val, (long *) arg);
+ newfragsize = 1 << (val & 0xFFFF);
+ if (newfragsize < 4 * PAGE_SIZE)
+ newfragsize = 4 * PAGE_SIZE;
+ if (newfragsize > (16 * PAGE_SIZE))
+ newfragsize = 16 * PAGE_SIZE;
+
+ newfragstotal = (val >> 16) & 0x7FFF;
+ if (newfragstotal < 2)
+ newfragstotal = 2;
+ if (newfragstotal > 32)
+ newfragstotal = 32;
+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize))
+ return 0;
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ mdelay(500);
+ jz_audio_fragstotal = newfragstotal;
+ jz_audio_fragsize = newfragsize;
+
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ mdelay(10);
+
+ return 0;
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg);
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+ case SNDCTL_DSP_SETDUPLEX:
+ return -EINVAL;
+ case SNDCTL_DSP_GETOSPACE:
+ {
+ int i, bytes = 0;
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ jz_audio_fragments = elements_in_queue(&out_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+
+ if (jz_audio_channels == 2)
+ bytes /= jz_audio_b;
+ else if (jz_audio_channels == 1)
+ bytes /= 4;
+ else
+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n");
+
+
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ /* unused fragment amount */
+ abinfo.fragments = jz_audio_fragments;
+ /* amount of fragments */
+ abinfo.fragstotal = jz_audio_fragstotal;
+ /* fragment size in bytes */
+ if (jz_audio_channels == 2)
+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b;
+ else if (jz_audio_channels == 1)
+ abinfo.fragsize = jz_audio_fragsize / 4;
+ else
+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n");
+
+ /* write size count without blocking in bytes */
+ abinfo.bytes = bytes;
+
+ return copy_to_user((void *)arg, &abinfo,
+ sizeof(abinfo)) ? -EFAULT : 0;
+ }
+ case SNDCTL_DSP_GETISPACE:
+ {
+ int i, bytes = 0;
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ jz_audio_fragments = elements_in_queue(&in_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+
+ if (jz_audio_channels == 2)
+ bytes /= jz_audio_b;
+ else if (jz_audio_channels == 1)
+ bytes /= 4;
+ else
+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n");
+
+ abinfo.fragments = jz_audio_fragments;
+ abinfo.fragstotal = jz_audio_fragstotal;
+
+ if (jz_audio_channels == 2)
+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b;
+ else if (jz_audio_channels == 1)
+ abinfo.fragsize = jz_audio_fragsize / 4;
+ else
+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n");
+
+ abinfo.bytes = bytes;
+
+ return copy_to_user((void *)arg, &abinfo,
+ sizeof(abinfo)) ? -EFAULT : 0;
+ }
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && in_dma_buf)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && out_dma_buf)
+ val |= PCM_ENABLE_OUTPUT;
+
+ return put_user(val, (int *)arg);
+ case SNDCTL_DSP_SETTRIGGER:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ return 0;
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextIn;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextOut;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ unfinish = 0;
+ fullc = elements_in_queue(&out_full_queue);
+ busyc = elements_in_queue(&out_busy_queue);
+ for(i = 0;i < fullc ;i ++) {
+ id = *(out_full_queue.id + i);
+ unfinish += *(out_dma_buf_data_count + id);
+ }
+ for(i = 0;i < busyc ;i ++) {
+ id = *(out_busy_queue.id + i);
+ unfinish += get_dma_residue(controller->dma1);
+ }
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ if (jz_audio_channels == 2)
+ unfinish /= jz_audio_b;
+ else if (jz_audio_channels == 1)
+ unfinish /= 4;
+ else
+ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n");
+
+ return put_user(unfinish, (int *) arg);
+ case SOUND_PCM_READ_RATE:
+ return put_user(jz_audio_rate, (int *)arg);
+ case SOUND_PCM_READ_CHANNELS:
+ return put_user(jz_audio_channels, (int *)arg);
+ case SOUND_PCM_READ_BITS:
+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg);
+ case SNDCTL_DSP_MAPINBUF:
+ case SNDCTL_DSP_MAPOUTBUF:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_WRITE_FILTER:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+
+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait)
+{
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ return POLLOUT | POLLWRNORM;
+
+ poll_wait(file, &controller->dac_wait, wait);
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ return POLLIN | POLLRDNORM;
+
+ poll_wait(file, &controller->adc_wait, wait);
+ }
+
+ spin_lock_irqsave(&controller->lock, flags);
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ mask |= POLLOUT | POLLWRNORM;
+ } else if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ return mask;
+}
+
+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+ int id, ret = 0, left_count, copy_count, cnt = 0;
+ unsigned long flags;
+
+ if (count < 0)
+ return -EINVAL;
+
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextIn = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ copy_count = jz_audio_fragsize / 4;
+
+ left_count = count;
+ if (first_record_call) {
+ first_record_call = 0;
+ audio_read_back_first:
+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ spin_lock(&controller->lock);
+ *(in_dma_buf_data_count + id) = copy_count * 4;
+
+ spin_unlock(&controller->lock);
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id));
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ sleep_on(&rx_wait_queue);
+ } else
+ goto audio_read_back_first;
+ }
+
+ while (left_count > 0) {
+ audio_read_back_second:
+ if (elements_in_queue(&in_full_queue) <= 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ else
+ sleep_on(&rx_wait_queue);
+ }
+
+ if ((id = get_buffer_id(&in_full_queue)) >= 0) {
+ spin_lock(&controller->lock);
+ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id);
+ spin_unlock(&controller->lock);
+ put_buffer_id(&in_empty_queue, id);
+ } else
+ goto audio_read_back_second;
+
+ if (elements_in_queue(&in_busy_queue) == 0) {
+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ spin_lock(&controller->lock);
+ *(in_dma_buf_data_count + id) = copy_count * 4;
+ spin_unlock(&controller->lock);
+
+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id));
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ }
+ }
+ if (ret + cnt > count) {
+ spin_lock(&controller->lock);
+ cnt = count - ret;
+ spin_unlock(&controller->lock);
+ }
+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt))
+ return ret ? ret : -EFAULT;
+
+ spin_lock(&controller->lock);
+ ret += cnt;
+ spin_unlock(&controller->lock);
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextIn += ret;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ spin_lock(&controller->lock);
+ left_count -= cnt;
+ spin_unlock(&controller->lock);
+ }
+ return ret;
+}
+
+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ int id, ret = 0, left_count, copy_count = 0;
+ unsigned int flags;
+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data;
+
+ if (count <= 0)
+ return -EINVAL;
+
+ if(set_replay_hp_or_speaker)
+ set_replay_hp_or_speaker();
+
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ if (jz_audio_channels == 2)
+ copy_count = jz_audio_fragsize / jz_audio_b;
+ else if(jz_audio_channels == 1)
+ copy_count = jz_audio_fragsize / 4;
+ left_count = count;
+ if (copy_from_user(controller->tmp1, buffer, count)) {
+ printk("copy_from_user failed:%d",ret);
+ return ret ? ret : -EFAULT;
+ }
+
+ while (left_count > 0) {
+ audio_write_back:
+ /*if (file->f_flags & O_NONBLOCK)
+ udelay(2);*/
+ if (elements_in_queue(&out_empty_queue) == 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret;
+ else
+ sleep_on(&tx_wait_queue);
+ }
+ /* the end fragment size in this write */
+ if (ret + copy_count > count)
+ copy_count = count - ret;
+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) {
+ replay_filler((signed long)controller->tmp1 + ret, copy_count, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ put_buffer_id(&out_full_queue, id);
+ dma_cache_wback_inv(*(out_dma_buf + id),
+ *(out_dma_buf_data_count + id));
+ } else
+ put_buffer_id(&out_empty_queue, id);
+ } else
+ goto audio_write_back;
+
+ left_count = left_count - copy_count;
+ ret += copy_count;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextOut += ret;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+ if (elements_in_queue(&out_busy_queue) == 0) {
+ if ((id=get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id);
+
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(controller->dma1,
+ file->private_data,
+ *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ last_dma_buffer_id = id;
+ if (jz_codec_config == 0) {
+ write_codec_file_bit(1, 0, 5);
+ gain_up_start = jiffies;
+ sleep_on(&pop_wait_queue);
+ //gain_up_end = jiffies;
+ jz_codec_config = 1;
+ //SB_ADC->1
+ //write_codec_file_bit(5, 1, 4);
+ //while(1);
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+#if defined(CONFIG_I2S_ICODEC)
+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample)
+{
+ int i,step_len;
+ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf;
+ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19;
+ unsigned long l_sample_count,r_sample_count,sample_count;
+ struct jz_i2s_controller_info *controller = i2s_controller;
+ signed int left_sam=0,right_sam=0,l_val,r_val;
+
+ switch (sample_oss) {
+ case 0x0:
+ break;
+ case 0x1:
+ left_sam = (signed int)l_sample;
+ right_sam = (signed int)r_sample;
+ break;
+ case 0x2:
+ break;
+ case 0x3:
+ break;
+ case 0x4:
+ break;
+ }
+
+ if(left_sam == 0 && right_sam == 0)
+ return;
+
+ switch (sample_oss) {
+ case 0x0:
+ break;
+ case 0x1:
+ step_len = jz_audio_speed / 10 * 3;
+ step_len = step_len / 2;
+ step_len = 0x7fff / step_len + 1;
+
+ l_sample_count = 0;
+ l_val = left_sam;
+
+ while(1) {
+ if(l_val > 0) {
+ if(l_val >= step_len) {
+ l_val -= step_len;
+ l_sample_count ++;
+ } else
+ break;
+ }
+
+ if(l_val < 0) {
+ if(l_val <= -step_len) {
+ l_val += step_len;
+ l_sample_count ++;
+ } else
+ break;
+ }
+
+ if(l_val == 0)
+ break;
+ }
+
+ r_sample_count = 0;
+ r_val = right_sam;
+ while(1) {
+ if(r_val > 0) {
+ if(r_val >= step_len) {
+ r_val -= step_len;
+ r_sample_count ++;
+ } else
+ break;
+ }
+
+ if(r_val < 0) {
+ if(r_val <= -step_len) {
+ r_val += step_len;
+ r_sample_count ++;
+ } else
+ break;
+ }
+
+ if(r_val == 0)
+ break;
+ }
+ /* fill up */
+ if(l_sample_count > r_sample_count)
+ sample_count = l_sample_count;
+ else
+ sample_count = r_sample_count;
+
+ l_val = left_sam;
+ r_val = right_sam;
+ for(i=0;i <= sample_count;i++) {
+
+ *pop_buf = (unsigned long)l_val;
+ pop_buf ++;
+
+ if(l_val > step_len)
+ l_val -= step_len;
+ else if(l_val < -step_len)
+ l_val += step_len;
+ else if(l_val >= -step_len && l_val <= step_len)
+ l_val = 0;
+
+ *pop_buf = (unsigned long)r_val;
+ pop_buf ++;
+ if(r_val > step_len)
+ r_val -= step_len;
+ else if(r_val < -step_len)
+ r_val += step_len;
+ else if(r_val >= -step_len && r_val <= step_len)
+ r_val = 0;
+ }
+
+ *pop_buf = 0;
+ pop_buf ++;
+ *pop_buf = 0;
+
+ pop_buf ++;
+ sample_count += 2;
+ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8);
+
+ pop_dma_flag = 1;
+ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE);
+ sleep_on(&pop_wait_queue);
+ pop_dma_flag = 0;
+ break;
+ case 0x2:
+ break;
+ case 0x3:
+ break;
+ case 0x4:
+ break;
+ }
+}
+#endif
diff --git a/sound/oss/jz_pcm_tlv320aic1106_dma.c b/sound/oss/jz_pcm_tlv320aic1106_dma.c
new file mode 100644
index 00000000000..f382955e0f2
--- /dev/null
+++ b/sound/oss/jz_pcm_tlv320aic1106_dma.c
@@ -0,0 +1,1837 @@
+/*
+ * linux/drivers/sound/jz_pcm_tlv320aic1106.c
+ *
+ * JzSOC On-Chip PCM audio driver.
+ *
+ * Copyright (C) 2005 by Ingenic Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Because the normal application of AUDIO devices are focused on Little_endian,
+ * then we only perform the little endian data format in driver.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/proc_fs.h>
+#include <linux/soundcard.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <asm/hardirq.h>
+#include <asm/jzsoc.h>
+#include "sound_config.h"
+
+#define NR_PCM 2
+#define MAXDELAY 50000
+#define JZCODEC_RW_BUFFER_SIZE 4
+#define JZCODEC_RW_BUFFER_TOTAL 3
+#define JZCODEC_USER_BUFFER 6
+
+#define MODE_is_8 0 // 1 is 8 bits, and 0 is 16 bits
+
+static int jz_audio_rate;
+static char jz_audio_format;
+static char jz_audio_volume;
+static char jz_audio_channels;
+static int jz_audio_fragments;//unused fragment amount
+static int jz_audio_fragstotal;
+static int jz_audio_fragsize;
+static int jz_audio_speed;
+static int jz_audio_dma_tran_count;//bytes count of one DMA transfer
+
+static void jz_update_filler(int bits, int channels);
+static int Init_In_Out_queue(int fragstotal,int fragsize);
+static int Free_In_Out_queue(int fragstotal,int fragsize);
+static irqreturn_t jz_pcm_irq(int irqnr, void *ref);
+static irqreturn_t jz_pcm_replay_dma_irq(int irqnr, void *ref);
+static irqreturn_t jz_pcm_record_dma_irq(int irqnr, void *ref);
+static void (*replay_filler)(unsigned long src_start, int count, int id);
+static int (*record_filler)(unsigned long dst_start, int count, int id);
+static void dump_pcmc_reg(void);
+
+static struct file_operations jz_pcm_audio_fops;
+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue);
+
+struct jz_pcm_controller_info {
+ int io_base;
+ int dma1; /* play */
+ int dma2; /* record */
+ char *name;
+ int dev_audio;
+ struct pcm_codec *pcm_codec[NR_PCM];
+ int opened1;
+ int opened2;
+ unsigned char *tmp1; /* tmp buffer for sample conversions */
+ unsigned char *tmp2;
+ spinlock_t lock;
+ spinlock_t ioctllock;
+
+ wait_queue_head_t dac_wait;
+ wait_queue_head_t adc_wait;
+ int nextIn; // byte index to next-in to DMA buffer
+ int nextOut; // byte index to next-out from DMA buffer
+ int count; // current byte count in DMA buffer
+ int finish; // current transfered byte count in DMA buffer
+ unsigned long total_bytes; // total bytes written or read
+ unsigned long blocks;
+ unsigned long error; // over/underrun
+};
+static struct jz_pcm_controller_info *pcm_controller = NULL;
+
+struct pcm_codec {
+ /* PCM controller connected with */
+ void *private_data;
+ char *name;
+ int id;
+ int dev_mixer;
+ /* controller specific lower leverl pcm accessing routines */
+ u16 (*codec_read) (u8 reg);//the function accessing Codec REGs
+ void (*codec_write) (u8 reg, u16 val);
+ /* Wait for codec-ready. Ok to sleep here. */
+ void (*codec_wait) (struct pcm_codec *codec);
+ /* OSS mixer masks */
+ int modcnt;
+ int supported_mixers;
+ int stereo_mixers;
+ int record_sources;
+ int bit_resolution;
+ /* OSS mixer interface */
+ int (*read_mixer) (struct pcm_codec *codec, int oss_channel);
+ void (*write_mixer)(struct pcm_codec *codec, int oss_channel,
+ unsigned int left, unsigned int right);
+ int (*recmask_io) (struct pcm_codec *codec, int rw, int mask);
+ int (*mixer_ioctl)(struct pcm_codec *codec, unsigned int cmd, unsigned long arg);
+ /* saved OSS mixer states */
+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+};
+
+typedef struct buffer_queue_s {
+ int count;
+ int *id;
+ int lock;
+} buffer_queue_t;
+
+static unsigned long *out_dma_buf = NULL;
+static unsigned long *out_dma_pbuf = NULL;
+static unsigned long *out_dma_buf_data_count = NULL;
+static unsigned long *in_dma_buf = NULL;
+static unsigned long *in_dma_pbuf = NULL;
+static unsigned long *in_dma_buf_data_count = NULL;
+
+static buffer_queue_t out_empty_queue;
+static buffer_queue_t out_full_queue;
+static buffer_queue_t out_busy_queue;
+static buffer_queue_t in_empty_queue;
+static buffer_queue_t in_full_queue;
+static buffer_queue_t in_busy_queue;
+static int first_record_call = 0;
+
+static inline int get_buffer_id(struct buffer_queue_s *q)
+{
+ int r, i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ if (q->count == 0) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ return -1;
+ }
+ r = *(q->id + 0);
+ for (i=0;i < q->count-1;i++)
+ *(q->id + i) = *(q->id + (i+1));
+ q->count --;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return r;
+}
+
+static inline void put_buffer_id(struct buffer_queue_s *q, int id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ *(q->id + q->count) = id;
+ q->count ++;
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+static inline int elements_in_queue(struct buffer_queue_s *q)
+{
+ int r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ r = q->count;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return r;
+}
+
+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode)
+{
+ unsigned long flags;
+ struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id;
+
+ //for DSP_GETOPTR
+ //spin_lock_irqsave(&controller->ioctllock, flags);
+ spin_lock(&controller->ioctllock);
+ jz_audio_dma_tran_count = count;
+ //spin_unlock_irqrestore(&controller->ioctllock, flags);
+ spin_unlock(&controller->ioctllock);
+ flags = claim_dma_lock();
+ __dmac_disable_module(0);//!!!!!!!!!
+ disable_dma(chan);
+ clear_dma_ff(chan);
+ set_dma_mode(chan, mode);
+#if MODE_is_8
+ __dmac_channel_set_src_port_width(chan, 8);
+ __dmac_channel_set_dest_port_width(chan, 8);
+ __dmac_channel_set_transfer_unit_8bit(chan);
+#else
+ __dmac_channel_set_src_port_width(chan, 16);
+ __dmac_channel_set_dest_port_width(chan, 16);
+ __dmac_channel_set_transfer_unit_16bit(chan);
+#endif
+
+ set_dma_addr(chan, phyaddr);
+ if (count == 0) {
+ count++;
+ printk("JzSOC DMA controller can't set dma 0 count!\n");
+ }
+
+ set_dma_count(chan, count);
+ enable_dma(chan);
+ __dmac_enable_module(0);
+ release_dma_lock(flags);
+#if 0
+ //for DSP_GETOPTR on FPGA
+ struct jz_dma_chan *tmpchan = &jz_dma_table[1];
+
+ spin_lock(&controller->ioctllock);
+ jz_audio_dma_tran_count = count;
+ spin_unlock(&controller->ioctllock);
+ flags = claim_dma_lock();
+ disable_dma(chan);
+ clear_dma_ff(chan);
+ set_dma_mode(chan, mode);
+#if MODE_is_8
+ __dmac_channel_set_src_port_width(chan, 8);
+ __dmac_channel_set_dest_port_width(chan, 8);
+ __dmac_channel_set_transfer_unit_8bit(chan);
+#else
+ __dmac_channel_set_src_port_width(chan, 16);
+ __dmac_channel_set_dest_port_width(chan, 16);
+ __dmac_channel_set_transfer_unit_16bit(chan);
+#endif
+ set_dma_addr(chan, phyaddr);
+ if (count == 0) {
+ count++;
+ printk("JzSOC DMA controller can't set dma 0 count!\n");
+ }
+ set_dma_count(chan, count);
+ enable_dma(chan);
+ release_dma_lock(flags);
+#if 0
+ __pcm_enable_tfs_intr();
+ __pcm_enable_tur_intr();
+ __pcm_enable_rfs_intr();
+ __pcm_enable_ror_intr();
+#endif
+#endif
+}
+
+static irqreturn_t jz_pcm_record_dma_irq(int irq, void *dev_id)
+{
+ int id1, id2;
+ struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id;
+ int dma = controller->dma2;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+ //for DSP_GETIPTR
+ spin_lock(&controller->ioctllock);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock(&controller->ioctllock);
+ id1 = get_buffer_id(&in_busy_queue);
+ put_buffer_id(&in_full_queue, id1);
+
+ wake_up(&rx_wait_queue);
+ wake_up(&controller->adc_wait);
+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id2);
+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1);
+
+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2));
+ audio_start_dma(dma,dev_id,
+ *(in_dma_pbuf + id2),
+ *(in_dma_buf_data_count + id2),
+ DMA_MODE_READ);
+ } else
+ in_busy_queue.count = 0;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t jz_pcm_irq(int irq, void *dev_id)
+{
+ struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id;
+ printk("pcm interrupt REG_PCM_INTS : 0x%08x\n",REG_PCM_INTS);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t jz_pcm_replay_dma_irq(int irq, void *dev_id)
+{
+ int id;
+ unsigned long flags;
+ struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id;
+ int dma = controller->dma1;
+
+ disable_dma(dma);
+ if (__dmac_channel_address_error_detected(dma)) {
+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__);
+ __dmac_channel_clear_address_error(dma);
+ }
+ if (__dmac_channel_transmit_end_detected(dma)) {
+ __dmac_channel_clear_transmit_end(dma);
+ //for DSP_GETOPTR
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->total_bytes += jz_audio_dma_tran_count;
+ controller->blocks ++;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ if ((id = get_buffer_id(&out_busy_queue)) < 0)
+ printk(KERN_DEBUG "Strange DMA finish interrupt for PCM module\n");
+ put_buffer_id(&out_empty_queue, id);
+ if ((id = get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id); //very busy
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+ }
+ } else
+ out_busy_queue.count = 0;
+
+ if (elements_in_queue(&out_empty_queue) > 0) {
+ wake_up(&tx_wait_queue);
+ wake_up(&controller->dac_wait);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int Init_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+ // recording
+ in_empty_queue.count = fragstotal;
+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf)
+ goto all_mem_err;
+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_pbuf)
+ goto all_mem_err;
+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!in_dma_buf_data_count)
+ goto all_mem_err;
+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_empty_queue.id)
+ goto all_mem_err;
+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_full_queue.id)
+ goto all_mem_err;
+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!in_busy_queue.id)
+ goto all_mem_err;
+
+ for (i=0;i < fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+
+ for (i = 0; i < fragstotal; i++) {
+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(in_dma_buf + i) == 0)
+ goto mem_failed_in;
+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i)));
+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
+ }
+
+ //playing
+ out_empty_queue.count = fragstotal;
+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_buf)
+ goto all_mem_err;
+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+ if (!out_dma_pbuf)
+ goto all_mem_err;
+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL);
+
+ if (!out_dma_buf_data_count)
+ goto all_mem_err;
+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_empty_queue.id)
+ goto all_mem_err;
+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_full_queue.id)
+ goto all_mem_err;
+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL);
+ if (!out_busy_queue.id)
+ goto all_mem_err;
+ for (i=0;i < fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ /*alloc DMA buffer*/
+ for (i = 0; i < fragstotal; i++) {
+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize));
+ if (*(out_dma_buf + i) == 0) {
+ printk(" can't allocate required DMA(OUT) buffers.\n");
+ goto mem_failed_out;
+ }
+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i)));
+ }
+
+ return 1;
+all_mem_err:
+ printk("error:allocate memory occur error 1!\n");
+ return 0;
+mem_failed_out:
+ printk("error:allocate memory occur error 2!\n");
+ for (i = 0; i < fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ }
+
+ return 0;
+mem_failed_in:
+ printk("error:allocate memory occur error 3!\n");
+ for (i = 0; i < fragstotal; i++) {
+ if(*(in_dma_buf + i))
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ return 0;
+}
+
+static int Free_In_Out_queue(int fragstotal,int fragsize)
+{
+ int i;
+ //playing
+ if(out_dma_buf != NULL) {
+ for (i = 0; i < fragstotal; i++) {
+ if(*(out_dma_buf + i))
+ free_pages(*(out_dma_buf + i), get_order(fragsize));
+ *(out_dma_buf + i) = 0; //release page error
+ }
+ kfree(out_dma_buf);
+ out_dma_buf = NULL;
+ }
+ if(out_dma_pbuf) {
+ kfree(out_dma_pbuf);
+ out_dma_pbuf = NULL;
+ }
+ if(out_dma_buf_data_count) {
+ kfree(out_dma_buf_data_count);
+ out_dma_buf_data_count = NULL;
+ }
+ if(out_empty_queue.id) {
+ kfree(out_empty_queue.id);
+ out_empty_queue.id = NULL;
+ }
+ if(out_full_queue.id) {
+ kfree(out_full_queue.id);
+ out_full_queue.id = NULL;
+ }
+ if(out_busy_queue.id) {
+ kfree(out_busy_queue.id);
+ out_busy_queue.id = NULL;
+ }
+ out_empty_queue.count = fragstotal;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+
+ // recording
+ if(in_dma_buf) {
+ for (i = 0; i < fragstotal; i++) {
+ if(*(in_dma_buf + i)) {
+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize);
+ free_pages(*(in_dma_buf + i), get_order(fragsize));
+ }
+ *(in_dma_buf + i) = 0; //release page error
+ }
+ kfree(in_dma_buf);
+ in_dma_buf = NULL;
+ }
+ if(in_dma_pbuf) {
+ kfree(in_dma_pbuf);
+ in_dma_pbuf = NULL;
+ }
+ if(in_dma_buf_data_count) {
+ kfree(in_dma_buf_data_count);
+ in_dma_buf_data_count = NULL;
+ }
+ if(in_empty_queue.id) {
+ kfree(in_empty_queue.id);
+ in_empty_queue.id = NULL;
+ }
+ if(in_full_queue.id) {
+ kfree(in_full_queue.id);
+ in_full_queue.id = NULL;
+ }
+ if(in_busy_queue.id) {
+ kfree(in_busy_queue.id);
+ in_busy_queue.id = NULL;
+ }
+
+ in_empty_queue.count = fragstotal;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+
+ return 1;
+}
+
+static int jz_audio_set_speed(int dev, int rate)
+{
+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 */
+ long codec_speed;
+ long speed = 0;
+
+ jz_audio_speed = rate;
+ if (rate > 48000)
+ rate = 48000;
+ if (rate < 8000)
+ rate = 8000;
+ jz_audio_rate = rate;
+
+ /*switch (rate) {
+ case 8000:
+ speed = 0;
+ break;
+ case 11025:
+ speed = 1;
+ break;
+ case 12000:
+ speed = 2;
+ break;
+ case 16000:
+ speed = 3;
+ break;
+ case 22050:
+ speed = 4;
+ break;
+ case 24000:
+ speed = 5;
+ break;
+ case 32000:
+ speed = 6;
+ break;
+ case 44100:
+ speed = 7;
+ break;
+ case 48000:
+ speed = 8;
+ break;
+ default:
+ break;
+ }
+ printk("set PCMIN or PCMOUT speed.\n");
+ __pcm_set_clk_rate(speed);
+ __pcm_set_sync_rate(256);*/
+
+ return jz_audio_rate;
+}
+
+
+static int record_fill_1x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ volatile unsigned char *s = (unsigned char*)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char*)dst_start;
+
+ while (count > 0) {
+ *dp = *s;
+ dp ++;
+ s++;
+ count --;
+ cnt ++;
+ }
+
+ return cnt;
+}
+
+static int record_fill_2x8_u(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ volatile unsigned char *s = (unsigned char*)(*(in_dma_buf + id));
+ volatile unsigned char *dp = (unsigned char*)dst_start;
+
+#if 1
+ while (count > 0) {
+ *dp = *s;
+ s ++;
+ dp ++;
+ count --;
+ cnt ++;
+ }
+#else
+ while (count > 0) {
+ *dp = *s;
+ s += 2; //skip right sample
+ dp ++;
+ count -= 2;
+ cnt ++;
+ }
+#endif
+ return cnt;
+}
+
+static int record_fill_1x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned short d1;
+ unsigned short *s = (unsigned short*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+
+ while (count > 0) {
+ *dp = *s;
+ s ++;
+ dp ++;
+ count -= 2;
+ cnt += 2;
+ }
+
+ return cnt;
+}
+
+static int record_fill_2x16_s(unsigned long dst_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned short *s = (unsigned short*)(*(in_dma_buf + id));
+ unsigned short *dp = (unsigned short *)dst_start;
+
+#if 1
+ while (count > 0) {
+ *dp = *s;
+ s ++;
+ dp ++;
+ count -= 2;
+ cnt += 2;
+ }
+#else
+ while (count > 0) {
+ *dp = *s;
+ s += 2; //skip right sample
+ dp ++;
+ count -= 4;
+ cnt += 2;/* count in byte */
+ }
+#endif
+
+ return cnt;
+}
+
+static void replay_fill_1x8_u(unsigned long src_start, int count, int id)
+{
+#if 0
+ volatile unsigned char *s = (unsigned char *)src_start;
+ volatile unsigned char *dp = (unsigned char *)(*(out_dma_buf + id));
+
+ *(out_dma_buf_data_count + id) = count;
+ while (count > 0) {
+ *dp = *s;
+ dp ++;
+ s ++;
+ count --;
+ }
+#else
+ volatile u8 *s = (u8 *)src_start;
+ volatile u8 *dp = (u8 *)(*(out_dma_buf + id));
+
+ *(out_dma_buf_data_count + id) = count;
+ while (count > 0) {
+ *dp = *s;
+ dp ++;
+ s ++;
+ count --;
+ }
+#endif
+}
+
+static void replay_fill_2x8_u(unsigned long src_start, int count, int id)
+{
+ volatile unsigned char *s = (unsigned char *)src_start;
+ volatile unsigned char *dp = (unsigned char *)(*(out_dma_buf + id));
+
+#if 1
+ *(out_dma_buf_data_count + id) = count;
+ while (count > 0) {
+ *dp = *s;
+ dp ++;
+ s ++;
+ count --;
+ }
+#else
+ while (count > 0) {
+ *dp = *s;
+ s += 2; //skip right sample
+ dp ++;
+ count -= 2;
+ cnt ++;
+ }
+ *(out_dma_buf_data_count + id) = cnt;
+#endif
+}
+
+
+static void replay_fill_1x16_s(unsigned long src_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned short d1, l1;
+ signed short sam_to;
+ volatile unsigned short *s = (unsigned short *)src_start;
+ volatile unsigned short *dp = (unsigned short*)(*(out_dma_buf + id));
+
+ while (count > 0) {
+ d1 = *s;
+
+ sam_to = (signed short)d1;
+ if (sam_to >= 0) {
+ sam_to = 0xfff * sam_to / 0x7fff;
+ } else {
+ sam_to = 0 - sam_to;
+ sam_to = 0xfff * sam_to / 0x7fff;
+ sam_to = 0 - sam_to;
+ }
+ d1 = (unsigned short)sam_to;
+ d1 = d1 << 3;
+ l1 = d1 | jz_audio_volume;
+
+ *dp = l1;
+ s ++;
+ dp ++;
+ count -= 2;
+ cnt += 2 ;
+ }
+ *(out_dma_buf_data_count + id) = cnt;
+}
+
+static void replay_fill_2x16_s(unsigned long src_start, int count, int id)
+{
+ int cnt = 0;
+ unsigned short d1, l1;
+ volatile unsigned short *s = (unsigned short *)src_start;
+ volatile unsigned short *dp = (unsigned short*)(*(out_dma_buf + id));
+
+#if 1
+ while (count > 0) {
+ d1 = *s;
+ l1 = (d1 & 0xfff8) | jz_audio_volume;
+ *dp = l1;
+ s ++;
+ dp ++;
+ count -= 2;
+ cnt += 2 ;
+ }
+ *(out_dma_buf_data_count + id) = cnt;
+#else
+ while (count > 0) {
+ d1 = *s;
+ l1 = (d1 & 0xfff8) | jz_audio_volume;
+ *dp = l1;
+ s += 2; //skip right sample
+ dp ++;
+ count -= 4;
+ cnt += 2;
+ }
+ *(out_dma_buf_data_count + id) = cnt;
+#endif
+}
+
+static unsigned int jz_audio_set_format(int dev, unsigned int fmt)
+{
+ switch (fmt) {
+ case AFMT_U8:
+ case AFMT_S16_LE:
+ jz_audio_format = fmt;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+ case AFMT_QUERY:
+ break;
+ }
+
+ return jz_audio_format;
+}
+
+static short jz_audio_set_channels(int dev, short channels)
+{
+ switch (channels) {
+ case 1:
+ case 2:
+ jz_audio_channels = channels;
+ jz_update_filler(jz_audio_format, jz_audio_channels);
+ break;
+ default:
+ printk("channel number is wrong. %d\n",__LINE__);
+ }
+
+ return jz_audio_channels;
+}
+
+static void init_codec(void)
+{
+ printk("set PCM codec RESET pin on LOW, while MCLK occur.\n");
+ printk("set LINSEL on LOW(8bits) or HIGH(13bits+3bits for PCMOUT gain).\n");
+}
+
+static void jz_audio_reset(void)
+{
+ __pcm_flush_fifo();
+ __pcm_disable_txfifo();
+ __pcm_disable_rxfifo();
+ __pcm_set_transmit_trigger(7);
+ __pcm_set_receive_trigger(7);
+ __pcm_omsb_next_sync();
+ __pcm_imsb_next_sync();
+#if MODE_is_8
+ __pcm_set_iss(8);//8bits decided by LINSEL
+ __pcm_set_oss(8);//8bits decided by LINSEL
+#else
+ __pcm_set_iss(16);//16bits decided by LINSEL
+ __pcm_set_oss(16);
+#endif
+ __pcm_disable_tfs_intr();
+ __pcm_disable_tur_intr();
+ __pcm_disable_rfs_intr();
+ __pcm_disable_ror_intr();
+
+ __pcm_disable_receive_dma();
+ __pcm_disable_transmit_dma();
+
+ //init_codec();
+}
+
+static int jz_audio_release(struct inode *inode, struct file *file);
+static int jz_audio_open(struct inode *inode, struct file *file);
+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg);
+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait);
+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos);
+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos);
+
+/* static struct file_operations jz_pcm_audio_fops */
+static struct file_operations jz_pcm_audio_fops =
+{
+ owner: THIS_MODULE,
+ open: jz_audio_open,
+ release: jz_audio_release,
+ write: jz_audio_write,
+ read: jz_audio_read,
+ poll: jz_audio_poll,
+ ioctl: jz_audio_ioctl
+};
+
+static int jz_pcm_open_mixdev(struct inode *inode, struct file *file)
+{
+ int i;
+ int minor = MINOR(inode->i_rdev);
+ struct jz_pcm_controller_info *controller = pcm_controller;
+
+ for (i = 0; i < NR_PCM; i++)
+ if (controller->pcm_codec[i] != NULL && controller->pcm_codec[i]->dev_mixer == minor)
+ goto match;
+
+ if (!controller)
+ return -ENODEV;
+match:
+ file->private_data = controller->pcm_codec[i];
+
+ return 0;
+}
+
+static int jz_pcm_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct pcm_codec *codec = (struct pcm_codec *)file->private_data;
+ return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static loff_t jz_pcm_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static struct file_operations jz_pcm_mixer_fops =
+{
+ owner: THIS_MODULE,
+ llseek: jz_pcm_llseek,
+ ioctl: jz_pcm_ioctl_mixdev,
+ open: jz_pcm_open_mixdev,
+};
+
+static int pcm_mixer_ioctl(struct pcm_codec *codec, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ long val = 0;
+
+ switch (cmd) {
+ case SOUND_MIXER_READ_STEREODEVS:
+ return put_user(0, (long *) arg);
+ case SOUND_MIXER_READ_CAPS:
+ val = SOUND_CAP_EXCL_INPUT;
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_READ_DEVMASK:
+ break;
+ case SOUND_MIXER_READ_RECMASK:
+ break;
+ case SOUND_MIXER_READ_RECSRC:
+ break;
+ case SOUND_MIXER_WRITE_VOLUME:
+ ret = get_user(val, (long *) arg);
+ if (ret)
+ return ret;
+ val = val & 0xff;
+ if(val < 0)
+ val = 0;
+ if(val > 100)
+ val = 100;
+ if (val == 100) {
+ dump_pcmc_reg();
+ return 100;
+ }
+ val = val / 10;
+ switch (val) {
+ case 0:
+ case 1:
+ jz_audio_volume = 7;
+ break;
+ case 2:
+ jz_audio_volume = 6;
+ break;
+ case 3:
+ jz_audio_volume = 5;
+ break;
+ case 4:
+ jz_audio_volume = 4;
+ break;
+ case 5:
+ jz_audio_volume = 3;
+ break;
+ case 6:
+ jz_audio_volume = 2;
+ break;
+ case 7:
+ case 8:
+ jz_audio_volume = 1;
+ break;
+ case 9:
+ case 10:
+ jz_audio_volume = 0;
+ break;
+ }
+ return 0;
+ case SOUND_MIXER_READ_VOLUME:
+ val = jz_audio_volume;
+ ret = val << 8;
+ val = val | ret;
+ return put_user(val, (long *) arg);
+ case SOUND_MIXER_WRITE_MIC:
+ printk("Can not justify Mic gain to the PCM codec.!\n");
+ return -ENOSYS;
+
+ case SOUND_MIXER_READ_MIC:
+ printk("Can not justify Mic gain to the PCM codec.!\n");
+ return -ENOSYS;
+ default:
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+
+
+int pcm_probe_codec(struct pcm_codec *codec)
+{
+ /* generic OSS to PCM wrapper */
+ codec->mixer_ioctl = pcm_mixer_ioctl;
+ return 1;
+}
+
+/* PCM codec initialisation. */
+static int __init jz_pcm_codec_init(struct jz_pcm_controller_info *controller)
+{
+ int num_pcm = 0;
+ struct pcm_codec *codec;
+
+ for (num_pcm = 0; num_pcm < NR_PCM; num_pcm++) {
+ if ((codec = kmalloc(sizeof(struct pcm_codec),GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memset(codec, 0, sizeof(struct pcm_codec));
+ codec->private_data = controller;
+ codec->id = num_pcm;
+
+ if (pcm_probe_codec(codec) == 0)
+ break;
+ if ((codec->dev_mixer = register_sound_mixer(&jz_pcm_mixer_fops, -1)) < 0) {
+ printk(KERN_ERR "Jz PCM: couldn't register mixer!\n");
+ kfree(codec);
+ break;
+ }
+ controller->pcm_codec[num_pcm] = codec;
+ }
+
+ return num_pcm;
+}
+
+static void jz_update_filler(int format, int channels)
+{
+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
+
+ switch (TYPE(format, channels)) {
+ default:
+ case TYPE(AFMT_U8, 1):
+ replay_filler = replay_fill_1x8_u;
+ record_filler = record_fill_1x8_u;
+ break;
+ case TYPE(AFMT_U8, 2):
+ /*replay_filler = replay_fill_2x8_u;
+ record_filler = record_fill_2x8_u;*/
+ printk("channel is 2. Line:%d\n",__LINE__);
+ break;
+ case TYPE(AFMT_S16_LE, 1):
+ replay_filler = replay_fill_1x16_s;
+ record_filler = record_fill_1x16_s;
+ break;
+ case TYPE(AFMT_S16_LE, 2):
+ /*replay_filler = replay_fill_2x16_s;
+ record_filler = record_fill_2x16_s;*/
+ printk("channel is 2. Line:%d\n",__LINE__);
+ break;
+ }
+}
+
+static void __init attach_jz_pcm(struct jz_pcm_controller_info *controller)
+{
+ char *name;
+ int adev;//No of Audio device.
+ int err;
+
+ name = controller->name;
+ /* register /dev/audio */
+ adev = register_sound_dsp(&jz_pcm_audio_fops, -1);
+ if (adev < 0)
+ goto audio_failed;
+ /* initialize PCM codec and register /dev/mixer */
+ if (jz_pcm_codec_init(controller) <= 0)
+ goto mixer_failed;
+
+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, JZCODEC_USER_BUFFER);
+ if (!controller->tmp1) {
+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name);
+ goto tmp1_failed;
+ }
+ printk("DMA_ID_PCM_TX=0x%08x DMA_ID_PCM_RX=0x%08x\n",DMA_ID_PCM_TX ,DMA_ID_PCM_RX);
+ if ((controller->dma1 = jz_request_dma(DMA_ID_PCM_TX, "audio dac", jz_pcm_replay_dma_irq, IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name);
+ goto dma1_failed;
+ }
+ if ((controller->dma2 = jz_request_dma(DMA_ID_PCM_RX, "audio adc", jz_pcm_record_dma_irq, IRQF_DISABLED, controller)) < 0) {
+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name);
+ goto dma2_failed;
+ }
+ printk("JzSOC On-Chip PCM controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2));
+
+ err = request_irq(IRQ_PCM, jz_pcm_irq, IRQF_DISABLED, "pcm irq", controller);
+ if (err < 0)
+ printk("can't allocate pcm irq.\n");
+ controller->dev_audio = adev;
+
+ return;
+dma2_failed:
+ jz_free_dma(controller->dma2);
+dma1_failed:
+ jz_free_dma(controller->dma1);
+tmp1_failed:
+ free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER);
+
+mixer_failed:
+ unregister_sound_dsp(adev);
+audio_failed:
+ return;
+}
+
+
+static int __init probe_jz_pcm(struct jz_pcm_controller_info **controller)
+{
+ if ((*controller = kmalloc(sizeof(struct jz_pcm_controller_info),
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_ERR "Jz PCM Controller: out of memory.\n");
+ return -ENOMEM;
+ }
+
+ (*controller)->name = "Jz PCM controller";
+ (*controller)->opened1 = 0;
+ (*controller)->opened2 = 0;
+ init_waitqueue_head(&(*controller)->adc_wait);
+ init_waitqueue_head(&(*controller)->dac_wait);
+ spin_lock_init(&(*controller)->lock);
+ init_waitqueue_head(&rx_wait_queue);
+ init_waitqueue_head(&tx_wait_queue);
+
+ return 0;
+}
+
+static void __exit unload_jz_pcm(struct jz_pcm_controller_info *controller)
+{
+ int adev = controller->dev_audio;
+
+ __pcm_reset();
+ schedule_timeout(5);
+ __pcm_disable();
+ __pcm_clk_disable();
+ __pcm_flush_fifo();
+
+ controller->dev_audio = -1;
+ jz_free_dma(controller->dma1);
+ jz_free_dma(controller->dma2);
+ free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER);
+
+ if (adev >= 0)
+ unregister_sound_dsp(controller->dev_audio);
+}
+
+static int __init init_jz_pcm(void)
+{
+ int errno;
+ /* 24M OSC ---> CPCCR.ECS ---> PCMCDR.PCMS ---> cpm_pcm_sysclk(X) */
+ long X = 12000000; //in Hz /* 6.144 MHz <= X <= 264.192 MHz */
+
+#if 0
+ /* pcm_sys_clk is from PLL divsion */
+ REG_CPM_PCMCDR = 0x8000001b;
+ REG_CPM_CPCCR |= 0x00400000;
+#endif
+ /* pcm_sys_clk is from external clock */
+ /* reset codec GPF4 */
+ __gpio_as_output(32 * 5 + 4);
+ __gpio_set_pin(32 * 5 + 4);
+ mdelay(1);
+
+ __pcm_reset();
+ schedule_timeout(5);
+ __pcm_clk_disable();
+
+ /* set CPM to output cpm-pcm-sysclk ,assume cpm-pcm-sysclk is X Hz */
+ /* PCMCLK must be 2048000 Hz, it is 256 mutil of PCMSYNC */
+ //__pcm_set_clk_rate(X, 2048000);
+ __pcm_set_clk_rate(X, 2000000);
+ /* PCMSYNC must be 8000 Hz. 2048000 / 256 = 8000 */
+ __pcm_set_sync_rate(2048000, 8000);
+ //__pcm_set_sync_rate(2000000, 8000);
+ __pcm_set_sync_len(0);
+
+ __pcm_flush_fifo();
+ __pcm_disable_txfifo();
+ __pcm_disable_rxfifo();
+ __pcm_set_transmit_trigger(7);
+ __pcm_set_receive_trigger(7);
+ __pcm_omsb_next_sync();
+ __pcm_imsb_next_sync();
+
+#if MODE_is_8
+ __pcm_set_iss(8);//8bits decided by LINSEL
+ __pcm_set_oss(8);
+#else
+ __pcm_set_iss(16);//16bits decided by LINSEL
+ __pcm_set_oss(16);
+#endif
+ __pcm_set_valid_slot(1);
+
+ __pcm_disable_tfs_intr();
+ __pcm_disable_tur_intr();
+ __pcm_disable_rfs_intr();
+ __pcm_disable_ror_intr();
+
+ __pcm_disable_receive_dma();
+ __pcm_disable_transmit_dma();
+
+ __pcm_last_sample();
+ __pcm_as_master();
+
+ __pcm_enable();
+ __pcm_clk_enable();
+
+ if ((errno = probe_jz_pcm(&pcm_controller)) < 0)
+ return errno;
+ attach_jz_pcm(pcm_controller);
+
+ out_empty_queue.id = NULL;
+ out_full_queue.id = NULL;
+ out_busy_queue.id = NULL;
+ in_empty_queue.id = NULL;
+ in_full_queue.id = NULL;
+ in_busy_queue.id = NULL;
+
+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE;
+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ;
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+
+ __gpio_clear_pin(32 * 5 + 4);
+ udelay(100);
+
+ __gpio_set_pin(32 * 5 + 4);
+ dump_pcmc_reg();
+
+ return 0;
+}
+
+
+static void __exit cleanup_jz_pcm(void)
+{
+ unload_jz_pcm(pcm_controller);
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+}
+
+module_init(init_jz_pcm);
+module_exit(cleanup_jz_pcm);
+
+static int drain_adc(struct jz_pcm_controller_info *ctrl, int nonblock)
+{
+ unsigned long flags;
+ int count, i=0;
+
+ for (;;) {
+ if ( i < MAXDELAY ) {
+ udelay(10);
+ i++;
+ } else
+ break;
+
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma2);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+
+ if (nonblock)
+ return -EBUSY;
+ }
+
+ return 0;
+}
+static int drain_dac(struct jz_pcm_controller_info *ctrl, int nonblock)
+{
+ unsigned long flags;
+ int count, ele, i=0;
+
+ for (;;) {
+ if(!nonblock) {//blocked
+ if ( i < MAXDELAY ) {
+ udelay(10);
+ i++;
+ } else
+ break;
+
+ ele = elements_in_queue(&out_full_queue);
+ if(ele <= 0) {
+ udelay(10);
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ }
+ } else {//non-blocked
+ mdelay(100);
+ ele = elements_in_queue(&out_full_queue);
+
+ if(ele <= 0) {
+ mdelay(100);
+
+ spin_lock_irqsave(&ctrl->lock, flags);
+ count = get_dma_residue(ctrl->dma1);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ if (count <= 0)
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int jz_audio_release(struct inode *inode, struct file *file)
+{
+ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data;
+
+ if (controller == NULL)
+ return -ENODEV;
+
+ if ( controller->opened1 == 1 ) {
+ __pcm_enable_transmit_dma();
+ __pcm_enable_txfifo();
+ drain_dac(controller, file->f_flags & O_NONBLOCK);
+ disable_dma(controller->dma1);
+ set_dma_count(controller->dma1, 0);
+
+ __pcm_disable_transmit_dma();
+ __pcm_disable_txfifo();
+
+ spin_lock(&controller->ioctllock);
+ controller->total_bytes = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+ spin_unlock(&controller->ioctllock);
+ //__pcm_disable();
+ controller->opened1 = 0;
+ }
+
+ if ( controller->opened2 == 1 ) {
+ first_record_call = 1;
+ __pcm_enable_receive_dma();
+ __pcm_enable_rxfifo();
+ drain_adc(controller, file->f_flags & O_NONBLOCK);
+ disable_dma(controller->dma2);
+ set_dma_count(controller->dma2, 0);
+ __pcm_disable_receive_dma();
+ __pcm_disable_rxfifo();
+
+ spin_lock(&controller->ioctllock);
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+ spin_unlock(&controller->ioctllock);
+ //__pcm_disable();
+ controller->opened2 = 0;
+ }
+ __pcm_disable_tfs_intr();
+ __pcm_disable_tur_intr();
+ __pcm_disable_rfs_intr();
+ __pcm_disable_ror_intr();
+
+ return 0;
+}
+
+static int jz_audio_open(struct inode *inode, struct file *file)
+{
+ int i;
+ struct jz_pcm_controller_info *controller = pcm_controller;
+
+ if (controller == NULL)
+ return -ENODEV;
+
+ if (controller->opened1 == 1 || controller->opened2 == 1 ) {
+ printk("\naudio is busy!\n");
+ return -EBUSY;
+ }
+ REG_DMAC_DMACKE(0) = 0x3f;
+ REG_DMAC_DMACKE(1) = 0x3f;
+ if (file->f_mode & FMODE_WRITE) {
+ if (controller->opened1 == 1)
+ return -EBUSY;
+ controller->opened1 = 1;
+ //for ioctl
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextOut = 0;
+
+ out_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(out_empty_queue.id + i) = i;
+ out_busy_queue.count = 0;
+ out_full_queue.count = 0;
+ /* set PCMOUT params */
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ if (controller->opened2 == 1)
+ return -EBUSY;
+ controller->opened2 = 1;
+ first_record_call = 1;
+ //for ioctl
+ controller->total_bytes = 0;
+ jz_audio_dma_tran_count = 0;
+ controller->count = 0;
+ controller->finish = 0;
+ controller->blocks = 0;
+ controller->nextIn = 0;
+ in_empty_queue.count = jz_audio_fragstotal;
+ for (i=0;i < jz_audio_fragstotal;i++)
+ *(in_empty_queue.id + i) = i;
+ in_full_queue.count = 0;
+ in_busy_queue.count = 0;
+ /* set PCMIN params */
+ }
+
+ file->private_data = controller;
+ jz_audio_reset();
+ __pcm_enable();
+
+ return 0;
+}
+
+static int jz_audio_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize;
+ unsigned long flags;
+ audio_buf_info abinfo;
+ int i, bytes, id;
+ count_info cinfo;
+ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data;
+
+ val = 0;
+ bytes = 0;
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *)arg);
+ case SNDCTL_DSP_RESET:
+ return 0;
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ drain_dac(controller, file->f_flags & O_NONBLOCK);
+ return 0;
+ case SNDCTL_DSP_SPEED:
+ {
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ /* set smaple rate */
+ if (val >= 0)
+ jz_audio_set_speed(controller->dev_audio, val);
+ return put_user(val, (int *)arg);
+ }
+ case SNDCTL_DSP_STEREO:
+ /* set stereo or mono channel */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1);
+ return 0;
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ //return put_user(4*PAGE_SIZE, (int *)arg);
+ return put_user(jz_audio_fragsize , (int *)arg);
+ case SNDCTL_DSP_GETFMTS:
+ /* Returns a mask of supported sample format*/
+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg);
+
+ case SNDCTL_DSP_SETFMT:
+ {
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ /* Select sample format */
+ if (val != AFMT_QUERY)
+ jz_audio_set_format(controller->dev_audio,val);
+ else
+ if (file->f_mode & FMODE_READ)
+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+ else
+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8;
+ return put_user(val, (int *)arg);
+ }
+
+ case SNDCTL_DSP_CHANNELS:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ printk("%s:%s:%d\n",__FILE__,__FUNCTION__,__LINE__);
+ jz_audio_set_channels(controller->dev_audio, val);
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_POST:
+ /* FIXME: the same as RESET ?? */
+ return 0;
+
+ case SNDCTL_DSP_SUBDIVIDE:
+ return 0;
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ get_user(val, (long *) arg);
+ newfragsize = 1 << (val & 0xFFFF);//16 least bits
+
+ if (newfragsize < 4 * PAGE_SIZE)
+ newfragsize = 4 * PAGE_SIZE;
+ if (newfragsize > (16 * PAGE_SIZE)) //16 PAGE_SIZE
+ newfragsize = 16 * PAGE_SIZE;
+
+ newfragstotal = (val >> 16) & 0x7FFF;
+ if (newfragstotal < 2)
+ newfragstotal = 2;
+ if (newfragstotal > 32)
+ newfragstotal = 32;
+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize))
+ return 0;
+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ mdelay(500);
+ jz_audio_fragstotal = newfragstotal;
+ jz_audio_fragsize = newfragsize;
+
+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize);
+ mdelay(10);
+
+ return 0;
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg);
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+ case SNDCTL_DSP_SETDUPLEX:
+ return -EINVAL;
+ case SNDCTL_DSP_GETOSPACE:
+ {
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ //unused fragment amount
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ jz_audio_fragments = elements_in_queue(&out_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ abinfo.fragments = jz_audio_fragments;
+ abinfo.fragstotal = jz_audio_fragstotal;
+ abinfo.fragsize = jz_audio_fragsize;
+ abinfo.bytes = bytes;
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+ }
+ case SNDCTL_DSP_GETISPACE:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ bytes = 0;
+ //unused fragment amount
+ jz_audio_fragments = elements_in_queue(&in_empty_queue);
+ for (i = 0; i < jz_audio_fragments; i++)
+ bytes += jz_audio_fragsize;
+
+ abinfo.fragments = jz_audio_fragments;
+ abinfo.fragstotal = jz_audio_fragstotal;
+ abinfo.fragsize = jz_audio_fragsize;
+ abinfo.bytes = bytes;
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && in_dma_buf)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && out_dma_buf)
+ val |= PCM_ENABLE_OUTPUT;
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_SETTRIGGER:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ return 0;
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextIn;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ cinfo.bytes = controller->total_bytes;
+ cinfo.blocks = controller->blocks;
+ cinfo.ptr = controller->nextOut;
+ controller->blocks = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ unfinish = 0;
+ fullc = elements_in_queue(&out_full_queue);
+ busyc = elements_in_queue(&out_busy_queue);
+ for(i = 0;i < fullc ;i ++) {
+ id = *(out_full_queue.id + i);
+ unfinish += *(out_dma_buf_data_count + id);
+ }
+ for(i = 0;i < busyc ;i ++) {
+ id = *(out_busy_queue.id + i);
+ unfinish += get_dma_residue(controller->dma1);
+ }
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+ return put_user(unfinish, (int *) arg);
+ case SOUND_PCM_READ_RATE:
+ return put_user(jz_audio_rate, (int *)arg);
+ case SOUND_PCM_READ_CHANNELS:
+ return put_user(jz_audio_channels, (int *)arg);
+ case SOUND_PCM_READ_BITS:
+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg);
+ case SNDCTL_DSP_MAPINBUF:
+ case SNDCTL_DSP_MAPOUTBUF:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_WRITE_FILTER:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait)
+{
+ unsigned long flags;
+ unsigned int mask = 0;
+ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data;
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ return POLLOUT | POLLWRNORM;
+ poll_wait(file, &controller->dac_wait, wait);
+ }
+
+ if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ return POLLIN | POLLRDNORM;
+ poll_wait(file, &controller->adc_wait, wait);
+ }
+
+ spin_lock_irqsave(&controller->lock, flags);
+ if (file->f_mode & FMODE_WRITE) {
+ if (elements_in_queue(&out_empty_queue) > 0)
+ mask |= POLLOUT | POLLWRNORM;
+ } else if (file->f_mode & FMODE_READ) {
+ if (elements_in_queue(&in_full_queue) > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ return mask;
+}
+
+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ int id, ret = 0, left_count, copy_count, cnt = 0;
+ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data;
+
+ if (count < 0)
+ return -EINVAL;
+
+ __pcm_enable_receive_dma();
+ __pcm_enable_rxfifo();
+
+ spin_lock(&controller->ioctllock);
+ controller->nextIn = 0;
+ spin_unlock(&controller->ioctllock);
+
+ spin_lock(&controller->lock);
+
+#if 0
+ if (count < 2 * PAGE_SIZE )
+ copy_count = count * 16 / (jz_audio_channels * jz_audio_format);
+ else
+ copy_count = 2 * PAGE_SIZE ;
+#else
+ if (count <= jz_audio_fragsize)
+ copy_count = count;
+ else
+ copy_count = jz_audio_fragsize;
+#endif
+
+ left_count = count;
+ spin_unlock(&controller->lock);
+
+ if (first_record_call) {
+ first_record_call = 0;
+audio_read_back_first:
+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+
+ spin_lock(&controller->lock);
+ *(in_dma_buf_data_count + id) = copy_count;
+ spin_unlock(&controller->lock);
+
+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id));
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+
+ sleep_on(&rx_wait_queue);
+ } else
+ goto audio_read_back_first;
+ }
+
+ while (left_count > 0) {
+audio_read_back_second:
+ if (elements_in_queue(&in_full_queue) <= 0) {
+ if (file->f_flags & O_NONBLOCK)
+ return ret ? ret : -EAGAIN;
+ else
+ sleep_on(&rx_wait_queue);
+ }
+
+ if ((id = get_buffer_id(&in_full_queue)) >= 0) {
+ spin_lock(&controller->lock);
+ cnt = record_filler((unsigned long)controller->tmp1+ret, copy_count, id);
+ spin_unlock(&controller->lock);
+ put_buffer_id(&in_empty_queue, id);
+ } else
+ goto audio_read_back_second;
+
+ if (elements_in_queue(&in_busy_queue) == 0) {
+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) {
+ put_buffer_id(&in_busy_queue, id);
+ spin_lock(&controller->lock);
+ *(in_dma_buf_data_count + id) = copy_count;
+ spin_unlock(&controller->lock);
+
+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id));
+ audio_start_dma(controller->dma2,file->private_data,
+ *(in_dma_pbuf + id),
+ *(in_dma_buf_data_count + id),
+ DMA_MODE_READ);
+ }
+ }
+ if (ret + cnt > count) {
+ spin_lock(&controller->lock);
+ cnt = count - ret;
+ spin_unlock(&controller->lock);
+ }
+ if (copy_to_user(buffer+ret, controller->tmp1+ret, cnt))
+ return ret ? ret : -EFAULT;
+ spin_lock(&controller->lock);
+ ret += cnt;
+ spin_unlock(&controller->lock);
+
+ spin_lock(&controller->ioctllock);
+ controller->nextIn += ret;
+ spin_unlock(&controller->ioctllock);
+
+ spin_lock(&controller->lock);
+ left_count -= cnt;
+ spin_unlock(&controller->lock);
+ }
+
+ return ret;
+}
+
+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ int id, ret, left_count, copy_count;
+ unsigned long flags;
+ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data;
+
+ if (count <= 0)
+ return -EINVAL;
+
+ __pcm_enable_transmit_dma();
+ __pcm_enable_txfifo();
+
+ spin_lock_irqsave(&controller->ioctllock, flags);
+ controller->nextOut = 0;
+ spin_unlock_irqrestore(&controller->ioctllock, flags);
+
+#if 0
+ if (count < 2 * PAGE_SIZE )
+ copy_count = count;
+ else
+ copy_count = 2 * PAGE_SIZE;
+#else
+ if (count <= jz_audio_fragsize)
+ copy_count = count;
+ else
+ copy_count = jz_audio_fragsize;
+#endif
+
+ left_count = count;
+ ret = 0;
+
+ if (copy_from_user(controller->tmp1, buffer, count)) {
+ printk("copy_from_user failed:%d",ret);
+ return ret ? ret : -EFAULT;
+ }
+
+ while (left_count > 0) {
+audio_write_back:
+ if (elements_in_queue(&out_empty_queue) == 0) {
+ // all are full
+ if (file->f_flags & O_NONBLOCK)
+ return ret;
+ else
+ sleep_on(&tx_wait_queue);
+ }
+ /* the end fragment size in this write */
+ if (ret + copy_count > count)
+ copy_count = count - ret;
+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) {
+ replay_filler((unsigned long)controller->tmp1 + ret, copy_count, id);
+ if(*(out_dma_buf_data_count + id) > 0) {
+ put_buffer_id(&out_full_queue, id); //busy in
+ dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id));
+ } else
+ put_buffer_id(&out_empty_queue, id); //spare
+ } else
+ goto audio_write_back;
+
+ left_count = left_count - copy_count;
+ ret += copy_count;//all is in byte
+
+ spin_lock(&controller->ioctllock);
+ controller->nextOut += ret;
+ spin_unlock(&controller->ioctllock);
+
+ if (elements_in_queue(&out_busy_queue) == 0) {
+ if ((id=get_buffer_id(&out_full_queue)) >= 0) {
+ put_buffer_id(&out_busy_queue, id);
+
+ if(*(out_dma_buf_data_count + id) > 0) {
+ audio_start_dma(controller->dma1,
+ file->private_data,
+ *(out_dma_pbuf + id),
+ *(out_dma_buf_data_count + id),
+ DMA_MODE_WRITE);
+
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void dump_pcmc_reg(void)
+{
+ printk("REG_DMAC_DMACKE(0) : 0x%08x\n",REG_DMAC_DMACKE(0));
+ printk("REG_DMAC_DMACKE(1) : 0x%08x\n",REG_DMAC_DMACKE(1));
+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR);
+ printk("REG_CPM_CPCCR : 0x%08x\n",REG_CPM_CPCCR);
+ printk("REG_CPM_PCMCDR : 0x%08x\n",REG_CPM_PCMCDR);
+ printk("REG_PCM_CLT : 0x%08x\n",REG_PCM_CTL);
+ printk("REG_PCM_CFG : 0x%08x\n",REG_PCM_CFG);
+ printk("REG_PCM_INTC : 0x%08x\n",REG_PCM_INTC);
+ printk("REG_PCM_INTS : 0x%08x\n",REG_PCM_INTS);
+ printk("REG_PCM_DIV : 0x%08x\n",REG_PCM_DIV);
+}
diff --git a/sound/oss/jzcodec.c b/sound/oss/jzcodec.c
new file mode 100644
index 00000000000..33c5cb2c219
--- /dev/null
+++ b/sound/oss/jzcodec.c
@@ -0,0 +1,442 @@
+/*
+ * linux/drivers/sound/jzcodec.c
+ *
+ * JzSOC internal audio driver.
+ *
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/proc_fs.h>
+#include <linux/soundcard.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <asm/hardirq.h>
+#include <asm/jzsoc.h>
+
+#include "sound_config.h"
+
+#define USE_NONE 1
+#define USE_MIC 2
+#define USE_LINEIN 3
+
+typedef struct hpvol_shift_s
+{
+ int hpvol;
+ int shift;
+} hpvol_shift_t;
+
+extern mixer_info info;
+extern _old_mixer_info old_info;
+extern int codec_volue_shift;
+extern hpvol_shift_t hpvol_shift_table[72];
+extern int abnormal_data_count;
+
+extern void (*set_codec_mode)(void);
+extern void (*each_time_init_codec)(void);
+extern int (*set_codec_startup_param)(void);
+extern void (*set_codec_volume_table)(void);
+extern void (*set_codec_record)(int mode);
+extern void (*set_codec_replay)(void);
+extern void (*set_codec_replay_record)(int mode);
+extern void (*turn_on_codec)(void);
+extern void (*turn_off_codec)(void);
+extern void (*set_codec_speed)(int rate);
+extern void (*reset_codec)(void);
+extern void (*codec_mixer_old_info_id_name)(void);
+extern void (*codec_mixer_info_id_name)(void);
+extern void (*set_codec_bass)(int val);
+extern void (*set_codec_volume)(int val);
+extern void (*set_codec_mic)(int val);
+extern void (*set_codec_line)(int val);
+extern void (*i2s_resume_codec)(void);
+extern void (*i2s_suspend_codec)(void);
+extern void (*set_codec_direct_mode)(void);
+extern void (*clear_codec_direct_mode)(void);
+
+static int jzcodec_reg[2];
+
+void set_jzcodec_mode(void);
+void each_time_init_jzcodec(void);
+int set_jzcodec_startup_param(void);
+void set_jzcodec_volume_table(void);
+void set_jzcodec_replay(void);
+void set_jzcodec_record(int mode);
+void turn_on_jzcodec(void);
+void turn_off_jzcodec(void);
+void set_jzcodec_speed(int rate);
+void reset_jzcodec(void);
+void jzcodec_mixer_old_info_id_name(void);
+void jzcodec_mixer_info_id_name(void);
+void set_jzcodec_bass(int val);
+void set_jzcodec_volume(int val);
+void set_jzcodec_mic(int val);
+void set_jzcodec_line(int val);
+void in_codec_app1(void);
+void in_codec_app12(void);
+void HP_turn_on(void);
+void HP_turn_off(void);
+void resume_jzcodec(void);
+void suspend_jzcodec(void);
+void set_jzcodec_replay_record(int mode);
+
+void set_jzcodec_mode(void)
+{
+ __i2s_internal_codec();
+ __i2s_as_slave();
+ __i2s_select_i2s();
+ __aic_select_i2s();
+
+ REG_ICDC_CDCCR1 = 0x001b2303;
+ schedule_timeout(1);
+ REG_ICDC_CDCCR1 = 0x001b2302;
+}
+
+void each_time_init_jzcodec(void)
+{
+ __i2s_disable();
+ __i2s_as_slave();
+ __i2s_set_oss_sample_size(16);
+ __i2s_set_iss_sample_size(16);
+}
+
+int set_jzcodec_startup_param(void)
+{
+ REG_ICDC_CDCCR1 = 0x001b2300;
+ schedule_timeout(50);
+ REG_ICDC_CDCCR1 = 0x00033300;
+ schedule_timeout(5);
+ REG_ICDC_CDCCR1 = 0x17026300;
+
+ return 1;
+}
+void set_jzcodec_volume_table(void)
+{
+ int errno,hpvol_step,sample_shift;
+
+ codec_volue_shift = 0;
+ hpvol_step = 3;
+ sample_shift = 0;
+ for(errno = 0;errno < 72;errno++) {
+ hpvol_shift_table[errno].hpvol = hpvol_step;
+ hpvol_shift_table[errno].shift = sample_shift;
+ hpvol_step --;
+ if(hpvol_step <= 0) {
+ hpvol_step = 3;
+ sample_shift ++;
+ }
+ }
+}
+
+void set_jzcodec_replay(void)
+{
+ in_codec_app1();
+}
+
+void set_jzcodec_record(int mode)
+{
+ switch (mode) {
+ case USE_NONE:
+ case USE_MIC:
+ in_codec_app12();
+ abnormal_data_count = 0;
+ break;
+ case USE_LINEIN:
+ REG_ICDC_CDCCR1 = 0x27022000;//for linein
+ mdelay(300);
+ break;
+ }
+}
+
+void set_jzcodec_replay_record(int mode)
+{
+ long val = 0;
+ REG_ICDC_CDCCR1 = 0x00037302;
+ mdelay(2);
+ REG_ICDC_CDCCR1 = 0x03006000;
+ mdelay(2);
+
+ switch (mode) {
+ case USE_NONE:
+ case USE_MIC:
+ REG_ICDC_CDCCR1 = 0x17022000;//for mic
+ break;
+ case USE_LINEIN:
+ REG_ICDC_CDCCR1 = 0x27022000;//for linein
+ break;
+ }
+
+ val = REG_ICDC_CDCCR2;
+ val &= 0x0000ff00;
+ val |= 0x00170030;
+ REG_ICDC_CDCCR2 = val;
+}
+
+void turn_on_jzcodec(void)
+{
+ HP_turn_on();
+}
+
+void set_jzcodec_direct_mode(void)
+{
+ long val = 0;
+ REG_ICDC_CDCCR1 = 0x14000000;
+ val &= 0x0000ff00;
+ val |= 0x001f0033;
+ REG_ICDC_CDCCR2 = val;
+ mdelay(300);
+}
+
+void clear_jzcodec_direct_mode(void)
+{
+ HP_turn_off();
+}
+
+void turn_off_jzcodec(void)
+{
+ HP_turn_off();
+}
+
+void set_jzcodec_speed(int rate)
+{
+ long codec_speed,speed = 0;
+ switch (rate) {
+ case 8000:
+ speed = 0;
+ break;
+ case 11025:
+ speed = 1;
+ break;
+ case 12000:
+ speed = 2;
+ break;
+ case 16000:
+ speed = 3;
+ break;
+ case 22050:
+ speed = 4;
+ break;
+ case 24000:
+ speed = 5;
+ break;
+ case 32000:
+ speed = 6;
+ break;
+ case 44100:
+ speed = 7;
+ break;
+ case 48000:
+ speed = 8;
+ break;
+ default:
+ break;
+ }
+
+ codec_speed = REG_ICDC_CDCCR2;
+ codec_speed |= 0x00000f00;
+
+ speed = speed << 8;
+ speed |= 0xfffff0ff;
+ codec_speed &= speed;
+ REG_ICDC_CDCCR2 = codec_speed;
+}
+
+void reset_jzcodec(void)
+{
+ REG_ICDC_CDCCR1 |= 1;
+ mdelay(1);
+ REG_ICDC_CDCCR1 &= 0xfffffffe;
+}
+
+void jzcodec_mixer_old_info_id_name(void)
+{
+ strncpy(info.id, "JZCODEC", sizeof(info.id));
+ strncpy(info.name,"Jz internal codec", sizeof(info.name));
+}
+
+void jzcodec_mixer_info_id_name(void)
+{
+ strncpy(old_info.id, "JZCODEC", sizeof(old_info.id));
+ strncpy(old_info.name,"Jz internal codec", sizeof(old_info.name));
+}
+
+void set_jzcodec_bass(int val)
+{
+ int bass_gain = 0;
+ if(val < 25)
+ bass_gain = 0;
+ if(val >= 25 && val < 50)
+ bass_gain = 1;
+ if(val >= 50 && val < 75)
+ bass_gain = 2;
+ if(val >= 75 && val <= 100 )
+ bass_gain = 3;
+
+ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3 << 4)) | (bass_gain << 4));
+}
+
+void set_jzcodec_volume(int val)
+{
+ unsigned int sample_oss;
+ int index,shift_max,vol_scale,vol_step,codec_volume;
+ shift_max = 0;
+ sample_oss = (REG_AIC_CR & 0x00380000) >> 19;
+
+ switch(sample_oss)
+ {
+ case 0x0:
+ shift_max = 4; /* 8 bits */
+ break;
+ case 0x1:
+ shift_max = 10; /* 16 bits */
+ break;
+ case 0x2:
+ shift_max = 12; /* 18 bits */
+ break;
+ case 0x3:
+ shift_max = 15; /* 20 bits */
+ break;
+ case 0x4:
+ shift_max = 19; /* 24 bits */
+ break;
+ }
+
+ vol_scale = 3 * (shift_max + 1);
+ vol_step = 100 / vol_scale;
+
+ for(index = 0;index <= 100;index += vol_step)
+ if( val <= index )
+ break;
+
+ if(index == 0)
+ index = vol_step;
+ index = index / vol_step;
+ if(index > vol_scale)
+ index = vol_scale;
+
+ index = vol_scale - index;
+ codec_volume = hpvol_shift_table[index].hpvol;
+ codec_volue_shift = hpvol_shift_table[index].shift;
+ codec_volume = 3;
+ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3)) | codec_volume);
+}
+
+void set_jzcodec_mic(int val)
+{
+ long mic_gain;
+
+ mic_gain = 31 * val /100;
+ REG_ICDC_CDCCR2 = (REG_ICDC_CDCCR2 | (0x3 << 4));
+ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (mic_gain << 16));
+}
+
+void set_jzcodec_line(int val)
+{
+ long line_gain;
+
+ line_gain = 31 * val /100;
+ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (line_gain << 16));
+}
+
+void HP_turn_on(void)
+{
+ long val = 0;
+ /* simple and slow anti-pop */
+ REG_ICDC_CDCCR1 = 0x00037302;
+ mdelay(2);
+ REG_ICDC_CDCCR1 = 0x03006000;
+ mdelay(2);
+ REG_ICDC_CDCCR1 = 0x03002000;
+
+ val = REG_ICDC_CDCCR2;
+ val &= 0x0000ff00;
+ val |= 0x001f0033;
+ REG_ICDC_CDCCR2 = val;
+}
+
+void HP_turn_off(void)
+{
+ mdelay(20);
+ REG_ICDC_CDCCR1 = 0x00033300;
+}
+
+void in_codec_app1(void)
+{
+ /* test is OK */
+ HP_turn_on();
+}
+
+void in_codec_app12(void)
+{
+ REG_ICDC_CDCCR1 = 0x14024300;
+ mdelay(300);
+}
+
+void resume_jzcodec(void)
+{
+ REG_ICDC_CDCCR2 = 0x00170800;
+ mdelay(2);
+ REG_ICDC_CDCCR1 = 0x001f2102;
+ mdelay(5);
+ REG_ICDC_CDCCR1 = 0x00033302;
+ mdelay(550);
+ REG_ICDC_CDCCR1 = 0x00033300;
+ REG_ICDC_CDCCR1 = jzcodec_reg[0];
+ REG_ICDC_CDCCR2 = jzcodec_reg[1];
+}
+
+void suspend_jzcodec(void)
+{
+
+ jzcodec_reg[0] = REG_ICDC_CDCCR1;
+ jzcodec_reg[1] = REG_ICDC_CDCCR2;
+
+ REG_ICDC_CDCCR1 = 0x001b2302;
+ mdelay(1);
+ REG_ICDC_CDCCR1 = 0x001b2102;
+}
+
+static int __init init_jzcodec(void)
+{
+ set_codec_mode = set_jzcodec_mode;
+ each_time_init_codec = each_time_init_jzcodec;
+
+ set_codec_startup_param = set_jzcodec_startup_param;
+ set_codec_volume_table = set_jzcodec_volume_table;
+ set_codec_record = set_jzcodec_record;
+ set_codec_replay = set_jzcodec_replay;
+ set_codec_replay_record = set_jzcodec_replay_record;
+ turn_on_codec = turn_on_jzcodec;
+ turn_off_codec = turn_off_jzcodec;
+ set_codec_speed = set_jzcodec_speed;
+ reset_codec = reset_jzcodec;
+ codec_mixer_old_info_id_name = jzcodec_mixer_old_info_id_name;
+ codec_mixer_info_id_name = jzcodec_mixer_info_id_name;
+ set_codec_bass = set_jzcodec_bass;
+ set_codec_volume = set_jzcodec_volume;
+ set_codec_mic = set_jzcodec_mic;
+ set_codec_line = set_jzcodec_line;
+ i2s_resume_codec = resume_jzcodec;
+ i2s_suspend_codec = suspend_jzcodec;
+ set_codec_direct_mode = set_jzcodec_direct_mode;
+ clear_codec_direct_mode = clear_jzcodec_direct_mode;
+
+ return 0;
+}
+
+
+static void __exit cleanup_jzcodec(void)
+{
+ REG_ICDC_CDCCR1 = 0x001b2302;
+
+}
+
+module_init(init_jzcodec);
+module_exit(cleanup_jzcodec);
diff --git a/sound/oss/jzdlv.c b/sound/oss/jzdlv.c
new file mode 100644
index 00000000000..0a61e4829dd
--- /dev/null
+++ b/sound/oss/jzdlv.c
@@ -0,0 +1,644 @@
+/*
+ * linux/drivers/sound/jzcodec.c
+ *
+ * JzSOC internal audio driver.
+ *
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/proc_fs.h>
+#include <linux/soundcard.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <asm/hardirq.h>
+#include <asm/jzsoc.h>
+
+#include "sound_config.h"
+#include "jzdlv.h"
+
+#define USE_NONE 1
+#define USE_MIC 2
+#define USE_LINEIN 3
+
+extern mixer_info info;
+extern _old_mixer_info old_info;
+extern int codec_volue_shift;
+
+extern void (*set_codec_mode)(void);
+extern void (*each_time_init_codec)(void);
+extern int (*set_codec_startup_param)(void);
+extern void (*set_codec_record)(void);
+extern void (*set_codec_replay)(void);
+extern void (*set_codec_replay_record)(void);
+extern void (*turn_on_codec)(void);
+extern void (*turn_off_codec)(void);
+extern void (*set_codec_speed)(int rate);
+extern void (*reset_codec)(void);
+extern void (*codec_mixer_old_info_id_name)(void);
+extern void (*codec_mixer_info_id_name)(void);
+extern void (*set_codec_bass)(int val);
+extern void (*set_codec_volume)(int val);
+extern void (*set_codec_mic)(int val);
+extern void (*set_codec_line)(int val);
+extern void (*i2s_resume_codec)(void);
+extern void (*i2s_suspend_codec)(void);
+extern void (*set_codec_direct_mode)(void);
+extern void (*clear_codec_direct_mode)(void);
+
+
+void set_dlv_mode(void);
+void each_time_init_jzcodec(void);
+int set_dlv_startup_param(void);
+void set_dlvjzcodec_volume_table(void);
+void set_dlv_replay(void);
+void set_dlv_record(void);
+void set_dlv_speed(int rate);
+void reset_dlv(void);
+void jzcodec_mixer_old_info_id_name(void);
+void jzcodec_mixer_info_id_name(void);
+void set_dlv_volume(int val);
+void set_dlv_mic(int val);
+
+extern int jz_mic_only;
+int read_codec_file(int addr)
+{
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ mdelay(1);
+ return(__icdc_get_value());
+}
+
+#if 0
+void printk_codec_files(void)
+{
+ int cnt;
+
+ printk("\n");
+
+ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR);
+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR);
+ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR);
+ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR);
+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR);
+ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR);
+ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR);
+ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA);
+
+ for (cnt = 0; cnt <= 27 ; cnt++) {
+ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt));
+ }
+ printk("\n");
+}
+#endif
+
+void write_codec_file(int addr, int val)
+{
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ __icdc_set_cmd(val); /* write */
+ mdelay(1);
+ __icdc_set_rgwr();
+ mdelay(1);
+}
+
+int write_codec_file_bit(int addr, int bitval, int mask_bit)
+{
+ int val;
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ mdelay(1);
+ val = __icdc_get_value(); /* read */
+
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ val &= ~(1 << mask_bit);
+ if (bitval == 1)
+ val |= 1 << mask_bit;
+
+ __icdc_set_cmd(val); /* write */
+ mdelay(1);
+ __icdc_set_rgwr();
+ mdelay(1);
+
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ val = __icdc_get_value(); /* read */
+
+ if (((val >> mask_bit) & bitval) == bitval)
+ return 1;
+ else
+ return 0;
+}
+void set_dlv_mode(void)
+{
+ /*REG_CPM_CPCCR &= ~(1 << 31);
+ REG_CPM_CPCCR &= ~(1 << 30);*/
+ write_codec_file(0, 0xf);
+
+ REG_AIC_I2SCR = 0x10;
+ __i2s_internal_codec();
+ __i2s_as_slave();
+ __i2s_select_i2s();
+ __aic_select_i2s();
+ __aic_reset();
+ mdelay(10);
+ REG_AIC_I2SCR = 0x10;
+ mdelay(20);
+
+ /* power on DLV */
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+}
+void reset_dlv_codec(void)
+{
+ /* reset DLV codec. from hibernate mode to sleep mode */
+ write_codec_file(0, 0xf);
+ write_codec_file_bit(6, 0, 0);
+ write_codec_file_bit(6, 0, 1);
+ mdelay(200);
+ //write_codec_file(0, 0xf);
+ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
+ write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0
+ mdelay(10);//wait for stability
+}
+
+void each_time_init_dlv(void)
+{
+ __i2s_disable();
+ __i2s_as_slave();
+ __aic_internal_codec();
+ __i2s_set_oss_sample_size(16);
+ __i2s_set_iss_sample_size(16);
+}
+
+int set_dlv_startup_param(void)
+{
+ __i2s_disable_transmit_intr();
+ __i2s_disable_receive_intr();
+
+ return 1;
+}
+/* set Audio data replay */
+void set_audio_data_replay(void)
+{
+ /* DAC path */
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ mdelay(10);
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ //mdelay(100);
+ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //mdelay(300);
+}
+
+#if 1 /* mask warning */
+/* set Record MIC input audio without playback */
+void set_record_mic_input_audio_without_playback(void)
+{
+ /* ADC path for MIC IN */
+ jz_mic_only = 1;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ mdelay(10);
+ write_codec_file_bit(1, 1, 2);
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+
+ write_codec_file(22, 0x40);//mic 1
+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ //write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file(1, 0x4);
+}
+#endif
+
+#if 1 /* mask warning */
+/* unset Record MIC input audio without playback */
+void unset_record_mic_input_audio_without_playback(void)
+{
+ /* ADC path for MIC IN */
+ jz_mic_only = 0;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 0 /* mask warning */
+/* set Record LINE input audio without playback */
+void set_record_line_input_audio_without_playback(void)
+{
+ /* ADC path for LINE IN */
+ jz_mic_only = 1;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+ write_codec_file(22, 0xf6);//line in 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1
+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ mdelay(10);
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file(1, 0x4);
+}
+#endif
+
+#if 0 /* mask warning */
+/* unset Record LINE input audio without playback */
+void unset_record_line_input_audio_without_playback(void)
+{
+ /* ADC path for LINE IN */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1
+
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 1 /* mask warning */
+/* set Playback LINE input audio direct only */
+void set_playback_line_input_audio_direct_only(void)
+{
+ jz_mic_only = 0;
+
+// jz_audio_reset();//or init_codec()
+ REG_AIC_I2SCR = 0x10;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+ write_codec_file(22, 0xf6);//line in 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ mdelay(10);
+ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1
+ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1
+}
+#endif
+
+#if 1 /* mask warning */
+/* unset Playback LINE input audio direct only */
+void unset_playback_line_input_audio_direct_only(void)
+{
+ write_codec_file_bit(6, 0, 3);//GIM->0
+ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ mdelay(100);
+ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 0 /* mask warning */
+/* set Record MIC input audio with direct playback */
+void set_record_mic_input_audio_with_direct_playback(void)
+{
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ jz_mic_only = 0;
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+ mdelay(10);
+
+ write_codec_file(22, 0x60);//mic 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ //write_codec_file(1, 0x4);
+}
+#endif
+
+#if 0 /* mask warning */
+/* unset Record MIC input audio with direct playback */
+void unset_record_mic_input_audio_with_direct_playback(void)
+{
+ /* ADC path for MIC IN */
+ jz_mic_only = 0;
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 0 /* mask warning */
+/* set Record playing audio mixed with MIC input audio */
+void set_record_playing_audio_mixed_with_mic_input_audio(void)
+{
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ mdelay(10);
+
+ write_codec_file(22, 0x63);//mic 1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0
+}
+#endif
+
+#if 0 /* mask warning */
+/* unset Record playing audio mixed with MIC input audio */
+void unset_record_playing_audio_mixed_with_mic_input_audio(void)
+{
+ /* ADC path */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 5);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 1 /* mask warning */
+/* set Record MIC input audio with Audio data replay (full duplex) */
+void set_record_mic_input_audio_with_audio_data_replay(void)
+{
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+}
+#endif
+
+#if 1 /* mask warning */
+/* unset Record MIC input audio with Audio data replay (full duplex) */
+void unset_record_mic_input_audio_with_audio_data_replay(void)
+{
+ /* ADC path */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 5);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 1 /* mask warning */
+/* set Record LINE input audio with Audio data replay (full duplex for linein) */
+void set_record_line_input_audio_with_audio_data_replay(void)
+{
+ write_codec_file(9, 0xff);
+ //write_codec_file(8, 0x30);
+ write_codec_file(8, 0x20);
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+
+
+ //jz_mic_only = 1;
+ write_codec_file(22, 0xc6);//line in 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+}
+#endif
+
+#if 1 /* mask warning */
+/* unset Record LINE input audio with Audio data replay (full duplex for linein) */
+void unset_record_line_input_audio_with_audio_data_replay(void)
+{
+ /* ADC path */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 5);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+#if 1
+/* unset Audio data replay */
+void unset_audio_data_replay(void)
+{
+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ //mdelay(800);
+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ //mdelay(800);
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 4);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+}
+#endif
+
+void set_dlv_replay(void)
+{
+ set_audio_data_replay();
+}
+
+void set_dlv_speed(int rate)
+{
+ int speed = 0, val;
+ speed = 0;
+ switch (rate) {
+ case 8000:
+ speed = 10;
+ break;
+ case 9600:
+ speed = 9;
+ break;
+ case 11025:
+ speed = 8;
+ break;
+ case 12000:
+ speed = 7;
+ break;
+ case 16000:
+ speed = 6;
+ break;
+ case 22050:
+ speed = 5;
+ break;
+ case 24000:
+ speed = 4;
+ break;
+ case 32000:
+ speed = 3;
+ break;
+ case 44100:
+ speed = 2;
+ break;
+ case 48000:
+ speed = 1;
+ break;
+ case 96000:
+ speed = 0;
+ break;
+ default:
+ break;
+ }
+
+ val = read_codec_file(4);
+ val = (speed << 4) | speed;
+ write_codec_file(4, val);
+}
+
+void reset_jzcodec(void)
+{
+
+}
+
+void dlv_mixer_old_info_id_name(void)
+{
+ strncpy(info.id, "JZDLV", sizeof(info.id));
+ strncpy(info.name,"Jz internal codec dlv on jz4750", sizeof(info.name));
+}
+
+void dlv_mixer_info_id_name(void)
+{
+ strncpy(old_info.id, "JZDLV", sizeof(old_info.id));
+ strncpy(old_info.name,"Jz internal codec dlv on jz4750", sizeof(old_info.name));
+}
+
+void set_dlv_mic(int val)
+{
+ int cur_vol ;
+ /* set gain */
+ //write_codec_file_bit(6, 1, 3);//GIM
+ cur_vol = 31 * val / 100;
+ cur_vol |= cur_vol << 4;
+ write_codec_file(19, cur_vol);//GIL,GIR
+}
+
+void set_dlv_line(int val)
+{
+ int cur_vol;
+ /* set gain */
+ cur_vol = 31 * val / 100;
+ cur_vol &= 0x1f;
+ write_codec_file(11, cur_vol);//GO1L
+ write_codec_file(12, cur_vol);//GO1R
+}
+
+void set_dlv_volume(int val)
+{
+ unsigned long cur_vol;
+ cur_vol = 31 * (100 - val) / 100;
+ write_codec_file(17, cur_vol | 0xc0);
+ write_codec_file(18, cur_vol);
+}
+
+static int __init init_dlv(void)
+{
+ set_codec_mode = set_dlv_mode;
+ each_time_init_codec = each_time_init_dlv;
+ reset_codec = reset_dlv_codec;
+ set_codec_startup_param = set_dlv_startup_param;
+
+ set_codec_replay = set_dlv_replay;
+
+ set_codec_speed = set_dlv_speed;
+
+ codec_mixer_old_info_id_name = dlv_mixer_old_info_id_name;
+ codec_mixer_info_id_name = dlv_mixer_info_id_name;
+
+ set_codec_volume = set_dlv_volume;
+ set_codec_mic = set_dlv_mic;
+ set_codec_line = set_dlv_line;
+
+ return 0;
+}
+
+
+static void __exit cleanup_dlv(void)
+{
+
+}
+
+module_init(init_dlv);
+module_exit(cleanup_dlv);
diff --git a/sound/oss/jzdlv.h b/sound/oss/jzdlv.h
new file mode 100644
index 00000000000..d361563783a
--- /dev/null
+++ b/sound/oss/jzdlv.h
@@ -0,0 +1,21 @@
+/* header file for dlv */
+void write_codec_file(int addr, int val);
+int read_codec_file(int addr);
+void printk_codec_files(void);
+int write_codec_file_bit(int addr, int bitval, int mask_bit);
+void set_audio_data_replay(void);
+void unset_audio_data_replay(void);
+void set_record_mic_input_audio_without_playback(void);
+void unset_record_mic_input_audio_without_playback(void);
+void set_record_line_input_audio_without_playback(void);
+void unset_record_line_input_audio_without_playback(void);
+void set_playback_line_input_audio_direct_only(void);
+void unset_playback_line_input_audio_direct_only(void);
+void set_record_mic_input_audio_with_direct_playback(void);
+void unset_record_mic_input_audio_with_direct_playback(void);
+void set_record_playing_audio_mixed_with_mic_input_audio(void);
+void unset_record_playing_audio_mixed_with_mic_input_audio(void);
+void set_record_mic_input_audio_with_audio_data_replay(void);
+void unset_record_mic_input_audio_with_audio_data_replay(void);
+void set_record_line_input_audio_with_audio_data_replay(void);
+void unset_record_line_input_audio_with_audio_data_replay(void);
diff --git a/sound/oss/os.h b/sound/oss/os.h
index a1a962d7f67..2fb00ab0711 100644
--- a/sound/oss/os.h
+++ b/sound/oss/os.h
@@ -9,7 +9,6 @@
#ifdef __KERNEL__
#include <linux/string.h>
#include <linux/fs.h>
-#include <asm/dma.h>
#include <asm/io.h>
#include <asm/param.h>
#include <linux/sched.h>
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index d3e786a9a0a..e827f85293d 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -35,6 +35,8 @@ source "sound/soc/s3c24xx/Kconfig"
source "sound/soc/s6000/Kconfig"
source "sound/soc/sh/Kconfig"
source "sound/soc/txx9/Kconfig"
+source "sound/soc/jz4740/Kconfig"
+source "sound/soc/jz4750/Kconfig"
# Supported codecs
source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 6f1e28de23c..8c8cc7608c6 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -13,3 +13,6 @@ obj-$(CONFIG_SND_SOC) += s3c24xx/
obj-$(CONFIG_SND_SOC) += s6000/
obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += txx9/
+obj-$(CONFIG_SND_SOC) += jz4740/
+obj-$(CONFIG_SND_SOC) += jz4750/
+
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index bbc97fd7664..a18a0f5868e 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1,82 +1,33 @@
-# Helper to resolve issues with configs that have SPI enabled but I2C
-# modular, meaning we can't build the codec driver in with I2C support.
-# We use an ordered list of conditional defaults to pick the appropriate
-# setting - SPI can't be modular so that case doesn't need to be covered.
-config SND_SOC_I2C_AND_SPI
- tristate
- default m if I2C=m
- default y if I2C=y
- default y if SPI_MASTER=y
-
-config SND_SOC_ALL_CODECS
- tristate "Build all ASoC CODEC drivers"
- select SND_SOC_L3
- select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
- select SND_SOC_AD1980 if SND_SOC_AC97_BUS
- select SND_SOC_AD73311 if I2C
- select SND_SOC_AK4104 if SPI_MASTER
- select SND_SOC_AK4535 if I2C
- select SND_SOC_CS4270 if I2C
- select SND_SOC_PCM3008
- select SND_SOC_SPDIF
- select SND_SOC_SSM2602 if I2C
- select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
- select SND_SOC_TLV320AIC23 if I2C
- select SND_SOC_TLV320AIC26 if SPI_MASTER
- select SND_SOC_TLV320AIC3X if I2C
- select SND_SOC_TWL4030 if TWL4030_CORE
- select SND_SOC_UDA134X
- select SND_SOC_UDA1380 if I2C
- select SND_SOC_WM8350 if MFD_WM8350
- select SND_SOC_WM8400 if MFD_WM8400
- select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
- select SND_SOC_WM8580 if I2C
- select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
- select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
- select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
- select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
- select SND_SOC_WM8900 if I2C
- select SND_SOC_WM8903 if I2C
- select SND_SOC_WM8940 if I2C
- select SND_SOC_WM8960 if I2C
- select SND_SOC_WM8971 if I2C
- select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
- select SND_SOC_WM8990 if I2C
- select SND_SOC_WM9081 if I2C
- select SND_SOC_WM9705 if SND_SOC_AC97_BUS
- select SND_SOC_WM9712 if SND_SOC_AC97_BUS
- select SND_SOC_WM9713 if SND_SOC_AC97_BUS
- help
- Normally ASoC codec drivers are only built if a machine driver which
- uses them is also built since they are only usable with a machine
- driver. Selecting this option will allow these drivers to be built
- without an explicit machine driver for test and development purposes.
-
- Support for the bus types used to access the codecs to be built must
- be selected separately.
-
- If unsure select "N".
-
-
config SND_SOC_AC97_CODEC
tristate
- select SND_AC97_CODEC
+ depends on SND_SOC
-config SND_SOC_AD1980
+config SND_SOC_WM8731
tristate
+ depends on SND_SOC
-config SND_SOC_AD73311
+config SND_SOC_WM8750
tristate
+ depends on SND_SOC
-config SND_SOC_AK4104
+config SND_SOC_WM8753
tristate
+ depends on SND_SOC
-config SND_SOC_AK4535
+config SND_SOC_WM9712
tristate
+ depends on SND_SOC
# Cirrus Logic CS4270 Codec
config SND_SOC_CS4270
tristate
+ depends on SND_SOC
+
+# Cirrus Logic CS4270 Codec Hardware Mute Support
+# Select if you have external muting circuitry attached to your CS4270.
+config SND_SOC_CS4270_HWMUTE
+ bool
+ depends on SND_SOC_CS4270
# Cirrus Logic CS4270 Codec VD = 3.3V Errata
# Select if you are affected by the errata where the part will not function
@@ -86,93 +37,14 @@ config SND_SOC_CS4270_VD33_ERRATA
bool
depends on SND_SOC_CS4270
-config SND_SOC_L3
- tristate
-
-config SND_SOC_PCM3008
- tristate
-
-config SND_SOC_SPDIF
- tristate
-
-config SND_SOC_SSM2602
- tristate
-
-config SND_SOC_STAC9766
- tristate
-
-config SND_SOC_TLV320AIC23
- tristate
-
-config SND_SOC_TLV320AIC26
- tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE
- depends on SPI
-
-config SND_SOC_TLV320AIC3X
- tristate
-
-config SND_SOC_TWL4030
- tristate
-
-config SND_SOC_UDA134X
- tristate
-
-config SND_SOC_UDA1380
- tristate
-
-config SND_SOC_WM8350
- tristate
-
-config SND_SOC_WM8400
- tristate
-
-config SND_SOC_WM8510
- tristate
-
-config SND_SOC_WM8580
- tristate
-
-config SND_SOC_WM8728
- tristate
-
-config SND_SOC_WM8731
- tristate
-
-config SND_SOC_WM8750
- tristate
-
-config SND_SOC_WM8753
- tristate
-
-config SND_SOC_WM8900
- tristate
-
-config SND_SOC_WM8903
- tristate
-
-config SND_SOC_WM8940
- tristate
-
-config SND_SOC_WM8960
- tristate
-
-config SND_SOC_WM8971
- tristate
-
-config SND_SOC_WM8988
- tristate
-
-config SND_SOC_WM8990
- tristate
-
-config SND_SOC_WM9081
- tristate
-
-config SND_SOC_WM9705
- tristate
-
-config SND_SOC_WM9712
- tristate
-
-config SND_SOC_WM9713
- tristate
+config SND_SOC_ICODEC
+ tristate "Jz4740 internal codec"
+ depends on SND_SOC && SND_JZ4740_SOC_PAVO && SND_JZ4740_SOC_I2S
+ help
+ Say Y if you want to use internal codec on Ingenic Jz4740 PAVO board.
+
+config SND_SOC_DLV
+ tristate "Jz4750 internal codec"
+ depends on SND_SOC && SND_JZ4750_SOC_APUS && SND_JZ4750_SOC_I2S
+ help
+ Say Y if you want to use internal codec on Ingenic Jz4750 APUS board. \ No newline at end of file
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8b7530546f4..45acc20288e 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,73 +1,17 @@
snd-soc-ac97-objs := ac97.o
-snd-soc-ad1980-objs := ad1980.o
-snd-soc-ad73311-objs := ad73311.o
-snd-soc-ak4104-objs := ak4104.o
-snd-soc-ak4535-objs := ak4535.o
-snd-soc-cs4270-objs := cs4270.o
-snd-soc-l3-objs := l3.o
-snd-soc-pcm3008-objs := pcm3008.o
-snd-soc-spdif-objs := spdif_transciever.o
-snd-soc-ssm2602-objs := ssm2602.o
-snd-soc-stac9766-objs := stac9766.o
-snd-soc-tlv320aic23-objs := tlv320aic23.o
-snd-soc-tlv320aic26-objs := tlv320aic26.o
-snd-soc-tlv320aic3x-objs := tlv320aic3x.o
-snd-soc-twl4030-objs := twl4030.o
-snd-soc-uda134x-objs := uda134x.o
-snd-soc-uda1380-objs := uda1380.o
-snd-soc-wm8350-objs := wm8350.o
-snd-soc-wm8400-objs := wm8400.o
-snd-soc-wm8510-objs := wm8510.o
-snd-soc-wm8580-objs := wm8580.o
-snd-soc-wm8728-objs := wm8728.o
snd-soc-wm8731-objs := wm8731.o
snd-soc-wm8750-objs := wm8750.o
snd-soc-wm8753-objs := wm8753.o
-snd-soc-wm8900-objs := wm8900.o
-snd-soc-wm8903-objs := wm8903.o
-snd-soc-wm8940-objs := wm8940.o
-snd-soc-wm8960-objs := wm8960.o
-snd-soc-wm8971-objs := wm8971.o
-snd-soc-wm8988-objs := wm8988.o
-snd-soc-wm8990-objs := wm8990.o
-snd-soc-wm9081-objs := wm9081.o
-snd-soc-wm9705-objs := wm9705.o
snd-soc-wm9712-objs := wm9712.o
-snd-soc-wm9713-objs := wm9713.o
+snd-soc-cs4270-objs := cs4270.o
+snd-soc-jzcodec-objs := jzcodec.o
+snd-soc-jzdlv-objs := jzdlv.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
-obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
-obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
-obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
-obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
-obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
-obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
-obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
-obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
-obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
-obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
-obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
-obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
-obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
-obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
-obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
-obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
-obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
-obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
-obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
-obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o
-obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o
obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
-obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
-obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
-obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
-obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o
-obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
-obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
-obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
-obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o
-obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
-obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
+obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_ICODEC) += snd-soc-jzcodec.o
+obj-$(CONFIG_SND_SOC_DLV) += snd-soc-jzdlv.o
diff --git a/sound/soc/codecs/jzcodec.c b/sound/soc/codecs/jzcodec.c
new file mode 100644
index 00000000000..05e9a4e1df7
--- /dev/null
+++ b/sound/soc/codecs/jzcodec.c
@@ -0,0 +1,745 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "../jz4740/jz4740-pcm.h"
+#include "jzcodec.h"
+
+#define AUDIO_NAME "jzcodec"
+#define JZCODEC_VERSION "1.0"
+
+/*
+ * Debug
+ */
+
+#define JZCODEC_DEBUG 0
+
+#ifdef JZCODEC_DEBUG
+#define dbg(format, arg...) \
+ printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) \
+ printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
+#define info(format, arg...) \
+ printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
+#define warn(format, arg...) \
+ printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
+
+struct snd_soc_codec_device soc_codec_dev_jzcodec;
+
+/* codec private data */
+struct jzcodec_data {
+ unsigned int sysclk;
+ struct snd_soc_codec codec;
+};
+
+static struct jzcodec_data jzcodec_data;
+
+/*
+ * jzcodec register cache
+ */
+static u32 jzcodec_reg[JZCODEC_CACHEREGNUM / 2];
+
+/*
+ * codec register is 16 bits width in ALSA, so we define array to store 16 bits configure paras
+ */
+static u16 jzcodec_reg_LH[JZCODEC_CACHEREGNUM];
+
+/*
+ * read jzcodec register cache
+ */
+static inline unsigned int jzcodec_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u16 *cache = codec->reg_cache;
+
+ if (reg >= JZCODEC_CACHEREGNUM)
+ return -1;
+ return cache[reg];
+}
+
+/*
+ * write jzcodec register cache
+ */
+static inline void jzcodec_write_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg, u16 value)
+{
+ u16 *cache = codec->reg_cache;
+ u32 reg_val;
+
+ if (reg >= JZCODEC_CACHEREGNUM) {
+ return;
+ }
+
+ cache[reg] = value;
+ /* update internal codec register value */
+ switch (reg) {
+ case 0:
+ case 1:
+ reg_val = cache[0] & 0xffff;
+ reg_val = reg_val | (cache[1] << 16);
+ jzcodec_reg[0] = reg_val;
+ break;
+ case 2:
+ case 3:
+ reg_val = cache[2] & 0xffff;
+ reg_val = reg_val | (cache[3] << 16);
+ jzcodec_reg[1] = reg_val;
+ break;
+ }
+}
+
+/*
+ * write to the jzcodec register space
+ */
+static int jzcodec_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ jzcodec_write_reg_cache(codec, reg, value);
+ if(codec->hw_write)
+ codec->hw_write(&value, NULL, reg);
+ return 0;
+}
+
+static int jzcodec_reset(struct snd_soc_codec *codec)
+{
+ u16 val;
+
+ val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW);
+ val = val | 0x1;
+ jzcodec_write(codec, ICODEC_1_LOW, val);
+ mdelay(1);
+
+ val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW);
+ val = val & ~0x1;
+ jzcodec_write(codec, ICODEC_1_LOW, val);
+ mdelay(1);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new jzcodec_snd_controls[] = {
+
+ //SOC_DOUBLE_R("Master Playback Volume", 1, 1, 0, 3, 0),
+ SOC_DOUBLE_R("Master Playback Volume", ICODEC_2_LOW, ICODEC_2_LOW, 0, 3, 0),
+ //SOC_DOUBLE_R("MICBG", ICODEC_2_LOW, ICODEC_2_LOW, 4, 3, 0),
+ //SOC_DOUBLE_R("Line", 2, 2, 0, 31, 0),
+ SOC_DOUBLE_R("Line", ICODEC_2_HIGH, ICODEC_2_HIGH, 0, 31, 0),
+};
+
+/* add non dapm controls */
+static int jzcodec_add_controls(struct snd_soc_codec *codec)
+{
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(jzcodec_snd_controls); i++) {
+ if ((err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&jzcodec_snd_controls[i], codec, NULL))) < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget jzcodec_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("LOUT"),
+ SND_SOC_DAPM_OUTPUT("LHPOUT"),
+ SND_SOC_DAPM_OUTPUT("ROUT"),
+ SND_SOC_DAPM_OUTPUT("RHPOUT"),
+ SND_SOC_DAPM_INPUT("MICIN"),
+ SND_SOC_DAPM_INPUT("RLINEIN"),
+ SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const struct snd_soc_dapm_route intercon_routes [] = {
+ /* output mixer */
+ {"Output Mixer", "Line Bypass Switch", "Line Input"},
+ {"Output Mixer", "HiFi Playback Switch", "DAC"},
+ {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
+
+ /* outputs */
+ {"RHPOUT", NULL, "Output Mixer"},
+ {"ROUT", NULL, "Output Mixer"},
+ {"LHPOUT", NULL, "Output Mixer"},
+ {"LOUT", NULL, "Output Mixer"},
+
+ /* input mux */
+ {"Input Mux", "Line In", "Line Input"},
+ {"Input Mux", "Mic", "Mic Bias"},
+ {"ADC", NULL, "Input Mux"},
+
+ /* inputs */
+ {"Line Input", NULL, "LLINEIN"},
+ {"Line Input", NULL, "RLINEIN"},
+ {"Mic Bias", NULL, "MICIN"},
+};
+
+static int jzcodec_add_widgets(struct snd_soc_codec *codec)
+{
+ int i,cnt;
+
+ cnt = ARRAY_SIZE(jzcodec_dapm_widgets);
+ for(i = 0; i < ARRAY_SIZE(jzcodec_dapm_widgets); i++) {
+ snd_soc_dapm_new_control(codec, &jzcodec_dapm_widgets[i]);
+ }
+
+ /* set up audio path interconnects */
+ snd_soc_dapm_add_routes(codec, intercon_routes, ARRAY_SIZE(intercon_routes));
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+static int jzcodec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ u16 reg_val = jzcodec_read_reg_cache(codec, ICODEC_2_LOW);
+
+ /* bit size. codec side */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ }
+ /* sample rate */
+ reg_val = reg_val & ~(0xf << 8);
+
+ switch (params_rate(params)) {
+ case 8000:
+ reg_val |= (0x0 << 8);
+ break;
+ case 11025:
+ reg_val |= (0x1 << 8);
+ break;
+ case 12000:
+ reg_val |= (0x2 << 8);
+ break;
+ case 16000:
+ reg_val |= (0x3 << 8);
+ break;
+ case 22050:
+ reg_val |= (0x4 << 8);
+ break;
+ case 24000:
+ reg_val |= (0x5 << 8);
+ break;
+ case 32000:
+ reg_val |= (0x6 << 8);
+ break;
+ case 44100:
+ reg_val |= (0x7 << 8);
+ break;
+ case 48000:
+ reg_val |= (0x8 << 8);
+ break;
+ default:
+ printk(" invalid rate :0x%08x\n",params_rate(params));
+ }
+
+ jzcodec_write(codec, ICODEC_2_LOW, reg_val);
+ return 0;
+}
+
+static int jzcodec_pcm_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
+{
+ int ret = 0;
+ u16 val;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ break;
+
+ case SNDRV_PCM_TRIGGER_START:
+ //case SNDRV_PCM_TRIGGER_RESUME:
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ val = 0x7302;
+ jzcodec_write(codec, ICODEC_1_LOW, val);
+ val = 0x0003;
+ jzcodec_write(codec, ICODEC_1_HIGH, val);
+ mdelay(2);
+ val = 0x6000;
+ jzcodec_write(codec, ICODEC_1_LOW, val);
+ val = 0x0300;
+ jzcodec_write(codec, ICODEC_1_HIGH, val);
+ mdelay(2);
+ val = 0x2000;
+ jzcodec_write(codec, ICODEC_1_LOW, val);
+ val = 0x0300;
+ jzcodec_write(codec, ICODEC_1_HIGH, val);
+ } else {
+ val = 0x4300;
+ jzcodec_write(codec, ICODEC_1_LOW, val);
+ val = 0x1402;
+ jzcodec_write(codec, ICODEC_1_HIGH, val);
+ }
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ //case SNDRV_PCM_TRIGGER_SUSPEND:
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ val = 0x3300;
+ jzcodec_write(codec, ICODEC_1_LOW, val);
+ val = 0x0003;
+ jzcodec_write(codec, ICODEC_1_HIGH, val);
+ } else {
+ val = 0x3300;
+ jzcodec_write(codec, ICODEC_1_LOW, val);
+ val = 0x0003;
+ jzcodec_write(codec, ICODEC_1_HIGH, val);
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int jzcodec_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ /*struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec; */
+
+ return 0;
+}
+
+static void jzcodec_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ /* deactivate */
+ if (!codec->active) {
+ udelay(50);
+ }
+}
+
+static int jzcodec_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW);
+
+ if (mute != 0)
+ mute = 1;
+ if (mute)
+ reg_val = reg_val | (0x1 << 14);
+ else
+ reg_val = reg_val & ~(0x1 << 14);
+
+ jzcodec_write(codec, ICODEC_1_LOW, reg_val);
+ return 0;
+}
+
+static int jzcodec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct jzcodec_data *jzcodec = codec->private_data;
+
+ jzcodec->sysclk = freq;
+ return 0;
+}
+/*
+ * Set's ADC and Voice DAC format. called by pavo_hw_params() in pavo.c
+ */
+static int jzcodec_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ /* struct snd_soc_codec *codec = codec_dai->codec; */
+
+ /* set master/slave audio interface. codec side */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* set master mode for codec */
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* set slave mode for codec */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format . set some parameter for codec side */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* set I2S mode for codec */
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ /* set right J mode */
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ /* set left J mode */
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ /* set dsp A mode */
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ /* set dsp B mode */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion. codec side */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* jzcodec_write(codec, 0, val); */
+ return 0;
+}
+
+static int jzcodec_dapm_event(struct snd_soc_codec *codec, int event)
+{
+/* u16 reg_val; */
+
+ switch (event) {
+ case SNDRV_CTL_POWER_D0: /* full On */
+ /* vref/mid, osc on, dac unmute */
+ /* u16 reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); */
+ /* jzcodec_write(codec, 0, val); */
+ break;
+ case SNDRV_CTL_POWER_D1: /* partial On */
+ case SNDRV_CTL_POWER_D2: /* partial On */
+ break;
+ case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+ /* everything off except vref/vmid, */
+ /*reg_val = 0x0800;
+ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val);
+ reg_val = 0x0017;
+ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val);
+ REG_ICDC_CDCCR1 = jzcodec_reg[0];
+ mdelay(2);
+ reg_val = 0x2102;
+ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val);
+ reg_val = 0x001f;
+ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val);
+ REG_ICDC_CDCCR1 = jzcodec_reg[0];
+ mdelay(2);
+ reg_val = 0x3302;
+ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val);
+ reg_val = 0x0003;
+ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val);
+ REG_ICDC_CDCCR1 = jzcodec_reg[0];*/
+ break;
+ case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+ /* everything off, dac mute, inactive */
+ /*reg_val = 0x2302;
+ jzcodec_write(codec, ICODEC_1_LOW, reg_val);
+ reg_val = 0x001b;
+ jzcodec_write(codec, ICODEC_1_HIGH, reg_val);
+ mdelay(1);
+ reg_val = 0x2102;
+ jzcodec_write(codec, ICODEC_1_LOW, reg_val);
+ reg_val = 0x001b;
+ jzcodec_write(codec, ICODEC_1_HIGH, reg_val);*/
+ break;
+ }
+// codec->dapm_state = event;
+ return 0;
+}
+
+#define JZCODEC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000)
+
+#define JZCODEC_FORMATS (SNDRV_PCM_FORMAT_S8 | SNDRV_PCM_FMTBIT_S16_LE)
+
+static struct snd_soc_dai_ops jzcodec_dai_ops = {
+ .trigger = jzcodec_pcm_trigger,
+ .prepare = jzcodec_pcm_prepare,
+ .hw_params = jzcodec_hw_params,
+ .shutdown = jzcodec_shutdown,
+ .digital_mute = jzcodec_mute,
+ .set_sysclk = jzcodec_set_dai_sysclk,
+ .set_fmt = jzcodec_set_dai_fmt,
+};
+
+struct snd_soc_dai jzcodec_dai = {
+ .name = "JZCODEC",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = JZCODEC_RATES,
+ .formats = JZCODEC_FORMATS,},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = JZCODEC_RATES,
+ .formats = JZCODEC_FORMATS,},
+ .ops = &jzcodec_dai_ops,
+};
+EXPORT_SYMBOL_GPL(jzcodec_dai);
+
+#ifdef CONFIG_PM
+static u16 jzcodec_reg_pm[JZCODEC_CACHEREGNUM];
+static int jzcodec_suspend(struct platform_device *pdev, pm_message_t state)
+{
+#if 0
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ jzcodec_reg_pm[ICODEC_1_LOW] = jzcodec_read_reg_cache(codec, ICODEC_1_LOW);
+ jzcodec_reg_pm[ICODEC_1_HIGH] = jzcodec_read_reg_cache(codec, ICODEC_1_HIGH);
+ jzcodec_reg_pm[ICODEC_2_LOW] = jzcodec_read_reg_cache(codec, ICODEC_2_LOW);
+ jzcodec_reg_pm[ICODEC_2_HIGH] = jzcodec_read_reg_cache(codec, ICODEC_2_HIGH);
+
+ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+#endif
+ return 0;
+}
+
+static int jzcodec_resume(struct platform_device *pdev)
+{
+#if 0
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+ u16 reg_val;
+
+ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+ reg_val = jzcodec_reg_pm[ICODEC_1_LOW];
+ jzcodec_write(codec, ICODEC_1_LOW, reg_val);
+ reg_val = jzcodec_reg_pm[ICODEC_1_HIGH];
+ jzcodec_write(codec, ICODEC_1_HIGH, reg_val);
+ reg_val = jzcodec_reg_pm[ICODEC_2_LOW];
+ jzcodec_write(codec, ICODEC_2_LOW, reg_val);
+ reg_val = jzcodec_reg_pm[ICODEC_2_HIGH];
+ jzcodec_write(codec, ICODEC_2_HIGH, reg_val);
+
+ jzcodec_dapm_event(codec, codec->suspend_dapm_state);
+#endif
+ return 0;
+}
+#else
+#define jzcodec_suspend NULL
+#define jzcodec_resume NULL
+#endif
+
+static int write_codec_reg(u16 * add, char * name, int reg)
+{
+ switch (reg) {
+ case 0:
+ case 1:
+ REG_ICDC_CDCCR1 = jzcodec_reg[0];
+ break;
+ case 2:
+ case 3:
+ REG_ICDC_CDCCR2 = jzcodec_reg[1];
+ break;
+ }
+ return 0;
+}
+
+
+/*
+ * initialise the JZCODEC driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+
+static int jzcodec_soc_codec_setup(struct snd_soc_codec *codec)
+{
+ int reg, ret = 0;
+
+ codec->hw_write = (hw_write_t)write_codec_reg;
+
+ for (reg = 0; reg < JZCODEC_CACHEREGNUM / 2; reg++) {
+ switch (reg) {
+ case 0:
+ jzcodec_reg[reg] = REG_ICDC_CDCCR1;
+ jzcodec_reg_LH[ICODEC_1_LOW] = jzcodec_reg[reg] & 0xffff;
+ jzcodec_reg_LH[ICODEC_1_HIGH] = (jzcodec_reg[reg] & 0xffff0000) >> 16;
+ break;
+ case 1:
+ jzcodec_reg[reg] = REG_ICDC_CDCCR2;
+ jzcodec_reg_LH[ICODEC_2_LOW] = jzcodec_reg[reg] & 0xffff;
+ jzcodec_reg_LH[ICODEC_2_HIGH] = (jzcodec_reg[reg] & 0xffff0000) >> 16;
+ break;
+ }
+ }
+
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->name = "JZCODEC";
+ codec->owner = THIS_MODULE;
+ codec->read = jzcodec_read_reg_cache;
+ codec->write = jzcodec_write;
+ //codec->dapm_event = jzcodec_dapm_event;
+ codec->dai = &jzcodec_dai;
+ codec->num_dai = 1;
+ codec->reg_cache_size = sizeof(jzcodec_reg_LH);
+ codec->reg_cache = kmemdup(jzcodec_reg_LH, sizeof(jzcodec_reg_LH), GFP_KERNEL);
+ if (codec->reg_cache == NULL)
+ return -ENOMEM;
+
+ jzcodec_reset(codec);
+
+ ret = snd_soc_register_codec(codec);
+ if (ret < 0) {
+ printk(KERN_ERR "jzdlv: failed to register codec.\n");
+ kfree(codec->reg_cache);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int jzcodec_soc_dev_setup(struct snd_soc_device *socdev, struct snd_soc_codec *codec)
+{
+ int ret;
+
+ u16 reg_val;
+
+ socdev->card->codec = codec;
+ mutex_init(&codec->mutex);
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ printk(KERN_ERR "jzcodec: failed to create pcms\n");
+ return ret;
+ }
+
+ /* power on device */
+ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+
+ /* clear suspend bit of jz4740 internal codec */
+ reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW);
+ reg_val = reg_val & ~(0x2);
+ jzcodec_write(codec, ICODEC_1_LOW, reg_val);
+ /* set vol bits */
+ reg_val = jzcodec_read_reg_cache(codec, ICODEC_2_LOW);
+ reg_val = reg_val | 0x3;
+ jzcodec_write(codec, ICODEC_2_LOW, reg_val);
+ /* set line in capture gain bits */
+ reg_val = jzcodec_read_reg_cache(codec, ICODEC_2_HIGH);
+ reg_val = reg_val | 0x1f;
+ jzcodec_write(codec, ICODEC_2_HIGH, reg_val);
+ /* set mic boost gain bits */
+ reg_val = jzcodec_read_reg_cache(codec, ICODEC_2_LOW);
+ reg_val = reg_val | (0x3 << 4);
+ jzcodec_write(codec, ICODEC_2_LOW, reg_val);
+ mdelay(5);
+ reg_val = 0x3300;
+ jzcodec_write(codec, ICODEC_1_LOW, reg_val);
+ reg_val = 0x0003;
+ jzcodec_write(codec, ICODEC_1_HIGH, reg_val);
+ jzcodec_add_controls(codec);
+ jzcodec_add_widgets(codec);
+
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "jzcodec: failed to register card\n");
+ goto card_err;
+ }
+ return ret;
+
+card_err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return ret;
+}
+
+static struct snd_soc_device *jzcodec_socdev;
+
+static int jzcodec_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = &jzcodec_data.codec;
+
+ jzcodec_socdev = socdev;
+
+ return jzcodec_soc_dev_setup(socdev, codec);
+}
+
+/* power down chip */
+static int jzcodec_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ if (codec->control_data)
+ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_jzcodec = {
+ .probe = jzcodec_probe,
+ .remove = jzcodec_remove,
+ .suspend = jzcodec_suspend,
+ .resume = jzcodec_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_jzcodec);
+
+static int __init jzcodec_init(void)
+{
+ struct snd_soc_codec *codec = &jzcodec_data.codec;
+
+ int rv;
+
+ codec->private_data = &jzcodec_data;
+ rv = jzcodec_soc_codec_setup(codec);
+ if (rv)
+ return rv;
+
+ return snd_soc_register_dai(&jzcodec_dai);
+}
+module_init(jzcodec_init);
+
+static void __exit jzcodec_exit(void)
+{
+ snd_soc_unregister_dai(&jzcodec_dai);
+}
+module_exit(jzcodec_exit);
+
+
+MODULE_DESCRIPTION("ASoC JZCODEC driver");
+MODULE_AUTHOR("Richard");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/jzcodec.h b/sound/soc/codecs/jzcodec.h
new file mode 100644
index 00000000000..78561327864
--- /dev/null
+++ b/sound/soc/codecs/jzcodec.h
@@ -0,0 +1,22 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ICODEC_H
+#define _ICODEC_H
+
+/* jzcodec register space */
+#define ICODEC_1_LOW 0x00 /* bit0 -- bit15 in CDCCR1 */
+#define ICODEC_1_HIGH 0x01 /* bit16 -- bit31 in CDCCR1 */
+#define ICODEC_2_LOW 0x02 /* bit0 -- bit16 in CDCCR2 */
+#define ICODEC_2_HIGH 0x03 /* bit16 -- bit31 in CDCCR2 */
+
+#define JZCODEC_CACHEREGNUM 4
+#define JZCODEC_SYSCLK 0
+
+extern struct snd_soc_dai jzcodec_dai;
+extern struct snd_soc_codec_device soc_codec_dev_jzcodec;
+
+#endif
diff --git a/sound/soc/codecs/jzdlv.c b/sound/soc/codecs/jzdlv.c
new file mode 100644
index 00000000000..f9b393f409d
--- /dev/null
+++ b/sound/soc/codecs/jzdlv.c
@@ -0,0 +1,969 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "../jz4750/jz4750-pcm.h"
+#include "jzdlv.h"
+
+#define AUDIO_NAME "jzdlv"
+#define JZDLV_VERSION "1.0"
+
+/*
+ * Debug
+ */
+
+#define JZDLV_DEBUG 0
+
+#ifdef JZDLV_DEBUG
+#define dbg(format, arg...) \
+ printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) \
+ printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
+#define info(format, arg...) \
+ printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
+#define warn(format, arg...) \
+ printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
+
+/* codec private data */
+struct jzdlv_data {
+ unsigned int sysclk;
+ struct snd_soc_codec codec;
+};
+
+static struct jzdlv_data jzdlv_data;
+/*
+ * jzdlv register cache
+ */
+static u16 jzdlv_reg[JZDLV_CACHEREGNUM];
+
+int read_codec_file(int addr)
+{
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ mdelay(1);
+ return(__icdc_get_value());
+}
+
+static void printk_codec_files(void)
+{
+ int cnt, val;
+
+ //printk("\n");
+#if 0
+ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR);
+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR);
+ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR);
+ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR);
+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR);
+ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR);
+ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR);
+ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA);
+#endif
+ for (cnt = 0; cnt < JZDLV_CACHEREGNUM ; cnt++) {
+ val = read_codec_file(cnt);
+ jzdlv_reg[cnt] = val;
+ //printk(" ( %d : 0x%x ) ",cnt ,jzdlv_reg[cnt]);
+ }
+ //printk("\n");
+}
+
+void write_codec_file(int addr, int val)
+{
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ __icdc_set_cmd(val); /* write */
+ mdelay(1);
+ __icdc_set_rgwr();
+ mdelay(1);
+ //jzdlv_reg[addr] = val;
+}
+EXPORT_SYMBOL(write_codec_file);
+
+int write_codec_file_bit(int addr, int bitval, int mask_bit)
+{
+ int val;
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ mdelay(1);
+ val = __icdc_get_value(); /* read */
+
+ val &= ~(1 << mask_bit);
+ if (bitval == 1)
+ val |= 1 << mask_bit;
+#if 0
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ __icdc_set_cmd(val); /* write */
+ mdelay(1);
+ __icdc_set_rgwr();
+ mdelay(1);
+#else
+ write_codec_file(addr, val);
+#endif
+ while (__icdc_rgwr_ready());
+ __icdc_set_addr(addr);
+ val = __icdc_get_value(); /* read */
+
+ if (((val >> mask_bit) & bitval) == bitval)
+ return 1;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(write_codec_file_bit);
+
+/*
+ * read jzdlv register cache
+ */
+static inline unsigned int jzdlv_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u16 *cache = codec->reg_cache;
+
+ if (reg >= JZDLV_CACHEREGNUM)
+ return -1;
+ return cache[reg];
+}
+
+static inline unsigned int jzdlv_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u8 data;
+ data = reg;
+ if (codec->hw_write(codec->control_data, &data, 1) != 1)
+ return -EIO;
+
+ if (codec->hw_read(codec->control_data, &data, 1) != 1)
+ return -EIO;
+
+ return data;
+}
+
+/*
+ * write jzdlv register cache
+ */
+static inline void jzdlv_write_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg, u16 value)
+{
+ u16 *cache = codec->reg_cache;
+
+ if (reg >= JZDLV_CACHEREGNUM) {
+ return;
+ }
+
+ cache[reg] = value;
+
+}
+
+/*
+ * write to the jzdlv register space
+ */
+static int jzdlv_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ jzdlv_write_reg_cache(codec, reg, value);
+ if(codec->hw_write)
+ codec->hw_write(&value, NULL, reg);
+ return 0;
+}
+
+/* set Audio data replay */
+void set_audio_data_replay(void)
+{
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x20);// only CCMC
+ mdelay(10);
+
+ /* DAC path */
+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ mdelay(100);
+ write_codec_file_bit(1, 0, 5);//DAC_MUTE->0
+}
+
+/* unset Audio data replay */
+void unset_audio_data_replay(void)
+{
+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
+ mdelay(200);
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ write_codec_file_bit(5, 1, 7);//SB_DAC->1
+ write_codec_file_bit(5, 1, 4);//SB_MIX->1
+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
+ write_codec_file_bit(6, 1, 1);//SB->1
+
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+}
+
+/* set Record MIC input audio without playback */
+static void set_record_mic_input_audio_without_playback(void)
+{
+ /* ADC path for MIC IN */
+ write_codec_file_bit(1, 1, 2);
+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1
+
+ write_codec_file(22, 0x40);//mic 1
+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1
+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
+
+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
+ write_codec_file_bit(6, 1, 3);// gain set
+
+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
+ mdelay(100);
+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
+ write_codec_file(1, 0x4);
+}
+
+/* unset Record MIC input audio without playback */
+static void unset_record_mic_input_audio_without_playback(void)
+{
+ /* ADC path for MIC IN */
+ write_codec_file_bit(5, 1, 4);//SB_ADC->1
+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
+ write_codec_file(22, 0xc0);//CR3.SB_MIC1
+}
+
+#if 0
+static irqreturn_t aic_codec_irq(int irq, void *dev_id)
+{
+ u8 file_9 = read_codec_file(9);
+ u8 file_8 = read_codec_file(8);
+
+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9);
+ if ((file_9 & 0x1f) == 0x10) {
+ // have hp short circuit
+ write_codec_file(8, 0x3f);//mask all interrupt
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ mdelay(300);
+ while ((read_codec_file(9) & 0x4) != 0x4);
+ while ((read_codec_file(9) & 0x10) == 0x10) {
+ write_codec_file(9, 0x10);
+ }
+ write_codec_file_bit(5, 0, 6);//SB_OUT->0
+ mdelay(300);
+ while ((read_codec_file(9) & 0x8) != 0x8);
+ write_codec_file(9, file_9);
+ write_codec_file(8, file_8);
+
+ return IRQ_HANDLED;
+ }
+
+ if (file_9 & 0x8)
+ ramp_up_end = jiffies;
+ else if (file_9 & 0x4)
+ ramp_down_end = jiffies;
+ else if (file_9 & 0x2)
+ gain_up_end = jiffies;
+ else if (file_9 & 0x1)
+ gain_down_end = jiffies;
+
+ write_codec_file(9, file_9);
+ if (file_9 & 0xf)
+ wake_up(&pop_wait_queue);
+ while (REG_ICDC_RGDATA & 0x100);
+
+ return IRQ_HANDLED;
+}
+#else
+static irqreturn_t aic_codec_irq(int irq, void *dev_id)
+{
+ u8 file_9 = read_codec_file(9);
+ u8 file_8 = read_codec_file(8);
+
+ //printk("--- 1 8:0x%x 9:0x%x ---\n",file_8,file_9);
+ if ((file_9 & 0x1f) == 0x10) {
+ write_codec_file(8, 0x3f);
+ write_codec_file_bit(5, 1, 6);//SB_OUT->1
+ mdelay(300);
+ while ((read_codec_file(9) & 0x4) != 0x4);
+ while ((read_codec_file(9) & 0x10) == 0x10) {
+ write_codec_file(9, 0x10);
+ }
+ write_codec_file_bit(5, 0, 6);//SB_OUT->0
+ mdelay(300);
+ while ((read_codec_file(9) & 0x8) != 0x8);
+ write_codec_file(9, file_9);
+ write_codec_file(8, file_8);
+
+ return IRQ_HANDLED;
+ }
+ /*if (file_9 & 0x8)
+ ramp_up_end = jiffies;
+ else if (file_9 & 0x4)
+ ramp_down_end = jiffies;
+ else if (file_9 & 0x2)
+ gain_up_end = jiffies;
+ else if (file_9 & 0x1)
+ gain_down_end = jiffies;*/
+
+ write_codec_file(9, file_9);
+ /*if (file_9 & 0xf)
+ wake_up(&pop_wait_queue);*/
+ while (REG_ICDC_RGDATA & 0x100);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+static int jzdlv_reset(struct snd_soc_codec *codec)
+{
+ /* reset DLV codec. from hibernate mode to sleep mode */
+ write_codec_file(0, 0xf);
+ write_codec_file_bit(6, 0, 0);
+ write_codec_file_bit(6, 0, 1);
+ mdelay(200);
+ //write_codec_file(0, 0xf);
+ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
+ write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0
+ mdelay(10);//wait for stability
+
+ return 0;
+}
+
+
+#if 0
+static int jzdlv_sync(struct snd_soc_codec *codec)
+{
+ u16 *cache = codec->reg_cache;
+ int i, r = 0;
+
+ for (i = 0; i < JZDLV_CACHEREGNUM; i++)
+ r |= jzdlv_write(codec, i, cache[i]);
+
+ return r;
+};
+#endif
+
+static const struct snd_kcontrol_new jzdlv_snd_controls[] = {
+
+ //SOC_DOUBLE_R("Master Playback Volume", 1, 1, 0, 3, 0),
+ SOC_DOUBLE_R("Master Playback Volume", DLV_CGR8, DLV_CGR9, 0, 31, 0),
+ //SOC_DOUBLE_R("MICBG", ICODEC_2_LOW, ICODEC_2_LOW, 4, 3, 0),
+ //SOC_DOUBLE_R("Line", 2, 2, 0, 31, 0),
+ SOC_DOUBLE_R("Line", DLV_CGR10, DLV_CGR10, 0, 31, 0),
+};
+
+/* add non dapm controls */
+static int jzdlv_add_controls(struct snd_soc_codec *codec)
+{
+ return snd_soc_add_controls(codec, jzdlv_snd_controls, ARRAY_SIZE(jzdlv_snd_controls));
+}
+
+static const struct snd_soc_dapm_widget jzdlv_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("LOUT"),
+ SND_SOC_DAPM_OUTPUT("LHPOUT"),
+ SND_SOC_DAPM_OUTPUT("ROUT"),
+ SND_SOC_DAPM_OUTPUT("RHPOUT"),
+ SND_SOC_DAPM_INPUT("MICIN"),
+ SND_SOC_DAPM_INPUT("RLINEIN"),
+ SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const struct snd_soc_dapm_route intercon_routes [] = {
+ /* output mixer */
+ {"Output Mixer", "Line Bypass Switch", "Line Input"},
+ {"Output Mixer", "HiFi Playback Switch", "DAC"},
+ {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
+
+ /* outputs */
+ {"RHPOUT", NULL, "Output Mixer"},
+ {"ROUT", NULL, "Output Mixer"},
+ {"LHPOUT", NULL, "Output Mixer"},
+ {"LOUT", NULL, "Output Mixer"},
+
+ /* input mux */
+ {"Input Mux", "Line In", "Line Input"},
+ {"Input Mux", "Mic", "Mic Bias"},
+ {"ADC", NULL, "Input Mux"},
+
+ /* inputs */
+ {"Line Input", NULL, "LLINEIN"},
+ {"Line Input", NULL, "RLINEIN"},
+ {"Mic Bias", NULL, "MICIN"},
+};
+
+static void init_codec(void)
+{
+ /* reset DLV codec. from hibernate mode to sleep mode */
+ write_codec_file(0, 0xf);
+ write_codec_file_bit(6, 0, 0);
+ write_codec_file_bit(6, 0, 1);
+ mdelay(200);
+ //write_codec_file(0, 0xf);
+ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
+ write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0
+ mdelay(10);//wait for stability
+}
+
+static int jzdlv_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, jzdlv_dapm_widgets, ARRAY_SIZE(jzdlv_dapm_widgets));
+ /* set up audio path interconnects */
+ snd_soc_dapm_add_routes(codec, intercon_routes, ARRAY_SIZE(intercon_routes));
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+static int jzdlv_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ int speed = 0;
+ int val = 0;
+
+ /* sample channel */
+ switch (params_channels(params)) {
+ case 1:
+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono
+ break;
+ case 2:
+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo
+ break;
+ }
+ /* sample rate */
+ switch (params_rate(params)) {
+ case 8000:
+ speed = 10;
+ break;
+ case 9600:
+ speed = 9;
+ break;
+ case 11025:
+ speed = 8;
+ break;
+ case 12000:
+ speed = 7;
+ break;
+ case 16000:
+ speed = 6;
+ break;
+ case 22050:
+ speed = 5;
+ break;
+ case 24000:
+ speed = 4;
+ break;
+ case 32000:
+ speed = 3;
+ break;
+ case 44100:
+ speed = 2;
+ break;
+ case 48000:
+ speed = 1;
+ break;
+ case 96000:
+ speed = 0;
+ break;
+ default:
+ printk(" invalid rate :0x%08x\n",params_rate(params));
+ }
+
+ val = (speed << 4) | speed;
+ jzdlv_write(codec, DLV_CCR2, val);
+
+ return 0;
+}
+
+static int jzdlv_pcm_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ break;
+ case SNDRV_PCM_TRIGGER_START:
+ //case SNDRV_PCM_TRIGGER_RESUME:
+
+ init_codec();
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ set_audio_data_replay();
+ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
+ mdelay(300);
+ REG_AIC_I2SCR = 0x10;
+ mdelay(20);
+ __aic_flush_fifo();
+ } else {
+ set_record_mic_input_audio_without_playback();
+ mdelay(10);
+ REG_AIC_I2SCR = 0x10;
+ mdelay(20);
+ __aic_flush_fifo();
+ write_codec_file_bit(5, 1, 7);
+ }
+
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ //case SNDRV_PCM_TRIGGER_SUSPEND:
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ unset_audio_data_replay();
+ } else {
+ unset_record_mic_input_audio_without_playback();
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int jzdlv_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ /*struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec; */
+
+ return 0;
+}
+
+static void jzdlv_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ /* deactivate */
+ if (!codec->active) {
+ udelay(50);
+ }
+}
+
+static int jzdlv_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 reg_val = jzdlv_read_reg_cache(codec, 2/*DLV_1_LOW*/);
+
+ if (mute != 0)
+ mute = 1;
+ if (mute)
+ reg_val = reg_val | (0x1 << 14);
+ else
+ reg_val = reg_val & ~(0x1 << 14);
+
+ //jzdlv_write(codec, DLV_1_LOW, reg_val);
+ return 0;
+}
+
+static int jzdlv_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct jzdlv_data *jzdlv = codec->private_data;
+
+ jzdlv->sysclk = freq;
+ return 0;
+}
+/*
+ * Set's ADC and Voice DAC format. called by apus_hw_params() in apus.c
+ */
+static int jzdlv_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ /* struct snd_soc_codec *codec = codec_dai->codec; */
+
+ /* set master/slave audio interface. codec side */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* set master mode for codec */
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* set slave mode for codec */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format . set some parameter for codec side */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* set I2S mode for codec */
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ /* set right J mode */
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ /* set left J mode */
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ /* set dsp A mode */
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ /* set dsp B mode */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion. codec side */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* jzcodec_write(codec, 0, val); */
+ return 0;
+}
+
+static int jzdlv_dapm_event(struct snd_soc_codec *codec, int event)
+{
+/* u16 reg_val; */
+
+ switch (event) {
+ case SNDRV_CTL_POWER_D0: /* full On */
+ /* vref/mid, osc on, dac unmute */
+ /* u16 reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); */
+ /* jzcodec_write(codec, 0, val); */
+ break;
+ case SNDRV_CTL_POWER_D1: /* partial On */
+ case SNDRV_CTL_POWER_D2: /* partial On */
+ break;
+ case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+ /* everything off except vref/vmid, */
+ /*reg_val = 0x0800;
+ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val);
+ reg_val = 0x0017;
+ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val);
+ REG_ICDC_CDCCR1 = jzcodec_reg[0];
+ mdelay(2);
+ reg_val = 0x2102;
+ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val);
+ reg_val = 0x001f;
+ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val);
+ REG_ICDC_CDCCR1 = jzcodec_reg[0];
+ mdelay(2);
+ reg_val = 0x3302;
+ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val);
+ reg_val = 0x0003;
+ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val);
+ REG_ICDC_CDCCR1 = jzcodec_reg[0];*/
+ break;
+ case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+ /* everything off, dac mute, inactive */
+ /*reg_val = 0x2302;
+ jzcodec_write(codec, ICODEC_1_LOW, reg_val);
+ reg_val = 0x001b;
+ jzcodec_write(codec, ICODEC_1_HIGH, reg_val);
+ mdelay(1);
+ reg_val = 0x2102;
+ jzcodec_write(codec, ICODEC_1_LOW, reg_val);
+ reg_val = 0x001b;
+ jzcodec_write(codec, ICODEC_1_HIGH, reg_val);*/
+ break;
+ }
+ //codec->dapm_state = event;
+ return 0;
+}
+
+#define JZDLV_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000)
+
+#define JZDLV_FORMATS (SNDRV_PCM_FORMAT_S8 | SNDRV_PCM_FMTBIT_S16_LE)
+
+static struct snd_soc_dai_ops jzdlv_dai_ops = {
+ .trigger = jzdlv_pcm_trigger,
+ .prepare = jzdlv_pcm_prepare,
+ .hw_params = jzdlv_hw_params,
+ .shutdown = jzdlv_shutdown,
+ .digital_mute = jzdlv_mute,
+ .set_sysclk = jzdlv_set_dai_sysclk,
+ .set_fmt = jzdlv_set_dai_fmt,
+};
+
+struct snd_soc_dai jzdlv_dai = {
+ .name = "JZDLV",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = JZDLV_RATES,
+ .formats = JZDLV_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = JZDLV_RATES,
+ .formats = JZDLV_FORMATS,
+ },
+ .ops = &jzdlv_dai_ops,
+};
+EXPORT_SYMBOL_GPL(jzdlv_dai);
+
+#ifdef CONFIG_PM
+//static u16 jzdlv_reg_pm[JZDLV_CACHEREGNUM];
+static int jzdlv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+// struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ //struct snd_soc_codec *codec = socdev->card->codec;
+#if 0
+ jzcodec_reg_pm[ICODEC_1_LOW] = jzcodec_read_reg_cache(codec, ICODEC_1_LOW);
+ jzcodec_reg_pm[ICODEC_1_HIGH] = jzcodec_read_reg_cache(codec, ICODEC_1_HIGH);
+ jzcodec_reg_pm[ICODEC_2_LOW] = jzcodec_read_reg_cache(codec, ICODEC_2_LOW);
+ jzcodec_reg_pm[ICODEC_2_HIGH] = jzcodec_read_reg_cache(codec, ICODEC_2_HIGH);
+
+ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+#endif
+ return 0;
+}
+
+static int jzdlv_resume(struct platform_device *pdev)
+{
+// struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ //struct snd_soc_codec *codec = socdev->card->codec;
+ //u16 reg_val;
+#if 0
+ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+ reg_val = jzcodec_reg_pm[ICODEC_1_LOW];
+ jzcodec_write(codec, ICODEC_1_LOW, reg_val);
+ reg_val = jzcodec_reg_pm[ICODEC_1_HIGH];
+ jzcodec_write(codec, ICODEC_1_HIGH, reg_val);
+ reg_val = jzcodec_reg_pm[ICODEC_2_LOW];
+ jzcodec_write(codec, ICODEC_2_LOW, reg_val);
+ reg_val = jzcodec_reg_pm[ICODEC_2_HIGH];
+ jzcodec_write(codec, ICODEC_2_HIGH, reg_val);
+
+ jzcodec_dapm_event(codec, codec->suspend_dapm_state);
+#endif
+ return 0;
+}
+#else
+#define jzdlv_suspend NULL
+#define jzdlv_resume NULL
+#endif
+/*
+ * initialise the JZDLV driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static struct snd_soc_device *jzdlv_socdev;
+
+static int write_codec_reg(u16 * add, char * name, int reg)
+{
+ write_codec_file(reg, *add);
+
+ return 0;
+}
+
+static int jzdlv_soc_codec_setup(struct snd_soc_codec *codec)
+{
+ int ret;
+
+ /* Add other interfaces here ,no I2C connection */
+ codec->hw_write = (hw_write_t)write_codec_reg;
+ //codec->hw_read = (hw_read_t)read_codec_reg;
+
+ /*REG_CPM_CPCCR &= ~(1 << 31);
+ REG_CPM_CPCCR &= ~(1 << 30);*/
+ write_codec_file(0, 0xf);
+
+ REG_AIC_I2SCR = 0x10;
+ __i2s_internal_codec();
+ __i2s_as_slave();
+ __i2s_select_i2s();
+ __aic_select_i2s();
+ __aic_reset();
+ mdelay(10);
+ REG_AIC_I2SCR = 0x10;
+ mdelay(20);
+
+ /* power on DLV */
+ write_codec_file(8, 0x3f);
+ write_codec_file(9, 0xff);
+ mdelay(10);
+
+ /* Stage 1 Start. */
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->name = "JZDLV";
+ codec->owner = THIS_MODULE;
+ codec->read = jzdlv_read_reg_cache;
+ codec->write = jzdlv_write;
+ //codec->dapm_event = jzdlv_dapm_event;
+ codec->dai = &jzdlv_dai;
+ codec->num_dai = 1;
+ codec->reg_cache_size = sizeof(jzdlv_reg);
+ codec->reg_cache = kmemdup(jzdlv_reg, sizeof(jzdlv_reg), GFP_KERNEL);
+ if (codec->reg_cache == NULL) {
+ printk(KERN_ERR "jzdlv: no enough memory for kmemdup.\n");
+ return -ENOMEM;
+ }
+
+ jzdlv_reset(codec);
+
+ ret = snd_soc_register_codec(codec);
+ if (ret < 0) {
+ printk(KERN_ERR "jzdlv: failed to register codec.\n");
+ kfree(codec->reg_cache);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int jzdlv_soc_dev_setup(struct snd_soc_device *socdev, struct snd_soc_codec *codec)
+{
+ int ret;
+
+ socdev->card->codec = codec;
+ mutex_init(&codec->mutex);
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ printk(KERN_ERR "jzdlv: failed to create pcms\n");
+ goto err;
+ }
+
+ /* power on device */
+ jzdlv_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+
+ ret = jzdlv_add_controls(codec);
+ if (ret)
+ goto err;
+
+ ret = jzdlv_add_widgets(codec);
+ if (ret)
+ goto err;
+
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "jzcodec: failed to register card\n");
+ goto err;
+ }
+
+ mdelay(10);
+ REG_AIC_I2SCR = 0x10;
+ mdelay(20);
+
+ /* power on DLV */
+ write_codec_file(9, 0xff);
+ write_codec_file(8, 0x3f);
+
+ ret = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL);
+ if (ret) {
+ printk("Could not get aic codec irq %d\n", IRQ_AIC);
+ goto err;
+ }
+
+ printk_codec_files();
+
+ return ret;
+
+err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return ret;
+}
+
+static int jzdlv_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = &jzdlv_data.codec;
+
+ jzdlv_socdev = socdev;
+
+ return jzdlv_soc_dev_setup(socdev, codec);
+}
+
+/* power down chip */
+static int jzdlv_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = &jzdlv_data.codec;
+
+ if (codec->control_data)
+ jzdlv_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+ kfree(codec->private_data);
+ kfree(codec);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_jzdlv = {
+ .probe = jzdlv_probe,
+ .remove = jzdlv_remove,
+ .suspend = jzdlv_suspend,
+ .resume = jzdlv_resume,
+};
+
+EXPORT_SYMBOL(soc_codec_dev_jzdlv);
+
+static int __init jzdlv_init(void)
+{
+ struct snd_soc_codec *codec = &jzdlv_data.codec;
+
+ int rv;
+
+ codec->private_data = &jzdlv_data;
+ rv = jzdlv_soc_codec_setup(codec);
+ if (rv)
+ return rv;
+
+ return snd_soc_register_dai(&jzdlv_dai);
+}
+module_init(jzdlv_init);
+
+static void __exit jzdlv_exit(void)
+{
+ snd_soc_unregister_dai(&jzdlv_dai);
+}
+module_exit(jzdlv_exit);
+
+MODULE_DESCRIPTION("ASoC JZDLV driver");
+MODULE_AUTHOR("Richard");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/jzdlv.h b/sound/soc/codecs/jzdlv.h
new file mode 100644
index 00000000000..319eae18740
--- /dev/null
+++ b/sound/soc/codecs/jzdlv.h
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _DLV_H
+#define _DLV_H
+
+/* jzdlv register space */
+
+#define DLV_AICR 0x00
+#define DLV_CR1 0x01
+#define DLV_CR2 0x02
+#define DLV_CCR1 0x03
+#define DLV_CCR2 0x04
+#define DLV_PMR1 0x05
+#define DLV_PMR2 0x06
+#define DLV_CRR 0x07
+#define DLV_ICR 0x08
+#define DLV_IFR 0x09
+#define DLV_CGR1 0x0a
+#define DLV_CGR2 0x0b
+#define DLV_CGR3 0x0c
+#define DLV_CGR4 0x0d
+#define DLV_CGR5 0x0e
+#define DLV_CGR6 0x0f
+#define DLV_CGR7 0x10
+#define DLV_CGR8 0x11
+#define DLV_CGR9 0x12
+#define DLV_CGR10 0x13
+#define DLV_TR1 0x14
+#define DLV_TR2 0x15
+#define DLV_CR3 0x16
+#define DLV_AGC1 0x17
+#define DLV_AGC2 0x18
+#define DLV_AGC3 0x19
+#define DLV_AGC4 0x1a
+#define DLV_AGC5 0x1b
+
+#define JZDLV_CACHEREGNUM (DLV_AGC5+1)
+#define JZDLV_SYSCLK 0
+
+int read_codec_file(int addr);
+int write_codec_file_bit(int addr, int bitval, int mask_bit);
+void write_codec_file(int addr, int val);
+
+extern struct snd_soc_dai jzdlv_dai;
+extern struct snd_soc_codec_device soc_codec_dev_jzdlv;
+
+#endif
diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig
new file mode 100644
index 00000000000..0bfbffeee54
--- /dev/null
+++ b/sound/soc/jz4740/Kconfig
@@ -0,0 +1,34 @@
+config SND_JZ4740_SOC
+ tristate "SoC Audio for Ingenic jz4740 chip"
+ depends on (JZ4740_PAVO || JZ4725_DIPPER || JZ4720_VIRGO) && SND_SOC
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the Jz4740 AC97, I2S or SSP interface. You will also need
+ to select the audio interfaces to support below.
+
+config SND_JZ4740_SOC_PAVO
+ tristate "SoC Audio support for Ingenic Jz4740 PAVO board"
+ depends on SND_JZ4740_SOC
+ help
+ Say Y if you want to add support for SoC audio of internal codec on Ingenic Jz4740 PAVO board.
+
+config SND_JZ4740_AC97
+ tristate "select AC97 protocol and AC97 codec pcm core support"
+ depends on SND_JZ4740_SOC && SND_JZ4740_SOC_PAVO
+ select SND_AC97_CODEC
+ help
+ Say Y if you want to add AC97 protocol support for pcm core.
+
+config SND_JZ4740_SOC_AC97
+ tristate "SoC Audio (AC97 protocol) for Ingenic jz4740 chip"
+ depends on SND_JZ4740_SOC && SND_JZ4740_AC97 && SND_JZ4740_SOC_PAVO
+ select AC97_BUS
+ select SND_SOC_AC97_BUS
+ help
+ Say Y if you want to use AC97 protocol and ac97 codec on Ingenic Jz4740 PAVO board.
+
+config SND_JZ4740_SOC_I2S
+ depends on SND_JZ4740_SOC && SND_JZ4740_SOC_PAVO
+ tristate "SoC Audio (I2S protocol) for Ingenic jz4740 chip"
+ help
+ Say Y if you want to use I2S protocol and I2S codec on Ingenic Jz4740 PAVO board.
diff --git a/sound/soc/jz4740/Makefile b/sound/soc/jz4740/Makefile
new file mode 100644
index 00000000000..4c79b138b3a
--- /dev/null
+++ b/sound/soc/jz4740/Makefile
@@ -0,0 +1,15 @@
+#
+# Jz4740 Platform Support
+#
+snd-soc-jz4740-objs := jz4740-pcm.o
+snd-soc-jz4740-ac97-objs := jz4740-ac97.o
+snd-soc-jz4740-i2s-objs := jz4740-i2s.o
+
+obj-$(CONFIG_SND_JZ4740_SOC) += snd-soc-jz4740.o
+obj-$(CONFIG_SND_JZ4740_SOC_AC97) += snd-soc-jz4740-ac97.o
+obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o
+
+# Jz4740 Machine Support
+snd-soc-pavo-objs := pavo.o
+
+obj-$(CONFIG_SND_JZ4740_SOC_PAVO) += snd-soc-pavo.o
diff --git a/sound/soc/jz4740/jz4740-ac97.c b/sound/soc/jz4740/jz4740-ac97.c
new file mode 100644
index 00000000000..84da470e94e
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-ac97.c
@@ -0,0 +1,261 @@
+/*
+ * linux/sound/jz4740-ac97.c -- AC97 support for the Ingenic jz4740 chip.
+ *
+ * Author: Richard
+ * Created: Dec 02, 2007
+ * Copyright: Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/irq.h>
+#include <linux/mutex.h>
+#include <asm/hardware.h>
+#include <asm/arch/audio.h>
+
+#include "jz4740-pcm.h"
+#include "jz4740-ac97.h"
+
+static DEFINE_MUTEX(car_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
+static volatile long gsr_bits;
+
+static unsigned short jz4740_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ unsigned short val = -1;
+ volatile u32 *reg_addr;
+
+ mutex_lock(&car_mutex);
+
+out: mutex_unlock(&car_mutex);
+ return val;
+}
+
+static void jz4740_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ volatile u32 *reg_addr;
+
+ mutex_lock(&car_mutex);
+
+ mutex_unlock(&car_mutex);
+}
+
+static void jz4740_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ gsr_bits = 0;
+}
+
+static void jz4740_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+}
+
+static irqreturn_t jz4740_ac97_irq(int irq, void *dev_id)
+{
+ long status;
+ return IRQ_NONE;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = jz4740_ac97_read,
+ .write = jz4740_ac97_write,
+ .warm_reset = jz4740_ac97_warm_reset,
+ .reset = jz4740_ac97_cold_reset,
+};
+
+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_out = {
+ .name = "AC97 PCM Stereo out",
+ .dev_addr = __PREG(PCDR),
+ .drcmr = &DRCMRTXPCDR,
+ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
+ DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_in = {
+ .name = "AC97 PCM Stereo in",
+ .dev_addr = __PREG(PCDR),
+ .drcmr = &DRCMRRXPCDR,
+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
+ DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_out = {
+ .name = "AC97 Aux PCM (Slot 5) Mono out",
+ .dev_addr = __PREG(MODR),
+ .drcmr = &DRCMRTXMODR,
+ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
+ DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_in = {
+ .name = "AC97 Aux PCM (Slot 5) Mono in",
+ .dev_addr = __PREG(MODR),
+ .drcmr = &DRCMRRXMODR,
+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
+ DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_mic_mono_in = {
+ .name = "AC97 Mic PCM (Slot 6) Mono in",
+ .dev_addr = __PREG(MCDR),
+ .drcmr = &DRCMRRXMCDR,
+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
+ DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+#ifdef CONFIG_PM
+static int jz4740_ac97_suspend(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *dai)
+{
+ return 0;
+}
+
+static int jz4740_ac97_resume(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *dai)
+{
+ return 0;
+}
+
+#else
+#define jz4740_ac97_suspend NULL
+#define jz4740_ac97_resume NULL
+#endif
+
+static int jz4740_ac97_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ return 0;
+}
+
+static void jz4740_ac97_remove(struct platform_device *pdev)
+{
+}
+
+static int jz4740_ac97_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_out;
+ else
+ cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_in;
+
+ return 0;
+}
+
+static int jz4740_ac97_hw_aux_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_out;
+ else
+ cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_in;
+
+ return 0;
+}
+
+static int jz4740_ac97_hw_mic_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return -ENODEV;
+ else
+ cpu_dai->dma_data = &jz4740_ac97_pcm_mic_mono_in;
+
+ return 0;
+}
+
+#define JZ4740_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000)
+
+struct snd_soc_cpu_dai jz4740_ac97_dai[] = {
+{
+ .name = "jz4740-ac97",
+ .id = 0,
+ .type = SND_SOC_DAI_AC97,
+ .probe = jz4740_ac97_probe,
+ .remove = jz4740_ac97_remove,
+ .suspend = jz4740_ac97_suspend,
+ .resume = jz4740_ac97_resume,
+ .playback = {
+ .stream_name = "AC97 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = JZ4740_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .stream_name = "AC97 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = JZ4740_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .hw_params = jz4740_ac97_hw_params,},
+},
+{
+ .name = "jz4740-ac97-aux",
+ .id = 1,
+ .type = SND_SOC_DAI_AC97,
+ .playback = {
+ .stream_name = "AC97 Aux Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = JZ4740_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .stream_name = "AC97 Aux Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = JZ4740_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .hw_params = jz4740_ac97_hw_aux_params,},
+},
+{
+ .name = "jz4740-ac97-mic",
+ .id = 2,
+ .type = SND_SOC_DAI_AC97,
+ .capture = {
+ .stream_name = "AC97 Mic Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = JZ4740_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .hw_params = jz4740_ac97_hw_mic_params,},
+},
+};
+
+EXPORT_SYMBOL_GPL(jz4740_ac97_dai);
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+MODULE_AUTHOR("Richard");
+MODULE_DESCRIPTION("AC97 driver for the Ingenic jz4740 chip");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/jz4740/jz4740-ac97.h b/sound/soc/jz4740/jz4740-ac97.h
new file mode 100644
index 00000000000..e80e2a0ad08
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-ac97.h
@@ -0,0 +1,21 @@
+/*
+ * linux/sound/soc/jz4740/jz4740-ac97.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _JZ4740_AC97_H
+#define _JZ4740_AC97_H
+
+#define JZ4740_DAI_AC97_HIFI 0
+#define JZ4740_DAI_AC97_AUX 1
+#define JZ4740_DAI_AC97_MIC 2
+
+extern struct snd_soc_cpu_dai jz4740_ac97_dai[3];
+
+/* platform data */
+extern struct snd_ac97_bus_ops jz4740_ac97_ops;
+
+#endif
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
new file mode 100644
index 00000000000..6f4f33603a8
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -0,0 +1,309 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Jiejing Zhang(kzjeef(at)gmail.com) 2009: Make jz soc sound card
+ * loaded by soc-core.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "jz4740-pcm.h"
+#include "jz4740-i2s.h"
+
+static struct jz4740_dma_client jz4740_dma_client_out = {
+ .name = "I2S PCM Stereo out"
+};
+
+static struct jz4740_dma_client jz4740_dma_client_in = {
+ .name = "I2S PCM Stereo in"
+};
+
+static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_out = {
+ .client = &jz4740_dma_client_out,
+ .channel = DMA_ID_AIC_TX,
+ .dma_addr = AIC_DR,
+ .dma_size = 2,
+};
+
+static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_in = {
+ .client = &jz4740_dma_client_in,
+ .channel = DMA_ID_AIC_RX,
+ .dma_addr = AIC_DR,
+ .dma_size = 2,
+};
+
+static int jz4740_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ /*struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;*/
+
+ return 0;
+}
+
+static int jz4740_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* 1 : ac97 , 0 : i2s */
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* 0 : slave */
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ /* 1 : master */
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+* Set Jz4740 Clock source
+*/
+static int jz4740_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ return 0;
+}
+
+static void jz4740_snd_tx_ctrl(int on)
+{
+ if (on) {
+ /* enable replay */
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+ __i2s_enable();
+
+ } else {
+ /* disable replay & capture */
+ __i2s_disable_replay();
+ __i2s_disable_record();
+ __i2s_disable_receive_dma();
+ __i2s_disable_transmit_dma();
+ __i2s_disable();
+ }
+}
+
+static void jz4740_snd_rx_ctrl(int on)
+{
+ if (on) {
+ /* enable capture */
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ __i2s_enable();
+
+ } else {
+ /* disable replay & capture */
+ __i2s_disable_replay();
+ __i2s_disable_record();
+ __i2s_disable_receive_dma();
+ __i2s_disable_transmit_dma();
+ __i2s_disable();
+ }
+}
+
+static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ /* int channels = params_channels(params); */
+
+ jz4740_snd_rx_ctrl(0);
+ jz4740_snd_rx_ctrl(0);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_out;
+ /*if (channels == 1)
+ __aic_enable_mono2stereo();
+ else
+ __aic_disable_mono2stereo();*/
+ } else
+ cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_in;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ __i2s_set_transmit_trigger(4);
+ __i2s_set_receive_trigger(3);
+ __i2s_set_oss_sample_size(8);
+ __i2s_set_iss_sample_size(8);
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ /* playback sample:16 bits, burst:16 bytes */
+ __i2s_set_transmit_trigger(4);
+ /* capture sample:16 bits, burst:16 bytes */
+ __i2s_set_receive_trigger(3);
+ __i2s_set_oss_sample_size(16);
+ __i2s_set_iss_sample_size(16);
+ break;
+ }
+
+ return 0;
+}
+
+static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
+{
+ int ret = 0;
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ jz4740_snd_rx_ctrl(1);
+ else
+ jz4740_snd_tx_ctrl(1);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ jz4740_snd_rx_ctrl(0);
+ else
+ jz4740_snd_tx_ctrl(0);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ } else {
+ }
+
+ return;
+}
+
+static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
+{
+ __i2s_internal_codec();
+ __i2s_as_slave();
+ __i2s_select_i2s();
+ __aic_select_i2s();
+ mdelay(2);
+
+ __i2s_disable();
+ __i2s_reset();
+ mdelay(2);
+
+ __i2s_disable();
+ __i2s_internal_codec();
+ __i2s_as_slave();
+ __i2s_select_i2s();
+ __aic_select_i2s();
+ __i2s_set_oss_sample_size(16);
+ __i2s_set_iss_sample_size(16);
+ __aic_play_lastsample();
+
+ __i2s_disable_record();
+ __i2s_disable_replay();
+ __i2s_disable_loopback();
+ __i2s_set_transmit_trigger(7);
+ __i2s_set_receive_trigger(7);
+
+ jz4740_snd_tx_ctrl(0);
+ jz4740_snd_rx_ctrl(0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
+{
+ if (!dai->active)
+ return 0;
+
+ return 0;
+}
+
+static int jz4740_i2s_resume(struct snd_soc_dai *dai)
+{
+ if (!dai->active)
+ return 0;
+
+ return 0;
+}
+
+#else
+#define jz4740_i2s_suspend NULL
+#define jz4740_i2s_resume NULL
+#endif
+
+#define JZ4740_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000)
+
+struct snd_soc_dai_ops snd_jz4740_i2s_dai_ops = {
+ .startup = jz4740_i2s_startup,
+ .shutdown = jz4740_i2s_shutdown,
+ .trigger = jz4740_i2s_trigger,
+ .hw_params = jz4740_i2s_hw_params,
+ .set_fmt = jz4740_i2s_set_dai_fmt,
+ .set_sysclk = jz4740_i2s_set_dai_sysclk,
+};
+
+struct snd_soc_dai jz4740_i2s_dai = {
+ .name = "jz4740-i2s",
+ .id = 0,
+ .probe = jz4740_i2s_probe,
+ .suspend = jz4740_i2s_suspend,
+ .resume = jz4740_i2s_resume,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = JZ4740_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = JZ4740_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &snd_jz4740_i2s_dai_ops,
+};
+
+EXPORT_SYMBOL_GPL(jz4740_i2s_dai);
+
+static int __init jz4740_i2s_init(void)
+{
+ return snd_soc_register_dai(&jz4740_i2s_dai);
+}
+
+static void __exit jz4740_i2s_exit(void)
+{
+ snd_soc_unregister_dai(&jz4740_i2s_dai);
+}
+
+module_init(jz4740_i2s_init);
+module_exit(jz4740_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Richard, cjfeng@ingenic.cn, www.ingenic.cn");
+MODULE_DESCRIPTION("jz4740 I2S SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/jz4740/jz4740-i2s.h b/sound/soc/jz4740/jz4740-i2s.h
new file mode 100644
index 00000000000..7c38f8d9f2a
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-i2s.h
@@ -0,0 +1,18 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _JZ4740_I2S_H
+#define _JZ4740_I2S_H
+
+/* jz4740 DAI ID's */
+#define JZ4740_DAI_I2S 0
+
+/* I2S clock */
+#define JZ4740_I2S_SYSCLK 0
+
+extern struct snd_soc_dai jz4740_i2s_dai;
+
+#endif
diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c
new file mode 100644
index 00000000000..de172ed6bb5
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-pcm.c
@@ -0,0 +1,687 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/io.h>
+#include "jz4740-pcm.h"
+
+static long sum_bytes = 0;
+static int first_transfer = 0;
+static int printk_flag = 0;
+static int tran_bit = 0;
+#ifdef CONFIG_SND_OSSEMUL
+static int hw_params_cnt = 0;
+#endif
+
+static struct jz4740_dma_client jz4740_dma_client_out = {
+ .name = "I2S PCM Stereo out"
+};
+
+static struct jz4740_dma_client jz4740_dma_client_in = {
+ .name = "I2S PCM Stereo in"
+};
+
+static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_out = {
+ .client = &jz4740_dma_client_out,
+ .channel = DMA_ID_AIC_TX,
+ .dma_addr = AIC_DR,
+ .dma_size = 2,
+};
+
+static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_in = {
+ .client = &jz4740_dma_client_in,
+ .channel = DMA_ID_AIC_RX,
+ .dma_addr = AIC_DR,
+ .dma_size = 2,
+};
+
+
+struct jz4740_dma_buf_aic {
+ struct jz4740_dma_buf_aic *next;
+ int size; /* buffer size in bytes */
+ dma_addr_t data; /* start of DMA data */
+ dma_addr_t ptr; /* where the DMA got to [1] */
+ void *id; /* client's id */
+};
+
+struct jz4740_runtime_data {
+ spinlock_t lock;
+ int state;
+ int aic_dma_flag; /* start dma transfer or not */
+ unsigned int dma_loaded;
+ unsigned int dma_limit;
+ unsigned int dma_period;
+ dma_addr_t dma_start;
+ dma_addr_t dma_pos;
+ dma_addr_t dma_end;
+ struct jz4740_pcm_dma_params *params;
+
+ dma_addr_t user_cur_addr; /* user current write buffer start address */
+ unsigned int user_cur_len; /* user current write buffer length */
+
+ /* buffer list and information */
+ struct jz4740_dma_buf_aic *curr; /* current dma buffer */
+ struct jz4740_dma_buf_aic *next; /* next buffer to load */
+ struct jz4740_dma_buf_aic *end; /* end of queue */
+
+};
+
+/* identify hardware playback capabilities */
+static const struct snd_pcm_hardware jz4740_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S8,
+ .rates = SNDRV_PCM_RATE_8000_48000/*0x3fe*/,
+ .rate_min = 8000,
+ .rate_min = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,//16 * 1024
+ .period_bytes_min = PAGE_SIZE,
+ .period_bytes_max = PAGE_SIZE * 2,
+ .periods_min = 2,
+ .periods_max = 128,//16,
+ .fifo_size = 32,
+};
+
+/* jz4740__dma_buf_enqueue
+ *
+ * queue an given buffer for dma transfer.
+ *
+ * data the physical address of the buffer data
+ * size the size of the buffer in bytes
+ *
+*/
+static int jz4740_dma_buf_enqueue(struct jz4740_runtime_data *prtd, dma_addr_t data, int size)
+{
+ struct jz4740_dma_buf_aic *aic_buf;
+
+ aic_buf = kzalloc(sizeof(struct jz4740_dma_buf_aic), GFP_KERNEL);
+ if (aic_buf == NULL) {
+ printk("aic buffer allocate failed,no memory!\n");
+ return -ENOMEM;
+ }
+ aic_buf->next = NULL;
+ aic_buf->data = aic_buf->ptr = data;
+ aic_buf->size = size;
+ if( prtd->curr == NULL) {
+ prtd->curr = aic_buf;
+ prtd->end = aic_buf;
+ prtd->next = NULL;
+ } else {
+ if (prtd->end == NULL)
+ printk("prtd->end is NULL\n");
+ prtd->end->next = aic_buf;
+ prtd->end = aic_buf;
+ }
+
+ /* if necessary, update the next buffer field */
+ if (prtd->next == NULL)
+ prtd->next = aic_buf;
+
+ return 0;
+}
+
+
+void audio_start_dma(struct jz4740_runtime_data *prtd, int mode)
+{
+ unsigned long flags;
+ struct jz4740_dma_buf_aic *aic_buf;
+ int channel;
+
+ switch (mode) {
+ case DMA_MODE_WRITE:
+ /* free cur aic_buf */
+ if (first_transfer == 1) {
+ first_transfer = 0;
+ } else {
+ aic_buf = prtd->curr;
+ if (aic_buf != NULL) {
+ prtd->curr = aic_buf->next;
+ prtd->next = aic_buf->next;
+ aic_buf->next = NULL;
+ kfree(aic_buf);
+ aic_buf = NULL;
+ }
+ }
+
+ aic_buf = prtd->next;
+ channel = prtd->params->channel;
+ if (aic_buf) {
+ disable_dma(channel);
+ jz_set_alsa_dma(channel, mode, tran_bit);
+ set_dma_addr(channel, aic_buf->data);
+ set_dma_count(channel, aic_buf->size);
+ enable_dma(channel);
+ prtd->aic_dma_flag |= AIC_START_DMA;
+ } else {
+ printk("next buffer is NULL for playback\n");
+ prtd->aic_dma_flag &= ~AIC_START_DMA;
+ return;
+ }
+ break;
+ case DMA_MODE_READ:
+ /* free cur aic_buf */
+ if (first_transfer == 1) {
+ first_transfer = 0;
+ } else {
+ aic_buf = prtd->curr;
+ if (aic_buf != NULL) {
+ prtd->curr = aic_buf->next;
+ prtd->next = aic_buf->next;
+ aic_buf->next = NULL;
+ kfree(aic_buf);
+ aic_buf = NULL;
+ }
+ }
+
+ aic_buf = prtd->next;
+ channel = prtd->params->channel;
+
+ if (aic_buf) {
+ disable_dma(channel);
+ jz_set_alsa_dma(channel, mode, tran_bit);
+ set_dma_addr(channel, aic_buf->data);
+ set_dma_count(channel, aic_buf->size);
+ enable_dma(channel);
+ prtd->aic_dma_flag |= AIC_START_DMA;
+ } else {
+ printk("next buffer is NULL for capture\n");
+ prtd->aic_dma_flag &= ~AIC_START_DMA;
+ return;
+ }
+ break;
+ }
+ /* dump_jz_dma_channel(channel); */
+}
+
+/*
+ * place a dma buffer onto the queue for the dma system to handle.
+*/
+static void jz4740_pcm_enqueue(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd = runtime->private_data;
+ /*struct snd_dma_buffer *buf = &substream->dma_buffer;*/
+ dma_addr_t pos = prtd->dma_pos;
+ int ret;
+
+ while (prtd->dma_loaded < prtd->dma_limit) {
+ unsigned long len = prtd->dma_period;
+
+ if ((pos + len) > prtd->dma_end) {
+ len = prtd->dma_end - pos;
+ }
+ ret = jz4740_dma_buf_enqueue(prtd, pos, len);
+ if (ret == 0) {
+ prtd->dma_loaded++;
+ pos += prtd->dma_period;
+ if (pos >= prtd->dma_end)
+ pos = prtd->dma_start;
+ } else
+ break;
+ }
+
+ prtd->dma_pos = pos;
+}
+
+/*
+ * call the function:jz4740_pcm_dma_irq() after DMA has transfered the current buffer
+ */
+static irqreturn_t jz4740_pcm_dma_irq(int dma_ch, void *dev_id)
+{
+ struct snd_pcm_substream *substream = dev_id;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd = runtime->private_data;
+ /*struct jz4740_dma_buf_aic *aic_buf = prtd->curr;*/
+ int channel = prtd->params->channel;
+ unsigned long flags;
+
+ disable_dma(channel);
+ prtd->aic_dma_flag &= ~AIC_START_DMA;
+ /* must clear TT bit in DCCSR to avoid interrupt again */
+ if (__dmac_channel_transmit_end_detected(channel)) {
+ __dmac_channel_clear_transmit_end(channel);
+ }
+ if (__dmac_channel_transmit_halt_detected(channel)) {
+ __dmac_channel_clear_transmit_halt(channel);
+ }
+
+ if (__dmac_channel_address_error_detected(channel)) {
+ __dmac_channel_clear_address_error(channel);
+ }
+
+ if (substream)
+ snd_pcm_period_elapsed(substream);
+
+ spin_lock(&prtd->lock);
+ prtd->dma_loaded--;
+ if (prtd->state & ST_RUNNING) {
+ jz4740_pcm_enqueue(substream);
+ }
+ spin_unlock(&prtd->lock);
+
+ local_irq_save(flags);
+ if (prtd->state & ST_RUNNING) {
+ if (prtd->dma_loaded) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ audio_start_dma(prtd, DMA_MODE_WRITE);
+ else
+ audio_start_dma(prtd, DMA_MODE_READ);
+ }
+ }
+ local_irq_restore(flags);
+ return IRQ_HANDLED;
+}
+
+/* some parameter about DMA operation */
+static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct jz4740_pcm_dma_params *dma = &jz4740_i2s_pcm_stereo_out;
+ size_t totbytes = params_buffer_bytes(params);
+ int ret;
+
+ if (!dma)
+ return 0;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ tran_bit = 8;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ tran_bit = 16;
+ break;
+ }
+
+ /* prepare DMA */
+ prtd->params = dma;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = jz_request_dma(DMA_ID_AIC_TX, prtd->params->client->name,
+ jz4740_pcm_dma_irq, IRQF_DISABLED, substream);
+ if (ret < 0)
+ return ret;
+ prtd->params->channel = ret;
+ } else {
+ ret = jz_request_dma(DMA_ID_AIC_RX, prtd->params->client->name,
+ jz4740_pcm_dma_irq, IRQF_DISABLED, substream);
+ if (ret < 0)
+ return ret;
+ prtd->params->channel = ret;
+ }
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ runtime->dma_bytes = totbytes;
+
+ spin_lock_irq(&prtd->lock);
+ prtd->dma_loaded = 0;
+ prtd->aic_dma_flag = 0;
+ prtd->dma_limit = runtime->hw.periods_min;
+ prtd->dma_period = params_period_bytes(params);
+ prtd->dma_start = runtime->dma_addr;
+ prtd->dma_pos = prtd->dma_start;
+ prtd->dma_end = prtd->dma_start + totbytes;
+ prtd->curr = NULL;
+ prtd->next = NULL;
+ prtd->end = NULL;
+ sum_bytes = 0;
+ first_transfer = 1;
+ printk_flag = 0;
+
+ __dmac_disable_descriptor(prtd->params->channel);
+ __dmac_channel_disable_irq(prtd->params->channel);
+ spin_unlock_irq(&prtd->lock);
+ return ret;
+}
+
+static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct jz4740_runtime_data *prtd = substream->runtime->private_data;
+
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ if (prtd->params) {
+ jz_free_dma(prtd->params->channel);
+ prtd->params = NULL;
+ }
+
+ return 0;
+}
+
+/* set some dma para for playback/capture */
+static int jz4740_dma_ctrl(int channel)
+{
+
+ disable_dma(channel);
+
+ /* must clear TT bit in DCCSR to avoid interrupt again */
+ if (__dmac_channel_transmit_end_detected(channel)) {
+ __dmac_channel_clear_transmit_end(channel);
+ }
+ if (__dmac_channel_transmit_halt_detected(channel)) {
+ __dmac_channel_clear_transmit_halt(channel);
+ }
+
+ if (__dmac_channel_address_error_detected(channel)) {
+ __dmac_channel_clear_address_error(channel);
+ }
+
+ return 0;
+
+}
+
+static int jz4740_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct jz4740_runtime_data *prtd = substream->runtime->private_data;
+ int ret = 0;
+
+ /* return if this is a bufferless transfer e.g */
+ if (!prtd->params)
+ return 0;
+
+ /* flush the DMA channel and DMA channel bit check */
+ jz4740_dma_ctrl(prtd->params->channel);
+ prtd->dma_loaded = 0;
+ prtd->dma_pos = prtd->dma_start;
+
+ /* enqueue dma buffers */
+ jz4740_pcm_enqueue(substream);
+
+ return ret;
+
+}
+
+static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd = runtime->private_data;
+
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ prtd->state |= ST_RUNNING;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ audio_start_dma(prtd, DMA_MODE_WRITE);
+ } else {
+ audio_start_dma(prtd, DMA_MODE_READ);
+ }
+
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ prtd->state &= ~ST_RUNNING;
+ break;
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ printk(" RESUME \n");
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ printk(" RESTART \n");
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static snd_pcm_uframes_t
+jz4740_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd = runtime->private_data;
+ struct jz4740_dma_buf_aic *aic_buf = prtd->curr;
+ long count,res;
+
+ dma_addr_t ptr;
+ snd_pcm_uframes_t x;
+ int channel = prtd->params->channel;
+
+ spin_lock(&prtd->lock);
+#if 1
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ count = get_dma_residue(channel);
+ count = aic_buf->size - count;
+ ptr = aic_buf->data + count;
+ res = ptr - prtd->dma_start;
+ } else {
+ count = get_dma_residue(channel);
+ count = aic_buf->size - count;
+ ptr = aic_buf->data + count;
+ res = ptr - prtd->dma_start;
+ }
+
+# else
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) {
+ count = get_dma_residue(channel);
+ count = aic_buf->size - count;
+ ptr = aic_buf->data + count;
+ REG_DMAC_DSAR(channel) = ptr;
+ res = ptr - prtd->dma_start;
+ } else {
+ ptr = REG_DMAC_DSAR(channel);
+ if (ptr == 0x0)
+ printk("\ndma address is 00000000 in running!\n");
+ res = ptr - prtd->dma_start;
+ }
+ } else {
+ if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) {
+ count = get_dma_residue(channel);
+ count = aic_buf->size - count;
+ ptr = aic_buf->data + count;
+ REG_DMAC_DTAR(channel) = ptr;
+ res = ptr - prtd->dma_start;
+ } else {
+ ptr = REG_DMAC_DTAR(channel);
+ if (ptr == 0x0)
+ printk("\ndma address is 00000000 in running!\n");
+ res = ptr - prtd->dma_start;
+ }
+ }
+#endif
+ spin_unlock(&prtd->lock);
+ x = bytes_to_frames(runtime, res);
+ if (x == runtime->buffer_size)
+ x = 0;
+
+ return x;
+}
+
+static int jz4740_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd;
+
+#ifdef CONFIG_SND_OSSEMUL
+ hw_params_cnt = 0;
+#endif
+ snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware);
+ prtd = kzalloc(sizeof(struct jz4740_runtime_data), GFP_KERNEL);
+ if (prtd == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&prtd->lock);
+
+ runtime->private_data = prtd;
+ REG_AIC_I2SCR = 0x10;
+ return 0;
+}
+
+static int jz4740_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4740_runtime_data *prtd = runtime->private_data;
+ struct jz4740_dma_buf_aic *aic_buf = NULL;
+
+#ifdef CONFIG_SND_OSSEMUL
+ hw_params_cnt = 0;
+#endif
+
+ if (prtd)
+ aic_buf = prtd->curr;
+
+ while (aic_buf != NULL) {
+ prtd->curr = aic_buf->next;
+ prtd->next = aic_buf->next;
+ aic_buf->next = NULL;
+ kfree(aic_buf);
+ aic_buf = NULL;
+ aic_buf = prtd->curr;
+ }
+
+ if (prtd) {
+ prtd->curr = NULL;
+ prtd->next = NULL;
+ prtd->end = NULL;
+ kfree(prtd);
+ }
+
+ return 0;
+}
+
+static int jz4740_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)//include/linux/mm.h
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned long start;
+ unsigned long off;
+ u32 len;
+ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+ return 0;
+}
+
+struct snd_pcm_ops jz4740_pcm_ops = {
+ .open = jz4740_pcm_open,
+ .close = jz4740_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = jz4740_pcm_hw_params,
+ .hw_free = jz4740_pcm_hw_free,
+ .prepare = jz4740_pcm_prepare,
+ .trigger = jz4740_pcm_trigger,
+ .pointer = jz4740_pcm_pointer,
+ .mmap = jz4740_pcm_mmap,
+};
+
+static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = jz4740_pcm_hardware.buffer_bytes_max;
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+
+ /*buf->area = dma_alloc_coherent(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);*/
+ buf->area = dma_alloc_noncoherent(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+ buf->bytes = size;
+ return 0;
+}
+
+static void jz4740_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_noncoherent(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ }
+}
+
+static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32);
+
+int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+ struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ printk("pcm new\n");
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &jz4740_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ if (dai->playback.channels_min) {
+ ret = jz4740_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto out;
+ }
+
+ if (dai->capture.channels_min) {
+ ret = jz4740_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto out;
+ }
+ out:
+
+ return ret;
+}
+
+struct snd_soc_platform jz4740_soc_platform = {
+ .name = "jz4740-audio",
+ .pcm_ops = &jz4740_pcm_ops,
+ .pcm_new = jz4740_pcm_new,
+ .pcm_free = jz4740_pcm_free_dma_buffers,
+};
+
+EXPORT_SYMBOL_GPL(jz4740_soc_platform);
+
+static int __init jz4740_soc_platform_init(void)
+{
+ return snd_soc_register_platform(&jz4740_soc_platform);
+}
+module_init(jz4740_soc_platform_init);
+
+static void __exit jz4740_soc_platform_exit(void)
+{
+ snd_soc_unregister_platform(&jz4740_soc_platform);
+}
+module_exit(jz4740_soc_platform_exit);
+
+MODULE_AUTHOR("Richard");
+MODULE_DESCRIPTION("Ingenic Jz4740 PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/jz4740/jz4740-pcm.h b/sound/soc/jz4740/jz4740-pcm.h
new file mode 100644
index 00000000000..68ea842d171
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-pcm.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _JZ4740_PCM_H
+#define _JZ4740_PCM_H
+
+#include <asm/jzsoc.h>
+
+#define ST_RUNNING (1<<0)
+#define ST_OPENED (1<<1)
+
+#define AIC_START_DMA (1<<0)
+#define AIC_END_DMA (1<<1)
+
+struct jz4740_dma_client {
+ char *name;
+};
+
+struct jz4740_pcm_dma_params {
+ struct jz4740_dma_client *client; /* stream identifier */
+ int channel; /* Channel ID */
+ dma_addr_t dma_addr;
+ int dma_size; /* Size of the DMA transfer */
+};
+
+/* platform data */
+extern struct snd_soc_platform jz4740_soc_platform;
+
+#endif
diff --git a/sound/soc/jz4740/pavo.c b/sound/soc/jz4740/pavo.c
new file mode 100644
index 00000000000..2e61f316885
--- /dev/null
+++ b/sound/soc/jz4740/pavo.c
@@ -0,0 +1,374 @@
+/*
+ * pavo.c -- SoC audio for PAVO
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/jzcodec.h"
+#include "jz4740-pcm.h"
+#include "jz4740-i2s.h"
+
+#define PAVO_HP 0
+#define PAVO_MIC 1
+#define PAVO_LINE 2
+#define PAVO_HEADSET 3
+#define PAVO_HP_OFF 4
+#define PAVO_SPK_ON 0
+#define PAVO_SPK_OFF 1
+
+ /* audio clock in Hz - rounded from 12.235MHz */
+#define PAVO_AUDIO_CLOCK 12288000
+
+static int pavo_jack_func;
+static int pavo_spk_func;
+
+unsigned short set_scoop_gpio(struct device *dev, unsigned short bit)
+{
+ unsigned short gpio_bit = 0;
+
+ return gpio_bit;
+}
+
+unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit)
+{
+ unsigned short gpio_bit = 0;
+
+ return gpio_bit;
+}
+
+static void pavo_ext_control(struct snd_soc_codec *codec)
+{
+ int spk = 0, mic = 0, line = 0, hp = 0, hs = 0;
+
+ /* set up jack connection */
+ switch (pavo_jack_func) {
+ case PAVO_HP:
+ hp = 1;
+ /* set = unmute headphone */
+ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ break;
+ case PAVO_MIC:
+ mic = 1;
+ /* reset = mute headphone */
+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ break;
+ case PAVO_LINE:
+ line = 1;
+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ break;
+ case PAVO_HEADSET:
+ hs = 1;
+ mic = 1;
+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ break;
+ }
+
+ if (pavo_spk_func == PAVO_SPK_ON)
+ spk = 1;
+
+ /* set the enpoints to their new connetion states */
+ if (spk)
+ snd_soc_dapm_enable_pin(codec, "Ext Spk");
+ else
+ snd_soc_dapm_disable_pin(codec, "Ext Spk");
+
+ if (mic)
+ snd_soc_dapm_enable_pin(codec, "Mic Jack");
+ else
+ snd_soc_dapm_disable_pin(codec, "Mic Jack");
+
+ if (line)
+ snd_soc_dapm_enable_pin(codec, "Line Jack");
+ else
+ snd_soc_dapm_disable_pin(codec, "Line Jack");
+
+ if (hp)
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ else
+ snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+
+ if (hp)
+ snd_soc_dapm_enable_pin(codec, "Headset Jack");
+ else
+ snd_soc_dapm_disable_pin(codec, "Headset Jack");
+
+ /* signal a DAPM event */
+ snd_soc_dapm_sync(codec);}
+
+static int pavo_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->card->codec;
+
+ /* check the jack status at stream startup */
+ pavo_ext_control(codec);
+ return 0;
+}
+
+/* we need to unmute the HP at shutdown as the mute burns power on pavo */
+static void pavo_shutdown(struct snd_pcm_substream *substream)
+{
+ /*struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->codec;*/
+
+ return;
+}
+
+static int pavo_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret = 0;
+
+ /* set codec DAI configuration */
+ ret = codec_dai->ops->set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = cpu_dai->ops->set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = codec_dai->ops->set_sysclk(codec_dai, JZCODEC_SYSCLK, 111,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set the I2S system clock as input (unused) */
+ ret = cpu_dai->ops->set_sysclk(cpu_dai, JZ4740_I2S_SYSCLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops pavo_ops = {
+ .startup = pavo_startup,
+ .hw_params = pavo_hw_params,
+ .shutdown = pavo_shutdown,
+};
+
+static int pavo_get_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = pavo_jack_func;
+ return 0;
+}
+
+static int pavo_set_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (pavo_jack_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ pavo_jack_func = ucontrol->value.integer.value[0];
+ pavo_ext_control(codec);
+ return 1;
+}
+
+static int pavo_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = pavo_spk_func;
+ return 0;
+}
+
+static int pavo_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (pavo_spk_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ pavo_spk_func = ucontrol->value.integer.value[0];
+ pavo_ext_control(codec);
+ return 1;
+}
+
+static int pavo_amp_event(struct snd_soc_dapm_widget *w, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ //set_scoop_gpio(&corgiscoop_device.dev, PAVO_SCP_APM_ON);
+ ;
+ else
+ //reset_scoop_gpio(&corgiscoop_device.dev, PAVO_SCP_APM_ON);
+ ;
+
+ return 0;
+}
+
+static int pavo_mic_event(struct snd_soc_dapm_widget *w, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
+ ;
+ else
+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
+ ;
+
+ return 0;
+}
+
+/* pavo machine dapm widgets */
+static const struct snd_soc_dapm_widget jzcodec_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", NULL),
+SND_SOC_DAPM_MIC("Mic Jack",pavo_mic_event),
+SND_SOC_DAPM_SPK("Ext Spk", pavo_amp_event),
+SND_SOC_DAPM_LINE("Line Jack", NULL),
+SND_SOC_DAPM_HP("Headset Jack", NULL),
+};
+
+/* pavo machine audio map (connections to the codec pins) */
+static const struct snd_soc_dapm_route audio_map [] = {
+
+ /* headset Jack - in = micin, out = LHPOUT*/
+ {"Headset Jack", NULL, "LHPOUT"},
+
+ /* headphone connected to LHPOUT1, RHPOUT1 */
+ {"Headphone Jack", NULL, "LHPOUT"},
+ {"Headphone Jack", NULL, "RHPOUT"},
+
+ /* speaker connected to LOUT, ROUT */
+ {"Ext Spk", NULL, "ROUT"},
+ {"Ext Spk", NULL, "LOUT"},
+
+ /* mic is connected to MICIN (via right channel of headphone jack) */
+ {"MICIN", NULL, "Mic Jack"},
+
+ /* Same as the above but no mic bias for line signals */
+ {"MICIN", NULL, "Line Jack"},
+
+ {NULL, NULL, NULL},
+};
+
+static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
+ "Off"};
+static const char *spk_function[] = {"On", "Off"};
+static const struct soc_enum pavo_enum[] = {
+ SOC_ENUM_SINGLE_EXT(5, jack_function),
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new jzcodec_pavo_controls[] = {
+ SOC_ENUM_EXT("Jack Function", pavo_enum[0], pavo_get_jack,
+ pavo_set_jack),
+ SOC_ENUM_EXT("Speaker Function", pavo_enum[1], pavo_get_spk,
+ pavo_set_spk),
+};
+
+/*
+ * Pavo for a jzcodec as connected on jz4740 Device
+ */
+static int pavo_jzcodec_init(struct snd_soc_codec *codec)
+{
+ int i, err;
+
+ snd_soc_dapm_nc_pin(codec, "LLINEIN");
+ snd_soc_dapm_nc_pin(codec, "RLINEIN");
+
+ /* Add pavo specific controls */
+ for (i = 0; i < ARRAY_SIZE(jzcodec_pavo_controls); i++) {
+ err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&jzcodec_pavo_controls[i],codec, NULL));
+ if (err < 0)
+ return err;
+ }
+
+ /* Add pavo specific widgets */
+ for(i = 0; i < ARRAY_SIZE(jzcodec_dapm_widgets); i++) {
+ snd_soc_dapm_new_control(codec, &jzcodec_dapm_widgets[i]);
+ }
+
+// snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+/* pavo digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link pavo_dai = {
+ .name = "JZCODEC",
+ .stream_name = "JZCODEC",
+ .cpu_dai = &jz4740_i2s_dai,
+ .codec_dai = &jzcodec_dai,
+ .init = pavo_jzcodec_init,
+ .ops = &pavo_ops,
+};
+
+/* pavo audio machine driver */
+static struct snd_soc_card snd_soc_card_pavo = {
+ .name = "Pavo",
+ .dai_link = &pavo_dai,
+ .platform = &jz4740_soc_platform,
+ .num_links = 1,
+};
+
+/* pavo audio subsystem */
+static struct snd_soc_device pavo_snd_devdata = {
+ .card = &snd_soc_card_pavo,
+ .codec_dev = &soc_codec_dev_jzcodec,
+ //.codec_data
+};
+
+static struct platform_device *pavo_snd_device;
+
+static int __init pavo_init(void)
+{
+ int ret;
+
+ pavo_snd_device = platform_device_alloc("soc-audio", -1);
+
+ if (!pavo_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(pavo_snd_device, &pavo_snd_devdata);
+ pavo_snd_devdata.dev = &pavo_snd_device->dev;
+ ret = platform_device_add(pavo_snd_device);
+
+ if (ret)
+ platform_device_put(pavo_snd_device);
+
+ return ret;
+}
+
+static void __exit pavo_exit(void)
+{
+ platform_device_unregister(pavo_snd_device);
+}
+
+module_init(pavo_init);
+module_exit(pavo_exit);
+
+/* Module information */
+MODULE_AUTHOR("Richard");
+MODULE_DESCRIPTION("ALSA SoC Pavo");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/jz4750/Kconfig b/sound/soc/jz4750/Kconfig
new file mode 100644
index 00000000000..7cf9b166b98
--- /dev/null
+++ b/sound/soc/jz4750/Kconfig
@@ -0,0 +1,34 @@
+config SND_JZ4750_SOC
+ tristate "SoC Audio for Ingenic jz4750 chip"
+ depends on (JZ4750_APUS || JZ4750_FUWA) && SND_SOC
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the Jz4750 AC97, I2S or SSP interface. You will also need
+ to select the audio interfaces to support below.
+
+config SND_JZ4750_SOC_APUS
+ tristate "SoC Audio support for Ingenic Jz4750 APUS board"
+ depends on SND_JZ4750_SOC
+ help
+ Say Y if you want to add support for SoC audio of internal codec on Ingenic Jz4750 APUS board.
+
+config SND_JZ4750_AC97
+ tristate "select AC97 protocol and AC97 codec pcm core support"
+ depends on SND_JZ4750_SOC && SND_JZ4750_SOC_APUS
+ select SND_AC97_CODEC
+ help
+ Say Y if you want to add AC97 protocol support for pcm core.
+
+config SND_JZ4750_SOC_AC97
+ tristate "SoC Audio (AC97 protocol) for Ingenic jz4750 chip"
+ depends on SND_JZ4750_SOC && SND_JZ4750_AC97 && SND_JZ4750_SOC_APUS
+ select AC97_BUS
+ select SND_SOC_AC97_BUS
+ help
+ Say Y if you want to use AC97 protocol and ac97 codec on Ingenic Jz4750 APUS board.
+
+config SND_JZ4750_SOC_I2S
+ depends on SND_JZ4750_SOC && SND_JZ4750_SOC_APUS
+ tristate "SoC Audio (I2S protocol) for Ingenic jz4750 chip"
+ help
+ Say Y if you want to use I2S protocol and I2S codec on Ingenic Jz4750 APUS board.
diff --git a/sound/soc/jz4750/Makefile b/sound/soc/jz4750/Makefile
new file mode 100644
index 00000000000..ba5cbfaa791
--- /dev/null
+++ b/sound/soc/jz4750/Makefile
@@ -0,0 +1,15 @@
+#
+# Jz4750 Platform Support
+#
+snd-soc-jz4750-objs := jz4750-pcm.o
+snd-soc-jz4750-ac97-objs := jz4750-ac97.o
+snd-soc-jz4750-i2s-objs := jz4750-i2s.o
+
+obj-$(CONFIG_SND_JZ4750_SOC) += snd-soc-jz4750.o
+obj-$(CONFIG_SND_JZ4750_SOC_AC97) += snd-soc-jz4750-ac97.o
+obj-$(CONFIG_SND_JZ4750_SOC_I2S) += snd-soc-jz4750-i2s.o
+
+# Jz4750 Machine Support
+snd-soc-apus-objs := apus.o
+
+obj-$(CONFIG_SND_JZ4750_SOC_APUS) += snd-soc-apus.o
diff --git a/sound/soc/jz4750/apus.c b/sound/soc/jz4750/apus.c
new file mode 100644
index 00000000000..36c39a1e249
--- /dev/null
+++ b/sound/soc/jz4750/apus.c
@@ -0,0 +1,365 @@
+/*
+ * apus.c -- SoC audio for APUS
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/jzsoc.h>
+
+#include "../codecs/jzdlv.h"
+#include "jz4750-pcm.h"
+#include "jz4750-i2s.h"
+
+#define APUS_HP 0
+#define APUS_MIC 1
+#define APUS_LINE 2
+#define APUS_HEADSET 3
+#define APUS_HP_OFF 4
+#define APUS_SPK_ON 0
+#define APUS_SPK_OFF 1
+
+static int apus_jack_func;
+static int apus_spk_func;
+
+unsigned short set_scoop_gpio(struct device *dev, unsigned short bit)
+{
+ unsigned short gpio_bit = 0;
+
+ return gpio_bit;
+}
+
+unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit)
+{
+ unsigned short gpio_bit = 0;
+
+ return gpio_bit;
+}
+
+static void apus_ext_control(struct snd_soc_codec *codec)
+{
+ int spk = 0, mic = 0, line = 0, hp = 0, hs = 0;
+
+ /* set up jack connection */
+ switch (apus_jack_func) {
+ case APUS_HP:
+ hp = 1;
+ /* set = unmute headphone */
+ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ break;
+ case APUS_MIC:
+ mic = 1;
+ /* reset = mute headphone */
+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ break;
+ case APUS_LINE:
+ line = 1;
+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ break;
+ case APUS_HEADSET:
+ hs = 1;
+ mic = 1;
+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
+ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+ break;
+ }
+
+ if (apus_spk_func == APUS_SPK_ON)
+ spk = 1;
+
+ /* set the enpoints to their new connetion states */
+ if (spk)
+ snd_soc_dapm_enable_pin(codec, "Ext Spk");
+ else
+ snd_soc_dapm_disable_pin(codec, "Ext Spk");
+
+ if (mic)
+ snd_soc_dapm_enable_pin(codec, "Mic Jack");
+ else
+ snd_soc_dapm_disable_pin(codec, "Mic Jack");
+
+ if (line)
+ snd_soc_dapm_enable_pin(codec, "Line Jack");
+ else
+ snd_soc_dapm_disable_pin(codec, "Line Jack");
+
+ if (hp)
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ else
+ snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+
+ if (hp)
+ snd_soc_dapm_enable_pin(codec, "Headset Jack");
+ else
+ snd_soc_dapm_disable_pin(codec, "Headset Jack");
+
+ /* signal a DAPM event */
+ snd_soc_dapm_sync(codec);
+}
+
+static int apus_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->card->codec;
+
+ /* check the jack status at stream startup */
+ apus_ext_control(codec);
+ return 0;
+}
+
+/* we need to unmute the HP at shutdown as the mute burns power on apus */
+static void apus_shutdown(struct snd_pcm_substream *substream)
+{
+ /*struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->codec;*/
+
+ return;
+}
+
+static int apus_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret = 0;
+
+ /* set codec DAI configuration */
+ ret = codec_dai->ops->set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = cpu_dai->ops->set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = codec_dai->ops->set_sysclk(codec_dai, JZDLV_SYSCLK, 111,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set the I2S system clock as input (unused) */
+ ret = cpu_dai->ops->set_sysclk(cpu_dai, JZ4750_I2S_SYSCLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops apus_ops = {
+ .startup = apus_startup,
+ .hw_params = apus_hw_params,
+ .shutdown = apus_shutdown,
+};
+
+static int apus_get_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = apus_jack_func;
+ return 0;
+}
+
+static int apus_set_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (apus_jack_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ apus_jack_func = ucontrol->value.integer.value[0];
+ apus_ext_control(codec);
+ return 1;
+}
+
+static int apus_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = apus_spk_func;
+ return 0;
+}
+
+static int apus_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (apus_spk_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ apus_spk_func = ucontrol->value.integer.value[0];
+ apus_ext_control(codec);
+ return 1;
+}
+
+static int apus_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ //set_scoop_gpio(&corgiscoop_device.dev, APUS_SCP_APM_ON);
+ ;
+ else
+ //reset_scoop_gpio(&corgiscoop_device.dev, APUS_SCP_APM_ON);
+ ;
+
+ return 0;
+}
+
+static int apus_mic_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
+ ;
+ else
+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
+ ;
+
+ return 0;
+}
+
+/* apus machine dapm widgets */
+static const struct snd_soc_dapm_widget jzdlv_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", NULL),
+SND_SOC_DAPM_MIC("Mic Jack",apus_mic_event),
+SND_SOC_DAPM_SPK("Ext Spk", apus_amp_event),
+SND_SOC_DAPM_LINE("Line Jack", NULL),
+SND_SOC_DAPM_HP("Headset Jack", NULL),
+};
+
+/* apus machine audio map (connections to the codec pins) */
+static const struct snd_soc_dapm_route audio_map [] = {
+ /* headset Jack - in = micin, out = LHPOUT*/
+ {"Headset Jack", NULL, "LHPOUT"},
+
+ /* headphone connected to LHPOUT1, RHPOUT1 */
+ {"Headphone Jack", NULL, "LHPOUT"},
+ {"Headphone Jack", NULL, "RHPOUT"},
+
+ /* speaker connected to LOUT, ROUT */
+ {"Ext Spk", NULL, "ROUT"},
+ {"Ext Spk", NULL, "LOUT"},
+
+ /* mic is connected to MICIN (via right channel of headphone jack) */
+ {"MICIN", NULL, "Mic Jack"},
+
+ /* Same as the above but no mic bias for line signals */
+ {"MICIN", NULL, "Line Jack"},
+};
+
+static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
+ "Off"};
+static const char *spk_function[] = {"On", "Off"};
+static const struct soc_enum apus_enum[] = {
+ SOC_ENUM_SINGLE_EXT(5, jack_function),
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new jzdlv_apus_controls[] = {
+ SOC_ENUM_EXT("Jack Function", apus_enum[0], apus_get_jack,
+ apus_set_jack),
+ SOC_ENUM_EXT("Speaker Function", apus_enum[1], apus_get_spk,
+ apus_set_spk),
+};
+
+/*
+ * Apus for a jzdlv as connected on jz4750 Device
+ */
+static int apus_jzdlv_init(struct snd_soc_codec *codec)
+{
+ int err;
+
+ snd_soc_dapm_nc_pin(codec, "LLINEIN");
+ snd_soc_dapm_nc_pin(codec, "RLINEIN");
+
+ /* Add apus specific controls */
+ err = snd_soc_add_controls(codec, jzdlv_apus_controls, ARRAY_SIZE(jzdlv_apus_controls));
+ if (err < 0)
+ return err;
+
+ /* Add apus specific widgets */
+ snd_soc_dapm_new_controls(codec, jzdlv_dapm_widgets, ARRAY_SIZE(jzdlv_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ snd_soc_dapm_sync(codec);
+ return 0;
+}
+
+/* apus digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link apus_dai = {
+ .name = "JZDLV",
+ .stream_name = "JZDLV",
+ .cpu_dai = &jz4750_i2s_dai,
+ .codec_dai = &jzdlv_dai,
+ .init = apus_jzdlv_init,
+ .ops = &apus_ops,
+};
+
+/* apus audio machine driver */
+static struct snd_soc_card snd_soc_card_apus = {
+ .name = "Apus",
+ .dai_link = &apus_dai,
+ .platform = &jz4750_soc_platform,
+ .num_links = 1,
+};
+
+/* apus audio subsystem */
+static struct snd_soc_device apus_snd_devdata = {
+ .card = &snd_soc_card_apus,
+ .codec_dev = &soc_codec_dev_jzdlv,
+ //.codec_data
+};
+
+static struct platform_device *apus_snd_device;
+
+static int __init apus_init(void)
+{
+ int ret;
+
+ apus_snd_device = platform_device_alloc("soc-audio", -1);
+
+ if (!apus_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(apus_snd_device, &apus_snd_devdata);
+ apus_snd_devdata.dev = &apus_snd_device->dev;
+ ret = platform_device_add(apus_snd_device);
+
+ if (ret)
+ platform_device_put(apus_snd_device);
+
+ return ret;
+}
+
+static void __exit apus_exit(void)
+{
+ platform_device_unregister(apus_snd_device);
+}
+
+module_init(apus_init);
+module_exit(apus_exit);
+
+/* Module information */
+MODULE_AUTHOR("Richard");
+MODULE_DESCRIPTION("ALSA SoC Apus");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/jz4750/jz4750-ac97.c b/sound/soc/jz4750/jz4750-ac97.c
new file mode 100644
index 00000000000..70d2bacbd7f
--- /dev/null
+++ b/sound/soc/jz4750/jz4750-ac97.c
@@ -0,0 +1,258 @@
+/*
+ * linux/sound/jz4740-ac97.c -- AC97 support for the Ingenic jz4740 chip.
+ *
+ * Author: Richard
+ * Created: Dec 02, 2007
+ * Copyright: Ingenic Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/irq.h>
+#include <linux/mutex.h>
+
+#include "jz4740-pcm.h"
+#include "jz4740-ac97.h"
+
+static DEFINE_MUTEX(car_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
+static volatile long gsr_bits;
+
+static unsigned short jz4740_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ unsigned short val = -1;
+ volatile u32 *reg_addr;
+
+ mutex_lock(&car_mutex);
+
+out: mutex_unlock(&car_mutex);
+ return val;
+}
+
+static void jz4740_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ volatile u32 *reg_addr;
+
+ mutex_lock(&car_mutex);
+
+ mutex_unlock(&car_mutex);
+}
+
+static void jz4740_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ gsr_bits = 0;
+}
+
+static void jz4740_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+}
+
+static irqreturn_t jz4740_ac97_irq(int irq, void *dev_id)
+{
+ long status;
+ return IRQ_NONE;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = jz4740_ac97_read,
+ .write = jz4740_ac97_write,
+ .warm_reset = jz4740_ac97_warm_reset,
+ .reset = jz4740_ac97_cold_reset,
+};
+
+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_out = {
+ .name = "AC97 PCM Stereo out",
+ .dev_addr = __PREG(PCDR),
+ .drcmr = &DRCMRTXPCDR,
+ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
+ DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_in = {
+ .name = "AC97 PCM Stereo in",
+ .dev_addr = __PREG(PCDR),
+ .drcmr = &DRCMRRXPCDR,
+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
+ DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_out = {
+ .name = "AC97 Aux PCM (Slot 5) Mono out",
+ .dev_addr = __PREG(MODR),
+ .drcmr = &DRCMRTXMODR,
+ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
+ DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_in = {
+ .name = "AC97 Aux PCM (Slot 5) Mono in",
+ .dev_addr = __PREG(MODR),
+ .drcmr = &DRCMRRXMODR,
+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
+ DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_mic_mono_in = {
+ .name = "AC97 Mic PCM (Slot 6) Mono in",
+ .dev_addr = __PREG(MCDR),
+ .drcmr = &DRCMRRXMCDR,
+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
+ DCMD_BURST16 | DCMD_WIDTH2,
+};
+
+#ifdef CONFIG_PM
+static int jz4740_ac97_suspend(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *dai)
+{
+ return 0;
+}
+
+static int jz4740_ac97_resume(struct platform_device *pdev,
+ struct snd_soc_cpu_dai *dai)
+{
+ return 0;
+}
+
+#else
+#define jz4740_ac97_suspend NULL
+#define jz4740_ac97_resume NULL
+#endif
+
+static int jz4740_ac97_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ return 0;
+}
+
+static void jz4740_ac97_remove(struct platform_device *pdev)
+{
+}
+
+static int jz4740_ac97_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_out;
+ else
+ cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_in;
+
+ return 0;
+}
+
+static int jz4740_ac97_hw_aux_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_out;
+ else
+ cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_in;
+
+ return 0;
+}
+
+static int jz4740_ac97_hw_mic_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return -ENODEV;
+ else
+ cpu_dai->dma_data = &jz4740_ac97_pcm_mic_mono_in;
+
+ return 0;
+}
+
+#define JZ4740_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000)
+
+struct snd_soc_cpu_dai jz4740_ac97_dai[] = {
+{
+ .name = "jz4740-ac97",
+ .id = 0,
+ .type = SND_SOC_DAI_AC97,
+ .probe = jz4740_ac97_probe,
+ .remove = jz4740_ac97_remove,
+ .suspend = jz4740_ac97_suspend,
+ .resume = jz4740_ac97_resume,
+ .playback = {
+ .stream_name = "AC97 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = JZ4740_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .stream_name = "AC97 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = JZ4740_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .hw_params = jz4740_ac97_hw_params,},
+},
+{
+ .name = "jz4740-ac97-aux",
+ .id = 1,
+ .type = SND_SOC_DAI_AC97,
+ .playback = {
+ .stream_name = "AC97 Aux Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = JZ4740_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .stream_name = "AC97 Aux Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = JZ4740_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .hw_params = jz4740_ac97_hw_aux_params,},
+},
+{
+ .name = "jz4740-ac97-mic",
+ .id = 2,
+ .type = SND_SOC_DAI_AC97,
+ .capture = {
+ .stream_name = "AC97 Mic Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = JZ4740_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .hw_params = jz4740_ac97_hw_mic_params,},
+},
+};
+
+EXPORT_SYMBOL_GPL(jz4740_ac97_dai);
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+MODULE_AUTHOR("Richard");
+MODULE_DESCRIPTION("AC97 driver for the Ingenic jz4740 chip");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/jz4750/jz4750-ac97.h b/sound/soc/jz4750/jz4750-ac97.h
new file mode 100644
index 00000000000..cd116e9f34b
--- /dev/null
+++ b/sound/soc/jz4750/jz4750-ac97.h
@@ -0,0 +1,21 @@
+/*
+ * linux/sound/soc/jz4750/jz4750-ac97.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _JZ4750_AC97_H
+#define _JZ4750_AC97_H
+
+#define JZ4750_DAI_AC97_HIFI 0
+#define JZ4750_DAI_AC97_AUX 1
+#define JZ4750_DAI_AC97_MIC 2
+
+extern struct snd_soc_cpu_dai jz4750_ac97_dai[3];
+
+/* platform data */
+extern struct snd_ac97_bus_ops jz4750_ac97_ops;
+
+#endif
diff --git a/sound/soc/jz4750/jz4750-i2s.c b/sound/soc/jz4750/jz4750-i2s.c
new file mode 100644
index 00000000000..9bd32a1685d
--- /dev/null
+++ b/sound/soc/jz4750/jz4750-i2s.c
@@ -0,0 +1,320 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "jz4750-pcm.h"
+#include "jz4750-i2s.h"
+#include "../codecs/jzdlv.h"
+
+static struct jz4750_dma_client jz4750_dma_client_out = {
+ .name = "I2S PCM Stereo out"
+};
+
+static struct jz4750_dma_client jz4750_dma_client_in = {
+ .name = "I2S PCM Stereo in"
+};
+
+static struct jz4750_pcm_dma_params jz4750_i2s_pcm_stereo_out = {
+ .client = &jz4750_dma_client_out,
+ .channel = DMA_ID_AIC_TX,
+ .dma_addr = AIC_DR,
+ .dma_size = 2,
+};
+
+static struct jz4750_pcm_dma_params jz4750_i2s_pcm_stereo_in = {
+ .client = &jz4750_dma_client_in,
+ .channel = DMA_ID_AIC_RX,
+ .dma_addr = AIC_DR,
+ .dma_size = 2,
+};
+
+static int jz4750_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ /*struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;*/
+
+ return 0;
+}
+
+static int jz4750_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* 1 : ac97 , 0 : i2s */
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* 0 : slave */
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ /* 1 : master */
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+* Set Jz4750 Clock source
+*/
+static int jz4750_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ return 0;
+}
+
+static void jz4750_snd_tx_ctrl(int on)
+{
+ if (on) {
+ /* enable replay */
+ __i2s_enable_transmit_dma();
+ __i2s_enable_replay();
+ __i2s_enable();
+
+ } else {
+ /* disable replay & capture */
+ __i2s_disable_replay();
+ __i2s_disable_record();
+ __i2s_disable_receive_dma();
+ __i2s_disable_transmit_dma();
+ __i2s_disable();
+ }
+}
+
+static void jz4750_snd_rx_ctrl(int on)
+{
+ if (on) {
+ /* enable capture */
+ __i2s_enable_receive_dma();
+ __i2s_enable_record();
+ __i2s_enable();
+
+ } else {
+ /* disable replay & capture */
+ __i2s_disable_replay();
+ __i2s_disable_record();
+ __i2s_disable_receive_dma();
+ __i2s_disable_transmit_dma();
+ __i2s_disable();
+ }
+}
+
+static int jz4750_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int channels = params_channels(params);
+
+ jz4750_snd_rx_ctrl(0);
+ jz4750_snd_rx_ctrl(0);
+ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ cpu_dai->dma_data = &jz4750_i2s_pcm_stereo_out;
+
+ if (channels == 1)
+ __aic_enable_mono2stereo();
+ else
+ __aic_disable_mono2stereo();
+ } else
+ rtd->dai->cpu_dai->dma_data = &jz4750_i2s_pcm_stereo_in;
+
+#if 1
+ switch (channels) {
+ case 1:
+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono
+ break;
+ case 2:
+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo
+ break;
+ }
+#endif
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ __i2s_set_transmit_trigger(4);
+ __i2s_set_receive_trigger(3);
+ __i2s_set_oss_sample_size(8);
+ __i2s_set_iss_sample_size(8);
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ /* playback sample:16 bits, burst:16 bytes */
+ __i2s_set_transmit_trigger(4);
+ /* capture sample:16 bits, burst:16 bytes */
+ __i2s_set_receive_trigger(3);
+ __i2s_set_oss_sample_size(16);
+ __i2s_set_iss_sample_size(16);
+ /* DAC path and ADC path */
+ write_codec_file(2, 0x00);
+ break;
+ }
+
+ return 0;
+}
+
+static int jz4750_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ jz4750_snd_rx_ctrl(1);
+ else
+ jz4750_snd_tx_ctrl(1);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ jz4750_snd_rx_ctrl(0);
+ else
+ jz4750_snd_tx_ctrl(0);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void jz4750_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ } else {
+ }
+
+ return;
+}
+
+static int jz4750_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
+{
+ __i2s_internal_codec();
+ __i2s_as_slave();
+ __i2s_select_i2s();
+ __aic_select_i2s();
+ mdelay(2);
+
+ __i2s_disable();
+ mdelay(2);
+ REG_AIC_I2SCR = 0x10;
+ __i2s_disable();
+ __i2s_internal_codec();
+ __i2s_as_slave();
+ __i2s_select_i2s();
+ __aic_select_i2s();
+ __i2s_set_oss_sample_size(16);
+ __i2s_set_iss_sample_size(16);
+ __aic_play_lastsample();
+
+ __i2s_disable_record();
+ __i2s_disable_replay();
+ __i2s_disable_loopback();
+ __i2s_set_transmit_trigger(7);
+ __i2s_set_receive_trigger(7);
+
+ jz4750_snd_tx_ctrl(0);
+ jz4750_snd_rx_ctrl(0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int jz4750_i2s_suspend(struct snd_soc_dai *dai)
+{
+ if (!dai->active)
+ return 0;
+
+ return 0;
+}
+
+static int jz4750_i2s_resume(struct snd_soc_dai *dai)
+{
+ if (!dai->active)
+ return 0;
+
+ return 0;
+}
+
+#else
+#define jz4750_i2s_suspend NULL
+#define jz4750_i2s_resume NULL
+#endif
+
+#define JZ4750_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_12000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_24000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000)
+
+static struct snd_soc_dai_ops jz4750_i2s_dai_ops = {
+ .startup = jz4750_i2s_startup,
+ .shutdown = jz4750_i2s_shutdown,
+ .trigger = jz4750_i2s_trigger,
+ .hw_params = jz4750_i2s_hw_params,
+ .set_fmt = jz4750_i2s_set_dai_fmt,
+ .set_sysclk = jz4750_i2s_set_dai_sysclk,
+};
+
+struct snd_soc_dai jz4750_i2s_dai = {
+ .name = "jz4750-i2s",
+ .id = 0,
+ .probe = jz4750_i2s_probe,
+ .suspend = jz4750_i2s_suspend,
+ .resume = jz4750_i2s_resume,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = JZ4750_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = JZ4750_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = &jz4750_i2s_dai_ops,
+};
+
+EXPORT_SYMBOL_GPL(jz4750_i2s_dai);
+
+static int __init jz4750_i2s_init(void)
+{
+ return snd_soc_register_dai(&jz4750_i2s_dai);
+}
+module_init(jz4750_i2s_init);
+
+static void __exit jz4750_i2s_exit(void)
+{
+ snd_soc_unregister_dai(&jz4750_i2s_dai);
+}
+module_exit(jz4750_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Richard, cjfeng@ingenic.cn, www.ingenic.cn");
+MODULE_DESCRIPTION("jz4750 I2S SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/jz4750/jz4750-i2s.h b/sound/soc/jz4750/jz4750-i2s.h
new file mode 100644
index 00000000000..f4f97dc5572
--- /dev/null
+++ b/sound/soc/jz4750/jz4750-i2s.h
@@ -0,0 +1,18 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _JZ4750_I2S_H
+#define _JZ4750_I2S_H
+
+/* jz4750 DAI ID's */
+#define JZ4750_DAI_I2S 0
+
+/* I2S clock */
+#define JZ4750_I2S_SYSCLK 0
+
+extern struct snd_soc_dai jz4750_i2s_dai;
+
+#endif
diff --git a/sound/soc/jz4750/jz4750-pcm.c b/sound/soc/jz4750/jz4750-pcm.c
new file mode 100644
index 00000000000..21a0cb4da3f
--- /dev/null
+++ b/sound/soc/jz4750/jz4750-pcm.c
@@ -0,0 +1,700 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/io.h>
+#include "jz4750-pcm.h"
+
+static long sum_bytes = 0;
+static int first_transfer = 0;
+static int printk_flag = 0;
+static int tran_bit = 0;
+#ifdef CONFIG_SND_OSSEMUL
+static int hw_params_cnt = 0;
+#endif
+
+struct jz4750_dma_buf_aic {
+ struct jz4750_dma_buf_aic *next;
+ int size; /* buffer size in bytes */
+ dma_addr_t data; /* start of DMA data */
+ dma_addr_t ptr; /* where the DMA got to [1] */
+ void *id; /* client's id */
+};
+
+struct jz4750_runtime_data {
+ spinlock_t lock;
+ int state;
+ int aic_dma_flag; /* start dma transfer or not */
+ unsigned int dma_loaded;
+ unsigned int dma_limit;
+ unsigned int dma_period;
+ dma_addr_t dma_start;
+ dma_addr_t dma_pos;
+ dma_addr_t dma_end;
+ struct jz4750_pcm_dma_params *params;
+
+ dma_addr_t user_cur_addr; /* user current write buffer start address */
+ unsigned int user_cur_len; /* user current write buffer length */
+
+ /* buffer list and information */
+ struct jz4750_dma_buf_aic *curr; /* current dma buffer */
+ struct jz4750_dma_buf_aic *next; /* next buffer to load */
+ struct jz4750_dma_buf_aic *end; /* end of queue */
+
+};
+
+/* identify hardware playback capabilities */
+static const struct snd_pcm_hardware jz4750_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_U16_LE |
+ SNDRV_PCM_FMTBIT_U8 |
+ SNDRV_PCM_FMTBIT_S8,
+ .rates = SNDRV_PCM_RATE_8000_96000/*0x3fe*/,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 1,//2
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,//16 * 1024
+ .period_bytes_min = PAGE_SIZE,
+ .period_bytes_max = PAGE_SIZE * 2,
+ .periods_min = 2,
+ .periods_max = 128,//16,
+ .fifo_size = 32,
+};
+
+/* jz4750__dma_buf_enqueue
+ *
+ * queue an given buffer for dma transfer.
+ *
+ * data the physical address of the buffer data
+ * size the size of the buffer in bytes
+ *
+*/
+static int jz4750_dma_buf_enqueue(struct jz4750_runtime_data *prtd, dma_addr_t data, int size)
+{
+ struct jz4750_dma_buf_aic *aic_buf;
+
+ aic_buf = kzalloc(sizeof(struct jz4750_dma_buf_aic), GFP_KERNEL);
+ if (aic_buf == NULL) {
+ printk("aic buffer allocate failed,no memory!\n");
+ return -ENOMEM;
+ }
+ aic_buf->next = NULL;
+ aic_buf->data = aic_buf->ptr = data;
+ aic_buf->size = size;
+ if( prtd->curr == NULL) {
+ prtd->curr = aic_buf;
+ prtd->end = aic_buf;
+ prtd->next = NULL;
+ } else {
+ if (prtd->end == NULL)
+ printk("prtd->end is NULL\n");
+ prtd->end->next = aic_buf;
+ prtd->end = aic_buf;
+ }
+
+ /* if necessary, update the next buffer field */
+ if (prtd->next == NULL)
+ prtd->next = aic_buf;
+
+ return 0;
+}
+
+void audio_start_dma(struct jz4750_runtime_data *prtd, int mode)
+{
+ unsigned long flags;
+ struct jz4750_dma_buf_aic *aic_buf;
+ int channel;
+
+ switch (mode) {
+ case DMA_MODE_WRITE:
+ /* free cur aic_buf */
+ if (first_transfer == 1) {
+ first_transfer = 0;
+ } else {
+ aic_buf = prtd->curr;
+ if (aic_buf != NULL) {
+ prtd->curr = aic_buf->next;
+ prtd->next = aic_buf->next;
+ aic_buf->next = NULL;
+ kfree(aic_buf);
+ aic_buf = NULL;
+ }
+ }
+
+ aic_buf = prtd->next;
+ channel = prtd->params->channel;
+ if (aic_buf) {
+ flags = claim_dma_lock();
+ disable_dma(channel);
+ jz_set_alsa_dma(channel, mode, tran_bit);
+ set_dma_addr(channel, aic_buf->data);
+ set_dma_count(channel, aic_buf->size);
+ enable_dma(channel);
+ release_dma_lock(flags);
+ prtd->aic_dma_flag |= AIC_START_DMA;
+ } else {
+ printk("next buffer is NULL for playback\n");
+ prtd->aic_dma_flag &= ~AIC_START_DMA;
+ return;
+ }
+ break;
+ case DMA_MODE_READ:
+ /* free cur aic_buf */
+ if (first_transfer == 1) {
+ first_transfer = 0;
+ } else {
+ aic_buf = prtd->curr;
+ if (aic_buf != NULL) {
+ prtd->curr = aic_buf->next;
+ prtd->next = aic_buf->next;
+ aic_buf->next = NULL;
+ kfree(aic_buf);
+ aic_buf = NULL;
+ }
+ }
+
+ aic_buf = prtd->next;
+ channel = prtd->params->channel;
+
+ if (aic_buf) {
+ flags = claim_dma_lock();
+ disable_dma(channel);
+ jz_set_alsa_dma(channel, mode, tran_bit);
+ set_dma_addr(channel, aic_buf->data);
+ set_dma_count(channel, aic_buf->size);
+ enable_dma(channel);
+ release_dma_lock(flags);
+ prtd->aic_dma_flag |= AIC_START_DMA;
+ } else {
+ printk("next buffer is NULL for capture\n");
+ prtd->aic_dma_flag &= ~AIC_START_DMA;
+ return;
+ }
+ break;
+ }
+}
+
+/*
+ * place a dma buffer onto the queue for the dma system to handle.
+*/
+static void jz4750_pcm_enqueue(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4750_runtime_data *prtd = runtime->private_data;
+ /*struct snd_dma_buffer *buf = &substream->dma_buffer;*/
+ dma_addr_t pos = prtd->dma_pos;
+ int ret;
+
+ while (prtd->dma_loaded < prtd->dma_limit) {
+ unsigned long len = prtd->dma_period;
+
+ if ((pos + len) > prtd->dma_end) {
+ len = prtd->dma_end - pos;
+ }
+ ret = jz4750_dma_buf_enqueue(prtd, pos, len);
+ if (ret == 0) {
+ prtd->dma_loaded++;
+ pos += prtd->dma_period;
+ if (pos >= prtd->dma_end)
+ pos = prtd->dma_start;
+ } else
+ break;
+ }
+
+ prtd->dma_pos = pos;
+}
+
+/*
+ * call the function:jz4750_pcm_dma_irq() after DMA has transfered the current buffer
+ */
+static irqreturn_t jz4750_pcm_dma_irq(int dma_ch, void *dev_id)
+{
+ struct snd_pcm_substream *substream = dev_id;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4750_runtime_data *prtd = runtime->private_data;
+ /*struct jz4750_dma_buf_aic *aic_buf = prtd->curr;*/
+ int channel = prtd->params->channel;
+ unsigned long flags;
+
+ disable_dma(channel);
+ prtd->aic_dma_flag &= ~AIC_START_DMA;
+ /* must clear TT bit in DCCSR to avoid interrupt again */
+ if (__dmac_channel_transmit_end_detected(channel)) {
+ __dmac_channel_clear_transmit_end(channel);
+ }
+ if (__dmac_channel_transmit_halt_detected(channel)) {
+ __dmac_channel_clear_transmit_halt(channel);
+ }
+
+ if (__dmac_channel_address_error_detected(channel)) {
+ __dmac_channel_clear_address_error(channel);
+ }
+ if (substream)
+ snd_pcm_period_elapsed(substream);
+
+ spin_lock(&prtd->lock);
+ prtd->dma_loaded--;
+ if (prtd->state & ST_RUNNING) {
+ jz4750_pcm_enqueue(substream);
+ }
+ spin_unlock(&prtd->lock);
+
+ local_irq_save(flags);
+ if (prtd->state & ST_RUNNING) {
+ if (prtd->dma_loaded) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ audio_start_dma(prtd, DMA_MODE_WRITE);
+ else
+ audio_start_dma(prtd, DMA_MODE_READ);
+ }
+ }
+ local_irq_restore(flags);
+ return IRQ_HANDLED;
+}
+
+/* some parameter about DMA operation */
+static int jz4750_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4750_runtime_data *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct jz4750_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
+ size_t totbytes = params_buffer_bytes(params);
+ int ret;
+
+#ifdef CONFIG_SND_OSSEMUL
+ if (hw_params_cnt)
+ return 0;
+ else
+ hw_params_cnt++ ;
+#endif
+
+ if (!dma)
+ return 0;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ tran_bit = 8;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ tran_bit = 16;
+ break;
+ }
+
+ /* prepare DMA */
+ prtd->params = dma;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = jz_request_dma(DMA_ID_AIC_TX, prtd->params->client->name,
+ jz4750_pcm_dma_irq, IRQF_DISABLED, substream);
+ if (ret < 0)
+ return ret;
+ prtd->params->channel = ret;
+ } else {
+ ret = jz_request_dma(DMA_ID_AIC_RX, prtd->params->client->name,
+ jz4750_pcm_dma_irq, IRQF_DISABLED, substream);
+ if (ret < 0)
+ return ret;
+ prtd->params->channel = ret;
+ }
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ runtime->dma_bytes = totbytes;
+
+ spin_lock_irq(&prtd->lock);
+ prtd->dma_loaded = 0;
+ prtd->aic_dma_flag = 0;
+ prtd->dma_limit = runtime->hw.periods_min;
+ prtd->dma_period = params_period_bytes(params);
+ prtd->dma_start = runtime->dma_addr;
+ prtd->dma_pos = prtd->dma_start;
+ prtd->dma_end = prtd->dma_start + totbytes;
+ prtd->curr = NULL;
+ prtd->next = NULL;
+ prtd->end = NULL;
+ sum_bytes = 0;
+ first_transfer = 1;
+ printk_flag = 0;
+
+ __dmac_disable_descriptor(prtd->params->channel);
+ __dmac_channel_disable_irq(prtd->params->channel);
+ spin_unlock_irq(&prtd->lock);
+
+ return ret;
+}
+
+static int jz4750_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct jz4750_runtime_data *prtd = substream->runtime->private_data;
+
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ if (prtd->params) {
+ jz_free_dma(prtd->params->channel);
+ prtd->params = NULL;
+ }
+
+ return 0;
+}
+
+/* set some dma para for playback/capture */
+static int jz4750_dma_ctrl(int channel)
+{
+ disable_dma(channel);
+
+ /* must clear TT bit in DCCSR to avoid interrupt again */
+ if (__dmac_channel_transmit_end_detected(channel)) {
+ __dmac_channel_clear_transmit_end(channel);
+ }
+ if (__dmac_channel_transmit_halt_detected(channel)) {
+ __dmac_channel_clear_transmit_halt(channel);
+ }
+
+ if (__dmac_channel_address_error_detected(channel)) {
+ __dmac_channel_clear_address_error(channel);
+ }
+
+ return 0;
+
+}
+
+static int jz4750_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct jz4750_runtime_data *prtd = substream->runtime->private_data;
+ int ret = 0;
+
+ /* return if this is a bufferless transfer e.g */
+ if (!prtd->params)
+ return 0;
+
+ /* flush the DMA channel and DMA channel bit check */
+ jz4750_dma_ctrl(prtd->params->channel);
+ prtd->dma_loaded = 0;
+ prtd->dma_pos = prtd->dma_start;
+
+ /* enqueue dma buffers */
+ jz4750_pcm_enqueue(substream);
+
+ return ret;
+
+}
+
+static int jz4750_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4750_runtime_data *prtd = runtime->private_data;
+
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ prtd->state |= ST_RUNNING;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ audio_start_dma(prtd, DMA_MODE_WRITE);
+ } else {
+ audio_start_dma(prtd, DMA_MODE_READ);
+ }
+
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ prtd->state &= ~ST_RUNNING;
+ break;
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ printk(" RESUME \n");
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ printk(" RESTART \n");
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static snd_pcm_uframes_t
+jz4750_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4750_runtime_data *prtd = runtime->private_data;
+ struct jz4750_dma_buf_aic *aic_buf = prtd->curr;
+ long count,res;
+
+ dma_addr_t ptr;
+ snd_pcm_uframes_t x;
+ int channel = prtd->params->channel;
+
+ spin_lock(&prtd->lock);
+#if 1
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ count = get_dma_residue(channel);
+ count = aic_buf->size - count;
+ ptr = aic_buf->data + count;
+ res = ptr - prtd->dma_start;
+ } else {
+ count = get_dma_residue(channel);
+ count = aic_buf->size - count;
+ ptr = aic_buf->data + count;
+ res = ptr - prtd->dma_start;
+ }
+
+# else
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) {
+ count = get_dma_residue(channel);
+ count = aic_buf->size - count;
+ ptr = aic_buf->data + count;
+ REG_DMAC_DSAR(channel) = ptr;
+ res = ptr - prtd->dma_start;
+ } else {
+ ptr = REG_DMAC_DSAR(channel);
+ if (ptr == 0x0)
+ printk("\ndma address is 00000000 in running!\n");
+ res = ptr - prtd->dma_start;
+ }
+ } else {
+ if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) {
+ count = get_dma_residue(channel);
+ count = aic_buf->size - count;
+ ptr = aic_buf->data + count;
+ REG_DMAC_DTAR(channel) = ptr;
+ res = ptr - prtd->dma_start;
+ } else {
+ ptr = REG_DMAC_DTAR(channel);
+ if (ptr == 0x0)
+ printk("\ndma address is 00000000 in running!\n");
+ res = ptr - prtd->dma_start;
+ }
+ }
+#endif
+ spin_unlock(&prtd->lock);
+ x = bytes_to_frames(runtime, res);
+ if (x == runtime->buffer_size)
+ x = 0;
+
+ return x;
+}
+
+static int jz4750_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4750_runtime_data *prtd;
+
+#ifdef CONFIG_SND_OSSEMUL
+ hw_params_cnt = 0;
+#endif
+ REG_DMAC_DMACKE(0) = 0x3f;
+ REG_DMAC_DMACKE(1) = 0x3f;
+ snd_soc_set_runtime_hwparams(substream, &jz4750_pcm_hardware);
+ prtd = kzalloc(sizeof(struct jz4750_runtime_data), GFP_KERNEL);
+ if (prtd == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&prtd->lock);
+
+ runtime->private_data = prtd;
+
+ return 0;
+}
+
+static int jz4750_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct jz4750_runtime_data *prtd = runtime->private_data;
+ struct jz4750_dma_buf_aic *aic_buf = NULL;
+
+#ifdef CONFIG_SND_OSSEMUL
+ hw_params_cnt = 0;
+#endif
+
+ if (prtd)
+ aic_buf = prtd->curr;
+
+ while (aic_buf != NULL) {
+ prtd->curr = aic_buf->next;
+ prtd->next = aic_buf->next;
+ aic_buf->next = NULL;
+ kfree(aic_buf);
+ aic_buf = NULL;
+ aic_buf = prtd->curr;
+ }
+
+ if (prtd) {
+ prtd->curr = NULL;
+ prtd->next = NULL;
+ prtd->end = NULL;
+ kfree(prtd);
+ }
+
+ return 0;
+}
+
+static int jz4750_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)//include/linux/mm.h
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned long start;
+ unsigned long off;
+ u32 len;
+ int ret = -ENXIO;
+
+ off = vma->vm_pgoff << PAGE_SHIFT;
+ start = runtime->dma_addr;
+
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + runtime->dma_bytes);
+ start &= PAGE_MASK;
+
+ if ((vma->vm_end - vma->vm_start + off) > len) {
+ return -EINVAL;
+ }
+
+ off += start;
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ vma->vm_flags |= VM_IO;
+
+#if defined(CONFIG_MIPS32)
+ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
+ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
+ /* pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; */
+#endif
+ ret = io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+
+ return ret;
+}
+
+struct snd_pcm_ops jz4750_pcm_ops = {
+ .open = jz4750_pcm_open,
+ .close = jz4750_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = jz4750_pcm_hw_params,
+ .hw_free = jz4750_pcm_hw_free,
+ .prepare = jz4750_pcm_prepare,
+ .trigger = jz4750_pcm_trigger,
+ .pointer = jz4750_pcm_pointer,
+ .mmap = jz4750_pcm_mmap,
+};
+
+static int jz4750_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = jz4750_pcm_hardware.buffer_bytes_max;
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+
+ /*buf->area = dma_alloc_coherent(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);*/
+ buf->area = dma_alloc_noncoherent(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+ buf->bytes = size;
+ return 0;
+}
+
+static void jz4750_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_noncoherent(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ }
+}
+
+static u64 jz4750_pcm_dmamask = DMA_BIT_MASK(32);
+
+int jz4750_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+ struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &jz4750_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ if (dai->playback.channels_min) {
+ ret = jz4750_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto out;
+ }
+
+ if (dai->capture.channels_min) {
+ ret = jz4750_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto out;
+ }
+ out:
+
+ return ret;
+}
+
+struct snd_soc_platform jz4750_soc_platform = {
+ .name = "jz4750-audio",
+ .pcm_ops = &jz4750_pcm_ops,
+ .pcm_new = jz4750_pcm_new,
+ .pcm_free = jz4750_pcm_free_dma_buffers,
+};
+
+EXPORT_SYMBOL_GPL(jz4750_soc_platform);
+
+static int __init jz4750_soc_platform_init(void)
+{
+ return snd_soc_register_platform(&jz4750_soc_platform);
+}
+module_init(jz4750_soc_platform_init);
+
+static void __exit jz4750_soc_platform_exit(void)
+{
+ snd_soc_unregister_platform(&jz4750_soc_platform);
+}
+module_exit(jz4750_soc_platform_exit);
+
+MODULE_AUTHOR("Richard");
+MODULE_DESCRIPTION("Ingenic Jz4750 PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/jz4750/jz4750-pcm.h b/sound/soc/jz4750/jz4750-pcm.h
new file mode 100644
index 00000000000..d7d4f722bab
--- /dev/null
+++ b/sound/soc/jz4750/jz4750-pcm.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _JZ4750_PCM_H
+#define _JZ4750_PCM_H
+
+#include <asm/jzsoc.h>
+
+#define ST_RUNNING (1<<0)
+#define ST_OPENED (1<<1)
+
+#define AIC_START_DMA (1<<0)
+#define AIC_END_DMA (1<<1)
+
+struct jz4750_dma_client {
+ char *name;
+};
+
+struct jz4750_pcm_dma_params {
+ struct jz4750_dma_client *client; /* stream identifier */
+ int channel; /* Channel ID */
+ dma_addr_t dma_addr;
+ int dma_size; /* Size of the DMA transfer */
+};
+
+/* platform data */
+extern struct snd_soc_platform jz4750_soc_platform;
+
+#endif