From dc3d3f1c49539c091d1cd0c7be30f08c7da85ff2 Mon Sep 17 00:00:00 2001 From: Mirko Vogt Date: Tue, 18 Aug 2009 12:44:38 +0200 Subject: [PATCH] yet another patchset - 2.6.27 it's basically also provided by ingenic and nativly based on 2.6.27, adjusted to fit into the OpenWrt-environment --- target/linux/xburst/files-2.6.27/Changelog | 11 + .../arch/mips/boot/compressed/Makefile | 42 + .../arch/mips/boot/compressed/dummy.c | 4 + .../arch/mips/boot/compressed/head.S | 85 + .../arch/mips/boot/compressed/ld.script | 151 + .../arch/mips/boot/compressed/misc.c | 242 + .../files-2.6.27/arch/mips/boot/tools/entry | 12 + .../arch/mips/boot/tools/filesize | 7 + .../arch/mips/configs/apus_defconfig | 1348 ++++ .../arch/mips/configs/cetus_defconfig | 1183 ++++ .../arch/mips/configs/dipper_defconfig | 1281 ++++ .../arch/mips/configs/f4760_defconfig | 892 +++ .../arch/mips/configs/fuwa_defconfig | 928 +++ .../arch/mips/configs/leo_defconfig | 1256 ++++ .../arch/mips/configs/lyra_defconfig | 981 +++ .../arch/mips/configs/pavo_defconfig | 1329 ++++ .../arch/mips/configs/pmp_defconfig | 1212 ++++ .../arch/mips/configs/virgo_defconfig | 1281 ++++ .../files-2.6.27/arch/mips/jz4730/Makefile | 22 + .../files-2.6.27/arch/mips/jz4730/board-pmp.c | 109 + .../files-2.6.27/arch/mips/jz4730/cpufreq.c | 596 ++ .../files-2.6.27/arch/mips/jz4730/dma.c | 509 ++ .../files-2.6.27/arch/mips/jz4730/i2c.c | 214 + .../files-2.6.27/arch/mips/jz4730/irq.c | 266 + .../files-2.6.27/arch/mips/jz4730/platform.c | 140 + .../xburst/files-2.6.27/arch/mips/jz4730/pm.c | 1098 +++ .../files-2.6.27/arch/mips/jz4730/proc.c | 292 + .../files-2.6.27/arch/mips/jz4730/prom.c | 198 + .../files-2.6.27/arch/mips/jz4730/reset.c | 40 + .../files-2.6.27/arch/mips/jz4730/setup.c | 182 + .../files-2.6.27/arch/mips/jz4730/sleep.S | 307 + .../files-2.6.27/arch/mips/jz4730/time.c | 129 + .../files-2.6.27/arch/mips/jz4740/Makefile | 26 + .../arch/mips/jz4740/board-dipper.c | 117 + .../files-2.6.27/arch/mips/jz4740/board-leo.c | 67 + .../arch/mips/jz4740/board-lyra.c | 114 + .../arch/mips/jz4740/board-pavo.c | 114 + .../arch/mips/jz4740/board-virgo.c | 114 + .../files-2.6.27/arch/mips/jz4740/cpufreq.c | 602 ++ .../files-2.6.27/arch/mips/jz4740/dma.c | 768 +++ .../files-2.6.27/arch/mips/jz4740/i2c.c | 273 + .../files-2.6.27/arch/mips/jz4740/irq.c | 265 + .../files-2.6.27/arch/mips/jz4740/platform.c | 169 + .../xburst/files-2.6.27/arch/mips/jz4740/pm.c | 410 ++ .../files-2.6.27/arch/mips/jz4740/proc.c | 873 +++ .../files-2.6.27/arch/mips/jz4740/prom.c | 198 + .../files-2.6.27/arch/mips/jz4740/reset.c | 46 + .../files-2.6.27/arch/mips/jz4740/setup.c | 188 + .../files-2.6.27/arch/mips/jz4740/time.c | 159 + .../files-2.6.27/arch/mips/jz4750/Makefile | 23 + .../arch/mips/jz4750/board-apus.c | 303 + .../arch/mips/jz4750/board-fuwa.c | 114 + .../files-2.6.27/arch/mips/jz4750/cpufreq.c | 601 ++ .../files-2.6.27/arch/mips/jz4750/dma.c | 836 +++ .../files-2.6.27/arch/mips/jz4750/i2c.c | 386 ++ .../files-2.6.27/arch/mips/jz4750/irq.c | 299 + .../files-2.6.27/arch/mips/jz4750/platform.c | 147 + .../xburst/files-2.6.27/arch/mips/jz4750/pm.c | 203 + .../files-2.6.27/arch/mips/jz4750/proc.c | 1058 +++ .../files-2.6.27/arch/mips/jz4750/prom.c | 198 + .../files-2.6.27/arch/mips/jz4750/reset.c | 46 + .../files-2.6.27/arch/mips/jz4750/setup.c | 206 + .../files-2.6.27/arch/mips/jz4750/time.c | 157 + .../files-2.6.27/arch/mips/jz4750d/Makefile | 23 + .../arch/mips/jz4750d/board-cetus.c | 301 + .../arch/mips/jz4750d/board-fuwa1.c | 81 + .../files-2.6.27/arch/mips/jz4750d/cpufreq.c | 600 ++ .../files-2.6.27/arch/mips/jz4750d/dma.c | 822 +++ .../files-2.6.27/arch/mips/jz4750d/i2c.c | 385 ++ .../files-2.6.27/arch/mips/jz4750d/irq.c | 299 + .../files-2.6.27/arch/mips/jz4750d/platform.c | 147 + .../files-2.6.27/arch/mips/jz4750d/pm.c | 201 + .../files-2.6.27/arch/mips/jz4750d/proc.c | 1056 +++ .../files-2.6.27/arch/mips/jz4750d/prom.c | 198 + .../files-2.6.27/arch/mips/jz4750d/reset.c | 46 + .../files-2.6.27/arch/mips/jz4750d/setup.c | 207 + .../files-2.6.27/arch/mips/jz4750d/time.c | 157 + .../files-2.6.27/arch/mips/jz4760/Makefile | 22 + .../arch/mips/jz4760/board-f4760.c | 81 + .../files-2.6.27/arch/mips/jz4760/cpufreq.c | 598 ++ .../files-2.6.27/arch/mips/jz4760/dma.c | 822 +++ .../files-2.6.27/arch/mips/jz4760/i2c.c | 273 + .../files-2.6.27/arch/mips/jz4760/irq.c | 299 + .../files-2.6.27/arch/mips/jz4760/platform.c | 166 + .../xburst/files-2.6.27/arch/mips/jz4760/pm.c | 461 ++ .../files-2.6.27/arch/mips/jz4760/proc.c | 885 +++ .../files-2.6.27/arch/mips/jz4760/prom.c | 198 + .../files-2.6.27/arch/mips/jz4760/reset.c | 46 + .../files-2.6.27/arch/mips/jz4760/setup.c | 199 + .../files-2.6.27/arch/mips/jz4760/time.c | 156 + .../drivers/i2c/busses/i2c-jz47xx.c | 330 + .../drivers/i2c/busses/i2c-jz47xx.h | 20 + .../drivers/input/keyboard/jz_gpio_keypad.c | 413 ++ .../drivers/input/keyboard/jz_keypad.c | 357 + .../drivers/input/keyboard/jz_keypad_5x5.c | 246 + .../drivers/input/touchscreen/jz_ts.c | 789 +++ .../xburst/files-2.6.27/drivers/misc/jz_cim.c | 748 ++ .../xburst/files-2.6.27/drivers/misc/jz_cim.h | 104 + .../files-2.6.27/drivers/misc/jz_sensor.c | 92 + .../files-2.6.27/drivers/misc/jz_sensor.h | 94 + .../files-2.6.27/drivers/misc/jz_tcsm.c | 132 + .../drivers/mmc/host/jz4750_mmc.c | 1014 +++ .../drivers/mmc/host/jz4750_mmc.h | 163 + .../files-2.6.27/drivers/mmc/host/jz_mmc.c | 995 +++ .../files-2.6.27/drivers/mmc/host/jz_mmc.h | 65 + .../drivers/mtd/mtd-utils/COPYING | 340 + .../drivers/mtd/mtd-utils/MAKEDEV | 42 + .../drivers/mtd/mtd-utils/Makefile | 102 + .../drivers/mtd/mtd-utils/compr.c | 538 ++ .../drivers/mtd/mtd-utils/compr.h | 119 + .../drivers/mtd/mtd-utils/compr_lzo.c | 120 + .../drivers/mtd/mtd-utils/compr_rtime.c | 119 + .../drivers/mtd/mtd-utils/compr_zlib.c | 145 + .../drivers/mtd/mtd-utils/crc32.c | 95 + .../drivers/mtd/mtd-utils/crc32.h | 19 + .../drivers/mtd/mtd-utils/device_table.txt | 129 + .../drivers/mtd/mtd-utils/doc_loadbios.c | 148 + .../drivers/mtd/mtd-utils/docfdisk.c | 317 + .../mtd-utils/feature-removal-schedule.txt | 9 + .../files-2.6.27/drivers/mtd/mtd-utils/fec.c | 917 +++ .../drivers/mtd/mtd-utils/fectest.c | 92 + .../drivers/mtd/mtd-utils/flash_erase.c | 189 + .../drivers/mtd/mtd-utils/flash_eraseall.c | 286 + .../drivers/mtd/mtd-utils/flash_info.c | 55 + .../drivers/mtd/mtd-utils/flash_lock.c | 84 + .../drivers/mtd/mtd-utils/flash_otp_dump.c | 54 + .../drivers/mtd/mtd-utils/flash_otp_info.c | 63 + .../drivers/mtd/mtd-utils/flash_otp_lock.c | 70 + .../drivers/mtd/mtd-utils/flash_otp_write.c | 96 + .../drivers/mtd/mtd-utils/flash_unlock.c | 64 + .../drivers/mtd/mtd-utils/flashcp.c | 389 ++ .../drivers/mtd/mtd-utils/ftl_check.c | 232 + .../drivers/mtd/mtd-utils/ftl_format.c | 342 + .../mtd/mtd-utils/include/linux/jffs2.h | 218 + .../mtd/mtd-utils/include/mtd/ftl-user.h | 76 + .../mtd/mtd-utils/include/mtd/inftl-user.h | 91 + .../mtd/mtd-utils/include/mtd/jffs2-user.h | 82 + .../mtd/mtd-utils/include/mtd/mtd-abi.h | 170 + .../mtd/mtd-utils/include/mtd/mtd-user.h | 21 + .../mtd/mtd-utils/include/mtd/nftl-user.h | 76 + .../mtd/mtd-utils/include/mtd/ubi-header.h | 372 + .../mtd/mtd-utils/include/mtd/ubi-user.h | 284 + .../drivers/mtd/mtd-utils/include/mtd_swab.h | 51 + .../drivers/mtd/mtd-utils/jffs-dump.c | 359 + .../drivers/mtd/mtd-utils/jffs2dump.c | 690 ++ .../drivers/mtd/mtd-utils/jffs2reader.c | 939 +++ .../drivers/mtd/mtd-utils/load_nandsim.sh | 123 + .../drivers/mtd/mtd-utils/mcast_image.h | 54 + .../drivers/mtd/mtd-utils/mkfs.jffs2.1 | 259 + .../drivers/mtd/mtd-utils/mkfs.jffs2.c | 1902 ++++++ .../drivers/mtd/mtd-utils/mtd-utils.spec | 40 + .../drivers/mtd/mtd-utils/mtd_debug.c | 418 ++ .../drivers/mtd/mtd-utils/nanddump.c | 403 ++ .../drivers/mtd/mtd-utils/nanddump_vfat.c | 365 + .../drivers/mtd/mtd-utils/nandtest.c | 284 + .../drivers/mtd/mtd-utils/nandwrite.c | 525 ++ .../drivers/mtd/mtd-utils/nandwrite_mlc.c | 446 ++ .../drivers/mtd/mtd-utils/nftl_format.c | 419 ++ .../drivers/mtd/mtd-utils/nftldump.c | 281 + .../drivers/mtd/mtd-utils/rbtree.c | 390 ++ .../drivers/mtd/mtd-utils/rbtree.h | 168 + .../drivers/mtd/mtd-utils/recv_image.c | 484 ++ .../drivers/mtd/mtd-utils/rfddump.c | 336 + .../drivers/mtd/mtd-utils/rfdformat.c | 158 + .../drivers/mtd/mtd-utils/serve_image.c | 299 + .../drivers/mtd/mtd-utils/summary.h | 178 + .../drivers/mtd/mtd-utils/sumtool.c | 951 +++ .../mtd/mtd-utils/tests/checkfs/Makefile | 14 + .../mtd/mtd-utils/tests/checkfs/README | 173 + .../mtd/mtd-utils/tests/checkfs/checkfs.c | 695 ++ .../mtd/mtd-utils/tests/checkfs/comm.c | 67 + .../mtd/mtd-utils/tests/checkfs/common.h | 7 + .../mtd/mtd-utils/tests/checkfs/makefiles.c | 264 + .../mtd/mtd-utils/tests/fs-tests/Makefile | 8 + .../mtd/mtd-utils/tests/fs-tests/help_all.sh | 27 + .../tests/fs-tests/integrity/Makefile | 22 + .../tests/fs-tests/integrity/integck.c | 1422 ++++ .../mtd/mtd-utils/tests/fs-tests/lib/Makefile | 18 + .../mtd/mtd-utils/tests/fs-tests/lib/tests.c | 1091 +++ .../mtd/mtd-utils/tests/fs-tests/lib/tests.h | 199 + .../mtd/mtd-utils/tests/fs-tests/run_all.sh | 49 + .../mtd-utils/tests/fs-tests/simple/Makefile | 28 + .../mtd-utils/tests/fs-tests/simple/ftrunc.c | 111 + .../mtd-utils/tests/fs-tests/simple/orph.c | 184 + .../mtd-utils/tests/fs-tests/simple/test_1.c | 150 + .../mtd-utils/tests/fs-tests/simple/test_2.c | 201 + .../mtd-utils/tests/fs-tests/stress/Makefile | 11 + .../tests/fs-tests/stress/atoms/Makefile | 40 + .../tests/fs-tests/stress/atoms/fwrite00.c | 209 + .../tests/fs-tests/stress/atoms/gcd_hupper.c | 259 + .../tests/fs-tests/stress/atoms/pdfrun.c | 143 + .../tests/fs-tests/stress/atoms/rmdir00.c | 133 + .../tests/fs-tests/stress/atoms/rndrm00.c | 157 + .../tests/fs-tests/stress/atoms/rndrm99.c | 431 ++ .../tests/fs-tests/stress/atoms/rndwrite00.c | 201 + .../tests/fs-tests/stress/atoms/stress_1.c | 109 + .../tests/fs-tests/stress/atoms/stress_2.c | 120 + .../tests/fs-tests/stress/atoms/stress_3.c | 122 + .../tests/fs-tests/stress/stress00.sh | 52 + .../tests/fs-tests/stress/stress01.sh | 40 + .../mtd-utils/tests/fs-tests/utils/Makefile | 19 + .../tests/fs-tests/utils/free_space.c | 56 + .../tests/fs-tests/utils/fstest_monitor.c | 281 + .../mtd/mtd-utils/tests/jittertest/COPYING | 340 + .../mtd-utils/tests/jittertest/JitterTest.c | 1044 +++ .../mtd/mtd-utils/tests/jittertest/Makefile | 46 + .../mtd/mtd-utils/tests/jittertest/README | 197 + .../mtd-utils/tests/jittertest/filljffs2.sh | 16 + .../tests/jittertest/plotJittervsFill.c | 312 + .../mtd/mtd-utils/tests/ubi-tests/Makefile | 48 + .../mtd/mtd-utils/tests/ubi-tests/README.udev | 25 + .../mtd/mtd-utils/tests/ubi-tests/common.c | 336 + .../mtd/mtd-utils/tests/ubi-tests/common.h | 103 + .../mtd/mtd-utils/tests/ubi-tests/integ.c | 783 +++ .../mtd/mtd-utils/tests/ubi-tests/io_basic.c | 179 + .../mtd/mtd-utils/tests/ubi-tests/io_paral.c | 249 + .../mtd/mtd-utils/tests/ubi-tests/io_read.c | 388 ++ .../mtd/mtd-utils/tests/ubi-tests/io_update.c | 298 + .../mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c | 301 + .../mtd-utils/tests/ubi-tests/mkvol_basic.c | 250 + .../mtd-utils/tests/ubi-tests/mkvol_paral.c | 110 + .../mtd/mtd-utils/tests/ubi-tests/rsvol.c | 305 + .../mtd/mtd-utils/tests/ubi-tests/runtests.sh | 39 + .../mtd/mtd-utils/tests/ubi-tests/volrefcnt.c | 122 + .../drivers/mtd/mtd-utils/ubi-utils/Makefile | 85 + .../drivers/mtd/mtd-utils/ubi-utils/README | 236 + .../drivers/mtd/mtd-utils/ubi-utils/UBI.TXT | 108 + .../mtd/mtd-utils/ubi-utils/doc/unubi.roff | 123 + .../mtd/mtd-utils/ubi-utils/inc/libubi.h | 268 + .../mtd/mtd-utils/ubi-utils/lib/Makefile.am | 58 + .../ubi-utils/new-utils/LICENSE.libiniparser | 21 + .../mtd-utils/ubi-utils/new-utils/Makefile | 81 + .../mtd/mtd-utils/ubi-utils/new-utils/README | 55 + .../new-utils/include/libiniparser.h | 280 + .../ubi-utils/new-utils/include/libmtd.h | 73 + .../ubi-utils/new-utils/include/libscan.h | 112 + .../ubi-utils/new-utils/include/libubi.h | 382 ++ .../ubi-utils/new-utils/include/libubigen.h | 110 + .../ubi-utils/new-utils/src/common.c | 194 + .../ubi-utils/new-utils/src/common.h | 84 + .../mtd-utils/ubi-utils/new-utils/src/crc32.c | 95 + .../mtd-utils/ubi-utils/new-utils/src/crc32.h | 19 + .../ubi-utils/new-utils/src/dictionary.c | 405 ++ .../ubi-utils/new-utils/src/dictionary.h | 174 + .../ubi-utils/new-utils/src/libiniparser.c | 646 ++ .../ubi-utils/new-utils/src/libmtd.c | 314 + .../ubi-utils/new-utils/src/libscan.c | 225 + .../ubi-utils/new-utils/src/libubi.c | 1154 ++++ .../ubi-utils/new-utils/src/libubi_int.h | 133 + .../ubi-utils/new-utils/src/libubigen.c | 335 + .../ubi-utils/new-utils/src/ubiattach.c | 205 + .../ubi-utils/new-utils/src/ubicrc32.c | 124 + .../ubi-utils/new-utils/src/ubicrcsf.c | 94 + .../ubi-utils/new-utils/src/ubicrcvol.c | 221 + .../ubi-utils/new-utils/src/ubidetach.c | 181 + .../ubi-utils/new-utils/src/ubidumpvol.c | 264 + .../ubi-utils/new-utils/src/ubiformat.c | 712 ++ .../ubi-utils/new-utils/src/ubimkvol.c | 310 + .../ubi-utils/new-utils/src/ubinfo.c | 409 ++ .../ubi-utils/new-utils/src/ubinize.c | 582 ++ .../ubi-utils/new-utils/src/ubirefimg.c | 99 + .../ubi-utils/new-utils/src/ubirmvol.c | 195 + .../ubi-utils/new-utils/src/ubiupdatevol.c | 335 + .../ubi-utils/perl/f128_nand_sample.cfg | 38 + .../ubi-utils/perl/f64_nor_sample.cfg | 39 + .../mtd/mtd-utils/ubi-utils/perl/mkpfi | 723 ++ .../mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl | 74 + .../mtd/mtd-utils/ubi-utils/scripts/Makefile | 75 + .../mtd/mtd-utils/ubi-utils/scripts/README | 11 + .../mtd/mtd-utils/ubi-utils/scripts/TODO | 5 + .../ubi-utils/scripts/bin2nand2bin_test.sh | 184 + .../ubi-utils/scripts/inject_biterror.pl | 94 + .../mtd-utils/ubi-utils/scripts/jffs2_test.sh | 91 + .../mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl | 32 + .../mtd/mtd-utils/ubi-utils/scripts/pdd.txt | 16 + .../mtd-utils/ubi-utils/scripts/run_all.sh | 101 + .../mtd/mtd-utils/ubi-utils/scripts/test.cfg | 23 + .../ubi-utils/scripts/ubi_jffs2_test.sh | 411 ++ .../mtd-utils/ubi-utils/scripts/ubi_test.sh | 328 + .../ubi-utils/scripts/ubi_tools_test.sh | 252 + .../mtd-utils/ubi-utils/scripts/unubi_test.sh | 105 + .../mtd/mtd-utils/ubi-utils/src/bin2nand.c | 344 + .../mtd/mtd-utils/ubi-utils/src/bootenv.c | 1032 +++ .../mtd/mtd-utils/ubi-utils/src/bootenv.h | 434 ++ .../mtd/mtd-utils/ubi-utils/src/config.h | 28 + .../mtd/mtd-utils/ubi-utils/src/crc32.c | 83 + .../mtd/mtd-utils/ubi-utils/src/crc32.h | 36 + .../mtd/mtd-utils/ubi-utils/src/eb_chain.c | 281 + .../mtd/mtd-utils/ubi-utils/src/error.c | 240 + .../mtd/mtd-utils/ubi-utils/src/error.h | 84 + .../mtd/mtd-utils/ubi-utils/src/example_ubi.h | 28 + .../mtd/mtd-utils/ubi-utils/src/hashmap.c | 412 ++ .../mtd/mtd-utils/ubi-utils/src/hashmap.h | 49 + .../mtd/mtd-utils/ubi-utils/src/libpfiflash.c | 1325 ++++ .../mtd/mtd-utils/ubi-utils/src/libubi.c | 915 +++ .../mtd/mtd-utils/ubi-utils/src/libubi_int.h | 129 + .../mtd/mtd-utils/ubi-utils/src/libubigen.c | 487 ++ .../mtd-utils/ubi-utils/src/libubimirror.c | 237 + .../mtd/mtd-utils/ubi-utils/src/list.c | 149 + .../mtd/mtd-utils/ubi-utils/src/list.h | 56 + .../mtd/mtd-utils/ubi-utils/src/mkbootenv.c | 168 + .../mtd/mtd-utils/ubi-utils/src/nand2bin.c | 493 ++ .../mtd/mtd-utils/ubi-utils/src/nandcorr.c | 95 + .../mtd/mtd-utils/ubi-utils/src/nandecc.c | 159 + .../mtd/mtd-utils/ubi-utils/src/nandecc.h | 29 + .../mtd-utils/ubi-utils/src/pddcustomize.c | 516 ++ .../drivers/mtd/mtd-utils/ubi-utils/src/peb.c | 116 + .../drivers/mtd/mtd-utils/ubi-utils/src/peb.h | 41 + .../drivers/mtd/mtd-utils/ubi-utils/src/pfi.c | 458 ++ .../drivers/mtd/mtd-utils/ubi-utils/src/pfi.h | 244 + .../mtd/mtd-utils/ubi-utils/src/pfi2bin.c | 682 ++ .../mtd/mtd-utils/ubi-utils/src/pfiflash.c | 264 + .../mtd/mtd-utils/ubi-utils/src/pfiflash.h | 76 + .../mtd-utils/ubi-utils/src/pfiflash_error.h | 75 + .../mtd/mtd-utils/ubi-utils/src/reader.c | 482 ++ .../mtd/mtd-utils/ubi-utils/src/reader.h | 87 + .../mtd/mtd-utils/ubi-utils/src/ubigen.c | 359 + .../mtd/mtd-utils/ubi-utils/src/ubigen.h | 149 + .../mtd/mtd-utils/ubi-utils/src/ubimirror.c | 213 + .../mtd/mtd-utils/ubi-utils/src/ubimirror.h | 66 + .../mtd/mtd-utils/ubi-utils/src/unubi.c | 1024 +++ .../mtd-utils/ubi-utils/src/unubi_analyze.c | 463 ++ .../mtd-utils/ubi-utils/src/unubi_analyze.h | 87 + .../mtd/mtd-utils/ubi-utils/testcases.txt | 9 + .../drivers/mtd/nand/jz4740_nand.c | 1038 +++ .../drivers/mtd/nand/jz4750_nand.c | 1785 +++++ .../files-2.6.27/drivers/mtd/udc_cache.c | 531 ++ .../files-2.6.27/drivers/net/jz4760_eth.c | 1755 +++++ .../files-2.6.27/drivers/net/jz4760_eth.h | 1054 +++ .../xburst/files-2.6.27/drivers/net/jz_eth.c | 1290 ++++ .../xburst/files-2.6.27/drivers/net/jz_eth.h | 403 ++ .../files-2.6.27/drivers/net/jzcs8900a.c | 652 ++ .../files-2.6.27/drivers/net/jzcs8900a.h | 235 + .../files-2.6.27/drivers/power/jz_battery.c | 298 + .../xburst/files-2.6.27/drivers/rtc/alarm.c | 574 ++ .../files-2.6.27/drivers/rtc/rtc-jz4750.c | 542 ++ .../files-2.6.27/drivers/usb/gadget/android.c | 431 ++ .../drivers/usb/gadget/f_mass_storage.c | 3350 +++++++++ .../drivers/usb/gadget/f_mass_storage.h | 65 + .../drivers/usb/gadget/jz4730_udc.c | 1403 ++++ .../drivers/usb/gadget/jz4730_udc.h | 107 + .../drivers/usb/gadget/jz4740_udc.c | 2297 +++++++ .../drivers/usb/gadget/jz4740_udc.h | 121 + .../drivers/usb/gadget/udc_hotplug.h | 50 + .../drivers/usb/gadget/udc_hotplug_core.c | 836 +++ .../files-2.6.27/drivers/usb/host/ohci-jz.c | 260 + .../files-2.6.27/drivers/usb/musb/jz4760.c | 109 + .../files-2.6.27/drivers/video/jz4740_slcd.c | 1334 ++++ .../files-2.6.27/drivers/video/jz4740_slcd.h | 376 + .../drivers/video/jz4750_android_lcd.c | 3041 +++++++++ .../drivers/video/jz4750_android_lcd.h | 267 + .../files-2.6.27/drivers/video/jz4750_lcd.c | 3013 ++++++++ .../files-2.6.27/drivers/video/jz4750_lcd.h | 796 +++ .../files-2.6.27/drivers/video/jz4750_tve.c | 166 + .../files-2.6.27/drivers/video/jz4750_tve.h | 59 + .../drivers/video/jz4755_android_lcd.c | 2841 ++++++++ .../drivers/video/jz4755_android_lcd.h | 268 + .../drivers/video/jz4755_android_tve.h | 57 + .../files-2.6.27/drivers/video/jz4760_lcd.c | 2993 ++++++++ .../files-2.6.27/drivers/video/jz4760_lcd.h | 331 + .../drivers/video/jz_auo_a043fl01v2.h | 129 + .../drivers/video/jz_kgm_spfd5420a.h | 382 ++ .../drivers/video/jz_toppoly_td043mgeb1.h | 157 + .../xburst/files-2.6.27/drivers/video/jzlcd.c | 1538 +++++ .../xburst/files-2.6.27/drivers/video/jzlcd.h | 791 +++ .../xburst/files-2.6.27/drivers/video/logo.c | 194 + .../files-2.6.27/include/asm-mips/jzsoc.h | 52 + .../include/asm-mips/mach-jz4730/board-pmp.h | 83 + .../include/asm-mips/mach-jz4730/clock.h | 184 + .../include/asm-mips/mach-jz4730/dma.h | 272 + .../include/asm-mips/mach-jz4730/jz4730.h | 40 + .../include/asm-mips/mach-jz4730/misc.h | 28 + .../include/asm-mips/mach-jz4730/ops.h | 2541 +++++++ .../include/asm-mips/mach-jz4730/regs.h | 2550 +++++++ .../include/asm-mips/mach-jz4730/serial.h | 33 + .../include/asm-mips/mach-jz4730/war.h | 25 + .../asm-mips/mach-jz4740/board-dipper.h | 69 + .../include/asm-mips/mach-jz4740/board-leo.h | 56 + .../include/asm-mips/mach-jz4740/board-lyra.h | 70 + .../include/asm-mips/mach-jz4740/board-pavo.h | 70 + .../asm-mips/mach-jz4740/board-virgo.h | 67 + .../include/asm-mips/mach-jz4740/clock.h | 173 + .../include/asm-mips/mach-jz4740/dma.h | 265 + .../include/asm-mips/mach-jz4740/jz4740.h | 56 + .../include/asm-mips/mach-jz4740/misc.h | 43 + .../include/asm-mips/mach-jz4740/ops.h | 2224 ++++++ .../include/asm-mips/mach-jz4740/regs.h | 2392 +++++++ .../include/asm-mips/mach-jz4740/serial.h | 30 + .../include/asm-mips/mach-jz4740/war.h | 25 + .../include/asm-mips/mach-jz4750/board-apus.h | 124 + .../include/asm-mips/mach-jz4750/board-fuwa.h | 71 + .../include/asm-mips/mach-jz4750/clock.h | 204 + .../include/asm-mips/mach-jz4750/dma.h | 307 + .../include/asm-mips/mach-jz4750/jz4750.h | 44 + .../include/asm-mips/mach-jz4750/misc.h | 44 + .../include/asm-mips/mach-jz4750/ops.h | 3569 ++++++++++ .../include/asm-mips/mach-jz4750/regs.h | 3412 ++++++++++ .../include/asm-mips/mach-jz4750/serial.h | 30 + .../include/asm-mips/mach-jz4750/war.h | 25 + .../asm-mips/mach-jz4750d/board-cetus.h | 112 + .../asm-mips/mach-jz4750d/board-draco.h | 131 + .../asm-mips/mach-jz4750d/board-fuwa1.h | 131 + .../include/asm-mips/mach-jz4750d/clock.h | 230 + .../include/asm-mips/mach-jz4750d/dma.h | 307 + .../include/asm-mips/mach-jz4750d/jz4750d.h | 43 + .../include/asm-mips/mach-jz4750d/misc.h | 44 + .../include/asm-mips/mach-jz4750d/ops.h | 3430 ++++++++++ .../include/asm-mips/mach-jz4750d/regs.h | 3397 ++++++++++ .../include/asm-mips/mach-jz4750d/serial.h | 30 + .../include/asm-mips/mach-jz4750d/war.h | 25 + .../asm-mips/mach-jz4760/board-f4760.h | 94 + .../include/asm-mips/mach-jz4760/clock.h | 231 + .../include/asm-mips/mach-jz4760/dma.h | 306 + .../include/asm-mips/mach-jz4760/jz4760.h | 40 + .../include/asm-mips/mach-jz4760/misc.h | 44 + .../include/asm-mips/mach-jz4760/ops.h | 3445 ++++++++++ .../include/asm-mips/mach-jz4760/regs.h | 3747 ++++++++++ .../include/asm-mips/mach-jz4760/serial.h | 30 + .../include/asm-mips/mach-jz4760/war.h | 25 + .../files-2.6.27/include/asm-mips/sizes.h | 56 + .../files-2.6.27/sound/oss/ac97_codec.c | 1206 ++++ .../xburst/files-2.6.27/sound/oss/ak4642en.c | 712 ++ .../xburst/files-2.6.27/sound/oss/jz_ac97.c | 2252 ++++++ .../xburst/files-2.6.27/sound/oss/jz_i2s.c | 2908 ++++++++ .../sound/oss/jz_pcm_tlv320aic1106_dma.c | 1839 +++++ .../xburst/files-2.6.27/sound/oss/jzcodec.c | 443 ++ .../xburst/files-2.6.27/sound/oss/jzdlv.c | 644 ++ .../xburst/files-2.6.27/sound/oss/jzdlv.h | 21 + .../files-2.6.27/sound/soc/codecs/jzcodec.c | 725 ++ .../files-2.6.27/sound/soc/codecs/jzcodec.h | 22 + .../files-2.6.27/sound/soc/codecs/jzdlv.c | 981 +++ .../files-2.6.27/sound/soc/codecs/jzdlv.h | 50 + .../files-2.6.27/sound/soc/jz4740/Kconfig | 34 + .../files-2.6.27/sound/soc/jz4740/Makefile | 15 + .../sound/soc/jz4740/jz4740-ac97.c | 261 + .../sound/soc/jz4740/jz4740-ac97.h | 21 + .../sound/soc/jz4740/jz4740-i2s.c | 297 + .../sound/soc/jz4740/jz4740-i2s.h | 18 + .../sound/soc/jz4740/jz4740-pcm.c | 689 ++ .../sound/soc/jz4740/jz4740-pcm.h | 33 + .../files-2.6.27/sound/soc/jz4740/pavo.c | 364 + .../files-2.6.27/sound/soc/jz4750/Kconfig | 34 + .../files-2.6.27/sound/soc/jz4750/Makefile | 15 + .../files-2.6.27/sound/soc/jz4750/apus.c | 405 ++ .../sound/soc/jz4750/jz4750-ac97.c | 261 + .../sound/soc/jz4750/jz4750-ac97.h | 21 + .../sound/soc/jz4750/jz4750-i2s.c | 311 + .../sound/soc/jz4750/jz4750-i2s.h | 18 + .../sound/soc/jz4750/jz4750-pcm.c | 687 ++ .../sound/soc/jz4750/jz4750-pcm.h | 33 + .../patches-2.6.27/001-ingenic-patchset.patch | 6033 +++++++++++++++++ .../patches-2.6.27/010-add-qi_lb60.patch | 375 + 452 files changed, 188939 insertions(+) create mode 100644 target/linux/xburst/files-2.6.27/Changelog create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/Makefile create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/dummy.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/head.S create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/ld.script create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/misc.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/boot/tools/entry create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/boot/tools/filesize create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/configs/apus_defconfig create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/configs/cetus_defconfig create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/configs/dipper_defconfig create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/configs/f4760_defconfig create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/configs/fuwa_defconfig create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/configs/leo_defconfig create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/configs/lyra_defconfig create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/configs/pavo_defconfig create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/configs/pmp_defconfig create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/configs/virgo_defconfig create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/Makefile create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/board-pmp.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/cpufreq.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/dma.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/i2c.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/irq.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/platform.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/pm.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/proc.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/prom.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/reset.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/setup.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/sleep.S create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4730/time.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/Makefile create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-dipper.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-leo.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-lyra.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-pavo.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-virgo.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/cpufreq.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/dma.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/i2c.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/irq.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/platform.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/pm.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/proc.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/prom.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/reset.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/setup.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4740/time.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/Makefile create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/board-apus.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/board-fuwa.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/cpufreq.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/dma.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/i2c.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/irq.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/platform.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/pm.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/proc.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/prom.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/reset.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/setup.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750/time.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/Makefile create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/board-cetus.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/board-fuwa1.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/cpufreq.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/dma.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/i2c.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/irq.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/platform.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/pm.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/proc.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/prom.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/reset.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/setup.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4750d/time.c create mode 100644 target/linux/xburst/files-2.6.27/arch/mips/jz4760/Makefile create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4760/board-f4760.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4760/cpufreq.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4760/dma.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4760/i2c.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4760/irq.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4760/platform.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4760/pm.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4760/proc.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4760/prom.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4760/reset.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4760/setup.c create mode 100755 target/linux/xburst/files-2.6.27/arch/mips/jz4760/time.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/i2c/busses/i2c-jz47xx.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/i2c/busses/i2c-jz47xx.h create mode 100755 target/linux/xburst/files-2.6.27/drivers/input/keyboard/jz_gpio_keypad.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/input/keyboard/jz_keypad.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/input/keyboard/jz_keypad_5x5.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/input/touchscreen/jz_ts.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/misc/jz_cim.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/misc/jz_cim.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/misc/jz_sensor.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/misc/jz_sensor.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/misc/jz_tcsm.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/mmc/host/jz4750_mmc.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/mmc/host/jz4750_mmc.h create mode 100755 target/linux/xburst/files-2.6.27/drivers/mmc/host/jz_mmc.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/mmc/host/jz_mmc.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/COPYING create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/MAKEDEV create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr_lzo.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr_rtime.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr_zlib.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/crc32.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/crc32.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/device_table.txt create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/doc_loadbios.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/docfdisk.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/feature-removal-schedule.txt create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/fec.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/fectest.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_erase.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_eraseall.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_info.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_lock.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_dump.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_info.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_lock.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_write.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_unlock.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flashcp.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ftl_check.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ftl_format.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/linux/jffs2.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/ftl-user.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/inftl-user.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/jffs2-user.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/mtd-user.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/nftl-user.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/ubi-header.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/ubi-user.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd_swab.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/jffs-dump.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/jffs2dump.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/jffs2reader.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/load_nandsim.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mcast_image.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mkfs.jffs2.1 create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mkfs.jffs2.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mtd-utils.spec create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mtd_debug.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nanddump.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nanddump_vfat.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nandtest.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nandwrite.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nandwrite_mlc.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nftl_format.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nftldump.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rbtree.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rbtree.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/recv_image.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rfddump.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rfdformat.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/serve_image.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/summary.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/sumtool.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/README create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/checkfs.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/comm.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/common.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/makefiles.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/help_all.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/integrity/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/integrity/integck.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/COPYING create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/README create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/README.udev create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/common.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/common.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/README create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/UBI.TXT create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/README create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirmvol.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/README create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/TODO create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/config.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/crc32.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/crc32.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/error.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/error.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libubi.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/list.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/list.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/peb.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/peb.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfi.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfi.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/reader.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/reader.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/unubi.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/testcases.txt create mode 100755 target/linux/xburst/files-2.6.27/drivers/mtd/nand/jz4740_nand.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/mtd/nand/jz4750_nand.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/mtd/udc_cache.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/net/jz4760_eth.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/net/jz4760_eth.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/net/jz_eth.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/net/jz_eth.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/net/jzcs8900a.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/net/jzcs8900a.h create mode 100755 target/linux/xburst/files-2.6.27/drivers/power/jz_battery.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/rtc/alarm.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/rtc/rtc-jz4750.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/usb/gadget/android.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/usb/gadget/f_mass_storage.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/usb/gadget/f_mass_storage.h create mode 100755 target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4730_udc.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4730_udc.h create mode 100755 target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4740_udc.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4740_udc.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/usb/gadget/udc_hotplug.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/usb/gadget/udc_hotplug_core.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/usb/host/ohci-jz.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/usb/musb/jz4760.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/video/jz4740_slcd.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz4740_slcd.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz4750_android_lcd.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz4750_android_lcd.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz4750_lcd.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz4750_lcd.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz4750_tve.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz4750_tve.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz4755_android_lcd.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz4755_android_lcd.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz4755_android_tve.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz4760_lcd.c create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz4760_lcd.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz_auo_a043fl01v2.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz_kgm_spfd5420a.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/jz_toppoly_td043mgeb1.h create mode 100755 target/linux/xburst/files-2.6.27/drivers/video/jzlcd.c create mode 100755 target/linux/xburst/files-2.6.27/drivers/video/jzlcd.h create mode 100644 target/linux/xburst/files-2.6.27/drivers/video/logo.c create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/jzsoc.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/board-pmp.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/clock.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/dma.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/jz4730.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/misc.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/ops.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/regs.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/serial.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/war.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-dipper.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-leo.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-lyra.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-pavo.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-virgo.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/clock.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/dma.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/jz4740.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/misc.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/ops.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/regs.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/serial.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/war.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/board-apus.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/board-fuwa.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/clock.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/dma.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/jz4750.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/misc.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/ops.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/regs.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/serial.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/war.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/board-cetus.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/board-draco.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/board-fuwa1.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/clock.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/dma.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/jz4750d.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/misc.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/ops.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/regs.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/serial.h create mode 100755 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/war.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/board-f4760.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/clock.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/dma.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/jz4760.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/misc.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/ops.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/regs.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/serial.h create mode 100755 target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/war.h create mode 100644 target/linux/xburst/files-2.6.27/include/asm-mips/sizes.h create mode 100755 target/linux/xburst/files-2.6.27/sound/oss/ac97_codec.c create mode 100755 target/linux/xburst/files-2.6.27/sound/oss/ak4642en.c create mode 100755 target/linux/xburst/files-2.6.27/sound/oss/jz_ac97.c create mode 100755 target/linux/xburst/files-2.6.27/sound/oss/jz_i2s.c create mode 100644 target/linux/xburst/files-2.6.27/sound/oss/jz_pcm_tlv320aic1106_dma.c create mode 100755 target/linux/xburst/files-2.6.27/sound/oss/jzcodec.c create mode 100755 target/linux/xburst/files-2.6.27/sound/oss/jzdlv.c create mode 100755 target/linux/xburst/files-2.6.27/sound/oss/jzdlv.h create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/codecs/jzcodec.c create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/codecs/jzcodec.h create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/codecs/jzdlv.c create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/codecs/jzdlv.h create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4740/Kconfig create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4740/Makefile create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-ac97.c create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-ac97.h create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-i2s.c create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-i2s.h create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-pcm.c create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-pcm.h create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4740/pavo.c create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4750/Kconfig create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4750/Makefile create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4750/apus.c create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-ac97.c create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-ac97.h create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-i2s.c create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-i2s.h create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-pcm.c create mode 100755 target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-pcm.h create mode 100644 target/linux/xburst/patches-2.6.27/001-ingenic-patchset.patch create mode 100644 target/linux/xburst/patches-2.6.27/010-add-qi_lb60.patch diff --git a/target/linux/xburst/files-2.6.27/Changelog b/target/linux/xburst/files-2.6.27/Changelog new file mode 100644 index 000000000..0f0f1e650 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/Changelog @@ -0,0 +1,11 @@ +2009.04.30 +* Fix a bug in using gpio keys when pressing two keys at the same time. + Updated file: + drivers/input/keyboard/gpio_keys.c + + +2009.04.28 +* Support detecting the power of battery. + Add File: + drivers/power/jz_battery.c + diff --git a/target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/Makefile b/target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/Makefile new file mode 100644 index 000000000..9b4132985 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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) \ + -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/target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/dummy.c b/target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/dummy.c new file mode 100644 index 000000000..31dbf45bf --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/dummy.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/head.S b/target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/head.S new file mode 100644 index 000000000..d9700eb50 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/ld.script b/target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/ld.script new file mode 100644 index 000000000..fcf8ba041 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/misc.c b/target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/misc.c new file mode 100644 index 000000000..2309feea3 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/boot/compressed/misc.c @@ -0,0 +1,242 @@ +/* + * 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); +static void gzip_mark(void **); +static void gzip_release(void **); + +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 *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +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" + +static void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error\n"); + if (free_mem_ptr == 0) error("Memory error\n"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("\nOut of memory\n"); + + return p; +} + +static void free(void *where) +{ /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +void* memset(void* s, int c, size_t n) +{ + int i; + char *ss = (char*)s; + + for (i=0;i> 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/target/linux/xburst/files-2.6.27/arch/mips/boot/tools/entry b/target/linux/xburst/files-2.6.27/arch/mips/boot/tools/entry new file mode 100644 index 000000000..376e822a6 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/boot/tools/filesize b/target/linux/xburst/files-2.6.27/arch/mips/boot/tools/filesize new file mode 100644 index 000000000..2142ad5af --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/configs/apus_defconfig b/target/linux/xburst/files-2.6.27/arch/mips/configs/apus_defconfig new file mode 100644 index 000000000..e3883cb0f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/configs/apus_defconfig @@ -0,0 +1,1348 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.27 +# Thu Jul 30 12:24:01 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_JZ4750_APUS=y +# CONFIG_JZ4750D_CETUS is not set +# CONFIG_JZ4760_F4760 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_MALTA 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_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_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_PAGEFLAGS_EXTENDED=y +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_RCU is not set +# 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_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +# CONFIG_GROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_RELAY=y +# CONFIG_NAMESPACES is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_PANIC_TIMEOUT=0 +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=y +CONFIG_COMPAT_BRK=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set +# CONFIG_HAVE_IOREMAP_PROT is not set +# CONFIG_HAVE_KPROBES is not set +# CONFIG_HAVE_KRETPROBES is not set +# CONFIG_HAVE_ARCH_TRACEHOOK is not set +# CONFIG_HAVE_DMA_ATTRS is not set +# CONFIG_USE_GENERIC_SMP_HELPERS is not set +# CONFIG_HAVE_CLK is not set +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_HAVE_GENERIC_DMA_COHERENT 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_FORCE_LOAD is not set +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 +# CONFIG_BLK_DEV_INTEGRITY 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" +CONFIG_CLASSIC_RCU=y + +# +# 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_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_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +# CONFIG_CONSOLE_EARLYSUSPEND is not set +CONFIG_FB_EARLYSUSPEND=y +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_ANDROID_PARANOID_NETWORK=y +# 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_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +# CONFIG_BT_RFCOMM is not set +# CONFIG_BT_BNEP is not set +# CONFIG_BT_HIDP is not set + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIBTUSB=y +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_EXT=y +CONFIG_WIRELESS_EXT_SYSFS=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 +# 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_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 is not set +CONFIG_MTD_HW_BCH_8BIT=y +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_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_JZ_TCSM=y +CONFIG_JZ_CIM=y +CONFIG_OV3640=y +# CONFIG_OV2640 is not set +# CONFIG_OV9650 is not set +# CONFIG_ANDROID_PMEM is not set +CONFIG_TIMED_OUTPUT=y +CONFIG_BINDER_IPC=y +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_KERNEL_DEBUGGER_CORE is not set +# CONFIG_LOW_MEMORY_KILLER is not set +CONFIG_LOGGER=y +# CONFIG_UID_STAT is not set +# CONFIG_ANDROID_RAM_CONSOLE 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=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_SCSI_DH 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_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=y +CONFIG_NETDEV_10000=y + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_IWLWIFI_LEDS 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_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 +# CONFIG_INPUT_KEYRESET is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# 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_GPIO=y +# CONFIG_KEYBOARD_JZ is not set +# CONFIG_KEYBOARD_JZ_5x5 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_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +CONFIG_TOUCHSCREEN_JZ=y +CONFIG_JZ_ADKEY=y +# 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_UCB1400 is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +CONFIG_INPUT_UINPUT=y +# CONFIG_INPUT_GPIO is not set +# CONFIG_INPUT_KEYCHORD 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 is not set +CONFIG_DEVMEM=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_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=2 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM 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 +# CONFIG_SPI is not set +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_BATTERY_DS2760 is not set +CONFIG_BATTERY_JZ=y +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_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_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +# 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_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_JZSOC_BOOT_LOGO=y +CONFIG_FB_565RLE_LOGO=y +# CONFIG_FB_565RGB_LOGO is not set +CONFIG_FB_ANDROID_JZSOC=y +# CONFIG_IPU_ANDROID_JZ4750 is not set +CONFIG_FB_JZ4750_ANDROID_LCD=y +CONFIG_FB_JZ4750_ANDROID_TFT=y +CONFIG_JZ4750_ANDROID_LCD_AUO_A043FL01V2=y +# CONFIG_JZ4750_ANDROID_LCD_TOPPOLY_TD043MGEB1 is not set +# CONFIG_FB_JZSOC 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 +# CONFIG_LOGO is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# 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 +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_MIPS is not set +CONFIG_SND_USB=y +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set +CONFIG_SND_SOC=y +CONFIG_SND_JZ4750_SOC=y +CONFIG_SND_JZ4750_SOC_APUS=y +# CONFIG_SND_JZ4750_AC97 is not set +CONFIG_SND_JZ4750_SOC_I2S=y +CONFIG_SND_SOC_DLV=y +# 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 +# CONFIG_USB_ANNOUNCE_NEW_DEVICES 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_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=y + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_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_MUSB_HDRC 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 + +# +# 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_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_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 +# CONFIG_USB_ISIGHTFW is not set +CONFIG_USB_GADGET=y +# 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=y +# 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_PXA25X is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_PXA27X 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_JZ_UDC_HOTPLUG=y +CONFIG_UDC_USE_LB_CACHE=y +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 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_ANDROID=y +# CONFIG_USB_CDC_COMPOSITE is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_EMBEDDED_SDIO is not set +# CONFIG_MMC_PARANOID_SD_INIT is not set + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_PARANOID_RESUME=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST 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_MMC_SDHCI is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# + +# +# LED Triggers +# +# CONFIG_LEDS_TRIGGERS is not set +CONFIG_SWITCH=y +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_ALARM=y +# CONFIG_RTC_DRV_TEST is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_JZ4750=y +# CONFIG_DMADEVICES is not set +# 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_OCFS2_FS is not set +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 + +# +# 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_YAFFS_FS=y +CONFIG_YAFFS_YAFFS1=y +# CONFIG_YAFFS_9BYTE_TAGS is not set +# 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_ALWAYS_CHECK_CHUNK_ERASED is not set +CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y +CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +CONFIG_MINIX_FS=y +# 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_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +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 is not set +# CONFIG_DLM 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_FRAME_WARN=1024 +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_DEBUG_MEMORY_INIT is not set +# CONFIG_SYSCTL_SYSCALL_CHECK 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_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# 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_LZO is not set +CONFIG_CRYPTO_HW=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_GENERIC_FIND_FIRST_BIT is not set +# 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_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/target/linux/xburst/files-2.6.27/arch/mips/configs/cetus_defconfig b/target/linux/xburst/files-2.6.27/arch/mips/configs/cetus_defconfig new file mode 100644 index 000000000..ca278d1d8 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/configs/cetus_defconfig @@ -0,0 +1,1183 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.27 +# Tue Jul 28 15:44:43 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_JZ4750_APUS is not set +CONFIG_JZ4750D_CETUS=y +# CONFIG_JZ4760_F4760 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_MALTA 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_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_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_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_PAGEFLAGS_EXTENDED=y +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_RCU is not set +# 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_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +# CONFIG_GROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_RELAY=y +# CONFIG_NAMESPACES is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="/home/clfeng/work/android-1.5r2/out/target/product/cetus/ramdisk.cpio.img" +CONFIG_INITRAMFS_ROOT_UID=0 +CONFIG_INITRAMFS_ROOT_GID=0 +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_PANIC_TIMEOUT=0 +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=y +CONFIG_COMPAT_BRK=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set +# CONFIG_HAVE_IOREMAP_PROT is not set +# CONFIG_HAVE_KPROBES is not set +# CONFIG_HAVE_KRETPROBES is not set +# CONFIG_HAVE_ARCH_TRACEHOOK is not set +# CONFIG_HAVE_DMA_ATTRS is not set +# CONFIG_USE_GENERIC_SMP_HELPERS is not set +# CONFIG_HAVE_CLK is not set +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_HAVE_GENERIC_DMA_COHERENT 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_FORCE_LOAD is not set +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 +# CONFIG_BLK_DEV_INTEGRITY 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" +CONFIG_CLASSIC_RCU=y +# CONFIG_PROBE_INITRD_HEADER is not set + +# +# 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_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_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +# CONFIG_CONSOLE_EARLYSUSPEND is not set +CONFIG_FB_EARLYSUSPEND=y +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_ANDROID_PARANOID_NETWORK=y +# 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_CAN 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_WIRELESS_EXT_SYSFS=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 +# 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_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 is not set +CONFIG_MTD_HW_BCH_8BIT=y +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_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_JZ_TCSM=y +# CONFIG_JZ_CIM is not set +# CONFIG_ANDROID_PMEM is not set +CONFIG_TIMED_OUTPUT=y +CONFIG_BINDER_IPC=y +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_KERNEL_DEBUGGER_CORE is not set +# CONFIG_LOW_MEMORY_KILLER is not set +CONFIG_LOGGER=y +# CONFIG_UID_STAT is not set +# CONFIG_ANDROID_RAM_CONSOLE 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_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=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_IWLWIFI_LEDS 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 +# CONFIG_INPUT_KEYRESET is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# 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_GPIO=y +# CONFIG_KEYBOARD_JZ is not set +# CONFIG_KEYBOARD_JZ_5x5 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_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +CONFIG_TOUCHSCREEN_JZ=y +CONFIG_JZ_ADKEY=y +# 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_UCB1400 is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 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 is not set +CONFIG_DEVMEM=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_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=2 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM 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 +# CONFIG_SPI is not set +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_BATTERY_DS2760 is not set +CONFIG_BATTERY_JZ=y +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_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_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +# 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_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_JZSOC_BOOT_LOGO=y +CONFIG_FB_565RLE_LOGO=y +# CONFIG_FB_565RGB_LOGO is not set +CONFIG_FB_ANDROID_JZ4755SOC=y +# CONFIG_IPU_ANDROID_JZ4755 is not set +CONFIG_FB_JZ4755_ANDROID_LCD=y +CONFIG_FB_JZ4755_ANDROID_TFT=y +CONFIG_JZ4755_ANDROID_LCD_AUO_A043FL01V2=y +# CONFIG_JZ4755_ANDROID_LCD_TOPPOLY_TD043MGEB1 is not set +# CONFIG_FB_ANDROID_JZSOC is not set +# CONFIG_FB_JZSOC 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 +# CONFIG_LOGO is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# 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 +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_MIPS is not set +CONFIG_SND_SOC=y +CONFIG_SND_JZ4750_SOC=y +CONFIG_SND_JZ4750_SOC_APUS=y +# CONFIG_SND_JZ4750_AC97 is not set +CONFIG_SND_JZ4750_SOC_I2S=y +CONFIG_SND_SOC_DLV=y +# CONFIG_SOUND_PRIME 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 +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_GADGET_MUSB_HDRC is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# +CONFIG_USB_GADGET=y +# 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=y +# 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_PXA25X is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_PXA27X 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_JZ_UDC_HOTPLUG=y +CONFIG_UDC_USE_LB_CACHE=y +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 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_ANDROID=y +# CONFIG_USB_CDC_COMPOSITE is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_EMBEDDED_SDIO is not set +# CONFIG_MMC_PARANOID_SD_INIT is not set + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_PARANOID_RESUME=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST 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_MMC_SDHCI is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# + +# +# LED Triggers +# +# CONFIG_LEDS_TRIGGERS is not set +CONFIG_SWITCH=y +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_ALARM=y +# CONFIG_RTC_DRV_TEST is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_JZ4750=y +# CONFIG_DMADEVICES is not set +# 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_OCFS2_FS is not set +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 + +# +# 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_YAFFS_FS=y +CONFIG_YAFFS_YAFFS1=y +# CONFIG_YAFFS_9BYTE_TAGS is not set +# 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_ALWAYS_CHECK_CHUNK_ERASED is not set +CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y +CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +CONFIG_MINIX_FS=y +# 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_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +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 is not set +# CONFIG_DLM 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_FRAME_WARN=1024 +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_DEBUG_MEMORY_INIT is not set +# CONFIG_SYSCTL_SYSCALL_CHECK 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_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# 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_LZO is not set +CONFIG_CRYPTO_HW=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_GENERIC_FIND_FIRST_BIT is not set +# 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_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/target/linux/xburst/files-2.6.27/arch/mips/configs/dipper_defconfig b/target/linux/xburst/files-2.6.27/arch/mips/configs/dipper_defconfig new file mode 100644 index 000000000..b046b2ccc --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/configs/f4760_defconfig b/target/linux/xburst/files-2.6.27/arch/mips/configs/f4760_defconfig new file mode 100644 index 000000000..83611dbb6 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/configs/f4760_defconfig @@ -0,0 +1,892 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.27 +# Fri Aug 7 10:22:22 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_JZ4750_APUS is not set +# CONFIG_JZ4750D_CETUS is not set +CONFIG_JZ4760_F4760=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_MALTA 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_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_SOC_JZ4760=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_PAGEFLAGS_EXTENDED=y +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_RCU is not set +# 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_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +# CONFIG_GROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_RELAY=y +# CONFIG_NAMESPACES is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_PANIC_TIMEOUT=0 +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=y +CONFIG_COMPAT_BRK=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set +# CONFIG_HAVE_IOREMAP_PROT is not set +# CONFIG_HAVE_KPROBES is not set +# CONFIG_HAVE_KRETPROBES is not set +# CONFIG_HAVE_ARCH_TRACEHOOK is not set +# CONFIG_HAVE_DMA_ATTRS is not set +# CONFIG_USE_GENERIC_SMP_HELPERS is not set +# CONFIG_HAVE_CLK is not set +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_HAVE_GENERIC_DMA_COHERENT 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_FORCE_LOAD is not set +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 +# CONFIG_BLK_DEV_INTEGRITY 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" +CONFIG_CLASSIC_RCU=y + +# +# 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_ARCH_SUSPEND_POSSIBLE=y +# CONFIG_PM 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=y +# 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_IP_MROUTE 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_ANDROID_PARANOID_NETWORK=y +# 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_CAN 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_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 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_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_JZ_ETH is not set +CONFIG_JZ4760_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 +# CONFIG_IWLWIFI_LEDS 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 +# CONFIG_INPUT_KEYRESET is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# 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_GPIO is not set +# CONFIG_KEYBOARD_JZ is not set +# CONFIG_KEYBOARD_JZ_5x5 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_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_JZ 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_UCB1400 is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 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_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_DEVMEM=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_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=2 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM 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 +# CONFIG_SPI 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 + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +# 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 + +# +# Multimedia devices +# + +# +# Multimedia core support +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_VIDEO_MEDIA is not set + +# +# Multimedia drivers +# +# 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 +# CONFIG_SOUND is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_SWITCH is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# 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_OCFS2_FS is not set +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 + +# +# 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_MINIX_FS=y +# 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_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +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 is not set +# CONFIG_DLM 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_FRAME_WARN=1024 +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_DEBUG_MEMORY_INIT is not set +# CONFIG_SYSCTL_SYSCALL_CHECK 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_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# 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_LZO is not set +CONFIG_CRYPTO_HW=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_GENERIC_FIND_FIRST_BIT is not set +# 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_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/target/linux/xburst/files-2.6.27/arch/mips/configs/fuwa_defconfig b/target/linux/xburst/files-2.6.27/arch/mips/configs/fuwa_defconfig new file mode 100644 index 000000000..f0bde8fc3 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/configs/leo_defconfig b/target/linux/xburst/files-2.6.27/arch/mips/configs/leo_defconfig new file mode 100644 index 000000000..6d5fbdb98 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/configs/lyra_defconfig b/target/linux/xburst/files-2.6.27/arch/mips/configs/lyra_defconfig new file mode 100644 index 000000000..eeb84d8ea --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/configs/pavo_defconfig b/target/linux/xburst/files-2.6.27/arch/mips/configs/pavo_defconfig new file mode 100644 index 000000000..59eab829e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/configs/pavo_defconfig @@ -0,0 +1,1329 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.27 +# Tue Mar 10 10:26:28 2009 +# +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_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_MALTA 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_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_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_PAGEFLAGS_EXTENDED=y +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_RCU is not set +# 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_AUDIT is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +# CONFIG_GROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_RELAY=y +# CONFIG_NAMESPACES is not set +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_PANIC_TIMEOUT=0 +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=y +CONFIG_COMPAT_BRK=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set +# CONFIG_HAVE_IOREMAP_PROT is not set +# CONFIG_HAVE_KPROBES is not set +# CONFIG_HAVE_KRETPROBES is not set +# CONFIG_HAVE_ARCH_TRACEHOOK is not set +# CONFIG_HAVE_DMA_ATTRS is not set +# CONFIG_USE_GENERIC_SMP_HELPERS is not set +# CONFIG_HAVE_CLK is not set +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_HAVE_GENERIC_DMA_COHERENT 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_FORCE_LOAD is not set +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 +# CONFIG_BLK_DEV_INTEGRITY 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" +CONFIG_CLASSIC_RCU=y + +# +# 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_POWERSAVE 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_ARCH_SUSPEND_POSSIBLE=y +# CONFIG_PM 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_ANDROID_PARANOID_NETWORK 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_CAN 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_WIRELESS_EXT_SYSFS=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 +# 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_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_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_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_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_ANDROID_PMEM is not set +CONFIG_TIMED_OUTPUT=y +CONFIG_BINDER_IPC=y +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_KERNEL_DEBUGGER_CORE is not set +# CONFIG_LOW_MEMORY_KILLER is not set +CONFIG_LOGGER=y +# CONFIG_UID_STAT is not set +# CONFIG_ANDROID_RAM_CONSOLE 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=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_SCSI_DH 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_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 +# CONFIG_IWLWIFI_LEDS 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_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 +# CONFIG_INPUT_KEYRESET 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_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_DEVMEM=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_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=2 +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM 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 +# CONFIG_SPI 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 + +# +# 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_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_MFD_TMIO is not set + +# +# Multimedia devices +# + +# +# Multimedia core support +# +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +CONFIG_VIDEO_ALLOW_V4L1=y +CONFIG_VIDEO_V4L1_COMPAT=y +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +# CONFIG_MEDIA_ATTACH is not set +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_V4L1=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_V4L_USB_DRIVERS=y +# CONFIG_USB_VIDEO_CLASS is not set +# CONFIG_USB_GSPCA is not set +# 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_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +CONFIG_RADIO_ADAPTERS=y +# CONFIG_USB_DSBR is not set +# CONFIG_USB_SI470X 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_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_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_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_SND is not set +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=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_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 +# CONFIG_USB_ANNOUNCE_NEW_DEVICES 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 +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=y + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_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_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 + +# +# 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_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_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_ISIGHTFW is not set +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_JZ4750 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_PXA25X is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_PXA27X 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_USB_G_PRINTER is not set +# CONFIG_USB_ANDROID is not set +# CONFIG_USB_CDC_COMPOSITE is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set +# CONFIG_MMC_EMBEDDED_SDIO is not set +# CONFIG_MMC_PARANOID_SD_INIT is not set + +# +# MMC/SD Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_PARANOID_RESUME=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD 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_SWITCH is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +# CONFIG_RTC_CLASS is not set +# CONFIG_DMADEVICES is not set +# 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_OCFS2_FS is not set +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 + +# +# 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_YAFFS_FS=y +CONFIG_YAFFS_YAFFS1=y +# CONFIG_YAFFS_9BYTE_TAGS is not set +# 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_ALWAYS_CHECK_CHUNK_ERASED is not set +CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y +CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 +# 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_MINIX_FS=y +# 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_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +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 is not set +# CONFIG_DLM 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_FRAME_WARN=1024 +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_DEBUG_MEMORY_INIT is not set +# CONFIG_SYSCTL_SYSCALL_CHECK 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_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_MANAGER=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# 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=m +CONFIG_CRYPTO_LZO=m +CONFIG_CRYPTO_HW=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_GENERIC_FIND_FIRST_BIT is not set +# CONFIG_CRC_CCITT is not set +CONFIG_CRC16=m +# 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_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/target/linux/xburst/files-2.6.27/arch/mips/configs/pmp_defconfig b/target/linux/xburst/files-2.6.27/arch/mips/configs/pmp_defconfig new file mode 100644 index 000000000..85575b4d3 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/configs/virgo_defconfig b/target/linux/xburst/files-2.6.27/arch/mips/configs/virgo_defconfig new file mode 100644 index 000000000..a0e02a023 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/jz4730/Makefile b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/Makefile new file mode 100644 index 000000000..d84b6b6cf --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/jz4730/board-pmp.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/board-pmp.c new file mode 100644 index 000000000..00860c1ce --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +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/target/linux/xburst/files-2.6.27/arch/mips/jz4730/cpufreq.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/cpufreq.c new file mode 100644 index 000000000..1bf47136a --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include + +#include + +#include +#include + +#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, ®s); + + 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(®s); + + 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 "); +MODULE_DESCRIPTION("cpufreq driver for Jz4730"); +MODULE_LICENSE("GPL"); + diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4730/dma.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/dma.c new file mode 100644 index 000000000..ca7d5498b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * 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/target/linux/xburst/files-2.6.27/arch/mips/jz4730/i2c.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/i2c.c new file mode 100644 index 000000000..91f55a7a3 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include + +#include + +/* 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/target/linux/xburst/files-2.6.27/arch/mips/jz4730/irq.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/irq.c new file mode 100644 index 000000000..658596fac --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/irq.c @@ -0,0 +1,266 @@ +/* + * linux/arch/mips/jz4730/irq.c + * + * JZ4730 interrupt routines. + * + * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * 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, + .enable = enable_intc_irq, + .disable = 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, + .enable = enable_gpio_irq, + .disable = 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, + .enable = enable_dma_irq, + .disable = 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); + irq_desc[i].chip = &intc_irq_type; + } + + /* Set up DMAC irq + */ + for (i = 0; i < NUM_DMA; i++) { + disable_dma_irq(IRQ_DMA_0 + i); + irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; + } + + /* Set up GPIO irq + */ + for (i = 0; i < NUM_GPIO; i++) { + disable_gpio_irq(IRQ_GPIO_0 + i); + irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; + } +} + +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< + * + * 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 +#include +#include +#include +#include + +#include + +/* 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/target/linux/xburst/files-2.6.27/arch/mips/jz4730/pm.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/pm.c new file mode 100644 index 000000000..a46e9c391 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * Huang Lihong + * 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 +#include +#include +#include +#include +#include + +#include +#include + +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/target/linux/xburst/files-2.6.27/arch/mips/jz4730/proc.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/proc.c new file mode 100644 index 000000000..49585bc5a --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include +#include + +#include +#include + +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/target/linux/xburst/files-2.6.27/arch/mips/jz4730/prom.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/prom.c new file mode 100644 index 000000000..5a5f6b8e6 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include + +#include +#include + +/* #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/target/linux/xburst/files-2.6.27/arch/mips/jz4730/reset.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/reset.c new file mode 100644 index 000000000..4c9e20c92 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +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/target/linux/xburst/files-2.6.27/arch/mips/jz4730/setup.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/setup.c new file mode 100644 index 000000000..4594b5626 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PC_KEYB +#include +#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/target/linux/xburst/files-2.6.27/arch/mips/jz4730/sleep.S b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/sleep.S new file mode 100644 index 000000000..9ee9e7036 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include + + .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/target/linux/xburst/files-2.6.27/arch/mips/jz4730/time.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4730/time.c new file mode 100644 index 000000000..806c7feb9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include + +#include +#include + +#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(void) +{ + 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(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/target/linux/xburst/files-2.6.27/arch/mips/jz4740/Makefile b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/Makefile new file mode 100644 index 000000000..ac4d3cd2d --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-dipper.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-dipper.c new file mode 100644 index 000000000..ca3022501 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +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/target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-leo.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-leo.c new file mode 100644 index 000000000..912636ae8 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +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/target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-lyra.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-lyra.c new file mode 100644 index 000000000..ea5662680 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +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/target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-pavo.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-pavo.c new file mode 100644 index 000000000..e2a550944 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +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/target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-virgo.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/board-virgo.c new file mode 100644 index 000000000..1429877b8 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +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/target/linux/xburst/files-2.6.27/arch/mips/jz4740/cpufreq.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/cpufreq.c new file mode 100644 index 000000000..d646a1e2e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include + +#include + +#include +#include + +#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, ®s); + + 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(®s); + + 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 "); +MODULE_DESCRIPTION("cpufreq driver for Jz4740"); +MODULE_LICENSE("GPL"); + diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4740/dma.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/dma.c new file mode 100644 index 000000000..dd5055e59 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * 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/target/linux/xburst/files-2.6.27/arch/mips/jz4740/i2c.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/i2c.c new file mode 100644 index 000000000..3080fdfa8 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include + +#include + +/* 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/target/linux/xburst/files-2.6.27/arch/mips/jz4740/irq.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/irq.c new file mode 100644 index 000000000..98543c285 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/irq.c @@ -0,0 +1,265 @@ +/* + * linux/arch/mips/jz4740/irq.c + * + * JZ4740 interrupt routines. + * + * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * 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, + .enable = enable_intc_irq, + .disable = 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, + .enable = enable_gpio_irq, + .disable = 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, + .enable = enable_dma_irq, + .disable = 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); + irq_desc[i].chip = &intc_irq_type; + } + + /* Set up DMAC irq + */ + for (i = 0; i < NUM_DMA; i++) { + disable_dma_irq(IRQ_DMA_0 + i); + irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; + } + + /* Set up GPIO irq + */ + for (i = 0; i < NUM_GPIO; i++) { + disable_gpio_irq(IRQ_GPIO_0 + i); + irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; + } +} + +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< + * + * 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 +#include +#include +#include +#include + +#include + +/* 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/target/linux/xburst/files-2.6.27/arch/mips/jz4740/pm.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/pm.c new file mode 100644 index 000000000..c90709147 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/pm.c @@ -0,0 +1,410 @@ +/* + * linux/arch/mips/jz4740/common/pm.c + * + * JZ4740 Power Management Routines + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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) +{ + + /* 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]; + + /* 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) +{ + printk("Put CPU into hibernate mode.\n"); + 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 + printk("Put CPU into sleep mode.\n"); + retval = jz_pm_do_sleep(); + +#ifndef CONFIG_JZ_POWEROFF + free_irq (IRQ_GPIO_0 + GPIO_WAKEUP, NULL); +#endif + + return retval; +} + + +/* + * valid states, only support standby(sleep) and mem(hibernate) + */ +static int jz_pm_valid(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + return 1; + default: + return 0; + } +} + +/* + * Jz CPU enter save power mode + */ +static int jz_pm_enter(suspend_state_t state) +{ + if (state == PM_SUSPEND_STANDBY) + jz_pm_sleep(); + else + jz_pm_hibernate(); + return 0; +} + + +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("Power Management for JZ\n"); + + suspend_set_ops(&jz_pm_ops); + return 0; + +} + +//module_init(jz_pm_init); + diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4740/proc.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/proc.c new file mode 100644 index 000000000..e9c5df3f6 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/proc.c @@ -0,0 +1,873 @@ +/* + * linux/arch/mips/jz4740/proc.c + * + * /proc/jz/ procfs for jz4740 on-chip modules. + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#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, "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; +} + + +/* 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<= 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 /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; +} + +/* + * /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 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); + } + + return 0; +} + +__initcall(jz_proc_init); diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4740/prom.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/prom.c new file mode 100644 index 000000000..406893976 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include + +#include +#include + +/* #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/target/linux/xburst/files-2.6.27/arch/mips/jz4740/reset.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/reset.c new file mode 100644 index 000000000..83577d868 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/reset.c @@ -0,0 +1,46 @@ +/* + * linux/arch/mips/jz4740/reset.c + * + * JZ4740 reset routines. + * + * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +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"); +} + +void jz_power_off(void) +{ + jz_halt(); +} diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4740/setup.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/setup.c new file mode 100644 index 000000000..564ed273e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/setup.c @@ -0,0 +1,188 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM +#include +#endif + +#ifdef CONFIG_PC_KEYB +#include +#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.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_power_off; +#ifdef CONFIG_PM + jz_pm_init(); +#endif + jz_soc_setup(); + jz_serial_setup(); + jz_board_setup(); +} + diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4740/time.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/time.c new file mode 100644 index 000000000..493853bd8 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4740/time.c @@ -0,0 +1,159 @@ +/* + * linux/arch/mips/jz4740/time.c + * + * Setting up the clock on the JZ4740 boards. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include + +#include +#include + +/* 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(void) +{ + /* 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 */ + .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(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/target/linux/xburst/files-2.6.27/arch/mips/jz4750/Makefile b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/Makefile new file mode 100644 index 000000000..7dcc3b486 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/jz4750/board-apus.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/board-apus.c new file mode 100644 index 000000000..128f16da9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/board-apus.c @@ -0,0 +1,303 @@ +/* + * linux/arch/mips/jz4750/board-apus.c + * + * JZ4750 APUS board setup routines. + * + * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +//#define DEBUG + +/********************************************************************************* + * Power management routines + ********************************************************************************/ + +/* + * __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) = ~0x03ff7fff; \ + REG_GPIO_PXFUNC(2) = ~0x01e00000; \ + REG_GPIO_PXSELC(2) = ~0x01e00000; \ + REG_GPIO_PXDIRC(2) = ~0x01e00000; \ + REG_GPIO_PXPES(2) = ~0x01e00000; \ + 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) + +extern void (*jz_timer_callback)(void); + +struct wakeup_key_s { + int gpio; /* gpio pin number */ + int active_low; /* the key interrupt pin is low voltage + or fall edge acitve */ +}; + +/* add wakeup keys here */ +static struct wakeup_key_s wakeup_key[] = { + { + .gpio = GPIO_CALL, + .active_low = ACTIVE_LOW_CALL, + }, + { + .gpio = GPIO_HOME, + .active_low = ACTIVE_LOW_HOME, + }, + { + .gpio = GPIO_BACK, + .active_low = ACTIVE_LOW_BACK, + }, + { + .gpio = GPIO_MENU, + .active_low = ACTIVE_LOW_MENU, + }, + { + .gpio = GPIO_ENDCALL, + .active_low = ACTIVE_LOW_ENDCALL, + }, + { + .gpio = GPIO_ADKEY_INT, + .active_low = ACTIVE_LOW_ADKEY, + }, +}; + +static void wakeup_key_setup(void) +{ + int i; + int num = sizeof(wakeup_key) / sizeof(wakeup_key[0]); + + for(i = 0; i < num; i++) { +#if 0 + if(wakeup_key[i].active_low) + __gpio_as_irq_fall_edge(wakeup_key[i].gpio); + else + __gpio_as_irq_rise_edge(wakeup_key[i].gpio); +#endif + __gpio_ack_irq(wakeup_key[i].gpio); + __gpio_unmask_irq(wakeup_key[i].gpio); + __intc_unmask_irq(IRQ_GPIO0 - (wakeup_key[i].gpio/32)); /* unmask IRQ_GPIOn */ + } +} + +/* 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. + */ +void jz_board_do_sleep(unsigned long *ptr) +{ + unsigned char i; +#ifdef DEBUG + __intc_unmask_irq(IRQ_UART3); + /* Print messages of GPIO registers for debug */ + for(i=0;i + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +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; +} + +/** + * Called by arch/mips/kernel/proc.c when 'cat /proc/cpuinfo'. + * Android requires the 'Hardware:' field in cpuinfo to setup the init.%hardware%.rc. + */ +const char *get_board_type(void) +{ + return "fuwa"; +} diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4750/cpufreq.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/cpufreq.c new file mode 100644 index 000000000..83f98b1cd --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include + +#include + +#include +#include + +#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, ®s); + + 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(®s); + + 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 "); +MODULE_DESCRIPTION("cpufreq driver for Jz4750"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4750/dma.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/dma.c new file mode 100644 index 000000000..2508111b4 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * 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/target/linux/xburst/files-2.6.27/arch/mips/jz4750/i2c.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/i2c.c new file mode 100644 index 000000000..a2ac59e60 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/i2c.c @@ -0,0 +1,386 @@ +/* + * linux/arch/mips/jz4750/i2c.c + * + * Jz4750 I2C routines. + * + * Copyright (C) 2005,2006 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include + +#include + +/* 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_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; +} + +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; +} + +int i2c_read_16(unsigned char device, unsigned char *buf, + unsigned short address, int count) +{ + int cnt = count; + int timeout = 5; + unsigned char tmpaddrh, tmpaddrl; + + tmpaddrh = (unsigned char)((address >> 8) & 0xff); + tmpaddrl = (unsigned char)(address & 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_nack(tmpaddrh) < 0) + goto address_err; + if (i2c_put_data(tmpaddrl) < 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_16(unsigned char device, unsigned char *buf, + unsigned short address, int count) +{ + int cnt = count; + int cnt_in_pg; + int timeout = 5; + unsigned char *tmpbuf; + unsigned char tmpaddrh, tmpaddrl; + + __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; + tmpaddrh = (unsigned char)((address >> 8) & 0xff); + tmpaddrl = (unsigned char)(address & 0xff); + + 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_nack(tmpaddrh) < 0) + goto address_err; + if (i2c_put_data(tmpaddrl) < 0) + goto address_err; + while (cnt) { + if (++cnt_in_pg > 8) { + __i2c_send_stop(); + mdelay(1); + tmpaddrh += 8; + goto start_write_page; + } + if (i2c_put_data(*tmpbuf) < 0) + break; + cnt--; + tmpbuf++; + } + + __i2c_send_stop(); + return count - cnt; + device_err: + printk("1:Write I2C device 0x%2x failed.\n", device); + address_err: + printk("2:Write I2C address 0x%2x failed.\n", address); + timeout--; + __i2c_send_stop(); + goto W_try_again; + + W_timeout: + printk("3: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); +EXPORT_SYMBOL(i2c_read_16); +EXPORT_SYMBOL(i2c_write_16); diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4750/irq.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/irq.c new file mode 100644 index 000000000..6a9d867d5 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * 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, + .enable = enable_intc_irq, + .disable = 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, + .enable = enable_gpio_irq, + .disable = 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, + .enable = enable_dma_irq, + .disable = 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); + irq_desc[i].chip = &intc_irq_type; + } + + /* Set up DMAC irq + */ + for (i = 0; i < NUM_DMA; i++) { + disable_dma_irq(IRQ_DMA_0 + i); + irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; + } + + /* Set up GPIO irq + */ + for (i = 0; i < NUM_GPIO; i++) { + disable_gpio_irq(IRQ_GPIO_0 + i); + irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; + } +} + +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< + * + * 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 +#include +#include +#include +#include + +#include + +/* 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, +}; + +struct platform_device jz4750_rtc_device = { + .name = "jz4750-rtc", + .id = -1, +}; + +/* All */ +static struct platform_device *jz_platform_devices[] __initdata = { + &jz_usb_ohci_device, + &jz_lcd_device, + &jz_usb_gdt_device, + &jz_mmc_device, + &jz4750_rtc_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/target/linux/xburst/files-2.6.27/arch/mips/jz4750/pm.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/pm.c new file mode 100644 index 000000000..1ba02cb5f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/pm.c @@ -0,0 +1,203 @@ +/* + * linux/arch/mips/jz4750/common/pm.c + * + * JZ4750 Power Management Routines + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void jz_board_do_sleep(unsigned long *ptr); +extern void jz_board_do_resume(unsigned long *ptr); + +static void 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 */ +} + +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[4*(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(); + + /* Mask all interrupts */ + REG_INTC_IMSR = 0xffffffff; + + /* Sleep on-board modules and setup wake event */ + jz_board_do_sleep(sleep_gpio_save); + + /* 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; + + printk("Resume CPU from sleep mode.\n"); + + return 0; +} + +/* Put CPU to HIBERNATE mode + *---------------------------------------------------------------------------- + * Power Management sleep sysctl interface + * + * Write "mem" to /sys/power/state invokes this function + * which initiates a poweroff. + */ +void jz_pm_hibernate(void) +{ + jz_pm_do_hibernate(); +} + +/* Put CPU to SLEEP mode + *---------------------------------------------------------------------------- + * Power Management sleep sysctl interface + * + * Write "standby" to /sys/power/state invokes this function + * which initiates a sleep. + */ + +int jz_pm_sleep(void) +{ + return jz_pm_do_sleep(); +} + +/* + * valid states, only support standby(sleep) and mem(hibernate) + */ +static int jz4750_pm_valid(suspend_state_t state) +{ + return state == PM_SUSPEND_MEM; +} + +/* + * Jz CPU enter save power mode + */ +static int jz4750_pm_enter(suspend_state_t state) +{ + return jz_pm_do_sleep(); +} + +static struct platform_suspend_ops jz4750_pm_ops = { + .valid = jz4750_pm_valid, + .enter = jz4750_pm_enter, +}; + +/* + * Initialize power interface + */ +int __init jz_pm_init(void) +{ + printk("JZ4750 Power Management\n"); + + suspend_set_ops(&jz4750_pm_ops); + return 0; +} diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4750/proc.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/proc.c new file mode 100644 index 000000000..de27d46cf --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/proc.c @@ -0,0 +1,1058 @@ +/* + * linux/arch/mips/jz4750/proc.c + * + * /proc/jz/ procfs for jz4750 on-chip modules. + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#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=%03ld\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>1) { + write_c0_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<= 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 */ +#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, 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 /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; +} + +/* Usage: + * + * echo n > /proc/jz/pmon // n = [0,1,2], select one event pair to be monitored, + // and enable pmonitor at once. + // 0: freeze count, cpu clock count; + // 1: icc-miss count, dcc-miss count + // 2: useless insn count, total insn count; + * echo ff > /proc/jz/pmon // disable pmonitor and show the event count. + */ + +#define EVENT_FREEZE_AND_CLOCK 0 +#define EVENT_ICACHE_AND_DCACHE 1 +#define EVENT_INSTRUCTION 2 +#define PMON_ENABLE_MASK 8 +#define PMON_PEVENT_MASK 12 + +#define __pmon_set_config(config) \ + { \ + __asm__ __volatile__( \ + "mtc0\t%0,$16, 7\n\t" \ + ::"r"(config) \ + ); \ + } +#define __pmon_get_count_high() \ + ({ int count; \ + __asm__ __volatile__( \ + "mfc0\t%0,$16, 4\n\t" \ + :"=r"(count): \ + ); \ + count; \ + }) +#define __pmon_get_count_left() \ + ({ int count; \ + __asm__ __volatile__( \ + "mfc0\t%0,$16, 5\n\t" \ + :"=r"(count): \ + ); \ + count; \ + }) +#define __pmon_get_count_right() \ + ({ int count; \ + __asm__ __volatile__( \ + "mfc0\t%0,$16, 6\n\t" \ + :"=r"(count): \ + ); \ + count; \ + }) + +#define __pmon_set_count_high(c) \ + { \ + __asm__ __volatile__( \ + "mtc0\t%0,$16, 4\n\t" \ + ::"r"(c) \ + ); \ + } +#define __pmon_set_count_left(c) \ + { \ + __asm__ __volatile__( \ + "mtc0\t%0,$16, 5\n\t" \ + ::"r"(c) \ + ); \ + } +#define __pmon_set_count_right(c) \ + { \ + __asm__ __volatile__( \ + "mtc0\t%0,$16, 6\n\t" \ + ::"r"(c) \ + ); \ + } + +static int is_pmon_started, pmon_event; + +static void pmon_show_count(int event) +{ + unsigned int high,left,right; + + high = __pmon_get_count_high(); + left = __pmon_get_count_left(); + right = __pmon_get_count_right(); + + if (high != 0) + { + printk("pmonitor right high count = 0x%x(%u) \n",high & 0xffff,high & 0xffff); + printk("pmonitor left high count = 0x%x(%u) \n",high >> 16, high >> 16); + } + + switch (event) + { + case 0: //freeze count, cpu clock count + printk("freeze count = 0x%x(%u) \n",left,left); + printk("cpu clock count = 0x%x(%u) \n",right,right); + break; + case 1: //icc-miss count, dcc-miss count + printk("icc-miss count = 0x%x(%u) \n",left,left); + printk("dcc-miss count = 0x%x(%u) \n",right,right); + break; + case 2: //useless insn count, total insn count + printk("useless insn count = 0x%x(%u) \n",left,left); + printk("total insn count = 0x%x(%u) \n",right,right); + break; + } +} + +static int pmon_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) +{ + unsigned int config7 = 0; + int cmd; + + if (count > 3) + { + printk("Pmonitor command error! \n"); + return count; + } + + cmd = simple_strtoul(buffer, 0, 16); + +// printk("\nPmonitor old event %x new event %x \n",pmon_event, cmd); + if (cmd < 0xff) + { + if (pmon_event != 0xff) + pmon_show_count(pmon_event); + + pmon_event = cmd; + __pmon_set_count_high(0); + __pmon_set_count_left(0); + __pmon_set_count_right(0); + config7 |= (cmd << PMON_PEVENT_MASK); + config7 |= (1 << PMON_ENABLE_MASK); + __pmon_set_config(config7); + is_pmon_started = 1; + } + else if (cmd == 0xff && is_pmon_started) + { + if (pmon_event != 0xff) + pmon_show_count(pmon_event); + + pmon_event = cmd; + config7 = 0; + __pmon_set_config(config7); + is_pmon_started = 0; + } + 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; + } + + /* 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; + } + + /* pmoniter */ + res = create_proc_entry("pmon", 0644, proc_jz_root); + if (res) { + res->read_proc = NULL; + res->write_proc = pmon_write_proc; + res->data = NULL; + } + + /* + * Reserve a 4MB 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"); + + return 0; +} + +__initcall(jz_proc_init); diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4750/prom.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/prom.c new file mode 100644 index 000000000..d04bb3e52 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include + +#include +#include + +/* #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/target/linux/xburst/files-2.6.27/arch/mips/jz4750/reset.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/reset.c new file mode 100644 index 000000000..90b521e10 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/reset.c @@ -0,0 +1,46 @@ +/* + * linux/arch/mips/jz4750/reset.c + * + * JZ4750 reset routines. + * + * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +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/target/linux/xburst/files-2.6.27/arch/mips/jz4750/setup.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/setup.c new file mode 100644 index 000000000..fc635bef7 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/setup.c @@ -0,0 +1,206 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM +#include +#endif + +#ifdef CONFIG_PC_KEYB +#include +#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_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(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(); + +#ifdef CONFIG_PM + jz_pm_init(); +#endif +} + diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4750/time.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/time.c new file mode 100644 index 000000000..8099218a1 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750/time.c @@ -0,0 +1,157 @@ +/* + * linux/arch/mips/jz4750/time.c + * + * Setting up the clock on the JZ4750 boards. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include + +#include +#include + +/* 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(void) +{ + /* 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 */ + .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(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/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/Makefile b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/Makefile new file mode 100644 index 000000000..a8b221240 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/board-cetus.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/board-cetus.c new file mode 100755 index 000000000..4c64bde10 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/board-cetus.c @@ -0,0 +1,301 @@ +/* + * linux/arch/mips/jz4750d/board-cetus.c + * + * JZ4750D CETUS board setup routines. + * + * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/********************************************************************************* + * Power management routines + ********************************************************************************/ + +/* + * __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) = ~0x03ff7fff; \ + REG_GPIO_PXFUNC(2) = ~0x01e00000; \ + REG_GPIO_PXSELC(2) = ~0x01e00000; \ + REG_GPIO_PXDIRC(2) = ~0x01e00000; \ + REG_GPIO_PXPES(2) = ~0x01e00000; \ + 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) + +extern void (*jz_timer_callback)(void); + +struct wakeup_key_s { + int gpio; /* gpio pin number */ + int active_low; /* the key interrupt pin is low voltage + or fall edge acitve */ +}; + +/* add wakeup keys here */ +static struct wakeup_key_s wakeup_key[] = { + { + .gpio = GPIO_CALL, + .active_low = ACTIVE_LOW_CALL, + }, + { + .gpio = GPIO_HOME, + .active_low = ACTIVE_LOW_HOME, + }, + { + .gpio = GPIO_BACK, + .active_low = ACTIVE_LOW_BACK, + }, + { + .gpio = GPIO_MENU, + .active_low = ACTIVE_LOW_MENU, + }, + { + .gpio = GPIO_ENDCALL, + .active_low = ACTIVE_LOW_ENDCALL, + }, + { + .gpio = GPIO_ADKEY_INT, + .active_low = ACTIVE_LOW_ADKEY, + }, +}; + +static void wakeup_key_setup(void) +{ + int i; + int num = sizeof(wakeup_key) / sizeof(wakeup_key[0]); + + for(i = 0; i < num; i++) { +#if 0 + if(wakeup_key[i].active_low) + __gpio_as_irq_fall_edge(wakeup_key[i].gpio); + else + __gpio_as_irq_rise_edge(wakeup_key[i].gpio); +#endif + __gpio_ack_irq(wakeup_key[i].gpio); + __gpio_unmask_irq(wakeup_key[i].gpio); + __intc_unmask_irq(IRQ_GPIO0 - (wakeup_key[i].gpio/32)); /* unmask IRQ_GPIOn */ + } +} + +/* 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. + */ +void jz_board_do_sleep(unsigned long *ptr) +{ + unsigned char i; +#ifdef DEBUG + __intc_unmask_irq(IRQ_UART3); + /* Print messages of GPIO registers for debug */ + for(i=0;i + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +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; +} + +/** + * Called by arch/mips/kernel/proc.c when 'cat /proc/cpuinfo'. + * Android requires the 'Hardware:' field in cpuinfo to setup the init.%hardware%.rc. + */ +const char *get_board_type(void) +{ + return "fuwa1"; +} diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/cpufreq.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/cpufreq.c new file mode 100755 index 000000000..4f6bb2dbe --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/cpufreq.c @@ -0,0 +1,600 @@ +/* + * linux/arch/mips/jz4750d/cpufreq.c + * + * cpufreq driver for JZ4750D + * + * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include + +#include + +#include +#include + +#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 ah1_clk; /* LCD clock, Hz */ + 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.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); +} + +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, ®s); + + 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(®s); + + 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 "); +MODULE_DESCRIPTION("cpufreq driver for Jz4750d"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/dma.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/dma.c new file mode 100755 index 000000000..290cc12d5 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * 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/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/i2c.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/i2c.c new file mode 100755 index 000000000..42a9fc931 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/i2c.c @@ -0,0 +1,385 @@ +/* + * linux/arch/mips/jz4750d/i2c.c + * + * Jz4750D I2C routines. + * + * Copyright (C) 2005,2006 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include + +#include + +/* 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_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; +} + +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; +} +int i2c_read_16(unsigned char device, unsigned char *buf, + unsigned short address, int count) +{ + int cnt = count; + int timeout = 5; + unsigned char tmpaddrh, tmpaddrl; + + tmpaddrh = (unsigned char)((address >> 8) & 0xff); + tmpaddrl = (unsigned char)(address & 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_nack(tmpaddrh) < 0) + goto address_err; + if (i2c_put_data(tmpaddrl) < 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_16(unsigned char device, unsigned char *buf, + unsigned short address, int count) +{ + int cnt = count; + int cnt_in_pg; + int timeout = 5; + unsigned char *tmpbuf; + unsigned char tmpaddrh, tmpaddrl; + + __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; + tmpaddrh = (unsigned char)((address >> 8) & 0xff); + tmpaddrl = (unsigned char)(address & 0xff); + + 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_nack(tmpaddrh) < 0) + goto address_err; + if (i2c_put_data(tmpaddrl) < 0) + goto address_err; + while (cnt) { + if (++cnt_in_pg > 8) { + __i2c_send_stop(); + mdelay(1); + tmpaddrh += 8; + goto start_write_page; + } + if (i2c_put_data(*tmpbuf) < 0) + break; + cnt--; + tmpbuf++; + } + + __i2c_send_stop(); + return count - cnt; + device_err: + printk("1:Write I2C device 0x%2x failed.\n", device); + address_err: + printk("2:Write I2C address 0x%2x failed.\n", address); + timeout--; + __i2c_send_stop(); + goto W_try_again; + + W_timeout: + printk("3: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); +EXPORT_SYMBOL(i2c_read_16); +EXPORT_SYMBOL(i2c_write_16); diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/irq.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/irq.c new file mode 100755 index 000000000..aa43d9b79 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * 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, + .enable = enable_intc_irq, + .disable = 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, + .enable = enable_gpio_irq, + .disable = 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, + .enable = enable_dma_irq, + .disable = 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); + irq_desc[i].chip = &intc_irq_type; + } + + /* Set up DMAC irq + */ + for (i = 0; i < NUM_DMA; i++) { + disable_dma_irq(IRQ_DMA_0 + i); + irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; + } + + /* Set up GPIO irq + */ + for (i = 0; i < NUM_GPIO; i++) { + disable_gpio_irq(IRQ_GPIO_0 + i); + irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; + } +} + +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< + * + * 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 +#include +#include +#include +#include + +#include +#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, +}; + +struct platform_device jz4750_rtc_device = { + .name = "jz4750-rtc", + .id = -1, +}; + +/* All */ +static struct platform_device *jz_platform_devices[] __initdata = { +// &jz_usb_ohci_device, + &jz_lcd_device, + &jz_usb_gdt_device, + &jz_mmc_device, + &jz4750_rtc_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/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/pm.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/pm.c new file mode 100755 index 000000000..b2f4efdda --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/pm.c @@ -0,0 +1,201 @@ +/* + * linux/arch/mips/jz4750d/pm.c + * + * JZ4750D Power Management Routines + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +//#define DEBUG +#ifdef DEBUG +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) +#endif + +extern void jz_board_do_sleep(unsigned long *ptr); +extern void jz_board_do_resume(unsigned long *ptr); + + +static void 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); + +} + +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[4*(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(); + + /* Mask all interrupts */ + REG_INTC_IMSR = 0xffffffff; + + /* Sleep on-board modules and setup wake event */ + jz_board_do_sleep(sleep_gpio_save); + + /* 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; + + printk("Resume CPU from sleep mode.\n"); + + return 0; +} + +/* Put CPU to HIBERNATE mode */ +void jz_pm_hibernate(void) +{ + jz_pm_do_hibernate(); +} + + +/* Put CPU to SLEEP mode */ +int jz_pm_sleep(void) +{ + return jz_pm_do_sleep(); +} + +/* + * valid states, only support standby(sleep) and mem(hibernate) + */ +static int jz4750_pm_valid(suspend_state_t state) +{ + return state == PM_SUSPEND_MEM; +} + +/* + * Jz CPU enter save power mode + */ +static int jz4750_pm_enter(suspend_state_t state) +{ + return jz_pm_do_sleep(); +} + +static struct platform_suspend_ops jz4750_pm_ops = { + .valid = jz4750_pm_valid, + .enter = jz4750_pm_enter, +}; + +/* + * Initialize power interface + */ +int __init jz_pm_init(void) +{ + printk("Power Management for JZ\n"); + + suspend_set_ops(&jz4750_pm_ops); + + return 0; +} + diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/proc.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/proc.c new file mode 100755 index 000000000..bcdaf0d79 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/proc.c @@ -0,0 +1,1056 @@ +/* + * linux/arch/mips/jz4750d/proc.c + * + * /proc/jz/ procfs for jz4750d on-chip modules. + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#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) { + 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<= 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 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 /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 */ +#define IMEM_MAX_ORDER 0 /* 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; +} + +/* Usage: + * + * echo n > /proc/jz/pmon // n = [0,1,2], select one event pair to be monitored, + // and enable pmonitor at once. + // 0: freeze count, cpu clock count; + // 1: icc-miss count, dcc-miss count + // 2: useless insn count, total insn count; + * echo ff > /proc/jz/pmon // disable pmonitor and show the event count. + */ + +#define EVENT_FREEZE_AND_CLOCK 0 +#define EVENT_ICACHE_AND_DCACHE 1 +#define EVENT_INSTRUCTION 2 +#define PMON_ENABLE_MASK 8 +#define PMON_PEVENT_MASK 12 + +#define __pmon_set_config(config) \ + { \ + __asm__ __volatile__( \ + "mtc0\t%0,$16, 7\n\t" \ + ::"r"(config) \ + ); \ + } +#define __pmon_get_count_high() \ + ({ int count; \ + __asm__ __volatile__( \ + "mfc0\t%0,$16, 4\n\t" \ + :"=r"(count): \ + ); \ + count; \ + }) +#define __pmon_get_count_left() \ + ({ int count; \ + __asm__ __volatile__( \ + "mfc0\t%0,$16, 5\n\t" \ + :"=r"(count): \ + ); \ + count; \ + }) +#define __pmon_get_count_right() \ + ({ int count; \ + __asm__ __volatile__( \ + "mfc0\t%0,$16, 6\n\t" \ + :"=r"(count): \ + ); \ + count; \ + }) + +#define __pmon_set_count_high(c) \ + { \ + __asm__ __volatile__( \ + "mtc0\t%0,$16, 4\n\t" \ + ::"r"(c) \ + ); \ + } +#define __pmon_set_count_left(c) \ + { \ + __asm__ __volatile__( \ + "mtc0\t%0,$16, 5\n\t" \ + ::"r"(c) \ + ); \ + } +#define __pmon_set_count_right(c) \ + { \ + __asm__ __volatile__( \ + "mtc0\t%0,$16, 6\n\t" \ + ::"r"(c) \ + ); \ + } + +static int is_pmon_started, pmon_event; + +static void pmon_show_count(int event) +{ + unsigned int high,left,right; + + high = __pmon_get_count_high(); + left = __pmon_get_count_left(); + right = __pmon_get_count_right(); + + if (high != 0) + { + printk("pmonitor right high count = 0x%x(%u) \n",high & 0xffff,high & 0xffff); + printk("pmonitor left high count = 0x%x(%u) \n",high >> 16, high >> 16); + } + + switch (event) + { + case 0: //freeze count, cpu clock count + printk("freeze count = 0x%x(%u) \n",left,left); + printk("cpu clock count = 0x%x(%u) \n",right,right); + break; + case 1: //icc-miss count, dcc-miss count + printk("icc-miss count = 0x%x(%u) \n",left,left); + printk("dcc-miss count = 0x%x(%u) \n",right,right); + break; + case 2: //useless insn count, total insn count + printk("useless insn count = 0x%x(%u) \n",left,left); + printk("total insn count = 0x%x(%u) \n",right,right); + break; + } +} + +static int pmon_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) +{ + unsigned int config7 = 0; + int cmd; + + if (count > 3) + { + printk("Pmonitor command error! \n"); + return count; + } + + cmd = simple_strtoul(buffer, 0, 16); + +// printk("\nPmonitor old event %x new event %x \n",pmon_event, cmd); + if (cmd < 0xff) + { + if (pmon_event != 0xff) + pmon_show_count(pmon_event); + + pmon_event = cmd; + __pmon_set_count_high(0); + __pmon_set_count_left(0); + __pmon_set_count_right(0); + config7 |= (cmd << PMON_PEVENT_MASK); + config7 |= (1 << PMON_ENABLE_MASK); + __pmon_set_config(config7); + is_pmon_started = 1; + } + else if (cmd == 0xff && is_pmon_started) + { + if (pmon_event != 0xff) + pmon_show_count(pmon_event); + + pmon_event = cmd; + config7 = 0; + __pmon_set_config(config7); + is_pmon_started = 0; + } + 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; + } + + /* 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; + } + + /* pmoniter */ + res = create_proc_entry("pmon", 0644, proc_jz_root); + if (res) { + res->read_proc = NULL; + res->write_proc = pmon_write_proc; + res->data = NULL; + } + + /* + * Reserve a 4MB memory for IPU on JZ4750D. + */ + 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"); + + return 0; +} + +__initcall(jz_proc_init); diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/prom.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/prom.c new file mode 100755 index 000000000..3c173d6ec --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include + +#include +#include + +/* #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/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/reset.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/reset.c new file mode 100755 index 000000000..90b521e10 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/reset.c @@ -0,0 +1,46 @@ +/* + * linux/arch/mips/jz4750/reset.c + * + * JZ4750 reset routines. + * + * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +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/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/setup.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/setup.c new file mode 100755 index 000000000..162b35abc --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/setup.c @@ -0,0 +1,207 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM +#include +#endif + +#ifdef CONFIG_PC_KEYB +#include +#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); +extern void jz_pm_hibernate(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(); +#ifdef CONFIG_PM + jz_pm_init(); +#endif +} + diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/time.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/time.c new file mode 100755 index 000000000..f1ab2b184 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4750d/time.c @@ -0,0 +1,157 @@ +/* + * linux/arch/mips/jz4750d/time.c + * + * Setting up the clock on the JZ4750D boards. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include + +#include +#include + +/* 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(void) +{ + /* 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 */ + .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(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/target/linux/xburst/files-2.6.27/arch/mips/jz4760/Makefile b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/Makefile new file mode 100644 index 000000000..60e572f70 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/Makefile @@ -0,0 +1,22 @@ +# +# Makefile for the Ingenic JZ4760. +# + +# 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_JZ4760_F4760) += board-f4760.o + +# PM support + +obj-$(CONFIG_PM_LEGACY) +=pm.o + +# CPU Frequency scaling support + +obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4760/board-f4760.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/board-f4760.c new file mode 100755 index 000000000..6ac8e8cbb --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/board-f4760.c @@ -0,0 +1,81 @@ +/* + * linux/arch/mips/jz4760/board-f4760.c + * + * JZ4760 F4760 board setup routines. + * + * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +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 f4760_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/jz4760/setup.c. + */ +} + +static void __init board_gpio_setup(void) +{ + /* + * Initialize SDRAM pins + */ +} + +void __init jz_board_setup(void) +{ + printk("JZ4760 F4760 board setup\n"); +// jz_restart(NULL); + board_cpm_setup(); + board_gpio_setup(); + + jz_timer_callback = f4760_timer_callback; +} + +/** + * Called by arch/mips/kernel/proc.c when 'cat /proc/cpuinfo'. + * Android requires the 'Hardware:' field in cpuinfo to setup the init.%hardware%.rc. + */ +const char *get_board_type(void) +{ + return "f4760"; +} diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4760/cpufreq.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/cpufreq.c new file mode 100755 index 000000000..f2a125d4b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/cpufreq.c @@ -0,0 +1,598 @@ +/* + * linux/arch/mips/jz4760/cpufreq.c + * + * cpufreq driver for JZ4760 + * + * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include + +#include + +#include +#include + +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ + "cpufreq-jz4760", 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 jz4760_freq_percpu_info { + struct cpufreq_frequency_table table[7]; +}; + +static struct jz4760_freq_percpu_info jz4760_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 jz4760_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 jz4760_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 = jz4760_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 jz4760_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, ®s); + + 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) + jz4760_transition(®s); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +} + +static int jz4760_freq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int new_index = 0; + + if (cpufreq_frequency_table_target(policy, + &jz4760_freq_table.table[0], + target_freq, relation, &new_index)) + return -EINVAL; + + jz4760_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 jz4760_freq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, + &jz4760_freq_table.table[0]); +} + +static int __init jz4760_cpufreq_driver_init(struct cpufreq_policy *policy) +{ + + struct cpufreq_frequency_table *table = &jz4760_freq_table.table[0]; + unsigned int MAX_FREQ; + + dprintk(KERN_INFO "Jz4760 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_jz4760_driver = { +// .flags = CPUFREQ_STICKY, + .init = jz4760_cpufreq_driver_init, + .verify = jz4760_freq_verify, + .target = jz4760_freq_target, + .get = jz4760_freq_get, + .name = "jz4760", +}; + +static int __init jz4760_cpufreq_init(void) +{ + return cpufreq_register_driver(&cpufreq_jz4760_driver); +} + +static void __exit jz4760_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&cpufreq_jz4760_driver); +} + +module_init(jz4760_cpufreq_init); +module_exit(jz4760_cpufreq_exit); + +MODULE_AUTHOR("Regen "); +MODULE_DESCRIPTION("cpufreq driver for Jz4760"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4760/dma.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/dma.c new file mode 100755 index 000000000..45192202c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/dma.c @@ -0,0 +1,822 @@ +/* + * linux/arch/mips/jz4760/dma.c + * + * Support functions for the JZ4760 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * 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 JZ4760_DMAC_TEST_ENABLE +#undef JZ4760_DMAC_TEST_ENABLE + +#ifdef JZ4760_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 jz4760_dma_irq(int irq, void *dev_id) +{ + printk("jz4760_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", jz4760_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", jz4760_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/target/linux/xburst/files-2.6.27/arch/mips/jz4760/i2c.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/i2c.c new file mode 100755 index 000000000..4c0bfc787 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/i2c.c @@ -0,0 +1,273 @@ +/* + * linux/arch/mips/jz4760/i2c.c + * + * Jz4760 I2C routines. + * + * Copyright (C) 2005,2006 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include + +#include + +/* 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/target/linux/xburst/files-2.6.27/arch/mips/jz4760/irq.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/irq.c new file mode 100755 index 000000000..c0915b1dc --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/irq.c @@ -0,0 +1,299 @@ +/* + * linux/arch/mips/jz4760/irq.c + * + * JZ4760 interrupt routines. + * + * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * 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, + .enable = enable_intc_irq, + .disable = 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, + .enable = enable_gpio_irq, + .disable = 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, + .enable = enable_dma_irq, + .disable = 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); + irq_desc[i].chip = &intc_irq_type; + } + + /* Set up DMAC irq + */ + for (i = 0; i < NUM_DMA; i++) { + disable_dma_irq(IRQ_DMA_0 + i); + irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; + } + + /* Set up GPIO irq + */ + for (i = 0; i < NUM_GPIO; i++) { + disable_gpio_irq(IRQ_GPIO_0 + i); + irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; + } +} + +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< + * + * 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 +#include +#include +#include +#include + +#include + +#include + +#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, +}; + +/* USB OTG Controller */ +static struct musb_hdrc_config jz_usb_otg_config = { + .multipoint = 0, + .dyn_fifo = 0, + .soft_con = 1, + .dma = 1, + .num_eps = 5, + .dma_channels = 5, +}; + +static struct musb_hdrc_platform_data jz_usb_otg_platform_data = { +#if defined(CONFIG_USB_MUSB_OTG) + .mode = MUSB_OTG, +#elif defined(CONFIG_USB_MUSB_HDRC_HCD) + .mode = MUSB_HOST, +#elif defined(CONFIG_USB_GADGET_MUSB_HDRC) + .mode = MUSB_PERIPHERAL, +#endif + .config = &jz_usb_otg_config, +}; + +static struct resource jz_usb_otg_resources[] = { + [0] = { + .start = CPHYSADDR(UDC_BASE), + .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_OTG, + .end = IRQ_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 usb_otg_dmamask = ~(u32)0; + +static struct platform_device jz_usb_otg_device = { + .name = "musb_hdrc", + .id = 0, + .dev = { + .dma_mask = &usb_otg_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = &jz_usb_otg_platform_data, + }, + .num_resources = ARRAY_SIZE(jz_usb_otg_resources), + .resource = jz_usb_otg_resources, +}; + +/** MMC/SD controller **/ +static struct resource jz_mmc_resources[] = { + [0] = { + .start = CPHYSADDR(MSC0_BASE), + .end = CPHYSADDR(MSC0_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_usb_otg_device, + &jz_lcd_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/target/linux/xburst/files-2.6.27/arch/mips/jz4760/pm.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/pm.c new file mode 100755 index 000000000..9e337ce24 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/pm.c @@ -0,0 +1,461 @@ +/* + * linux/arch/mips/jz4760/common/pm.c + * + * JZ4760 Power Management Routines + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#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, "H0CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_h0clk())); + 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<= 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 /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 JZ4760. + */ + 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/target/linux/xburst/files-2.6.27/arch/mips/jz4760/prom.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/prom.c new file mode 100755 index 000000000..f30a77b8c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/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 +#include +#include +#include + +#include +#include + +/* #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_JZ4760; + + 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 "JZ4760"; +} + +EXPORT_SYMBOL(prom_getcmdline); +EXPORT_SYMBOL(get_ethernet_addr); +EXPORT_SYMBOL(str2eaddr); diff --git a/target/linux/xburst/files-2.6.27/arch/mips/jz4760/reset.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/reset.c new file mode 100755 index 000000000..c815987d0 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/reset.c @@ -0,0 +1,46 @@ +/* + * linux/arch/mips/jz4760/reset.c + * + * JZ4760 reset routines. + * + * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +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/target/linux/xburst/files-2.6.27/arch/mips/jz4760/setup.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/setup.c new file mode 100755 index 000000000..a5c67fced --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/setup.c @@ -0,0 +1,199 @@ +/* + * linux/arch/mips/jz4760/common/setup.c + * + * JZ4760 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PC_KEYB +#include +#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_h0clk(); + 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/target/linux/xburst/files-2.6.27/arch/mips/jz4760/time.c b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/time.c new file mode 100755 index 000000000..45e4989c9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/arch/mips/jz4760/time.c @@ -0,0 +1,156 @@ +/* + * linux/arch/mips/jz4760/time.c + * + * Setting up the clock on the JZ4760 boards. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include + +#include +#include + +/* 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(void) +{ + /* 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(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/target/linux/xburst/files-2.6.27/drivers/i2c/busses/i2c-jz47xx.c b/target/linux/xburst/files-2.6.27/drivers/i2c/busses/i2c-jz47xx.c new file mode 100644 index 000000000..16f947e85 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/i2c/busses/i2c-jz47xx.c @@ -0,0 +1,330 @@ +/* + * i2c_jz47xx.c + * I2C adapter for the INGENIC I2C bus access. + * + * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "i2c-jz47xx.h" + +/* I2C protocol */ +#define I2C_READ 1 +#define I2C_WRITE 0 + +#define TIMEOUT 1000 +unsigned short sub_addr = 0; +int addr_val = 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); + 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_jz_setclk(unsigned int i2cclk) +{ + __i2c_set_clk(jz_clocks.extalclk, i2cclk); +} + +static int xfer_read(unsigned char device, struct i2c_adapter *adap, unsigned char *buf, int length) +{ + int cnt = length; + int timeout = 5; + + device = (0xa << 3) | ((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 */ + + if (addr_val) { + __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 */ + __i2c_send_start(); + + while (cnt) { + if (cnt == 1) { + if (i2c_get_data(buf, 0) < 0) + break; + } else { + if (i2c_get_data(buf, 1) < 0) + break; + } + cnt--; + buf++; + } + addr_val = 0; + 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, struct i2c_adapter *adap, unsigned char *buf, int length) +{ + int cnt = length; + int cnt_in_pg; + int timeout = 5; + unsigned char *tmpbuf; + unsigned char tmpaddr; + + device = (0xa << 3) | ((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; + tmpaddr = device; + start_write_page: + cnt_in_pg = 0; + __i2c_send_start(); + if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) + goto device_err; + if (addr_val) { + 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; + goto start_write_page; + } + if (i2c_put_data(*tmpbuf) < 0) + break; + cnt--; + tmpbuf++; + } + __i2c_send_stop(); + addr_val = 0; + return length - 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; +} + +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, adap, pmsg->buf, pmsg->len); + else + ret = xfer_write(pmsg->addr, adap, 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; + + __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/target/linux/xburst/files-2.6.27/drivers/i2c/busses/i2c-jz47xx.h b/target/linux/xburst/files-2.6.27/drivers/i2c/busses/i2c-jz47xx.h new file mode 100644 index 000000000..eb8611067 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/input/keyboard/jz_gpio_keypad.c b/target/linux/xburst/files-2.6.27/drivers/input/keyboard/jz_gpio_keypad.c new file mode 100755 index 000000000..a9376b29e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/input/keyboard/jz_gpio_keypad.c @@ -0,0 +1,413 @@ +/* + * linux/drivers/input/keyboard/jz_gpio_keys.c + * + * Keypad driver based on GPIO pins for Jz4750 APUS board. + * + * User applications can access to this device via /dev/input/eventX. + * + * Copyright (c) 2005 - 2009 Ingenic Semiconductor Inc. + * + * Author: Richard + * Regen + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +//#define DEBUG +#ifdef DEBUG +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) +#endif + +/* Device name */ +#ifdef CONFIG_JZ4750_APUS +#define DEV_NAME "apus-keypad" +#else +#ifdef CONFIG_JZ4750D_CETUS +#define DEV_NAME "cetus-keypad" +#else +#define DEV_NAME "jz-keypad" +#endif +#endif + +/* Key codes */ +#define ANDROID_MENU KEY_MENU +#define ANDROID_CALL KEY_SEND +#define ANDROID_HOME KEY_HOME +#define ANDROID_ENDCALL KEY_END +#define ANDROID_BACK KEY_BACK + +/* Timer interval */ +#define SCAN_INTERVAL 5 + +/* + * GPIO Buttons + */ +static struct gpio_keys_button board_buttons[] = { +#if 0 + { + .gpio = GPIO_WAKEUP, + .code = KEY_1, + .desc = "Button 0", + .active_low = 1, + }, +#endif + { + .gpio = GPIO_CALL, + .code = ANDROID_CALL, + .desc = "Button 1", + .active_low = ACTIVE_LOW_CALL, + }, + { + .gpio = GPIO_HOME, + .code = ANDROID_HOME, + .desc = "Button 2", + .active_low = ACTIVE_LOW_HOME, + }, + { + .gpio = GPIO_BACK, + .code = ANDROID_BACK, + .desc = "Button 3", + .active_low = ACTIVE_LOW_BACK, + }, + { + .gpio = GPIO_MENU, + .code = ANDROID_MENU, + .desc = "Button 4", + .active_low = ACTIVE_LOW_MENU, + }, + { + .gpio = GPIO_ENDCALL, + .code = ANDROID_ENDCALL, + .desc = "Button 5", + .active_low = ACTIVE_LOW_ENDCALL, + }, +#if 0 + { + .gpio = GPIO_SW7, + .code = KEY_7, + .desc = "Button 6", + .active_low = 1, + }, +#endif +}; + +static struct timer_list button_timer; +static int button_no; + +static struct gpio_keys_platform_data board_button_data = { + .buttons = board_buttons, + .nbuttons = ARRAY_SIZE(board_buttons), +}; + +static struct platform_device board_button_device = { + .name = DEV_NAME, + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &board_button_data, + } +}; + +static void enable_gpio_irqs(struct gpio_keys_platform_data *pdata) +{ + int i; + + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + + if (button->active_low) + __gpio_as_irq_fall_edge(button->gpio); + else + __gpio_as_irq_rise_edge(button->gpio); + } +} + +static void button_timer_callback(unsigned long data) +{ + int gpio = board_buttons[button_no].gpio; + int code = board_buttons[button_no].code; + int active_low = board_buttons[button_no].active_low; + struct platform_device *pdev = (struct platform_device *)data; + struct input_dev *input = platform_get_drvdata(pdev); + int state; + static int button_pressed = 0; + + state = __gpio_get_pin(gpio); + + if (active_low) { + if (state == 0) { + /* button pressed */ + button_pressed = 1; + input_report_key(input, code, 1); + input_sync(input); + mod_timer(&button_timer, jiffies + SCAN_INTERVAL); + dprintk("gpio %d down, code:%d \n", gpio, code); + } else { + /* button released */ + if (button_pressed) { + input_report_key(input, code, 0); + input_sync(input); + button_pressed = 0; + dprintk("gpio %d up, code:%d \n", gpio, code); + } + __gpio_as_irq_fall_edge(gpio); + } + } else { + if (state == 1) { + /* button pressed */ + button_pressed = 1; + input_report_key(input, code, 1); + input_sync(input); + mod_timer(&button_timer, jiffies + SCAN_INTERVAL); + dprintk("gpio %d down code:%d \n", gpio, code); + } else { + /* button released */ + if (button_pressed) { + input_report_key(input, code, 0); + input_sync(input); + dprintk("gpio %d up code:%d \n", gpio, code); + } + __gpio_as_irq_rise_edge(gpio); + } + } +} + +static irqreturn_t jz_gpio_interrupt(int irq, void *dev_id) +{ + int i; + struct platform_device *pdev = dev_id; + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + + dprintk("--irq of gpio:%d\n", irq - IRQ_GPIO_0); + + __gpio_ack_irq(irq - IRQ_GPIO_0); /* clear flag */ + + if (!timer_pending(&button_timer)) { + 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 + SCAN_INTERVAL); + dprintk("--mod_timer for gpio:%d\n", gpio); + break; + } + } + } + + return IRQ_HANDLED; +} + +static int __devinit gpio_keys_probe(struct platform_device *pdev) +{ + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input; + int i, error; + int wakeup = 0; + + input = input_allocate_device(); + if (!input) + return -ENOMEM; + + platform_set_drvdata(pdev, input); + + input->name = pdev->name; + input->dev.parent = &pdev->dev; + + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + + input->evbit[0] = BIT(EV_KEY) | BIT(EV_SYN); + + set_bit(ANDROID_MENU, input->keybit); + set_bit(ANDROID_HOME, input->keybit); + set_bit(ANDROID_CALL, input->keybit); + set_bit(ANDROID_BACK, input->keybit); + set_bit(ANDROID_ENDCALL, input->keybit); + + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; + int irq; + unsigned int type = button->type ?: EV_KEY; + + irq = IRQ_GPIO_0 + button->gpio; + if (irq < 0) { + error = irq; + pr_err("%s: Unable to get irq number" + " for GPIO %d, error %d\n", DEV_NAME, + button->gpio, error); + goto fail; + } + + error = request_irq(irq, jz_gpio_interrupt, + IRQF_SAMPLE_RANDOM | IRQF_DISABLED, + button->desc ? button->desc : "gpio_keys", + pdev); + if (error) { + pr_err("%s: Unable to claim irq %d; error %d\n", + DEV_NAME, irq, error); + goto fail; + } + + if (button->wakeup) + wakeup = 1; + + input_set_capability(input, type, button->code); + } + + /* Enable all GPIO irqs */ + enable_gpio_irqs(pdata); + + /* Init timer */ + init_timer(&button_timer); + button_timer.data = (unsigned long)&board_button_device; + button_timer.function = button_timer_callback; + + error = input_register_device(input); + if (error) { + pr_err("%s: Unable to register input device, " + "error: %d\n", DEV_NAME, error); + goto fail; + } + + device_init_wakeup(&pdev->dev, wakeup); + + return 0; + + fail: + while (--i >= 0) { + free_irq(pdata->buttons[i].gpio + IRQ_GPIO_0 , pdev); + } + + platform_set_drvdata(pdev, NULL); + input_free_device(input); + + return error; +} + +static int __devexit gpio_keys_remove(struct platform_device *pdev) +{ + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + 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 = pdata->buttons[i].gpio + IRQ_GPIO_0; + free_irq(irq, pdev); + } + + input_unregister_device(input); + + return 0; +} + +#ifdef CONFIG_PM + +static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state) +{ +#if 0 + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + int i; + + 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 = button->gpio + IRQ_GPIO_0; + enable_irq_wake(irq); + } + } + } +#endif + return 0; +} + +static int gpio_keys_resume(struct platform_device *pdev) +{ + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; +#if 0 + int i; + + 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 = button->gpio + IRQ_GPIO_0; + disable_irq_wake(irq); + } + } + } +#endif + + /* Enable all GPIO irqs */ + enable_gpio_irqs(pdata); + + return 0; +} +#else +#define gpio_keys_suspend NULL +#define gpio_keys_resume NULL +#endif + +static 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 = DEV_NAME, + } +}; + +static int __init gpio_keys_init(void) +{ + int ret; + + platform_device_register(&board_button_device); + ret = platform_driver_register(&gpio_keys_device_driver); + + return ret; +} + +static void __exit gpio_keys_exit(void) +{ + platform_device_unregister(&board_button_device); + platform_driver_unregister(&gpio_keys_device_driver); +} + +module_init(gpio_keys_init); +module_exit(gpio_keys_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Regen Huang "); +MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs"); diff --git a/target/linux/xburst/files-2.6.27/drivers/input/keyboard/jz_keypad.c b/target/linux/xburst/files-2.6.27/drivers/input/keyboard/jz_keypad.c new file mode 100755 index 000000000..3e6e3090b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/input/keyboard/jz_keypad.c @@ -0,0 +1,357 @@ +/* + * linux/drivers/input/keyboard/jz_keypad.c + * + * JZ Keypad Driver + * + * Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc. + * + * Author: Richard + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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); + jz_kbd->suspended = 1; + + return 0; +} + +static int jz_kbd_resume(struct platform_device *dev) +{ + struct jz_kbd *jz_kbd = platform_get_drvdata(dev); + + 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: JZ Keypad Registered\n"); + + 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/target/linux/xburst/files-2.6.27/drivers/input/keyboard/jz_keypad_5x5.c b/target/linux/xburst/files-2.6.27/drivers/input/keyboard/jz_keypad_5x5.c new file mode 100644 index 000000000..22b7e9b06 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/input/keyboard/jz_keypad_5x5.c @@ -0,0 +1,246 @@ +/* + * JZ Keypad ( 5 x 5 ) Driver + * + * Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc. + * + * Author: Jason 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include + +#include +#include + +#define KB_ROWS 5 +#define KB_COLS 5 +#define KB_COUNT 25 + + +#define JZ_KEY_PRESSED 0x01 +#define JZ_KEY_RELEASED 0x00 + +#define SCAN_INTERVAL 10 /* jiffies */ + +#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_LEFTCTRL, KEY_LEFTALT, KEY_BACKSPACE, KEY_ENTER +}; + +static unsigned short jz_kbd_status[KB_ROWS * KB_COLS] = {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; + +/* An element shows the scan result of a whole row. LSB --> column 0 */ +static unsigned short scan_result[KB_ROWS]; + +/** + * 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; + unsigned long flags; + + if (kbd_data->suspended) + return; + + spin_lock_irqsave(&kbd_data->lock, flags); + + jz_do_scan(scan_result); + + /* handle gpio event */ + for (row = 0; row < KB_ROWS; row++) { + for (col = 0; col < KB_COLS; col++) { + + if ( !(scan_result[row] & 0x01) ) { + /* oh! a key pressed ... may be it is not news ...*/ + input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1); + input_sync(kbd_data->input); + jz_kbd_status[row * KB_ROWS + col] = JZ_KEY_PRESSED; + + } else { + /* if the key has been pressed ... release it */ + if (jz_kbd_status[row * KB_ROWS + col]) { + input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 0); + input_sync(kbd_data->input); + jz_kbd_status[row * KB_ROWS + col] = JZ_KEY_RELEASED; + } + } + + scan_result[row] >>= 1; + } + } + + 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); +} + +static int __init jz_kbd_init(void) +{ + struct input_dev *input_dev; + int i, error; + + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + 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->name = "JZ 5x5 Keypad"; + input_dev->phys = g_jz_kbd.phys; + 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); + + input_set_drvdata(input_dev, &g_jz_kbd); + 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 void __exit jz_kbd_exit(void) +{ + del_timer_sync(&g_jz_kbd.timer); + + SET_GPIOS_AS_INPUT(); + + input_unregister_device(g_jz_kbd.input); +} + +module_init(jz_kbd_init); +module_exit(jz_kbd_exit); + +MODULE_AUTHOR("Jason "); +MODULE_DESCRIPTION("JZ 5x5 keypad driver"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/drivers/input/touchscreen/jz_ts.c b/target/linux/xburst/files-2.6.27/drivers/input/touchscreen/jz_ts.c new file mode 100644 index 000000000..5d1b8dc4e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/input/touchscreen/jz_ts.c @@ -0,0 +1,789 @@ +/* + * JZ Touch Screen Driver + * + * Copyright (c) 2005 - 2009 Ingenic Semiconductor Inc. + * + * Author: Jason 20090219 + * Regen 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 + +/* 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 DIFF(a,b) (((a)>(b))?((a)-(b)):((b)-(a))) +#define MIN(a,b) (((a)<(b))?(a):(b)) + + + +/* + * TS deriver + */ +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 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; +}; + +/* + * TS Event type + */ +struct ts_event { + u16 status; + u16 x; + u16 y; + u16 pressure; + u16 pad; +}; + +#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 + +/************************************************************************/ +/* SAR ADC OPS */ +/************************************************************************/ + +typedef struct datasource { + u16 xbuf; + u16 ybuf; + u16 zbuf; +}datasource_t; + +static datasource_t data_s; +static unsigned int p; + +static DECLARE_WAIT_QUEUE_HEAD (sadc_wait_queue); + +static int first_time = 0; +//static unsigned long last_x, last_y, last_p; +static unsigned int old_x, old_y; + +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) +{ + 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 +} + +static inline void sadc_start_sadcin(void) +{ + REG_SADC_ENA |= SADC_ENA_SADCINEN; +} + +static void sadc_start_pbat(void) +{ + 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_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.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); + + ts_enable_pendown_irq(); + + sadc_enable_ts(); +} + +/** + * Read the battery voltage + */ +unsigned int jz_read_battery(void) +{ + unsigned int v; + unsigned int timeout = 0x3fff; + u16 pbat; + + if(!(REG_SADC_STATE & SADC_STATE_PBATRDY) ==1) + sadc_start_pbat(); + + while(!(REG_SADC_STATE & SADC_STATE_PBATRDY) && --timeout) + ; + + pbat = REG_SADC_BATDAT; + v = pbat & 0x0fff; + REG_SADC_STATE = SADC_STATE_PBATRDY; + return v; +} + +#define TSMAXX 3920 +#define TSMAXY 3700 +#define TSMINX 150 +#define TSMINY 270 + +#define SCREEN_MAXX 479 +#define SCREEN_MAXY 271 + +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 inline void ts_data_ready(void) +{ + REG_SADC_CTRL |= SADC_CTRL_TSRDYM; +} + +static int adc_read(struct jz_ts_t *ts) +{ + struct datasource *ds = &data_s; + u32 xybuf,z; + + while (!(REG_SADC_STATE & SADC_STATE_TSRDY)) { + REG_SADC_CTRL &= ~SADC_CTRL_TSRDYM; + } + + 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; +} + +/* + * Acquire raw pen coodinate data and compute touch screen + * pressure resistance. Hold spinlock when calling. + */ +int adc_acquire_event(struct jz_ts_t *ts, struct ts_event *event) +{ + unsigned int x_raw[SAMPLE_TIMES], y_raw[SAMPLE_TIMES], p_raw[SAMPLE_TIMES]; + int i; + unsigned int avl_x, avl_y, avl_p, diff_x, diff_y; + struct datasource *ds = &data_s; + avl_x = avl_y = avl_p = 0; + + for (i = 0; i < SAMPLE_TIMES; i++) { + if (adc_read(ts)) { + goto _INVALID_POINT; + } + + x_raw[i] = ds->ybuf; + y_raw[i] = ds->xbuf; + p_raw[i] = ds->zbuf; + +#ifdef MIN_PRESSURE + if (p_raw[i] < MIN_PRESSURE) { + goto _INVALID_POINT; + } +#endif + avl_x += x_raw[i]; + avl_y += y_raw[i]; + avl_p += p_raw[i]; +#if 0 + printk("x_raw = %u , y_raw = %u , z_raw = %u\n",x_raw[i],y_raw[i],p_raw[i]); +#endif + + } + + avl_x /= SAMPLE_TIMES; + avl_y /= SAMPLE_TIMES; + avl_p /= SAMPLE_TIMES; + + /* Verify delta data. */ + for (i = 1; i < SAMPLE_TIMES; i++) + { + if ( ((DIFF(x_raw[i],x_raw[i-1]) / MIN(x_raw[i],x_raw[i-1])) * 100) > MAX_DELTA_OF_SAMPLING ) + goto _INVALID_POINT; + + if ( ((DIFF(y_raw[i],y_raw[i-1]) / MIN(y_raw[i],y_raw[i-1])) * 100) > MAX_DELTA_OF_SAMPLING ) + goto _INVALID_POINT; + + if ( ((DIFF(p_raw[i],p_raw[i-1]) / MIN(p_raw[i],p_raw[i-1])) * 100) > MAX_DELTA_OF_SAMPLING ) + goto _INVALID_POINT; + } + + /* Compare with last point. */ + 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 >= MAX_DELTA_X_OF_2_POINTS || diff_y >= MAX_DELTA_Y_OF_2_POINTS) + goto _INVALID_POINT; + + old_x = avl_x; + old_y = avl_y; + + + /* Android need it ... transform the raw value to screen coordinate. */ + event->x = transform_to_screen_x(ts, avl_x); + event->y = transform_to_screen_y(ts, avl_y); + + event->pressure = (u16)avl_p; + event->status = PENDOWN; + + return 1; + +_INVALID_POINT: + + return 0; +} + + +/* + * 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 +} + +static inline int PenIsDown(void) +{ + return p; +} + +#ifdef CONFIG_JZ_ADKEY +/** + * Read the battery voltage + */ +static unsigned int read_sadcin(void) +{ + unsigned int v; + unsigned int timeout = 0x3ff; + u16 val; + + 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; + return v; +} + +static unsigned int key_scan(int ad_val) +{ + int i; + + for(i = 0; i= 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; + + spin_lock(&ts->lock); + + 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); + 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); + 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); + 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); + input_sync(ts->input_dev); + udelay(1000); + __gpio_as_irq_rise_edge(GPIO_ADKEY_INT); + } + } + + spin_unlock(&ts->lock); +} + +static irqreturn_t key_interrupt(int irq, void * dev_id) +{ + struct jz_ts_t *ts = dev_id; + + spin_lock(&ts->lock); + + __gpio_ack_irq(GPIO_ADKEY_INT); + __gpio_as_input(GPIO_ADKEY_INT); + sadc_start_sadcin(); + mod_timer(&ts->key_timer, jiffies + KEY_SCAN_INTERVAL); + + spin_unlock(&ts->lock); + + return IRQ_HANDLED; +} +#endif + +/************************************************************************/ +/* Touch Screen module */ +/************************************************************************/ + +static int pen_is_down = 0; + +static irqreturn_t pendown_interrupt(int irq, void * dev_id) +{ + struct jz_ts_t *ts = dev_id; + + spin_lock_irq(&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); + ts->first_read = 0; + 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); + + } else { // pen_is_down == 1 + + ts->acq_timer.expires = jiffies + TS_SCAN_INTERVAL; + del_timer(&ts->acq_timer); + ts->first_read = 1; + add_timer(&ts->acq_timer); + } + + spin_unlock_irq(&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_irq(&ts->lock); + + if (PenIsDown()) { + + ts->pen_is_down = 1; + + if (adc_acquire_event(ts, &event)) {// check event is valid or not? + 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); + /* Android need it ... */ + input_report_key(ts->input_dev, BTN_TOUCH, 1); + + input_sync(ts->input_dev); + } + + // schedule next acquire + ts->acq_timer.expires = jiffies + TS_SCAN_INTERVAL; + 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) { + 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); + } + } + + spin_unlock_irq(&ts->lock); +} + +static struct jz_ts_t *jz_ts; +static int __init jz_ts_init(void) +{ + struct input_dev *input_dev; + struct jz_ts_t *ts; + int error; + + 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, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_MAXY, 0, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 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; + + // 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; + + if (error) { + printk("Input device register failed !\n"); + goto err_free_dev; + } + + sadc_init_clock(6); + ts_disable_pendown_irq(); + ts_disable_penup_irq(); + + error = request_irq(IRQ_SADC, pendown_interrupt, IRQF_DISABLED, TS_NAME, ts); + if (error) { + pr_err("unable to get PenDown IRQ %d", IRQ_SADC); + goto err_free_irq; + } +#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) +{ + free_irq(IRQ_SADC, jz_ts); + input_unregister_device(jz_ts->input_dev); + + ts_disable_pendown_irq(); + ts_disable_penup_irq(); + + sadc_disable_ts(); +} + +module_init(jz_ts_init); +module_exit(jz_ts_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("JZ TouchScreen Driver"); +MODULE_AUTHOR("Jason "); diff --git a/target/linux/xburst/files-2.6.27/drivers/misc/jz_cim.c b/target/linux/xburst/files-2.6.27/drivers/misc/jz_cim.c new file mode 100644 index 000000000..77bac8142 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/misc/jz_cim.c @@ -0,0 +1,748 @@ +/* + * linux/drivers/misc/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include "jz_cim.h" +#include "jz_sensor.h" + + +MODULE_AUTHOR("Lemon Liu"); +MODULE_DESCRIPTION("Ingenic Camera driver"); +MODULE_LICENSE("GPL"); + +//#define CIM_DEBUG +#undef CIM_DEBUG +#ifdef CIM_DEBUG +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) +#endif + +#define CIM_NAME "cim" + + +/* + * 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 { + cim_config_t cim_cfg; + preview_param_t view_par; + picture_param_t pic_par; + unsigned char *mem_base; + unsigned char *frm_buf; /*current trans buffer pointer*/ + unsigned char *jpeg_buf; /* buf for jpeg data */ + unsigned int mem_size; + wait_queue_head_t wait_queue; +}; + +static struct cim_device jz_cim_info = { +#ifdef CONFIG_OV3640 + .cim_cfg = { + .cfg = CIM_CFG_PACK_4 | CIM_CFG_DSM_GCM | CIM_CFG_VSP | CIM_CFG_PCP + | CIM_CFG_BYPASS | CIM_CFG_DMA_BURST_INCR8 | CIM_CTRL_FAST_MODE, + .ctrl = CIM_CTRL_FRC_1 | CIM_CTRL_RXF_TRIG_4, + .mclk = 24000000, + }, +#elif defined(CONFIG_OV2640) + .cim_cfg = { + .cfg = CIM_CFG_PACK_4 | CIM_CFG_DSM_GCM | CIM_CFG_VSP | CIM_CFG_BYPASS, + + .ctrl = CIM_CTRL_FRC_1 | CIM_CTRL_RXF_TRIG_4, + .mclk = 24000000, + }, +#elif defined(CONFIG_OV9650) + .cim_cfg = { + .cfg = CIM_CFG_PACK_4 | CIM_CFG_DSM_GCM | CIM_CFG_VSP | CIM_CFG_BYPASS, + + .ctrl = CIM_CTRL_FRC_1 | CIM_CTRL_RXF_TRIG_4, + .mclk = 24000000, + }, +#else /* CONFIG-SENSOR*/ +#error "Define Sensor first..." +#endif + .view_par = {320, 240, 16, "yuv422"}, + .pic_par = {640, 480, 16, "yuv422",}, +}; + +static int cim_inited = 0; +static int jpeg_reading_flag; +static int cim_tran_buf_id; /*cim dma current transfer buffer ID*/ +static int data_ready_buf_id; /*data ready for yuv convert buffer ID*/ +static struct cim_desc cim_frame_desc[CIM_BUF_NUM] __attribute__ ((aligned (16))); +static struct cim_desc cim_jpeg_desc __attribute__ ((aligned (16))); +static struct cim_desc cim_test_jpeg_desc __attribute__ ((aligned (16))); + + +static struct cim_device *jz_cim = &jz_cim_info; + +/*========================================================================== + * CIM Module operations + *========================================================================*/ + +/* + * Init CIM module + */ +static void cim_print_regs(void) +{ + printk("REG_CIM_CFG \t= \t0x%08x\n", REG_CIM_CFG); + printk("REG_CIM_CTRL \t= \t0x%08x\n", REG_CIM_CTRL); + printk("REG_CIM_STATE \t= \t0x%08x\n", REG_CIM_STATE); + printk("REG_CIM_IID \t= \t0x%08x\n", REG_CIM_IID); + printk("REG_CIM_DA \t= \t0x%08x\n", REG_CIM_DA); + printk("REG_CIM_FA \t= \t0x%08x\n", REG_CIM_FA); + printk("REG_CIM_FID \t= \t0x%08x\n", REG_CIM_FID); + printk("REG_CIM_CMD \t= \t0x%08x\n", REG_CIM_CMD); + printk("REG_CIM_SIZE \t= \t0x%08x\n", REG_CIM_SIZE); + printk("REG_CIM_OFFSET \t= \t0x%08x\n", REG_CIM_OFFSET); +} + +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; + +#ifndef CIM_EXTCLK + /* Set the master clock output, If use pll clock, enable it */ + __cim_set_master_clk(__cpm_get_hclk(), c->mclk); +#endif + + /* Enable sof, eof and stop interrupts*/ + __cim_enable_eof_intr(); + +// __cim_enable_stop_intr(); +#if defined(CONFIG_SOC_JZ4750) + __cim_enable_rxfifo_overflow_intr(); +#endif +} + +/* + * CIM start/stop operations + */ +#if 0 +static int cim_start_dma(void) +{ + + if (start_inited == 0) { + __cim_disable(); + __cim_set_da(virt_to_phys(jz_cim->frame_desc)); + __cim_clear_state(); // clear state register + __cim_reset_rxfifo(); // resetting rxfifo + __cim_unreset_rxfifo(); + start_inited = 1; + __cim_enable_dma(); // enable dma + __cim_enable(); + } + interruptible_sleep_on(&jz_cim->wait_queue); + frm_buf = (unsigned char *)cim_frame_desc[data_ready_buf_id].framebuf; + return 0; +} +#endif + +inline static int get_ready_buf_id(void) +{ + interruptible_sleep_on(&jz_cim->wait_queue); + return data_ready_buf_id; +} + +inline void cim_start(void) +{ + dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); + cim_tran_buf_id = 0; + data_ready_buf_id = 0; + __cim_disable(); + __cim_set_da(virt_to_phys(&cim_frame_desc[cim_tran_buf_id])); + __cim_clear_state(); // clear state register + __cim_reset_rxfifo(); // resetting rxfifo + __cim_unreset_rxfifo(); + __cim_enable_dma(); // enable dma + __cim_enable(); +} +inline static void cim_stop(void) +{ + __cim_disable(); + __cim_disable_dma(); + __cim_clear_state(); +} +static int cim_device_init(void) +{ + cim_config(&jz_cim->cim_cfg); + __sensor_gpio_init(); + return 0; +} + +static int cim_snapshot(int mode) +{ + int i; + dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); + jpeg_reading_flag = 1; + for(i = 0; i < INVALID_PIC_BUF; i++) { + __cim_disable(); + __cim_set_da(virt_to_phys((&cim_test_jpeg_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(&jz_cim->wait_queue); + } + __cim_disable(); + __cim_set_da(virt_to_phys(&cim_jpeg_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(&jz_cim->wait_queue); + jpeg_reading_flag = 0; + return 0; +} + + +/*========================================================================== + * Framebuffer allocation and destroy + *========================================================================*/ +static struct cim_desc *init_cim_desc_list(void * base) +{ + int i; + unsigned char *p_buf; + struct cim_desc *p_desc; + struct cim_desc *desc_list_head __attribute__ ((aligned (16))); + struct cim_desc *desc_list_tail __attribute__ ((aligned (16))); + + + int frmsize = (((jz_cim->view_par.width * jz_cim->view_par.height + * jz_cim->view_par.bpp + 7) >> 3) + 3) >> 2; /* word aligned */ + + desc_list_head = desc_list_tail = NULL; + + for (i = 0; i < CIM_BUF_NUM; i++) { + p_desc = &cim_frame_desc[i]; + p_buf = (void*)((((unsigned int)base + (MAX_PRE_SIZE * i)) >> 3) << 3); + + 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); + + jz_cim->view_par.framebuf[i] = virt_to_phys(p_buf); + 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 = i; + desc_list_tail->dmacmd = frmsize; +#if defined(CONFIG_SOC_JZ4750) + desc_list_tail->dmacmd |= CIM_CMD_EOFINT; +#else + desc_list_tail->dmacmd |= (CIM_CMD_EOFINT | CIM_CMD_OFRCV); +#endif + dprintk("framedesc\t= 0x%08x\n",(unsigned int)virt_to_phys(desc_list_tail)); + dprintk("framebuf \t= 0x%08x\n", (unsigned int)desc_list_tail->framebuf); + dprintk("frameid \t= 0x%08x\n", (unsigned int)desc_list_tail->frameid); + dprintk("dmacmd \t= 0x%08x\n", (unsigned int)desc_list_tail->dmacmd); + dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd); + } + desc_list_tail->nextdesc = virt_to_phys(desc_list_head); + + for (i = 0; i < CIM_BUF_NUM; i++) + dma_cache_wback((unsigned long)(&cim_frame_desc[i]), sizeof(struct cim_desc)); + + /* prepare the jpeg descriptor */ + + p_buf = (void*)((((unsigned int)base + (MAX_PRE_SIZE * CIM_BUF_NUM)) >> 3) << 3); + + cim_test_jpeg_desc.framebuf = (unsigned int)virt_to_phys(p_buf); + cim_test_jpeg_desc.nextdesc = (unsigned int)virt_to_phys(NULL); + cim_test_jpeg_desc.frameid = 0xf0; + cim_test_jpeg_desc.dmacmd = (4 >> 2) | CIM_CMD_EOFINT | CIM_CMD_STOP; + dma_cache_wback_inv((unsigned long)&cim_test_jpeg_desc, sizeof(struct cim_desc)); + + jz_cim->pic_par.framebuf[0] = virt_to_phys(p_buf); + cim_jpeg_desc.framebuf = (unsigned int)virt_to_phys(p_buf); + cim_jpeg_desc.nextdesc = (unsigned int)virt_to_phys(NULL); + cim_jpeg_desc.frameid = 0xff; + + frmsize = (((jz_cim->pic_par.width * jz_cim->pic_par.height + * 16) >> 3) + 3) >> 2; /* word aligned */ + if (strcmp(jz_cim->pic_par.format, "jpeg") == 0) { + if (frmsize > (MAX_PICTURE_SIZE >> 2)) + cim_jpeg_desc.dmacmd = (MAX_PICTURE_SIZE >> 2); + else + cim_jpeg_desc.dmacmd = frmsize; + } + else/* if ((strcmp(jz_cim->pic_par.format, "yuv422") == 0) || + (strcmp(jz_cim->pic_par.format, "rgb565") == 0)) */ + cim_jpeg_desc.dmacmd = frmsize; + cim_jpeg_desc.frameid = 0xff; + + cim_jpeg_desc.dmacmd |= (CIM_CMD_EOFINT | CIM_CMD_STOP); + dma_cache_wback_inv((unsigned long)&cim_jpeg_desc, sizeof(struct cim_desc)); + + return 0; +} + +static int cim_fb_alloc(void) +{ +#ifndef USE_DEFAULT_MEM + int page_order; +#endif + /* Alloc max preview frame for chang preview size */ + /* Total memsize = preview size + picture size */ + jz_cim->mem_size = MAX_PRE_SIZE * CIM_BUF_NUM + MAX_PICTURE_SIZE; + +#ifndef USE_DEFAULT_MEM + + /* If no default memory, Alloc memory here */ + page_order = get_order(jz_cim->mem_size); + jz_cim->mem_base = (unsigned char *)__get_free_pages(GFP_KERNEL, page_order); + if (jz_cim->mem_base == NULL) + return -ENOMEM; +#endif + + /* Descriptor list for cim DMA */ + init_cim_desc_list(jz_cim->mem_base); + return 0; +} + +static void cim_fb_destroy(void) +{ +#if 0 + int pages; + struct cim_desc *jz_frame_desc, *p_desc; + __cim_disable_dma(); + __cim_disable(); + + dprintk("jz_cim->frame_desc = %x\n", (u32)jz_cim->frame_desc); + if (jz_cim->frame_desc == NULL) { + printk("Original memory is NULL\n"); + return; + } + jz_frame_desc = jz_cim->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; + jz_cim->frame_desc = NULL; + start_init = 1; +#endif +} + +/*========================================================================== + * 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); + dprintk("REG_CIM_IID \t= \t0x%08x\n", REG_CIM_IID); + dprintk("REG_CIM_FID \t= \t0x%08x\n", REG_CIM_FID); +*/ + + if (state & CIM_STATE_DMA_EOF) { + if (jpeg_reading_flag != 1) { + data_ready_buf_id = REG_CIM_IID; + cim_tran_buf_id = REG_CIM_FID; + wake_up_interruptible(&jz_cim->wait_queue); +// printk("preview sleep \n"); + REG_CIM_STATE &= ~CIM_STATE_DMA_EOF; + return IRQ_HANDLED; + } + else { + cim_stop(); + printk("wake_up_interruptible\n"); + wake_up_interruptible(&jz_cim->wait_queue); + REG_CIM_STATE = 0; + } + } +#if defined(CONFIG_SOC_JZ4750) + if (state & CIM_STATE_RXF_OF) { + printk("OverFlow interrupt!\n"); + __cim_disable(); + REG_CIM_STATE = 0; + __cim_reset_rxfifo(); // resetting rxfifo + __cim_unreset_rxfifo(); + __cim_enable_dma(); // enable dma + __cim_enable(); + return IRQ_HANDLED; + } +#endif + /* clear status flags*/ + REG_CIM_STATE = 0; + + return IRQ_HANDLED; +} + +/*========================================================================== + * 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, + mmap: cim_mmap, + +}; + +static int cim_open(struct inode *inode, struct file *filp) +{ + if (cim_inited == 0) { + cim_device_init(); + } + /* allocate frame buffers */ + cim_inited = 1; + dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); + 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) +{ + unsigned long off = *l; + if ((size + off) > jz_cim->mem_size) + size = jz_cim->mem_size; + memcpy(buf, jz_cim->mem_base + off, size); + return size; +} + +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; +} + +/************************** + * IOCTL Handlers * + **************************/ + +/* + * If use default mem, app need trans a mem_base to cim though "IOCTL_SET_MEM".(only once) + * Else driver will alloc memory by itself. See cim_fb_alloc() for detail. + * + * Then "IOCTL_SET_CIM_CONFIG" and "IOCTL_SET_PREVIEW_PARAM" will be call to set preview parametes. + * Now, call IOCTL_START_CIM to start data tranfer. + * When Take a picture, + * + */ +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_SET_I2C_ADDR: + if (copy_from_user(&i2c_addr, (void *)arg, 4)) + return -EFAULT; + break; + case IOCTL_SET_I2C_CLK: + if (copy_from_user(&i2c_clk, (void *)arg, 4)) + return -EFAULT; + break; + case IOCTL_WRITE_I2C_REG: + { + unsigned char regval[2]; + + if (copy_from_user(regval, (void *)arg, 2)) + return -EFAULT; + + sensor_write_reg(regval[0], regval[1]); + break; + } + case IOCTL_READ_I2C_REG: + { + unsigned char reg, val; + + if (copy_from_user(®, (void *)arg, 1)) + return -EFAULT; + + val = sensor_read_reg(reg); + + if (copy_to_user((void *)(arg + 1), &val, 1)) + return -EFAULT; + break; + } + case IOCTL_WRITE_I2C_REG16: + { + unsigned short regval[2]; + + if (copy_from_user(regval, (void *)arg, 4)) + return -EFAULT; + + sensor_write_reg16(regval[0], (unsigned char)regval[1]); + break; + } + case IOCTL_READ_I2C_REG16: + { + unsigned short reg, val; + + if (copy_from_user(®, (void *)arg, 2)) + return -EFAULT; + + val = sensor_read_reg16(reg); + + if (copy_to_user((void *)(arg + 1), &val, 2)) + return -EFAULT; + break; + } +#ifdef USE_DEFAULT_MEM + case IOCTL_SET_MEM: + jz_cim->mem_base = (unsigned char *)arg; + cim_fb_alloc(); + break; +#endif + case IOCTL_START_CIM: + cim_start(); + break; + case IOCTL_STOP_CIM: + cim_stop(); + return 0; + case IOCTL_GET_CIM_CONFIG: + dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); + return copy_to_user((void *)argp, (void *)&jz_cim->cim_cfg, + sizeof(cim_config_t)) ? -EFAULT : 0; + break; + + case IOCTL_SET_CIM_CONFIG: + if (copy_from_user((void *)&jz_cim->cim_cfg, (void *)arg, + sizeof(cim_config_t))) + return -EFAULT; + cim_config(&jz_cim->cim_cfg); + break; + case IOCTL_GET_PREVIEW_PARAM: + dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); + return copy_to_user(argp, &jz_cim->view_par, sizeof(preview_param_t)) ? -EFAULT : 0; + break; + case IOCTL_SET_PREVIEW_PARAM: + { + int i, framesize, wpf; /* words per frame */ + preview_param_t p; + + + if (copy_from_user((void *)&p, (void *)arg, sizeof(preview_param_t))) + return -EFAULT; + + framesize = (p.width * p.height * p.bpp + 7) >> 3; + if (framesize > MAX_PRE_SIZE){ + printk("ERROR! Preview size is too large!\n"); + return -EINVAL; + } + jz_cim->view_par.width = p.width; + jz_cim->view_par.height = p.height; + jz_cim->view_par.bpp = p.bpp; + wpf = (framesize +3) >> 2 ; + for (i = 0; i < CIM_BUF_NUM; i++) { + cim_frame_desc[i].dmacmd &= ~CIM_CMD_LEN_MASK; + cim_frame_desc[i].dmacmd |= wpf; + dma_cache_wback((unsigned long)(&cim_frame_desc[i]), sizeof(struct cim_desc)); + } + break; + } + case IOCTL_GET_PICTURE_PARAM: + return copy_to_user(argp, &jz_cim->pic_par, sizeof(picture_param_t)) ? -EFAULT : 0; + break; + case IOCTL_SET_PICTURE_PARAM: + { + int framesize, wpf; /* words per frame */ + picture_param_t p; + + if (copy_from_user((void *)&p, (void *)arg, sizeof(picture_param_t))) + return -EFAULT; + framesize = (p.width * p.height * 16 + 7) >> 3; + jz_cim->pic_par.width = p.width; + jz_cim->pic_par.height = p.height; + wpf = (framesize + 3) >> 2 ; + cim_jpeg_desc.dmacmd &= ~CIM_CMD_LEN_MASK; + cim_jpeg_desc.dmacmd |= wpf; + dma_cache_wback((unsigned long)(&cim_jpeg_desc), sizeof(struct cim_desc)); + break; + } + case IOCTL_PRINT_REGS: + cim_print_regs(); + break; + + case IOCTL_TAKE_PICTURE: + cim_snapshot(0); + break; + case IOCTL_GET_CURRENT_BUF_ID: + { + int id; + id = get_ready_buf_id(); + return copy_to_user(argp, &id, 4) ? -EFAULT : 0; + } + 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 = virt_to_phys(jz_cim->mem_base); + len = PAGE_ALIGN((start & ~PAGE_MASK) + ((unsigned long)jz_cim->mem_size)); + start &= PAGE_MASK; + + 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; +} +static struct miscdevice cim_dev = { + CIM_MINOR, + "cim", + &cim_fops +}; + +/* + * Module init and exit + */ + +static int __init cim_init(void) +{ + int ret; + + /* GPIO init for cim pins and i2c SDA & SCL */ + __gpio_as_cim(); + __gpio_as_i2c(); + + /* waitqueue */ + init_waitqueue_head(&jz_cim->wait_queue); + +#ifndef USE_DEFAULT_MEM + /* Alloc memory for cim DMA*/ + + printk("Alloc memory for cim DMA\n"); + ret = cim_fb_alloc(); + if (ret) { + printk("No mem: Alloc memory for cim DMA\n"); + return ret; + } +#endif + /* request interrupt for cim */ + if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, CIM_NAME, jz_cim))) { + printk(KERN_ERR "request_irq return error, ret=%d\n", ret); + cim_fb_destroy(); + printk(KERN_ERR "CIM could not get IRQ\n"); + return ret; + } + + /* Register as a misc device */ + ret = misc_register(&cim_dev); + if (ret < 0) { + return ret; + } + + printk("Virtual Driver of JZ CIM registered\n"); + return 0; +} + +static void __exit cim_exit(void) +{ + misc_deregister(&cim_dev); +} + +module_init(cim_init); +module_exit(cim_exit); diff --git a/target/linux/xburst/files-2.6.27/drivers/misc/jz_cim.h b/target/linux/xburst/files-2.6.27/drivers/misc/jz_cim.h new file mode 100644 index 000000000..4efe43f68 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/misc/jz_cim.h @@ -0,0 +1,104 @@ +/* + * linux/drivers/misc/jz_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 __JZ_CIM_H__ +#define __JZ_CIM_H__ + +/* use ext clock as mclk */ +#define CIM_EXTCLK 24000000 + + +/* If use default 16M mem, enable it*/ +//#define USE_DEFAULT_MEM + +/* Camera Preview buffer number */ +#define CIM_BUF_NUM 3 +#define INVALID_PIC_BUF 0 + +//#define IMEM_MAX_ORDER 12 /* max 2^12 * 4096 = 16MB */ + +/* + * Define the Max Image Size CIM Support + */ +#define MAX_IMAGE_WIDTH 4096 +#define MAX_IMAGE_HEIGHT 4096 +#define MAX_PRE_WIDTH 640 +#define MAX_PRE_HEIGHT 480 +#define MAX_IMAGE_BPP 16 +#define MAX_PRE_SIZE (MAX_PRE_WIDTH * MAX_PRE_HEIGHT * MAX_IMAGE_BPP >> 3) +#define MAX_FRAME_SIZE (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP >> 3) + +/* + * IOCTL_XXX commands + */ +#define IOCTL_SET_I2C_ADDR 0x0 +#define IOCTL_SET_I2C_CLK 0x1 +#define IOCTL_WRITE_I2C_REG 0x2 +#define IOCTL_READ_I2C_REG 0x3 +#define IOCTL_WRITE_I2C_REG16 0x4 +#define IOCTL_READ_I2C_REG16 0x5 +#define IOCTL_SET_MEM 0x6 +#define IOCTL_START_CIM 0x7 // arg type: void +#define IOCTL_STOP_CIM 0x8 // arg type: void +#define IOCTL_GET_PREVIEW_PARAM 0x9 // arg type: preview param * +#define IOCTL_SET_PREVIEW_PARAM 0xA // arg type: preview param * +#define IOCTL_GET_PICTURE_PARAM 0xB // arg type: img_param_t * +#define IOCTL_SET_PICTURE_PARAM 0xC // arg type: img_param_t * +#define IOCTL_GET_CIM_CONFIG 0xD // arg type: cim_config_t * +#define IOCTL_SET_CIM_CONFIG 0xE // arg type: cim_config_t * +#define IOCTL_PRINT_REGS 0xF // NULL +#define IOCTL_TAKE_PICTURE 0x10 +#define IOCTL_GET_CURRENT_BUF_ID 0x11 + +/* 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/misc/jz_cim.h, please define camera for your board." +#endif + + +/* preview-format=rgb565|yuv422 */ +typedef struct{ + unsigned int width; + unsigned int height; + unsigned int bpp; + char format[20]; + unsigned int framebuf[CIM_BUF_NUM]; +} preview_param_t; + +/* picture-format=yuv422|jpeg */ +typedef struct{ + unsigned int width; + unsigned int height; + unsigned int bpp; +// const char *format; + char format[20]; + unsigned int framebuf[CIM_BUF_NUM]; +} picture_param_t; + +typedef struct{ + unsigned int cfg; + unsigned int ctrl; + unsigned int mclk; + unsigned int size; + unsigned int offs; +} cim_config_t; + + +struct jz_camera_device_platform_data { + int gpio_reset; + void (*config_gpio_on) (void); + void (*config_gpio_off)(void); +}; + + +#endif /*__JZ_CIM_H__*/ diff --git a/target/linux/xburst/files-2.6.27/drivers/misc/jz_sensor.c b/target/linux/xburst/files-2.6.27/drivers/misc/jz_sensor.c new file mode 100644 index 000000000..ddd92966f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/misc/jz_sensor.c @@ -0,0 +1,92 @@ +/* + * linux/drivers/misc/jz_sensor.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "jz_cim.h" +#include "jz_sensor.h" + +unsigned int i2c_addr = 0x60; +unsigned int i2c_clk = 100000; + +/* I2C ops to init senser */ +void sensor_write_reg(unsigned char reg, unsigned char val) +{ + i2c_open(); + i2c_setclk(i2c_clk); + i2c_write((i2c_addr >> 1), &val, reg, 1); + i2c_close(); +} + +int sensor_write_reg16(unsigned short reg, unsigned char val) +{ + int ret; + i2c_open(); + i2c_setclk(i2c_clk); + ret = i2c_write_16(i2c_addr >> 1, &val, reg, 1); + i2c_close(); + return ret; +} + +unsigned char sensor_read_reg(unsigned char reg) +{ + unsigned char val; + + i2c_open(); + i2c_setclk(i2c_clk); + i2c_read((i2c_addr >> 1), &val, reg, 1); + i2c_close(); + return val; +} + +/* + * Get sensor register through i2c bus + */ + +unsigned char sensor_read_reg16(unsigned short reg) +{ + unsigned char val; + i2c_open(); + i2c_setclk(i2c_clk); + i2c_read_16(i2c_addr >> 1, &val, reg, 1); + i2c_close(); + return val; +} + diff --git a/target/linux/xburst/files-2.6.27/drivers/misc/jz_sensor.h b/target/linux/xburst/files-2.6.27/drivers/misc/jz_sensor.h new file mode 100644 index 000000000..e5057e13c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/misc/jz_sensor.h @@ -0,0 +1,94 @@ +/* + * linux/drivers/misc/jz_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 __JZ_SENSOR_H__ +#define __JZ_SENSOR_H__ + +#include "jz_cim.h" + + +#define IN_YUV422 1 /*Sensor output YUV422*/ + +/* + * Define the Max Image Size Sensor Support, Should less than CIM MAX + */ +#if defined(CONFIG_OV3640) +#define MAX_SENSOR_WIDTH 2048 +#define MAX_SENSOR_HEIGHT 1536 +#define MAX_SENSOR_BPP 16 +#define SENSOR_PRE_WIDTH 320 +#define SENSOR_PRE_HEIGHT 240 +#elif defined(CONFIG_OV2640) +#define MAX_SENSOR_WIDTH 1600 +#define MAX_SENSOR_HEIGHT 1200 +#define MAX_SENSOR_BPP 16 +#define SENSOR_PRE_WIDTH 320 +#define SENSOR_PRE_HEIGHT 240 +#elif defined(CONFIG_OV9650) +#define MAX_SENSOR_WIDTH 1280 +#define MAX_SENSOR_HEIGHT 1024 +#define MAX_SENSOR_BPP 16 +#define SENSOR_PRE_WIDTH 320 +#define SENSOR_PRE_HEIGHT 240 +#else +#define MAX_SENSOR_WIDTH 1280 +#define MAX_SENSOR_HEIGHT 1024 +#define MAX_SENSOR_BPP 16 +#define SENSOR_PRE_WIDTH 320 +#define SENSOR_PRE_HEIGHT 240 +#endif + +#if defined(CONFIG_OV3640) || defined(CONFIG_OV2640) +//#define JPEG_OUTPUT_SUPPORT +#endif + +#if defined(JPEG_OUTPUT_SUPPORT) +#define MAX_PICTURE_SIZE (6*1024*1024) /* for 2048*1536*2 */ +#else +#define MAX_PICTURE_SIZE (MAX_SENSOR_WIDTH * MAX_SENSOR_HEIGHT * MAX_IMAGE_BPP >> 3) +#endif + + +#if defined(CONFIG_OV9650) || defined(CONFIG_OV2640) +#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_OV3640) +#define __sensor_gpio_init() \ +do {\ + __gpio_as_output(GPIO_CAMERA_RST); \ + __gpio_clear_pin(GPIO_CAMERA_RST);\ + mdelay(50); \ + __gpio_set_pin(GPIO_CAMERA_RST); \ +} while(0) + +#endif + + +extern unsigned int i2c_addr; +extern unsigned int i2c_clk; + +/* I2C APP */ + +extern int i2c_write_16(unsigned char device, unsigned char *buf, unsigned short address, int count); +extern int i2c_read_16(unsigned char device, unsigned char *buf, unsigned short address, int count); + + +extern void sensor_write_reg(unsigned char reg, unsigned char val); +extern int sensor_write_reg16(unsigned short reg, unsigned char val); +extern unsigned char sensor_read_reg(unsigned char reg); +extern unsigned char sensor_read_reg16(unsigned short reg); + +#endif diff --git a/target/linux/xburst/files-2.6.27/drivers/misc/jz_tcsm.c b/target/linux/xburst/files-2.6.27/drivers/misc/jz_tcsm.c new file mode 100644 index 000000000..4e51b8607 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/misc/jz_tcsm.c @@ -0,0 +1,132 @@ +/* + * linux/drivers/misc/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +MODULE_AUTHOR("Jianli Wei"); +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); + + printk("pt_regs =%p\n", info); + printk("cp0 status=0x%08x\n", (unsigned int)info->cp0_status); + info->cp0_status &= ~0x10; + info->cp0_status |= 0x08000000; // a tricky + printk("cp0 status=0x%08x\n", (unsigned int)info->cp0_status); + + return 0; +} + +static int tcsm_release(struct inode *inode, struct file *filp) +{ + struct pt_regs *info = task_pt_regs(current); + + info->cp0_status |= 0x10; + info->cp0_status &= ~0x08000000; // 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; +} + +static struct miscdevice tcsm_dev = { + TCSM_MINOR, + "tcsm", + &tcsm_fops +}; + + +/* + * Module init and exit + */ + +static int __init tcsm_init(void) +{ + int ret; + + ret = misc_register(&tcsm_dev); + if (ret < 0) { + return ret; + } + + printk("Virtual Driver of JZ TCSM registered\n"); + return 0; +} + +static void __exit tcsm_exit(void) +{ + misc_deregister(&tcsm_dev); +} + +module_init(tcsm_init); +module_exit(tcsm_exit); diff --git a/target/linux/xburst/files-2.6.27/drivers/mmc/host/jz4750_mmc.c b/target/linux/xburst/files-2.6.27/drivers/mmc/host/jz4750_mmc.c new file mode 100755 index 000000000..426285ba0 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mmc/host/jz4750_mmc.c @@ -0,0 +1,1014 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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); + } + + REG_MSC_CLKRT(MSC_ID) = 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(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_MSC0_JZ4750 + empty = (__msc0_card_detected(slot) == 0) ? 1 : 0; +#else + empty = (__msc1_card_detected(slot) == 0) ? 1 : 0; +#endif + + if (empty) { + /* wait for card insertion */ +#if ACTIVE_LOW_MSC_CD == 0 + __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN); +#else + __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN); +#endif + } else { + /* wait for card removal */ +#if ACTIVE_LOW_MSC_CD == 0 + __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; + + 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 + __gpio_as_msc0_8bit(); + __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 < 6) + 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 < 6) + 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 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); + + 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); +#ifdef CONFIG_MSC0_JZ4750 + __msc0_disable_power(); +#else + __msc1_disable_power(); +#endif + jz_free_dma(rxdmachan); + jz_free_dma(txdmachan); + free_irq(IRQ_MSC, host); + mmc_free_host(mmc); + } + return 0; +} + +#if 0 /* Do nothing at present. Should just disable power for future. */ +static int jz_mmc_suspend(struct platform_device *dev, pm_message_t state) +{ + struct mmc_host *mmc = platform_get_drvdata(dev); + int ret = 0; + + 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 (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/target/linux/xburst/files-2.6.27/drivers/mmc/host/jz4750_mmc.h b/target/linux/xburst/files-2.6.27/drivers/mmc/host/jz4750_mmc.h new file mode 100755 index 000000000..7b9544fd8 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mmc/host/jz4750_mmc.h @@ -0,0 +1,163 @@ +#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 +#define ACTIVE_LOW_MSC_CD ACTIVE_LOW_MSC0_CD +#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 +#define ACTIVE_LOW_MSC_CD ACTIVE_LOW_MSC1_CD +#endif + +#define MSC_1BIT_BUS 0 +#define MSC_4BIT_BUS 1 +#define MSC_8BIT_BUS 2 + +#define SZ_4K 0x00001000 + +#ifdef CONFIG_MSC0_JZ4750 +#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) + +#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*/ +#endif +#ifdef CONFIG_MSC1_JZ4750 +#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) + +#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 + + +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 + +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/target/linux/xburst/files-2.6.27/drivers/mmc/host/jz_mmc.c b/target/linux/xburst/files-2.6.27/drivers/mmc/host/jz_mmc.c new file mode 100755 index 000000000..7b653feb9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mmc/host/jz_mmc.c @@ -0,0 +1,995 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 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); + + 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); + + jz_mmc_stop_clock(); + __msc_disable_power(); + jz_free_dma(rxdmachan); + jz_free_dma(txdmachan); + free_irq(IRQ_MSC, host); + 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/target/linux/xburst/files-2.6.27/drivers/mmc/host/jz_mmc.h b/target/linux/xburst/files-2.6.27/drivers/mmc/host/jz_mmc.h new file mode 100755 index 000000000..c733529b7 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/COPYING b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/COPYING new file mode 100644 index 000000000..60549be51 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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. + + + Copyright (C) 19yy + + 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. + + , 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/MAKEDEV b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/MAKEDEV new file mode 100644 index 000000000..b31e61fd6 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/Makefile b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/Makefile new file mode 100644 index 000000000..add022abd --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/Makefile @@ -0,0 +1,102 @@ + +# -*- 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)/.$( ${DESTDIR}/${MANDIR}/man1/mkfs.jffs2.1.gz + make -C $(BUILDDIR)/ubi-utils install diff --git a/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr.c new file mode 100644 index 000000000..7028c936a --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr.c @@ -0,0 +1,538 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2004 Ferenc Havasi , + * University of Szeged, Hungary + * + * For licensing information, see the file 'LICENCE' in this directory + * in the jffs2 directory. + */ + +#include "compr.h" +#include +#include +#include + +#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;iname, 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr.h new file mode 100644 index 000000000..51bf0dd63 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr.h @@ -0,0 +1,119 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2004 Ferenc Havasi , + * University of Szeged, Hungary + * + * For licensing information, see the file 'LICENCE' in the + * jffs2 directory. + */ + +#ifndef __JFFS2_COMPR_H__ +#define __JFFS2_COMPR_H__ + +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr_lzo.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr_lzo.c new file mode 100644 index 000000000..a0bb3621d --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * + * 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 +#include +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr_rtime.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr_rtime.c new file mode 100644 index 000000000..131536cf6 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * + * 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 +#include +#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= 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr_zlib.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/compr_zlib.c new file mode 100644 index 000000000..400b18a15 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * + * 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 +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/crc32.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/crc32.c new file mode 100644 index 000000000..6b1e50c42 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/crc32.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/crc32.h new file mode 100644 index 000000000..ee3145bc1 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/crc32.h @@ -0,0 +1,19 @@ +#ifndef CRC32_H +#define CRC32_H + +#include + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/device_table.txt b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/device_table.txt new file mode 100644 index 000000000..74fdc5605 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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: +# +# 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 +# + +# +/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/doc_loadbios.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/doc_loadbios.c new file mode 100644 index 000000000..0a11fd203 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/doc_loadbios.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/docfdisk.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/docfdisk.c new file mode 100644 index 000000000..56fffc4d6 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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 [ [ [ [ 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/feature-removal-schedule.txt b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/feature-removal-schedule.txt new file mode 100644 index 000000000..d0116f887 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/fec.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/fec.c new file mode 100644 index 000000000..09e8453f0 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include + +/* + * 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 +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 +#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 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; ik ; + 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/fectest.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/fectest.c new file mode 100644 index 000000000..d5893b91a --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/fectest.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_erase.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_erase.c new file mode 100644 index 000000000..873161760 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_erase.c @@ -0,0 +1,189 @@ +/* + * flash_erase.c -- erase parts of a MTD device + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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,®count) == 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_eraseall.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_eraseall.c new file mode 100644 index 000000000..6d68e085b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "crc32.h" + +#include +#include + +#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 * 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_info.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_info.c new file mode 100644 index 000000000..f5ed1c6ff --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_info.c @@ -0,0 +1,55 @@ +/* + * flash_info.c -- print info about a MTD device + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +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,®count) == 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, ®info) == 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_lock.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_lock.c new file mode 100644 index 000000000..dca679456 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include + +#include + +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 \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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_dump.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_dump.c new file mode 100644 index 000000000..a18130d24 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_dump.c @@ -0,0 +1,54 @@ +/* + * flash_otp_dump.c -- display One-Time-Programm data + */ + +#include +#include +#include +#include +#include +#include + +#include + +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 ] \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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_info.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_info.c new file mode 100644 index 000000000..c9486ee54 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_info.c @@ -0,0 +1,63 @@ +/* + * flash_otp_info.c -- print info about One-Time-Programm data + */ + +#include +#include +#include +#include +#include +#include + +#include + +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 ] \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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_lock.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_lock.c new file mode 100644 index 000000000..d0e06cdb7 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_lock.c @@ -0,0 +1,70 @@ +/* + * flash_otp_lock.c -- lock area of One-Time-Program data + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +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 \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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_write.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_write.c new file mode 100644 index 000000000..f01df5143 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_otp_write.c @@ -0,0 +1,96 @@ +/* + * flash_otp_write.c -- write One-Time-Program data + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 \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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_unlock.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_unlock.c new file mode 100644 index 000000000..648dc4f42 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flash_unlock.c @@ -0,0 +1,64 @@ +/* + * FILE flash_unlock.c + * + * This utility unlock all sectors of flash device. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 \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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flashcp.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flashcp.c new file mode 100644 index 000000000..7f7764a6d --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/flashcp.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2d3D, Inc. + * Written by Abraham vd Merwe + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 \n" + "\n" + "usage: %s [ -v | --verbose ] \n" + " %s -h | --help\n" + "\n" + " -h | --help Show this help message\n" + " -v | --verbose Show progress reports\n" + " File which you want to copy to flash\n" + " 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ftl_check.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ftl_check.c new file mode 100644 index 000000000..f41e79a34 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + . 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ftl_format.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ftl_format.c new file mode 100644 index 000000000..ae00c9941 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + . 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/linux/jffs2.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/linux/jffs2.h new file mode 100644 index 000000000..61847ebcf --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * + * 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/ftl-user.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/ftl-user.h new file mode 100644 index 000000000..42edc8cb2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * . 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/inftl-user.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/inftl-user.h new file mode 100644 index 000000000..a137de134 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/jffs2-user.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/jffs2-user.h new file mode 100644 index 000000000..2ebfb4419 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h new file mode 100644 index 000000000..08e3b9fd0 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h @@ -0,0 +1,170 @@ +/* + * $Id: mtd-abi.h,v 1.1.1.1 2008-10-30 14:29:21 lhhuang Exp $ + * + * Portions of MTD ABI definition which are shared by kernel and user space + */ + +#ifndef __MTD_ABI_H__ +#define __MTD_ABI_H__ + +#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into + separate files was to avoid #ifdef __KERNEL__ */ +#define __user +#endif + +typedef unsigned long long size_mtd_t; +typedef unsigned long long loff_mtd_t; + +struct erase_info_user { + uint64_t start; + uint64_t length; +}; + +struct mtd_oob_buf { + uint32_t start; + uint32_t length; + unsigned char __user *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_STUPID_LOCK 0x2000 /* Always locked after reset */ + +// 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 { + uint8_t type; + uint32_t flags; + uint64_t size; // Total size of the MTD + uint32_t erasesize; + uint32_t writesize; + uint32_t 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) */ + uint32_t ecctype; + uint32_t eccsize; +}; + +struct region_info_user { + uint64_t offset; /* At which this region starts, + * from the beginning of the MTD */ + uint32_t erasesize; /* For this region */ + uint32_t numblocks; /* Number of blocks in this region */ + uint32_t regionindex; +}; + +struct otp_info { + uint32_t start; + uint32_t length; + uint32_t 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 MEMWRITEPAGE _IOWR('M', 20, struct mtd_page_buf) + +/* + * Obsolete legacy interface. Keep it in order not to break userspace + * interfaces + */ +struct nand_oobinfo { + uint32_t useecc; + uint32_t eccbytes; + uint32_t oobfree[8][2]; + uint32_t eccpos[104]; /* more fields(13*8) are required for + * 8-bit BCH ECC and 4KB pagesize nand, by Regen */ +}; + +struct nand_oobfree { + uint32_t offset; + uint32_t 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 { + uint32_t eccbytes; + uint32_t eccpos[128]; + uint32_t 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 { + uint32_t corrected; + uint32_t failed; + uint32_t badblocks; + uint32_t 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/mtd-user.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/mtd-user.h new file mode 100644 index 000000000..aa7d840b8 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/mtd-user.h @@ -0,0 +1,21 @@ +/* + * $Id: mtd-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ + * + * MTD ABI header for use by user space only. + */ + +#ifndef __MTD_USER_H__ +#define __MTD_USER_H__ + +#include + +/* This file is blessed for inclusion by userspace */ +#include + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/nftl-user.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/nftl-user.h new file mode 100644 index 000000000..b53a930ae --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/ubi-header.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/ubi-header.h new file mode 100644 index 000000000..386fa3c61 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +/* 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/ubi-user.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd/ubi-user.h new file mode 100644 index 000000000..cb0536d2d --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd_swab.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd_swab.h new file mode 100644 index 000000000..c3340a643 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/include/mtd_swab.h @@ -0,0 +1,51 @@ +#ifndef MTD_SWAB_H +#define MTD_SWAB_H + +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/jffs-dump.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/jffs-dump.c new file mode 100644 index 000000000..31cdad21f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/jffs-dump.c @@ -0,0 +1,359 @@ +/* + * Dump JFFS filesystem. + * Useful when it buggers up. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/jffs2dump.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/jffs2dump.c new file mode 100644 index 000000000..65034dede --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; is.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; is.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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/jffs2reader.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/jffs2reader.c new file mode 100644 index 000000000..cde1d06ca --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * + * 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 [-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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/load_nandsim.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/load_nandsim.sh new file mode 100644 index 000000000..bda3c790c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 " + echo " " + 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mcast_image.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mcast_image.h new file mode 100644 index 000000000..07b6e316e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mcast_image.h @@ -0,0 +1,54 @@ +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mkfs.jffs2.1 b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mkfs.jffs2.1 new file mode 100644 index 000000000..4080032e4 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +.SH SEE ALSO +.BR mkfs (8), +.BR mkfs.jffs (1), +.BR fakeroot (1) diff --git a/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mkfs.jffs2.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mkfs.jffs2.c new file mode 100644 index 000000000..cdf2a5a83 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * 2002 Axis Communications AB + * 2001, 2002 Erik Andersen + * 2004 University of Szeged, Hungary + * 2006 KaiGai Kohei + * + * 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 . + * + * Major architectural rewrite by Erik Andersen + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef WITHOUT_XATTR +#include +#include +#endif +#include +#define crc32 __complete_crap +#include +#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; id_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: + + /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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mtd-utils.spec b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mtd-utils.spec new file mode 100644 index 000000000..606a6a211 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 - 1.0 +- Initial build. + diff --git a/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mtd_debug.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mtd_debug.c new file mode 100644 index 000000000..85d48e924 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/mtd_debug.c @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2d3D, Inc. + * Written by Abraham vd Merwe + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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,®ions[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 \n" + " %s read \n" + " %s write \n" + " %s erase \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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nanddump.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nanddump.c new file mode 100644 index 000000000..46f81f4fc --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nanddump_vfat.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nanddump_vfat.c new file mode 100644 index 000000000..812d3f94b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nandtest.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nandtest.c new file mode 100644 index 000000000..058040207 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nandtest.c @@ -0,0 +1,284 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "mtd/mtd-user.h" + +void usage(void) +{ + fprintf(stderr, "usage: nandtest [OPTIONS] \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.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nandwrite_mlc.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nandwrite_mlc.c new file mode 100644 index 000000000..52f5b18e0 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nftl_format.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nftl_format.c new file mode 100644 index 000000000..42949a039 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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] [ []]\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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nftldump.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/nftldump.c new file mode 100644 index 000000000..6d72acd7b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 []\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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rbtree.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rbtree.c new file mode 100644 index 000000000..dd50134b2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rbtree.c @@ -0,0 +1,390 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + (C) 2002 David Woodhouse + + 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 +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rbtree.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rbtree.h new file mode 100644 index 000000000..9597b10e2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rbtree.h @@ -0,0 +1,168 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + + 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 +#include + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/recv_image.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/recv_image.c new file mode 100644 index 000000000..3b7930401 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/recv_image.c @@ -0,0 +1,484 @@ + +#define _XOPEN_SOURCE 500 +#define _USE_MISC + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 \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= 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rfddump.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rfddump.c new file mode 100644 index 000000000..73b0ecab8 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/rfddump.c @@ -0,0 +1,336 @@ +/* + * rfddump.c + * + * Copyright (C) 2005 Sean Young + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* 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; idata_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 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 []\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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/summary.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/summary.h new file mode 100644 index 000000000..95f25c62b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/summary.h @@ -0,0 +1,178 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2004 Ferenc Havasi , + * Zoltan Sogor , + * Patrik Kluba , + * University of Szeged, Hungary + * + * For licensing information, see the file 'LICENCE' in this directory. + */ + +#ifndef JFFS2_SUMMARY_H +#define JFFS2_SUMMARY_H + +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/sumtool.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/sumtool.c new file mode 100644 index 000000000..2e3d94dd0 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/sumtool.c @@ -0,0 +1,951 @@ +/* + * sumtool.c + * + * Copyright (C) 2004 Zoltan Sogor , + * Ferenc Havasi + * University of Szeged, Hungary + * 2006 KaiGai Kohei + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/Makefile b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/Makefile new file mode 100644 index 000000000..ac94dde8c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/README b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/README new file mode 100644 index 000000000..f817c0f3e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/checkfs.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/checkfs.c new file mode 100644 index 000000000..795794649 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 \n", argv[0]); + printf("%s : Set com port to send ok to pwr dn msg on\n", + CMDLINE_PORT); + printf("%s : Set Max size in bytes of each file to be created.\n", + CMDLINE_MAXFILEBYTES); + printf("%s : 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 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 +#include +#include + + + +/* + 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/common.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/common.h new file mode 100644 index 000000000..cbac10766 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/makefiles.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/checkfs/makefiles.c new file mode 100644 index 000000000..8589bbf74 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile new file mode 100644 index 000000000..8d5782406 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c new file mode 100644 index 000000000..9b8f44330 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h new file mode 100644 index 000000000..db08628aa --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +/* 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh new file mode 100644 index 000000000..e79993a29 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile new file mode 100644 index 000000000..819099317 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c new file mode 100644 index 000000000..86edf6503 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c new file mode 100644 index 000000000..f6d89564f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c new file mode 100644 index 000000000..69eafe4fa --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c new file mode 100644 index 000000000..20944606a --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile new file mode 100644 index 000000000..c24ff3f14 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile new file mode 100644 index 000000000..9fbfd39ec --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c new file mode 100644 index 000000000..2f40b3db2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c new file mode 100644 index 000000000..31c175da6 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c new file mode 100644 index 000000000..35365804a --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c new file mode 100644 index 000000000..c1d0729fd --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c new file mode 100644 index 000000000..724b1c3ad --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c new file mode 100644 index 000000000..77518398f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c new file mode 100644 index 000000000..655d9cc23 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c new file mode 100644 index 000000000..86f94c2dd --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c new file mode 100644 index 000000000..a9bc31a9c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c new file mode 100644 index 000000000..99fb05dbf --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh new file mode 100644 index 000000000..60f8c0dbf --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh new file mode 100644 index 000000000..5913c1cc5 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile new file mode 100644 index 000000000..9fb60b5b1 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c new file mode 100644 index 000000000..88036aac3 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c new file mode 100644 index 000000000..298ee2683 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/COPYING b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/COPYING new file mode 100644 index 000000000..60549be51 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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. + + + Copyright (C) 19yy + + 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. + + , 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c new file mode 100644 index 000000000..59c2eb76c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 /* fopen, printf, fprintf, fclose */ +#include /* strcpy, strcmp */ +#include /* exit, atol, atoi */ +#include /* setitimer, settimeofday, gettimeofday */ +#include /* signal */ +#include /* sched_setscheduler, sched_get_priority_min,*/ +/* sched_get_priority_max */ +#include /* gettimeofday, sleep */ +#include +#include +#include +#include + + + +/**************************** 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 /* 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)],"", + 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 , --time ] "); + printf( "Set interrupt period to milliseconds.\n"); + printf(" "); + printf( "Range: [%ld, %ld] milliseconds.\n", + MIN_INT_PERIOD_MILLISEC, MAX_INT_PERIOD_MILLISEC); + printf(" [-p , --priority ] "); + printf( "Set scheduler priority to .\n"); + printf(" "); + printf( "Range: [%d, %d] (higher number = higher priority)\n", + MinPriority, MaxPriority); + printf(" [--grab_kprofile ] Read the /proc/profile if jitter is > THRESHOLD and store in file.\n"); + printf(" [--siggc ] 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/Makefile b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/Makefile new file mode 100644 index 000000000..2f113297b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/README b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/README new file mode 100644 index 000000000..7dbccded2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh new file mode 100644 index 000000000..10651f460 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c new file mode 100644 index 000000000..cc678e02a --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include + +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] -t [--jitter_threshold] \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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/Makefile b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/Makefile new file mode 100644 index 000000000..b02dca402 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/README.udev b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/README.udev new file mode 100644 index 000000000..06e71d378 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/common.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/common.c new file mode 100644 index 000000000..a5064fb15 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/common.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/common.h new file mode 100644 index 000000000..3e8ada808 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c new file mode 100644 index 000000000..e8bffabb3 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c @@ -0,0 +1,783 @@ +#define _LARGEFILE64_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 [] \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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c new file mode 100644 index 000000000..256b71b07 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c new file mode 100644 index 000000000..7b0c3d9bb --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c new file mode 100644 index 000000000..57a8da7da --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c new file mode 100644 index 000000000..f7a122efe --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c new file mode 100644 index 000000000..2e3c450bc --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c new file mode 100644 index 000000000..880c14942 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c new file mode 100644 index 000000000..74be5fa04 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c new file mode 100644 index 000000000..8ec93bcb3 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh new file mode 100644 index 000000000..fa10c3e2b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 " + 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c new file mode 100644 index 000000000..a56deae96 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/Makefile b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/Makefile new file mode 100644 index 000000000..35919b0f2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/Makefile @@ -0,0 +1,85 @@ +# +# 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) + 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 + 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/README b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/README new file mode 100644 index 000000000..d976a7654 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/UBI.TXT b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/UBI.TXT new file mode 100644 index 000000000..9a1c3c78c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff new file mode 100644 index 000000000..6cebc461f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +.sp 0 +Drake Dowsett +.SH CONTACT +Andreas Arnez diff --git a/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h new file mode 100644 index 000000000..d39c1b93e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include + +#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 ) + * + * 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am new file mode 100644 index 000000000..1b0dc01a6 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser new file mode 100644 index 000000000..dbfa45dae --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile new file mode 100644 index 000000000..28b72524f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile @@ -0,0 +1,81 @@ +# +# 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) + +# 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 + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/README b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/README new file mode 100644 index 000000000..41c595762 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h new file mode 100644 index 000000000..0b0ab646a --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include + +/* + * The following #include is necessary on many Unixes but not Linux. + * It is not needed for Windows platforms. + * Uncomment it if needed. + */ +/* #include */ + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h new file mode 100644 index 000000000..d3c6a6320 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h new file mode 100644 index 000000000..5afc93e3a --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h new file mode 100644 index 000000000..8fd857a5c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h new file mode 100644 index 000000000..c2b95b001 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c new file mode 100644 index 000000000..bcb775c1c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include + +/** + * 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h new file mode 100644 index 000000000..fdc69db5e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c new file mode 100644 index 000000000..6b1e50c42 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h new file mode 100644 index 000000000..ee3145bc1 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h @@ -0,0 +1,19 @@ +#ifndef CRC32_H +#define CRC32_H + +#include + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c new file mode 100644 index 000000000..7681e2dde --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include + +/** 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>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 (sizesize = 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 ; isize ; 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 ; isize ; 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 ; isize ; 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 ; isize ; 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 ; isize ; 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 ; isize ; 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 ; in != 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h new file mode 100644 index 000000000..860573568 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include + +/*--------------------------------------------------------------------------- + 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c new file mode 100644 index 000000000..6f9028cfe --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include + +/*---------------------------- 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 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 ; isize ; 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 ; isize ; 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 ; isize ; 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 ; isize ; i++) { + if (d->key[i]==NULL) + continue ; + fprintf(f, "%s = %s\n", d->key[i], d->val[i]); + } + return ; + } + for (i=0 ; isize ; 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c new file mode 100644 index 000000000..aab4b0ea0 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include + +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c new file mode 100644 index 000000000..342749840 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c new file mode 100644 index 000000000..9f16a47b0 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h new file mode 100644 index 000000000..2e664b875 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c new file mode 100644 index 000000000..f3e776902 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include + +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c new file mode 100644 index 000000000..3e19ecaf3 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include + +#include +#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= 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 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 " [-m ] [-d ]\n" +"\t\t[--mtdn=] [--devn ]\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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c new file mode 100644 index 000000000..4f5b32e8f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include + +#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 " [-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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c new file mode 100644 index 000000000..6a06fb2cf --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c new file mode 100644 index 000000000..8658cd884 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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 " [-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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c new file mode 100644 index 000000000..50670d05b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include + +#include +#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 to delete\n" +"-m, --mtdn= 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 " [-d ] [-m ]\n" +"\t\t[--devn ] [--mtdn=]\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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c new file mode 100644 index 000000000..802ef3d64 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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= 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= 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\"\n" +"-B, --broken-update broken update, this is for testing"; + +static const char *usage = +"Usage: " PROGRAM_NAME " [-t] [-h] [-V] [--truncate] [--help]\n" +"\t\t\t[--version] \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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c new file mode 100644 index 000000000..d82461c5f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#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= 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= 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= flash image file\n" +"-e, --erase-counter= use 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= 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 " [-h] [-V] [-y] [-q] [-v]\n" +"\t\t\t[-x ] [-E ] [-s ] [-O ] [-n]\n" +"\t\t\t[--help] [--version] [--yes] [--verbose] [--quiet]\n" +"\t\t\t[--ec=] [--vid-hdr-offset=]\n" +"\t\t\t[--ubi-ver=] [--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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c new file mode 100644 index 000000000..fd8c56852 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * Frank Haverkamp + */ + +#include +#include +#include +#include +#include + +#include +#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= volume alignment (default is 1)\n" +"-n, --vol_id= UBI volume ID, if not specified, the volume ID\n" +" will be assigned automatically\n" +"-N, --name= volume name\n" +"-s, --size= volume size volume size in bytes, kilobytes (KiB)\n" +" or megabytes (MiB)\n" +"-S, --lebs= alternative way to give volume size in logical\n" +" eraseblocks\n" +"-m, --maxavsize set volume size to maximum available size\n" +"-t, --type= 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= 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\""; + + +static const char *usage = +"Usage: " PROGRAM_NAME " [-h] [-a ] [-n ] [-N ]\n" +"\t\t\t[-s ] [-S ] [-t ] [-V] [-m]\n" +"\t\t\t[--alignment=][--vol_id=] [--name=]\n" +"\t\t\t[--size=] [--lebs=] [--type=] [--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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c new file mode 100644 index 000000000..fdf169a66 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include + +#include +#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 to get information about\n" +"-n, --vol_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 ] [-n ] [-a] [-h] [-V] [--vol_id=]\n" +"\t\t[--devn ] [--all] [--help] [--version]\n" +"Usage 2: " PROGRAM_NAME " [-a] [-h] [-V] [--all] [--help] [--version]\n" +"Usage 3: " PROGRAM_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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c new file mode 100644 index 000000000..b786f70a1 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#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= output file name\n" +"-p, --peb-size= 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= minimum input/output unit size of the flash\n" +" in bytes\n" +"-s, --sub-page-size= 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= 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= the erase counter value to put to EC headers\n" +" (default is 0)\n" +"-x, --ubi-ver= 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=] [--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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c new file mode 100644 index 000000000..f5187d546 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + + +#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 + * Frank Haverkamp + */ + +#include +#include +#include +#include +#include + +#include +#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 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= 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\""; + +static const char *usage = +"Usage: " PROGRAM_NAME " [-n ] [--vol_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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c new file mode 100644 index 000000000..69de89569 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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= 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= 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\"\n" +"-B, --broken-update broken update, this is for testing"; + +static const char *usage = +"Usage: " PROGRAM_NAME " [-t] [-h] [-V] [--truncate] [--help]\n" +"\t\t\t[--version] \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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg new file mode 100644 index 000000000..e468d9d03 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg new file mode 100644 index 000000000..fd44e2773 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi new file mode 100644 index 000000000..2cce587ba --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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); + ©_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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl new file mode 100644 index 000000000..add5f9d9d --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile new file mode 100644 index 000000000..ebd9bc6c0 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile @@ -0,0 +1,75 @@ +# +# Makefile +# +# Testcase for UBI pfi update. +# +# Author: Frank Haverkamp +# + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/README b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/README new file mode 100644 index 000000000..899b4a18f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/TODO b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/TODO new file mode 100644 index 000000000..f093e7754 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh new file mode 100644 index 000000000..a17c91bf0 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl new file mode 100644 index 000000000..b4a862a13 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl @@ -0,0 +1,94 @@ +#!/usr/bin/perl -w +# +# 2007 Frank Haverkamp +# +# 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 + +Byte-offset where bit-error should be injected. + +=item B<--bitmask>=I + +Bit-mask where to inject errors in the byte. + +=item B<--input>=I + +Input file. + +=item B<--output>=I + +Output file. + +=back + +=head1 DESCRIPTION + +B will read the given input file and inject +biterrors at the I specified. The location of the biterrors +are defined by the I parameter. + +=cut diff --git a/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh new file mode 100644 index 000000000..0cc9f0c3a --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl new file mode 100644 index 000000000..f0fd46477 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl @@ -0,0 +1,32 @@ +#!/usr/bin/perl -w + +# +# Author: Artem B. Bityutskiy +# +# 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 = ; +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt new file mode 100644 index 000000000..a3ad91522 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh new file mode 100644 index 000000000..040bcbdec --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 " + 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg new file mode 100644 index 000000000..0b5ec48dc --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh new file mode 100644 index 000000000..883903dbe --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +# +# 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh new file mode 100644 index 000000000..73e4b195f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +# +# 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh new file mode 100644 index 000000000..7f121f134 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +# +# 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh new file mode 100644 index 000000000..40dc2e24b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +# + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c new file mode 100644 index 000000000..c7c7ccc8b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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= Padding in Byte/Mi/ki. Default = no padding\n" +" -p, --pagesize= Pagesize in Byte/Mi/ki. Default = 2048\n" +" -o, --output= Output filename. Interleaved Data/OOB if\n" +" output-oob not specified.\n" +" -q, --output-oob= 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 ] [-p ] [-o ] [-q ]\n" +" [--copyright] [--padding=] [--pagesize=]\n" +" [--output=] [--output-oob=] [--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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c new file mode 100644 index 000000000..fd02bd199 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include + +#include "hashmap.h" +#include "error.h" + +#include +#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: "); + + 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h new file mode 100644 index 000000000..8fecdbf41 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 /* FILE */ +#include +#include + +/* 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: + * @verbatimkey1=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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/config.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/config.h new file mode 100644 index 000000000..55e60f31e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/crc32.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/crc32.c new file mode 100644 index 000000000..666e2171f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include + +/* 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/crc32.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/crc32.h new file mode 100644 index 000000000..31362b094 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c new file mode 100644 index 000000000..da5c2e344 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/error.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/error.c new file mode 100644 index 000000000..4aaedadbb --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/error.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/error.h new file mode 100644 index 000000000..05d807878 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h new file mode 100644 index 000000000..23c7b54ef --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c new file mode 100644 index 000000000..3511d56c9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h new file mode 100644 index 000000000..1b13e9533 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c new file mode 100644 index 000000000..7e3d3b3ce --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * Drake Dowsett + * Contact: Andreas Arnez + */ + +/* 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 +#include +#include +#include +#define __USE_GNU +#include +#include +#include +#include + +#include +#include + +#include /* FIXME Is this ok here? */ +#include + +#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 /* 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libubi.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libubi.c new file mode 100644 index 000000000..a028fc6dd --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h new file mode 100644 index 000000000..e68b79121 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c new file mode 100644 index 000000000..1fce3f9c3 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include + +#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, ""); + return; + } + if (!u->ec) { + fprintf(stderr, ""); + err = 1; + } + if (!u->v) { + fprintf(stderr, ""); + 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c new file mode 100644 index 000000000..d06770ede --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include + +#include +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/list.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/list.c new file mode 100644 index 000000000..6eb716bc3 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/list.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/list.h new file mode 100644 index 000000000..e8452a2c4 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c new file mode 100644 index 000000000..952f651fa --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include + +#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= Write the output data to 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 ] [--copyright] [--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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c new file mode 100644 index 000000000..be62e3077 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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= Data output file\n" +" -O, --oob= OOB output file\n" +" -p, --pagesize= NAND pagesize\n" +" -b, --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 ] [-O ] [-p ]\n" +" [--output=] [--oob=] [--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 */ + args->pagesize = str_to_num(optarg); + break; + + case 'b': /* --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= */ + args->output_file = optarg; + break; + + case 'O': /* --oob= */ + 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c new file mode 100644 index 000000000..caa07e2f2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c new file mode 100644 index 000000000..71660eff5 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h new file mode 100644 index 000000000..bcf198296 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c new file mode 100644 index 000000000..859346c57 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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= Binary input file. For debug purposes.\n" +" -l, --list List card bootenv/pdd values.\n" +" -o, --output= Binary output file. For debug purposes.\n" +" -s, --side= 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 ] [-o ] [-s ]\n" +" [--both] [--copyright] [--input=] [--list]\n" +" [--output=] [--side=] [--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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/peb.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/peb.c new file mode 100644 index 000000000..08b770f43 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/peb.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/peb.h new file mode 100644 index 000000000..246bce832 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfi.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfi.c new file mode 100644 index 000000000..fa835e205 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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. + * + * Wed Feb 8 11:38:22 CET 2006: Initial creation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfi.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfi.h new file mode 100644 index 000000000..8c5cc07b9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * Andreas Arnez + * Joern Engel + * Frank Haverkamp + * + * @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 /* 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 . + */ +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 . + * + * 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c new file mode 100644 index 000000000..a8c76a3db --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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= */ + 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c new file mode 100644 index 000000000..754fe333c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include + +#include +#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= Write a logfile to .\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= Specify the pdd-update algorithm. is either\n" +" 'keep', 'merge' or 'overwrite'.\n" +" -r, --raw-flash= Flash the raw data. Use the specified mtd device.\n" +" -s, --side= 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 ] [-p ] [-r ] [-s ]\n" +" [--copyright] [--logfile=] [--verbose] [--complete]\n" +" [--pdd-update=] [--raw-flash=] [--side=]\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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h new file mode 100644 index 000000000..039705de0 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * + * @brief The pfiflash library offers an interface for using the + * pfiflash * utility. + */ + +#include /* 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h new file mode 100644 index 000000000..0f27f4ad5 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + * Contact: Andreas Arnez + */ + +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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/reader.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/reader.c new file mode 100644 index 000000000..0ea8c6d84 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/reader.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/reader.h new file mode 100644 index 000000000..715e4641c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c new file mode 100644 index 000000000..9fcafab84 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include + +#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= Set the alignment size to (default 1).\n" +" Values can be specified as bytes, 'ki' or 'Mi'.\n" +" -B, --blocksize= Set the eraseblock size to (default 128\n" +" KiB).\n" +" Values can be specified as bytes, 'ki' or 'Mi'.\n" +" -E, --erasecount= Set the erase count to (default 0)\n" +" -I, --id= The UBI volume id.\n" +" -O, --offset= Offset from start of an erase block to the UBI\n" +" volume header.\n" +" -T, --type= The UBI volume type:\n" +" 1 = dynamic, 2 = static\n" +" -X, --setver= Set UBI version number to (default 1)\n" +"\n" +" Input/Output:\n" +" -i, --infile= Read input from file.\n" +" -o, --outfile= Write output to file (default is stdout).\n" +"\n" +" Special options:\n" +" -U, --broken-update= Create an ubi image which simulates a broken\n" +" update.\n" +" 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 ] [-B ] [-E ] [-I ]\n" +" [-O ] [-T ] [-X ] [-i ] [-o ]\n" +" [-U ] [--copyright] [--debug] [--verbose] [--alignment=]\n" +" [--blocksize=] [--erasecount=] [--id=]\n" +" [--offset=] [--type=] [--setver=]\n" +" [--infile=] [--outfile=]\n" +" [--broken-update=] [--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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h new file mode 100644 index 000000000..0f43a4646 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 /* FILE */ +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c new file mode 100644 index 000000000..2cc4596de --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include + +#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= Use the side 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 ] [--copyright] [--side=]\n" +" [--help] [--usage] [--version] \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...] " + " \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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h new file mode 100644 index 000000000..d7ae2adf4 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +/** + * @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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/unubi.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/unubi.c new file mode 100644 index 000000000..ebd527c07 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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= Extract and rebuild volume\n" +"\n" +" OPTIONS\n" +" -b, --blocksize= Specify size of eraseblocks in image in bytes\n" +" (default 128KiB)\n" +" -d, --dir= Specify output directory\n" +" -D, --debug Enable debug output\n" +" -s, --headersize= 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 ] [-b ] [-d ]\n" +" [-s ] [--analyze] [--info-table]\n" +" [--rebuild=] [--blocksize=]\n" +" [--dir=] [--headersize=] [--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= */ + args->bsize = str_to_num(optarg); + break; + case 's': /* --header-size= */ + args->hsize = str_to_num(optarg); + break; + case 'd': /* --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= */ + 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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c new file mode 100644 index 000000000..ceaa85ff0 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h new file mode 100644 index 000000000..858821973 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/testcases.txt b/target/linux/xburst/files-2.6.27/drivers/mtd/mtd-utils/ubi-utils/testcases.txt new file mode 100644 index 000000000..dcc1c35a2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/mtd/nand/jz4740_nand.c b/target/linux/xburst/files-2.6.27/drivers/mtd/nand/jz4740_nand.c new file mode 100755 index 000000000..04db59d4c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/nand/jz4740_nand.c @@ -0,0 +1,1038 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 */ + +/* + * Define partitions for flash devices + */ +#ifdef CONFIG_JZ4740_PAVO +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: 0 }, + { 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 }, +}; + + +/* 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 +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 VFAT partition", + offset: 64 * 0x100000, + size: 64 * 0x100000 }, +}; +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 +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: 120 * 0x100000 }, + { name: "NAND DATA1 partition", + offset: 128 * 0x100000, + size: 128 * 0x100000 }, + { name: "NAND DATA2 partition", + offset: 256 * 0x100000, + size: 256 * 0x100000 }, + { name: "NAND VFAT partition", + offset: 512 * 0x100000, + size: 512 * 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 */ + 20, /* reserved blocks of mtd4 */ + 20}; /* reserved blocks of mtd5 */ +#endif /* CONFIG_JZ4740_LYRA */ + +#ifdef CONFIG_JZ4725_DIPPER +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 VFAT 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 */ +#endif /* CONFIG_JZ4740_DIPPER */ + +#ifdef CONFIG_JZ4720_VIRGO +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: 120 * 0x100000 }, + { name: "NAND DATA1 partition", + offset: 128 * 0x100000, + size: 128 * 0x100000 }, + { name: "NAND DATA2 partition", + offset: 256 * 0x100000, + size: 256 * 0x100000 }, + { name: "NAND VFAT partition", + offset: 512 * 0x100000, + size: 512 * 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 */ + 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 nr_partitions, 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/target/linux/xburst/files-2.6.27/drivers/mtd/nand/jz4750_nand.c b/target/linux/xburst/files-2.6.27/drivers/mtd/nand/jz4750_nand.c new file mode 100755 index 000000000..65de9184d --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/nand/jz4750_nand.c @@ -0,0 +1,1785 @@ +/* + * linux/drivers/mtd/nand/jz4750_nand.c + * + * JZ4750 NAND driver + * + * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc. + * 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +/* 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; + +extern int global_page; /* for two-plane operations */ + +/* + * MTD structure for JzSOC board + */ +static struct mtd_info *jz_mtd = NULL; +extern struct mtd_info *jz_mtd1; +extern char all_use_planes; + +/* + * Define partitions for flash devices + */ +#if defined(CONFIG_JZ4750_FUWA) || defined(CONFIG_JZ4750D_FUWA1) +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}, +}; + +/* 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 or CONFIG_JZ4750_APUS */ + +#if defined(CONFIG_JZ4750_APUS) || defined(CONFIG_JZ4750D_CETUS) + +/* Reserve 32MB for bootloader, splash1, splash2 and radiofw */ +#define MISC_OFFSET (32 * 0x100000) + +#define MISC_SIZE ( 1 * 0x100000) +#define RECOVERY_SIZE ( 5 * 0x100000) +#define BOOT_SIZE ( 4 * 0x100000) +#define SYSTEM_SIZE (128 * 0x100000) +#define USERDATA_SIZE (128 * 0x100000) +#define CACHE_SIZE (128 * 0x100000) +#define STORAGE_SIZE (MTDPART_SIZ_FULL) + +static struct mtd_partition partition_info[] = { + + /* Android partitions: + * + * misc@mtd0 : raw + * recovery@mtd1: raw + * boot@mtd2: raw + * system@mtd3: yaffs2 + * userdata@mtd4: yaffs2 + * cache@mtd5: yaffs2 + * storage@mtd6: vfat + */ + {name: "misc", + offset: MISC_OFFSET, + size: MISC_SIZE, + use_planes: 0}, + {name: "recovery", + offset: (MISC_OFFSET+MISC_SIZE), + size: RECOVERY_SIZE, + use_planes: 0}, + {name: "boot", + offset: (MISC_OFFSET+MISC_SIZE+RECOVERY_SIZE), + size: BOOT_SIZE, + use_planes: 0}, + {name: "system", + offset: (MISC_OFFSET+MISC_SIZE+RECOVERY_SIZE+BOOT_SIZE), + size: SYSTEM_SIZE, + use_planes: 0}, + {name: "userdata", + offset: (MISC_OFFSET+MISC_SIZE+RECOVERY_SIZE+BOOT_SIZE+SYSTEM_SIZE), + size: USERDATA_SIZE, + use_planes: 0}, + {name: "cache", + offset: (MISC_OFFSET+MISC_SIZE+RECOVERY_SIZE+BOOT_SIZE+SYSTEM_SIZE+USERDATA_SIZE), + size: CACHE_SIZE, + use_planes: 0}, + {name: "storage", + offset: (MISC_OFFSET+MISC_SIZE+RECOVERY_SIZE+BOOT_SIZE+SYSTEM_SIZE+USERDATA_SIZE+CACHE_SIZE), + size: STORAGE_SIZE, + use_planes: 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[] = { + 10, /* reserved blocks of mtd0 */ + 10, /* reserved blocks of mtd1 */ + 10, /* reserved blocks of mtd2 */ + 10, /* reserved blocks of mtd3 */ + 10, /* reserved blocks of mtd4 */ + 10, /* reserved blocks of mtd5 */ + 12 /* reserved blocks of mtd6 */ +}; +#endif /* CONFIG_JZ4750_FUWA or 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) +{ + 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 0x0d221200 + + __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; +#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; +#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; +#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 defined(CONFIG_MTD_NAND_DMA) + __ecc_dma_enable(); +#endif + } + + if (mode == NAND_ECC_WRITE) { + __ECC_ENCODING(); + __ecc_cnt_enc(eccsize + oob_per_eccsize); +#if defined(CONFIG_MTD_NAND_DMA) + __ecc_dma_enable(); +#endif + } +} + +/** + * 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; +} + +#else /* cpu mode */ + +/** + * jzsoc_nand_bch_correct_data + * @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(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; +} +#endif /* CONFIG_MTD_NAND_DMA */ + +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"); + err = wait_event_interruptible_timeout(nand_prog_wait_queue, dma_ack1, 3 * HZ); + 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) + 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); +} + +#else /* nand write in cpu mode */ + +static void nand_write_page_hwecc_bch(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 */ +static void nand_write_page_hwecc_bch_planes(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) + 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(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(mtd, chip, buf + pagesize); +} +#endif /* CONFIG_MTD_NAND_DMA */ + +/** + * 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; +} + +#else /* nand read in cpu mode */ + +static int nand_read_page_hwecc_bch(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(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(mtd, chip, buf); + + /* Read 2nd page */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page + ppb); + nand_read_page_hwecc_bch(mtd, chip, buf+pagesize); + return 0; +} +#endif /* CONFIG_MTD_NAND_DMA */ + +#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) + 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) + 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 + 15) / 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 */ +/* + * Main initialization routine + */ +int __init jznand_init(void) +{ + struct nand_chip *this; + int nr_partitions, ret, i; + + printk(KERN_INFO "JZ NAND init"); +#if defined(CONFIG_MTD_NAND_DMA) +#if defined(CONFIG_MTD_NAND_DMABUF) + printk(KERN_INFO " DMA mode, using DMA buffer in NAND driver.\n"); +#else + printk(KERN_INFO " DMA mode, using DMA buffer in upper layer.\n"); +#endif +#else + printk(KERN_INFO " CPU mode.\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.\n"); + return -ENOMEM; + } + + /* Allocate memory for NAND when using only one plane */ + 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; + + 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.correct = jzsoc_nand_bch_correct_data; + this->ecc.hwctl = jzsoc_nand_enable_bch_hwecc; + this->ecc.mode = NAND_ECC_HW; + this->ecc.size = 512; + this->ecc.read_page = nand_read_page_hwecc_bch; + this->ecc.write_page = nand_write_page_hwecc_bch; +#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_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_bch_planes; + this->ecc.write_page = nand_write_page_hwecc_bch_planes; + 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); + } + } + + /* 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; + } + +#if defined(CONFIG_MTD_NAND_DMA) + jz4750_nand_dma_init(jz_mtd); +#endif + + ((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; + + /* 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 + +#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/target/linux/xburst/files-2.6.27/drivers/mtd/udc_cache.c b/target/linux/xburst/files-2.6.27/drivers/mtd/udc_cache.c new file mode 100644 index 000000000..6cb5eb416 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/mtd/udc_cache.c @@ -0,0 +1,531 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 int 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 int 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/target/linux/xburst/files-2.6.27/drivers/net/jz4760_eth.c b/target/linux/xburst/files-2.6.27/drivers/net/jz4760_eth.c new file mode 100644 index 000000000..42980e2cc --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/net/jz4760_eth.c @@ -0,0 +1,1755 @@ +/* + * linux/drivers/net/jz4760_eth.c + * + * Jz4760 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "jz4760_eth.h" + +#define P2ADDR(a) (((unsigned long)(a) & 0x1fffffff) | 0xa0000000) +#define P1ADDR(a) (((unsigned long)(a) & 0x1fffffff) | 0x80000000) + +//#define USE_RMII 1 + +//#define ETH_DEBUG +#ifdef ETH_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 "jz4760_eth" +#define DRV_VERSION "0.1" +#define DRV_AUTHOR "Jason Wang " +#define DRV_DESC "JzSOC 4760 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); + +#if 0 +/* + * 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); +#endif + +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; + } + printk("get_mac_address return ...\n"); + return 0; +} + +/*---------------------------------------------------------------------*/ + +static u32 jz_eth_curr_mode(struct net_device *dev); + +/* + * Link check routines + */ +static void start_check(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + struct task_struct *t; + + np->thread_die = 0; + init_waitqueue_head(&np->thr_wait); + init_completion(&np->thr_exited); + + t = kthread_create(link_check_thread,(void *)dev, dev->name); + if (IS_ERR(t)) + errprintk("%s: unable to start kernel thread\n",dev->name); + np->thread = t; +} + +static int close_check(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + int ret = 0; + + if (np->thread != NULL) { + np->thread_die = 1; + wmb(); + send_sig(SIGTERM, np->thread, 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; + unsigned char current_link; + unsigned long timeout; + + daemonize("%s", dev->name); + spin_lock_irq(¤t->sighand->siglock); + sigemptyset(¤t->blocked); + recalc_sigpending(); + spin_unlock_irq(¤t->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(¤t->sighand->siglock); + flush_signals(current); + spin_unlock_irq(¤t->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); +} + +static void skb_dump(struct sk_buff *skb) +{ + printk("skb ----------- [ 0x%08x ]\n", (unsigned int)skb); + printk("head = 0x%08x, data = 0x%08x, tail = 0x%08x, end = 0x%08x\n", + (unsigned int)(skb->head), (unsigned int)(skb->data), + (unsigned int)(skb->tail), (unsigned int)(skb->end)); + printk("truesize = %d (0x%08x), len = %d (0x%08x)\n", + skb->truesize, skb->truesize, skb->len, skb->len); + printk("headroom = %d (0x%08x), tailroom = %d (0x%08x)\n", + skb_headroom(skb), skb_headroom(skb), skb_tailroom(skb), skb_tailroom(skb)); + printk("---------------------------\n"); +} + +#ifdef ETH_DEBUG + +static void desc_dump(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + int i; + + printk("==================================================\n"); +/* + for (i = 0; i < NUM_TX_DESCS; i++) { + printk("tx desc %2d :[0x%08x], addr = 0x%08x, pkt_size = 0x%08x, next = 0x%08x\n", + i, &(np->tx_ring[i]), np->tx_ring[i].pkt_addr, np->tx_ring[i].pkt_size, np->tx_ring[i].next_desc); + } +*/ + for (i = 0; i < 4/*NUM_RX_DESCS*/; i++) { + printk("rx desc %2d :[0x%08x], addr = 0x%08x, pkt_size = 0x%08x, next = 0x%08x\n", + i, &(np->rx_ring[i]), np->rx_ring[i].pkt_addr, np->rx_ring[i].pkt_size, np->rx_ring[i].next_desc); + } + printk("==================================================\n"); +} + +static void dma_regs_dump(char *str) +{ + printk("%s", str); + printk("==================================================\n"); + printk("DMA_TCR = 0x%08x DMA_TDR = 0x%08x\n", REG32(ETH_DMA_TCR), REG32(ETH_DMA_TDR)); + printk("DMA_TSR = 0x%08x DMA_RCR = 0x%08x\n", REG32(ETH_DMA_TSR), REG32(ETH_DMA_RCR)); + printk("DMA_RDR = 0x%08x DMA_RSR = 0x%08x\n", REG32(ETH_DMA_RDR), REG32(ETH_DMA_RSR)); + printk("DMA_IMR = 0x%08x DMA_IR = 0x%08x\n", REG32(ETH_DMA_IMR), REG32(ETH_DMA_IR)); + printk("==================================================\n"); +} + +static void mac_regs_dump(void) +{ + printk("==================================================\n"); + printk("MAC_MCR1 = 0x%08x MAC_MCR2 = 0x%08x\n", REG32(ETH_MAC_MCR1), REG32(ETH_MAC_MCR2)); + printk("MAC_IPGR = 0x%08x MAC_NIPGR= 0x%08x\n", REG32(ETH_MAC_IPGR), REG32(ETH_MAC_NIPGR)); + printk("MAC_CWR = 0x%08x MAC_MFR = 0x%08x\n", REG32(ETH_MAC_CWR), REG32(ETH_MAC_MFR)); + printk("MAC_PSR = 0x%08x MAC_TR = 0x%08x\n", REG32(ETH_MAC_PSR), REG32(ETH_MAC_TR)); + printk("MAC_MCFGR= 0x%08x MAC_MCMDR= 0x%08x\n", REG32(ETH_MAC_MCFGR), REG32(ETH_MAC_MCMDR)); + printk("MAC_MADRR= 0x%08x MAC_MINDR= 0x%08x\n", REG32(ETH_MAC_MADRR), REG32(ETH_MAC_MINDR)); + printk("MAC_SA0 = 0x%08x MAC_SA1 = 0x%08x MAC_SA2 = 0x%08x\n", + REG32(ETH_MAC_SA0), REG32(ETH_MAC_SA1), REG32(ETH_MAC_SA2)); + printk("==================================================\n"); +} + +static void fifo_regs_dump(void) +{ + printk("==================================================\n"); + printk("FIFO_CR0 = 0x%08x\n", REG32(ETH_FIFO_CR0)); + printk("FIFO_CR1 = 0x%08x\n", REG32(ETH_FIFO_CR1)); + printk("FIFO_CR2 = 0x%08x\n", REG32(ETH_FIFO_CR2)); + printk("FIFO_CR3 = 0x%08x\n", REG32(ETH_FIFO_CR3)); + printk("FIFO_CR4 = 0x%08x\n", REG32(ETH_FIFO_CR4)); + printk("FIFO_CR5 = 0x%08x\n", REG32(ETH_FIFO_CR5)); +#if 0 + printk("RAR0 = 0x%08x RAR1 = 0x%08x\n", REG32(ETH_FIFO_RAR0), REG32(ETH_FIFO_RAR1)); + printk("RAR2 = 0x%08x RAR3 = 0x%08x\n", REG32(ETH_FIFO_RAR2), REG32(ETH_FIFO_RAR3)); + printk("RAR4 = 0x%08x RAR5 = 0x%08x\n", REG32(ETH_FIFO_RAR4), REG32(ETH_FIFO_RAR5)); + printk("RAR6 = 0x%08x RAR7 = 0x%08x\n", REG32(ETH_FIFO_RAR6), REG32(ETH_FIFO_RAR7)); +#endif + printk("==================================================\n"); +} + +static void stat_regs_dump(void) +{ + + printk("==================================================\n"); + printk("ETH_STAT_TR64= 0x%08x, ETH_STAT_TR127= 0x%08x, ETH_STAT_TR255= 0x%08x, ETH_STAT_TR511= 0x%08x\n", + REG32(ETH_STAT_TR64), REG32(ETH_STAT_TR127), REG32(ETH_STAT_TR255), REG32(ETH_STAT_TR511)); + printk("ETH_STAT_TR1K= 0x%08x, ETH_STAT_TRMAX= 0x%08x, ETH_STAT_TRMGV= 0x%08x\n", + REG32(ETH_STAT_TR1K), REG32(ETH_STAT_TRMAX), REG32(ETH_STAT_TRMGV)); + + printk("------\nETH_STAT_RBYT= 0x%08x, ETH_STAT_RPKT= 0x%08x, ETH_STAT_RFCS= 0x%08x, ETH_STAT_RMCA= 0x%08x\n", + REG32(ETH_STAT_RBYT), REG32(ETH_STAT_RPKT), REG32(ETH_STAT_RFCS), REG32(ETH_STAT_RMCA)); + printk("ETH_STAT_RDRP= 0x%08x\n", REG32(ETH_STAT_RDRP)); + + printk("------\nETH_STAT_TBYT= 0x%08x, ETH_STAT_TPKT= 0x%08x, ETH_STAT_TFCS = 0x%08x, ETH_STAT_TNCL= 0x%08x\n", + REG32(ETH_STAT_TBYT), REG32(ETH_STAT_TPKT), REG32(ETH_STAT_TFCS), REG32(ETH_STAT_TNCL)); + printk("ETH_STAT_TDRP= 0x%08x\n", REG32(ETH_STAT_TDRP)); + printk("==================================================\n"); + +/* + printk("==================================================\n"); + + printk("ETH_STAT_TR64= 0x%08x, ETH_STAT_TR127= 0x%08x, ETH_STAT_TR255= 0x%08x, ETH_STAT_TR511= 0x%08x\n", + REG32(ETH_STAT_TR64), REG32(ETH_STAT_TR127), REG32(ETH_STAT_TR255), REG32(ETH_STAT_TR511)); + printk("ETH_STAT_TR1K= 0x%08x, ETH_STAT_TRMAX= 0x%08x, ETH_STAT_TRMGV= 0x%08x\n", + REG32(ETH_STAT_TR1K), REG32(ETH_STAT_TRMAX), REG32(ETH_STAT_TRMGV)); + printk("ETH_STAT_RBYT= 0x%08x, ETH_STAT_RPKT= 0x%08x, ETH_STAT_RFCS= 0x%08x, ETH_STAT_RMCA= 0x%08x\n", + REG32(ETH_STAT_RBYT), REG32(ETH_STAT_RPKT), REG32(ETH_STAT_RFCS), REG32(ETH_STAT_RMCA)); + printk("ETH_STAT_RBCA= 0x%08x, ETH_STAT_RXCF= 0x%08x, ETH_STAT_RXPF= 0x%08x, ETH_STAT_RXUO= 0x%08x\n", + REG32(ETH_STAT_RBCA), REG32(ETH_STAT_RXCF), REG32(ETH_STAT_RXPF), REG32(ETH_STAT_RXUO)); + printk("ETH_STAT_RALN= 0x%08x, ETH_STAT_RFLR= 0x%08x, ETH_STAT_RCDE= 0x%08x, ETH_STAT_RCSE= 0x%08x\n", + REG32(ETH_STAT_RALN), REG32(ETH_STAT_RFLR), REG32(ETH_STAT_RCDE), REG32(ETH_STAT_RCSE)); + printk("ETH_STAT_RUND= 0x%08x, ETH_STAT_ROVR= 0x%08x, ETH_STAT_RFRG= 0x%08x, ETH_STAT_RJBR= 0x%08x\n", + REG32(ETH_STAT_RUND), REG32(ETH_STAT_ROVR), REG32(ETH_STAT_RFRG), REG32(ETH_STAT_RJBR)); + printk("ETH_STAT_RDRP= 0x%08x\n", REG32(ETH_STAT_RDRP)); + printk("ETH_STAT_TBYT= 0x%08x, ETH_STAT_TPKT= 0x%08x, ETH_STAT_TMCA= 0x%08x, ETH_STAT_TBCA= 0x%08x\n", + REG32(ETH_STAT_TBYT), REG32(ETH_STAT_TPKT), REG32(ETH_STAT_TMCA), REG32(ETH_STAT_TBCA)); + printk("ETH_STAT_TXPF= 0x%08x, ETH_STAT_TDFR= 0x%08x, ETH_STAT_TEDF= 0x%08x, ETH_STAT_TSCL= 0x%08x\n", + REG32(ETH_STAT_TXPF), REG32(ETH_STAT_TDFR), REG32(ETH_STAT_TEDF), REG32(ETH_STAT_TSCL)); + printk("ETH_STAT_TMCL= 0x%08x, ETH_STAT_TLCL= 0x%08x, ETH_STAT_TXCL= 0x%08x, ETH_STAT_TNCL= 0x%08x\n", + REG32(ETH_STAT_TMCL), REG32(ETH_STAT_TLCL), REG32(ETH_STAT_TXCL), REG32(ETH_STAT_TNCL)); + printk("ETH_STAT_TPFH= 0x%08x, ETH_STAT_TDRP= 0x%08x, ETH_STAT_TJBR= 0x%08x, ETH_STAT_TFCS= 0x%08x\n", + REG32(ETH_STAT_TPFH), REG32(ETH_STAT_TDRP), REG32(ETH_STAT_TJBR), REG32(ETH_STAT_TFCS)); + printk("ETH_STAT_TXCF= 0x%08x, ETH_STAT_TOVR= 0x%08x, ETH_STAT_TUND= 0x%08x, ETH_STAT_TFRG= 0x%08x\n", + REG32(ETH_STAT_TXCF), REG32(ETH_STAT_TOVR), REG32(ETH_STAT_TUND), REG32(ETH_STAT_TFRG)); + printk("ETH_STAT_CAR1= 0x%08x, ETH_STAT_CAR2= 0x%08x, ETH_STAT_CARM1= 0x%08x, ETH_STAT_CARM2= 0x%08x\n", + REG32(ETH_STAT_CAR1), REG32(ETH_STAT_CAR2), REG32(ETH_STAT_CARM1), REG32(ETH_STAT_CARM2)); + printk("==================================================\n"); +*/ +} + +static void counters_dump(struct jz_eth_private *np) +{ + int i = 0; + + printk("\n"); + + do { + printk("cnts[%d] = %d\n", i, np->carry_counters[i]); + } while (++i < STAT_CNT_NUM); +} + +static void sal_regs_dump(void) +{ + printk("==================================================\n"); + printk("ETH_SAL_AFR = 0x%08x, ETH_SAL_HT1 = 0x%08x, ETH_SAL_HT2 = 0x%08x\n", + REG32(ETH_SAL_AFR), REG32(ETH_SAL_HT1), REG32(ETH_SAL_HT2)); + printk("==================================================\n"); +} + +/* + * 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 && idata[i+j]); + } + printk("\n"); + } + return; +} + +static void eth_dbg_tx(struct sk_buff *skb, int len) +{ + + int i, j; + + printk("T: %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 && idata[i+j]); + } + printk("\n"); + } + return; +} + +#if 0 +/* + * Show all mii registers - this routine is used for test + */ +static void mii_db_out(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + 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 + +#endif // ETH_DEBUG + +/* + * MII operation routines + */ +static inline void mii_wait(void) +{ + int i; + for (i = 0; i < MAX_WAIT; i++, mdelay(1)) { + if (!__mac_mii_is_busy()) + return ; + } + +// printk("\nMAC_MCMDR= 0x%04x MAC_MADRR= 0x%04x MAC_MINDR = 0x%04x\n", +// REG16(ETH_MAC_MCMDR), REG16(ETH_MAC_MADRR), REG16(ETH_MAC_MINDR)); + + if (i == MAX_WAIT) + printk("MII wait timeout\n"); +} + +static int mdio_read(struct net_device *dev,int phy_id, int location) +{ + int retval = 0; + + __mac_send_mii_read_cmd(phy_id, location, MII_NO_SCAN); + mii_wait(); + retval = __mac_mii_read_data(); + + return retval; + +} + +static void mdio_write(struct net_device *dev,int phy_id, int location, int data) +{ + __mac_send_mii_write_cmd(phy_id, location, data); + mii_wait(); +} + + +/* + * Search MII phy + */ +static int jz_search_mii_phy(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + 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; +} + +#if 1 // multicast + +/* + * 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 hash_h, hash_l, hash_bit; + + if (dev->flags & IFF_PROMISC) { + /* Accept any kinds of packets */ + __sal_set_mode(AFR_PRO); + __sal_set_hash_table(0xffffffff, 0xffffffff); + + printk("%s: enter promisc mode!\n",dev->name); + } else if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > MULTICAST_FILTER_LIMIT)) { + /* Accept all multicast packets */ + __sal_set_mode(AFR_PRM); + __sal_set_hash_table(0xffffffff, 0xffffffff); + printk("%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; + __sal_get_hash_table(hash_h, hash_l); + + 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 ETH_DEBUG + int j; + for (j=0;jdmi_addrlen;j++) + printk("%2.2x:",mclist->dmi_addr[j]); + printk("\n"); +#endif + //printk("dmi.addrlen => %d\n",mclist->dmi_addrlen); + //printk("dmi.users => %d\n",mclist->dmi_users); + //printk("dmi.gusers => %d\n",mclist->dmi_users); + } + __sal_set_hash_table(hash_h, hash_l); + + __sal_set_mode(AFR_AMC); + + //printk("This is multicast hash table high bits [%4.4x]\n",readl(ETH_SAL_HT1)); + //printk("This is multicast hash table low bits [%4.4x]\n",readl(ETH_SAL_HT2)); + //printk("%s: enter multicast mode!\n",dev->name); + } +} +#endif // multicast + +static inline int jz_phy_reset(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + 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 < 2000; count++) { + mdelay(1); + mii_reg0 = mdio_read(dev,np->valid_phy, MII_BMCR); + if (!(mii_reg0 & MII_CR_RST)) + break; //reset completed + } + + if (count == 2000) + return 1; //phy error + else + return 0; +} + +/* + * Start Auto-Negotiation function for PHY + */ +/* +static int jz_autonet_complete(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + 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 *)dev->priv; + 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); + np->full_duplex=1; + } + if (np->media==1) { + infoprintk("%s: Current Operation Mode is [10M Half Duplex]",dev->name); + np->full_duplex=0; + } + printk("\n"); + return flag; +} + +static void config_mac(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + u32 mac_cfg_1 = 0, mac_cfg_2 = 0; + + // Enable tx & rx flow control, enable receive + mac_cfg_1 = MCR1_TFC | MCR1_RFC | MCR1_RE; + +#ifdef USE_RMII + // Enable RMII + mac_cfg_1 |= 1 << 13; +#endif + + // Enable loopack mode + //mac_cfg_1 |= MCR1_LB; + + /* bit 7 bit 6 bit 5 + MCR2_ADPE MCR2_VPE MCR2_PCE + x x 0 No pad, check CRC + > 0 0 1 Pad to 60B, append CRC + x 1 1 Pad to 64B, append CRC + 1 0 1 if un-tagged, Pad to 60B, append CRC + if VLAN tagged, Pad to 64B, append CRC + + if set MCR2_PCE(bit 5) + MCR2_CE(bit 4) must be set. + + We need to pad frame to 60B and append 4-byte CRC. + */ + + mac_cfg_2 = MCR2_PCE | MCR2_CE; + + // Pure preamble enforcement + //mac_cfg_2 |= MCR2_PPE; + + // Frame length checking + mac_cfg_2 |= MCR2_FLC; + + if (np->full_duplex) { + mac_cfg_2 |= MCR2_FD; + __mac_set_IPGR(0x15); + + } else { + + __mac_set_IPGR(0x12); + } + + REG16(ETH_MAC_MCR1) = mac_cfg_1; + REG16(ETH_MAC_MCR2) = mac_cfg_2; + + __mac_set_NIPGR1(0x0c); + __mac_set_NIPGR2(0x12); + + //mac_regs_dump(); +} + +static void config_fifo(void) +{ + int i; + + __fifo_reset_all(); + + REG32(ETH_FIFO_CR0) |= 0x80000000; + + /* 4k rx FiFo */ + + __fifo_set_fr_threshold(0x180); + __fifo_set_high_wm(0x200); + __fifo_set_low_wm(0x40); + + /* 4k tx FiFo */ +/* + __fifo_set_ft_threshold(0x0200); + __fifo_set_ft_high_wm(0x0300); +*/ + /* for 2k FiFo both tx */ + __fifo_set_ft_threshold(0x0180); + __fifo_set_ft_high_wm(0x01b0); + + __fifo_set_XOFF_RTX(4); + __fifo_set_pause_control(); + + REG32(ETH_FIFO_CR4) &= 0x0000; + REG32(ETH_FIFO_CR5) |= 0xffff; + + __fifo_set_drop_cond(RSV_CRCE); + __fifo_set_dropdc_cond(RSV_CRCE); +/* + __fifo_set_drop_cond(RSV_MP); + __fifo_set_dropdc_cond(RSV_MP); + + __fifo_set_drop_cond(RSV_LCE); + __fifo_set_dropdc_cond(RSV_LCE); +*/ + __fifo_enable_all_modules(); + + for (i = 0; + i < MAX_WAIT && !__fifo_all_enabled(); + i++, udelay(100)) { + ; + } + + if (i == MAX_WAIT) { + printk("config_fifo: Wait time out !\n"); + return; + } + //fifo_regs_dump(); +} + +static void config_sal(void) +{ + /* SAL config */ + __sal_set_mode(AFR_AMC | AFR_ABC); + __sal_set_hash_table(0, 0); +} + +/* +static void config_stat(void) +{ + __stat_disable(); + __stat_clear_counters(); + // clear carry registers + REG32(ETH_STAT_CAR1) = REG32(ETH_STAT_CAR1); + REG32(ETH_STAT_CAR2) = REG32(ETH_STAT_CAR2); + __stat_disable_carry_irq(); + __stat_enable_carry_irq(); + //printk("CARM1 = 0x%08x, CARM2 = 0x%08x\n", REG32(ETH_STAT_CARM1), REG32(ETH_STAT_CARM2)); + + __stat_enable(); + printk("Enable eth stat module.\n"); + +} +*/ + +static int autonet_complete(struct net_device *dev) +{ + int i; + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + + for (i = 0; + i < MAX_WAIT && !(mdio_read(dev, np->valid_phy, MII_BMSR) & 0x0020); + i++, udelay(10)) { + ; + } + + if (i == MAX_WAIT) { + printk("autonet_comlete: autonet time out!\n"); + return -1; + } + + return 0; +} + +static void config_phy(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + + u32 mii_anlpar, phy_mode; + + mii_anlpar = mdio_read(dev, np->valid_phy, MII_ANLPAR); + + if (mii_anlpar != 0xffff) { + mii_anlpar = mdio_read(dev, np->valid_phy, MII_ANLPAR); // read twice to make data stable + if ((mii_anlpar & 0x0100) || (mii_anlpar & 0x01C0) == 0x0040) { + printk("config_phy: full_duplex !!!\n"); + np->full_duplex = 1; + } + phy_mode = mii_anlpar >> 5; + +#ifdef USE_RMII + + if (phy_mode & MII_ANLPAR_100M) + REG32(ETH_MAC_PSR) |= PSR_OS; +#endif + + printk("ETH: setting %s %s-duplex based on MII tranceiver #%d\n", + (phy_mode & MII_ANLPAR_100M) ? "100Mbps" : "10Mbps", + np->full_duplex ? "full" : "half", np->mii_phy_cnt); + + } else { + printk("config_phy: mii_anlpar is 0xffff, may be error ???\n"); + } + +} + +/* + * 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 *)dev->priv; + struct ethtool_cmd ecmd; + int i; + + __gpio_as_eth(); + + __eth_disable_irq(); + __mac_set_mii_clk(0x7); + __mac_reset(); + +#if 0 + /* mii operation */ + if (jz_phy_reset(dev)) { + errprintk("PHY device do not reset!\n"); + return -EPERM; // return operation not permitted + } +#endif + + __eth_set_mac_address(dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + + 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); +// New code, could make it work on 100M mode ... + if (autonet_complete(dev)) + printk("ETH Auto-Negotiation failed\n"); + + config_phy(dev); +// old configuration + 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<dma_rx_ring); + __eth_set_tx_desc_addr(np->dma_tx_ring); + + /* Burst length: 4, 8 or 16 */ + //__eth_dma_set_burst_len(BURST_LEN_4); + + //dma_regs_dump("set burst length\n"); + + /* Clear status registers */ + __eth_clear_rx_flags(); + __eth_clear_rx_pkt_cnt(); + __eth_clear_tx_flags(); + __eth_clear_tx_pkt_cnt(); + + __eth_enable_irq(); + __eth_dma_rx_enable(); + + printk("eth hw init completed.\n"); + return 0; +} + +static void jz_eth_read_stats(struct jz_eth_private *np, int carry1, int carry2) +{ + return ; + + if (carry1 != 0) { + if (carry1 & CAR1_RPK) np->carry_counters[CNT_RPKT]++; + if (carry1 & CAR1_RBY) np->carry_counters[CNT_RBYT]++; + if (carry1 & CAR1_RFC) np->carry_counters[CNT_RFCS]++; + if (carry1 & CAR1_RDR) np->carry_counters[CNT_RDRP]++; + if (carry1 & CAR1_RMC) np->carry_counters[CNT_RMCA]++; + printk("carry1 = 0x%08x\n", carry1); + } + + if (carry2 != 0) { + if (carry2 & CAR2_TPK) np->carry_counters[CNT_TPKT]++; + if (carry2 & CAR2_TBY) np->carry_counters[CNT_TBYT]++; + if (carry2 & CAR2_TFC) np->carry_counters[CNT_TFCS]++; + if (carry2 & CAR2_TDP) np->carry_counters[CNT_TDRP]++; + if (carry2 & CAR2_TNC) np->carry_counters[CNT_TNCL]++; + printk("carry2 = 0x%08x\n", carry2); + } + + np->stats.rx_packets = REG32(ETH_STAT_RPKT) + (np->carry_counters[CNT_RPKT] << 18); + np->stats.tx_packets = REG32(ETH_STAT_TPKT) + (np->carry_counters[CNT_TPKT] << 18); + np->stats.rx_bytes = REG32(ETH_STAT_RBYT) + (np->carry_counters[CNT_RBYT] << 24); + np->stats.tx_bytes = REG32(ETH_STAT_TBYT) + (np->carry_counters[CNT_TBYT] << 24); + np->stats.rx_errors = REG32(ETH_STAT_RFCS) + (np->carry_counters[CNT_RFCS] << 12); + np->stats.tx_errors = REG32(ETH_STAT_TFCS) + (np->carry_counters[CNT_TFCS] << 12); + np->stats.rx_dropped = REG32(ETH_STAT_RDRP) + (np->carry_counters[CNT_RDRP] << 12); + np->stats.tx_dropped = REG32(ETH_STAT_TDRP) + (np->carry_counters[CNT_TDRP] << 12); + np->stats.multicast = REG32(ETH_STAT_RMCA) + (np->carry_counters[CNT_RMCA] << 18); + np->stats.collisions = REG32(ETH_STAT_TNCL) + (np->carry_counters[CNT_TNCL] << 13); + + //counters_dump(np); + +} + +static int jz_eth_open(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + int retval, i; + + errprintk("jz_eth_open\n"); + + 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++) { + //printk("Rx_ring[%d] address: 0x%08x\n", i, &(np->rx_ring[i])); + np->rx_ring[i].pkt_addr = cpu_to_le32(np->dma_rx_buf + i*RX_BUF_SIZE); + np->rx_ring[i].pkt_size = cpu_to_le32(EMPTY_FLAG_MASK); + np->rx_ring[i].next_desc= cpu_to_le32(np->dma_rx_ring + (i+1) * sizeof (jz_desc_t)); + } + np->rx_ring[NUM_RX_DESCS - 1].next_desc = cpu_to_le32(np->dma_rx_ring); + + for (i = 0; i < NUM_TX_DESCS; i++) { + //printk("Tx_ring[%d] address: 0x%08x\n", i, &(np->tx_ring[i])); + np->tx_ring[i].pkt_addr = cpu_to_le32(0); + np->tx_ring[i].pkt_size = cpu_to_le32(EMPTY_FLAG_MASK); + np->tx_ring[i].next_desc= cpu_to_le32(np->dma_tx_ring + (i+1) * sizeof (jz_desc_t)); + } + np->tx_ring[NUM_TX_DESCS - 1].next_desc = cpu_to_le32(np->dma_tx_ring); + + np->rx_head = 0; + np->tx_head = np->tx_tail = 0; + + //desc_dump(dev); + + for (i = 0; i < STAT_CNT_NUM; i++) + np->carry_counters[i] = 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); + + __eth_disable(); + + 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 *)dev->priv; +// unsigned int flags; + +// spin_lock_irqsave(&np->lock, flags); + + jz_eth_read_stats(np, 0, 0); + +// spin_unlock_irqrestore(&np->lock, flags); + + return &np->stats; +} + +/* + * ethtool routines + */ +static int jz_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct jz_eth_private *np = dev->priv; + 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 *)dev->priv; + 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*)dev->priv; + jz_desc_t *rx_head_desc = &(np->rx_ring[np->rx_head]); + struct sk_buff *skb; + unsigned char *pkt_ptr; + u32 pkt_len; + + int i = 0; + +/* + printk("<<< eth_rxready\n"); + printk("rx_head_desc: 0x08%x, rx_head = %d\n", rx_head_desc, np->rx_head); + printk("rx_ring[.] = 0x%x, virt_to_bus(rx_ring[.]) = 0x%x, virt_to_phys(rx_ring[.]) = 0x%x\n", + np->rx_ring[np->rx_head], virt_to_bus(&np->rx_ring[np->rx_head]), virt_to_phys(&np->rx_ring[np->rx_head])); + + desc_dump(dev); + + dma_regs_dump("before eth_rxready\n"); +*/ + /* empty_flag == 0 */ + while (!__desc_get_empty_flag(le32_to_cpu(rx_head_desc->pkt_size))) { + i++; +/* + printk("<---- %x %x %x %x %x %x\n", + *((unsigned char *)bus_to_virt(rx_head_desc->pkt_addr) + 0), + *((unsigned char *)bus_to_virt(rx_head_desc->pkt_addr) + 1), + *((unsigned char *)bus_to_virt(rx_head_desc->pkt_addr) + 2), + *((unsigned char *)bus_to_virt(rx_head_desc->pkt_addr) + 3), + *((unsigned char *)bus_to_virt(rx_head_desc->pkt_addr) + 4), + *((unsigned char *)bus_to_virt(rx_head_desc->pkt_addr) + 5)); +*/ + pkt_ptr = bus_to_virt(le32_to_cpu(rx_head_desc->pkt_addr)); + pkt_len = (__desc_get_pkt_size(le32_to_cpu(rx_head_desc->pkt_size))) - 4; + + skb = dev_alloc_skb(pkt_len + 2); + if (skb == NULL) { + printk("%s: Memory squeeze, dropping. dev_alloc_skb(0x%08x)\n", + dev->name, pkt_len + 2); + np->stats.rx_dropped++; + __eth_reduce_pkt_recv_cnt(); + //break; + return ; + } + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align */ + + memcpy(skb->data, pkt_ptr, pkt_len); + skb_put(skb, pkt_len); +/* + printk("R : "); + for (i = 0; i < 16; i++) + printk("%02x ", *((unsigned char*)skb->data + i)); + + printk("\n"); +*/ + skb->protocol = eth_type_trans(skb,dev); + netif_rx(skb); /* pass the packet to upper layers */ + dev->last_rx = jiffies; + + __eth_reduce_pkt_recv_cnt(); + + //dma_regs_dump("after reduce recv cnt\n"); + + np->rx_ring[np->rx_head].pkt_size = EMPTY_FLAG_MASK; + np->rx_head ++; + if (np->rx_head >= NUM_RX_DESCS) + np->rx_head = 0; + } + if (i == 0) { + printk("BUG: eth_rxready\n"); + BUG_ON(1); + } +} + +/* + * Tx timeout routine + */ +static void jz_eth_tx_timeout(struct net_device *dev) +{ + //struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + + jz_init_hw(dev); + netif_wake_queue(dev); +} + +/* + * One packet was transmitted + */ +static void eth_txdone(struct net_device *dev, int counter) +{ + struct jz_eth_private *np = (struct jz_eth_private*)dev->priv; + int tx_tail = np->tx_tail; + +/* + if (tx_tail > np->tx_head) { + printk("BUG 006, tx_tail = 0x%08x, tx_head = 0x%08x\n", tx_tail, np->tx_head); + BUG_ON(); + } +*/ + +// while (tx_tail != np->tx_head && count-- > 0) { + + if (counter <= 0) { + printk("BUG: eth_txdone, counter = %d\n", counter); + BUG_ON(1); + } + + while (counter-- > 0) { + int entry = tx_tail % NUM_TX_DESCS; +// s32 pkt_size = le32_to_cpu(np->tx_ring[entry].pkt_size); +// np->stats.tx_packets++; + + /* Free the original skb */ + if (np->tx_skb[entry]) { + dev_kfree_skb_irq(np->tx_skb[entry]); + np->tx_skb[entry] = 0; + } + tx_tail++; + __eth_reduce_pkt_sent_cnt(); + } + +/* + if (count > 0) { + printk("BUG 004, t = 0x%08x, count = 0x%08x\n", t, count); + printk("tx_tail = 0x%08x, tx_head = 0x%08x\n", np->tx_tail, np->tx_head); + BUG_ON(1); + } +*/ + +/* + if (tx_tail != np->tx_head) { + printk("BUG 005\n"); + BUG_ON(1); + } +*/ + 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 length, struct sk_buff *skb) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + int entry = np->tx_head % NUM_TX_DESCS; + int i; + + np->tx_ring[entry].pkt_addr = cpu_to_le32(virt_to_bus(buf)); + np->tx_ring[entry].pkt_size = cpu_to_le32(length & ~EMPTY_FLAG_MASK); + np->tx_skb[entry] = skb; + + //printk("desc.pktaddr = 0x%08x, buf = 0x%08x\n", np->tx_ring[entry].pkt_addr, buf); + + /* Notice us when will send a packet which begin with address: xxx1(binary) */ + if (unlikely(np->tx_ring[entry].pkt_addr & 0x1)) { + skb_dump(skb); + printk("desc.pktaddr = 0x%08x\n", np->tx_ring[entry].pkt_addr); + for (i = -2; i < 16; i++) { + printk("%02x ", *((unsigned char *)le32_to_cpu(bus_to_virt(np->tx_ring[entry].pkt_addr)) + i)); + } + printk("\n"); + for (i = -2; i < 16; i++) { + printk("%02x ", *((unsigned char *)le32_to_cpu(buf) + i)); + } + printk("\n"); + for (i = -2; i < 16; i++) { + printk("%02x ", *((unsigned char *)(bus_to_virt(np->tx_ring[entry].pkt_addr)) + i)); + } + printk("\n"); + } +} + +/* + * 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 *)dev->priv; + u32 length; + + if (np->tx_full) { + return 0; + } + + length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; + dma_cache_wback((unsigned long)skb->data, length); + + load_tx_packet(dev, (char *)skb->data, length, skb); + + spin_lock_irq(&np->lock); + np->tx_head ++; + + //dma_regs_dump("before tx enable\n"); + //fifo_regs_dump(); + //mac_regs_dump(); + + __eth_dma_tx_enable(); /* Start the TX */ + + //dma_regs_dump("after tx enable\n"); + //fifo_regs_dump(); + //mac_regs_dump(); + + 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 = dev->priv; + unsigned int tx_sts; + unsigned int rx_sts; + unsigned int counter; + unsigned int carry1 = 0; + unsigned int carry2 = 0; + + spin_lock(&np->lock); + + __eth_disable_irq(); + + /* Read tx & rx state reg, which indicate action */ + tx_sts = REG32(ETH_DMA_TSR); + rx_sts = REG32(ETH_DMA_RSR); + + __eth_clear_tx_flags(); /* Clear UNDERRUN and BUSERROR */ + __eth_clear_rx_flags(); /* Clear OVERFLOW and BUSERROR */ + + /* Tx UNDERRUN: one or more frames have already been sent. Current tx round has completed. */ + if (tx_sts & TSR_UNDERRUN) { + /* To clear counter and PKTSENT bit, __eth_reduce_pkt_sent_cnt() was called inside */ + counter = (tx_sts & TSR_PKTCNT_MASK) >> 16; + if (counter != 0) + eth_txdone(dev, counter); + } + + /* Rx PKTRECV: one frame has already been received. Receive frame until there is no PKTRECV */ + if (rx_sts & RSR_PKTRECV) { + /* To reduce counter and PKTRECV bit, __eth_reduce_pkt_recv_cnt() must called after each round */ + eth_rxready(dev); + } + + if ( !(tx_sts & TSR_FLAGS) && !(rx_sts & RSR_FLAGS) ) { + + //printk("before read carry regs\n"); + + carry1 = REG32(ETH_STAT_CAR1); + carry2 = REG32(ETH_STAT_CAR2); + REG32(ETH_STAT_CAR1) = carry1; + REG32(ETH_STAT_CAR2) = carry2; + + //printk("IRQ: carry1 = 0x%08x, carry2 = 0x%08x\n", carry1, carry2); + +/* + if (carry1 || carry2) { + jz_eth_read_stats(np, carry1, carry2); + } else { + printk("tx_sts = 0x%08x, rx_sts = 0x%08x\n", tx_sts, rx_sts); + printk("BUG: interrupt, no irq source\n"); + BUG_ON(1); + } +*/ + //dma_regs_dump("before leave carry irq handler.\n"); + goto _exit_irq; + } + + /* Fatal bus error */ + if (tx_sts & TSR_BUSERR || rx_sts & RSR_BUSERR) { + __eth_disable(); + printk("%s: Fatal bus error occurred, sts=[%#8x %#8x], device stopped.\n", dev->name, tx_sts, rx_sts); + goto _exit_irq; + } + /* Rx overflow */ + if (rx_sts & RSR_OVERFLOW) { + printk("RX_OVERFLOW\n"); + __eth_dma_rx_enable(); + } + +_exit_irq: + + __eth_enable_irq(); + + 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 *)dev->priv; + 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. */ + __eth_disable_irq(); + __eth_disable(); + __stat_disable_carry_irq(); + + spin_unlock_irqrestore(&jep->lock, flags); + + return 0; +} + +/* + * Resume the ETH interface. + */ +static int jz_eth_resume(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + + 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 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 = (struct jz_eth_private *)P2ADDR(dev->priv); + dev->priv = np; + 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); + + ether_setup(dev); // ?? the function has already been called in alloc_etherdev + dev->irq = IRQ_ETH; + dev->open = jz_eth_open; + dev->stop = jz_eth_close; + dev->hard_start_xmit = jz_eth_send_packet; + dev->get_stats = jz_eth_get_stats; + + dev->set_multicast_list = jz_set_multicast_list; + dev->do_ioctl = jz_eth_ioctl; + dev->tx_timeout = jz_eth_tx_timeout; + dev->watchdog_timeo = ETH_TX_TIMEOUT; + + // configure MAC address + get_mac_address(dev); + + if ((err = register_netdev(dev)) != 0) { + printk("%s: Cannot register net device, error %d\n", + DRV_NAME, err); + free_netdev(dev); + return -ENOMEM; + } + + printk("jz_eth_init finish!\n"); +//#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 = dev->priv; + + 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/target/linux/xburst/files-2.6.27/drivers/net/jz4760_eth.h b/target/linux/xburst/files-2.6.27/drivers/net/jz4760_eth.h new file mode 100644 index 000000000..03c2f3a33 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/net/jz4760_eth.h @@ -0,0 +1,1054 @@ +/* + * Jz4760 On-Chip ethernet driver. + * + * Copyright (C) 2005 - 2007 Ingenic Semiconductor Inc. Jason + * + * 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 __JZ4760_ETH_H__ +#define __JZ4760_ETH_H__ + + +// ---------------------------------------------------------------------------------- +// PE-MACMII registers (16-bit) +// ---------------------------------------------------------------------------------- + +#define ETH_MAC_MCR1 (ETHC_BASE + 0x00 )// MAC configuration register #1 +#define ETH_MAC_MCR2 (ETHC_BASE + 0x04 )// MAC configuration register #2 +#define ETH_MAC_IPGR (ETHC_BASE + 0x08 )// Back-to-Back Inter-Packet-Gap register +#define ETH_MAC_NIPGR (ETHC_BASE + 0x0c )// Non-Back-to-Back Inter-Packet-Gap register +#define ETH_MAC_CWR (ETHC_BASE + 0x10 )// Collision Window / Retry register +#define ETH_MAC_MFR (ETHC_BASE + 0x14 )// Maximum Frame register +#define ETH_MAC_PSR (ETHC_BASE + 0x18 )// PHY Support register (SMII / RMII / PMD / ENDEC) +#define ETH_MAC_TR (ETHC_BASE + 0x1c )// Test register +#define ETH_MAC_MCFGR (ETHC_BASE + 0x20 )// MII Mgmt Configuration +#define ETH_MAC_MCMDR (ETHC_BASE + 0x24 )// MII Mgmt Command +#define ETH_MAC_MADRR (ETHC_BASE + 0x28 )// MII Mgmt Address +#define ETH_MAC_MWTDR (ETHC_BASE + 0x2c )// MII Mgmt Write Data +#define ETH_MAC_MRDDR (ETHC_BASE + 0x30 )// MII Mgmt Read Data +#define ETH_MAC_MINDR (ETHC_BASE + 0x34 )// MII Mgmt Indicators + +#define ETH_MAC_SA0 (ETHC_BASE + 0x40 )// Station Address +#define ETH_MAC_SA1 (ETHC_BASE + 0x44 )// Station Address +#define ETH_MAC_SA2 (ETHC_BASE + 0x48 )// Station Address + +// Constants for ETH_MAC_MCR1 register +#define MCR1_SOFTRST (1 << 15) // Soft reset +#define MCR1_SMLTRST (1 << 14) // Simulation reset +#define MCR1_MCSRRST (1 << 11) // MAC Control Sublayer / Rx domain logic reset +#define MCR1_RFUNRST (1 << 10) // Rx Function logic reset +#define MCR1_MCSTRST (1 << 9) // MAC Control Sublayer / Tx domain logic reset +#define MCR1_TFUNRST (1 << 8) // Tx Function logic reset +#define MCR1_LB (1 << 4) // Tx interface loop back to Rx interface +#define MCR1_TFC (1 << 3) // Enable Tx flow control +#define MCR1_RFC (1 << 2) // Enable Rx flow control +#define MCR1_PARF (1 << 1) // Pass all receive frames +#define MCR1_RE (1 << 0) // Enable receive + +// Constants for ETH_MAC_MCR2 register +#define MCR2_ED (1 << 14) // Defer to carrier indefinitely as per the Standard +#define MCR2_BPNB (1 << 13) // Back Pressure / No Backoff +#define MCR2_NB (1 << 12) // No Backoff +#define MCR2_LPE (1 << 9) // Long Preamble Enforcement +#define MCR2_PPE (1 << 8) // Pure Preamble Enforcement +#define MCR2_ADPE (1 << 7) // Auto-Detect Pad Enable +#define MCR2_VPE (1 << 6) // VLAN Pad Enable +#define MCR2_PCE (1 << 5) // Pad / CRC Enable +#define MCR2_CE (1 << 4) // CRC Enable +#define MCR2_DC (1 << 3) // Delayed CRC +#define MCR2_HFE (1 << 2) // Huge Frame Enable +#define MCR2_FLC (1 << 1) // Frame Length Checking +#define MCR2_FD (1 << 0) // Full-Duplex + +// Contants for ETH_MAC_IPGR register +#define IPGR_MASK 0x007f // In Full-Duplex the recommended value is 0x15(21d) + +// Contants for ETH_MAC_NIPGR register +#define NIPGR_P1_MASK 0x7f00 // The recommended value is 0xC(12d) +#define NIPGR_P2_MASK 0x007f // The recommended value is 0x12(18d) + +// Contants for ETH_MAC_CWR register +#define CWR_CW_MASK 0x3f00 // Collision window, Default value is 0x37(55d) +#define CWR_RM_MASK 0x000f // Retry time, default & standard is 0xF(15d) + +// Contants for ETH_MAC_PSR register +#define PSR_RIM (1 << 15) // Reset Interface Module +#define PSR_PM (1 << 12) // PHY Module +#define PSR_RPERMII (1 << 11) // Reset PERMII +#define PSR_OS (1 << 8) // Operating Speed +#define PSR_RPE100M (1 << 7) // Reset PE100M module +#define PSR_FQ (1 << 6) // Force Quiet +#define PSR_NC (1 << 5) // No Cipher +#define PSR_DLF (1 << 4) // Disable Link Fail +#define PSR_RPE10T (1 << 3) // Reset PE10T module +#define PSR_EJP (1 << 1) // Enable Jabber Protection +#define PSR_BM (1 << 0) // Bit Mode + +// Contants for ETH_MAC_TR register +#define TR_TB (1 << 2) // Test Backpressure +#define TR_TP (1 << 1) // Test Pause +#define TR_SPQ (1 << 0) // Shortcut Pause Quanta + +// Contants for ETH_MAC_MCFGR register +#define MCFGR_RST (1 << 15) // Reset MII Mgmt +#define MCFGR_CS_MASK 0x001c // Clock Reset +#define MCFGR_SP (1 << 1) // Suppress Preamble +#define MCFGR_SI (1 << 0) // Scan Increment + +// Contants for ETH_MAC_MCMDR register +#define MCMDR_SCAN (1 << 1) // Cause MII Mgmt module to perform Read cycles continuously +#define MCMDR_READ (1 << 0) // Cause MII Mgmt module to perform single Read cycles +#define MII_SCAN (1 << 1) +#define MII_NO_SCAN 0 + +// Contants for ETH_MAC_MADRR register +#define MADRR_PA_MASK 0x1f00 // PHY Address +#define MADRR_RA_MASK 0x001f // Register Address + +// Contants for ETH_MAC_MINDR register +#define MINDR_LF (1 << 3) // Link Fail +#define MINDR_NV (1 << 2) // Not Valid +#define MINDR_S (1 << 1) // Scanning +#define MINDR_BUSY (1 << 0) // Busy + +// ---------------------------------------------------------------------------------- +// M-AHBE DMA control and status registers (32-bit) +// ---------------------------------------------------------------------------------- + +#define ETH_DMA_TCR (ETHC_BASE + 0x180)// Transmit control +#define ETH_DMA_TDR (ETHC_BASE + 0x184)// Pointer to Transmit Descriptor +#define ETH_DMA_TSR (ETHC_BASE + 0x188)// Transmit Status +#define ETH_DMA_RCR (ETHC_BASE + 0x18c)// Receive Control +#define ETH_DMA_RDR (ETHC_BASE + 0x190)// Pointer to Receive Descriptor +#define ETH_DMA_RSR (ETHC_BASE + 0x194)// Receive Status +#define ETH_DMA_IMR (ETHC_BASE + 0x198)// Interrupt Mask +#define ETH_DMA_IR (ETHC_BASE + 0x19c)// Interrupts +/* ETH_DMA_IR = ETH_DMA_IMR _AND_ corresponding status flags which in ETH_DMA_TSR and ETH_DMA_RSR + * + * ETH_DMA_IR is read only, so the way to disable all interrupt is clear ETH_DMA_IMR or ETH_DMA_T(R)SR. + * Clear ETH_DMA_IMR is better. Then read status and call handle routine. + * Reset ETH_DMA_IMR after all interrupt-enabled status flags be cleared. + */ + +// Constants for ETH_DMA_TCR register +#define TCR_ENABLE (1 << 0) // Enable DMA tx packet transfers + +// Constants for ETH_DMA_TSR register +#define TSR_PKTSENT (1 << 0) // Indicates packet(s) have(has) been successfully txed +#define TSR_UNDERRUN (1 << 1) // Set whenever DMA controller reads a Empty Flag +#define TSR_BUSERR (1 << 3) // Indicates that DMA controller found tx bus error +#define TSR_PKTCNT_MASK (0xFF << 16) // Bit mask of tx packet counter +#define TSR_FLAGS (TSR_PKTSENT | TSR_UNDERRUN | TSR_BUSERR) + +// Constants for ETH_DMA_RCR register +#define RCR_ENABLE (1 << 0) // Enable DMA rx packet transfers + +// Constants for ETH_DMA_RSR register +#define RSR_PKTRECV (1 << 0) // Indicates packet(s) have(has) been successfully rxed +#define RSR_OVERFLOW (1 << 1) // Set whenever DMA controller reads a Non-Empty Flag +#define RSR_BUSERR (1 << 3) // Indicates that DMA controller found rx bus error +#define RSR_PKTCNT_MASK (0xFF << 16) // Bit mask of rx packet counter +#define RSR_FLAGS (RSR_PKTRECV | RSR_OVERFLOW | RSR_BUSERR) + +// Constants for ETH_DMA_IMR register +#define IMR_PKTSENT (1 << 0) // Packet sent interrupt mask +#define IMR_UNDERRUN (1 << 1) // Underrun interrupt mask +#define IMR_TBUSERR (1 << 3) // Tx bus error interrupt mask +#define IMR_PKTRECV (1 << 4) // Packet received interrupt mask +#define IMR_OVERFLOW (1 << 6) // Overflow interrupt mask +#define IMR_RBUSERR (1 << 7) // Rx bus error interrupt mask +#define IMR_ALL_IRQ (IMR_UNDERRUN | IMR_TBUSERR | IMR_OVERFLOW | IMR_RBUSERR | IMR_PKTRECV) +//#define IMR_ALL_IRQ (IMR_UNDERRUN | IMR_TBUSERR | IMR_OVERFLOW | IMR_RBUSERR | IMR_PKTSENT | IMR_PKTRECV) + +#define BURST_LEN_LO (1 << 27) +#define BURST_LEN_HI (1 << 28) +// Burst length configuration. +// HI LO Burst length +// 0 0 4 +// 0 1 8 +// 1 0 16 +// 1 1 4 +#define BURST_LEN_4 (0 << 27) +#define BURST_LEN_8 (1 << 27) +#define BURST_LEN_16 (2 << 27) + +// ---------------------------------------------------------------------------------- +// M-MIIFIF (32-bits) registers (32-bit) +// ---------------------------------------------------------------------------------- + +#define ETH_FIFO_CR0 (ETHC_BASE + 0x3c )// Configuration Register 0 +#define ETH_FIFO_CR1 (ETHC_BASE + 0x4c )// Configuration Register 1 +#define ETH_FIFO_CR2 (ETHC_BASE + 0x50 )// Configuration Register 2 +#define ETH_FIFO_CR3 (ETHC_BASE + 0x54 )// Configuration Register 3 +#define ETH_FIFO_CR4 (ETHC_BASE + 0x58 )// Configuration Register 4 +#define ETH_FIFO_CR5 (ETHC_BASE + 0x5c )// Configuration Register 5 + +#define ETH_FIFO_RAR0 (ETHC_BASE + 0x60 )// RAM Access Register 0 +#define ETH_FIFO_RAR1 (ETHC_BASE + 0x64 )// RAM Access Register 1 +#define ETH_FIFO_RAR2 (ETHC_BASE + 0x68 )// RAM Access Register 2 +#define ETH_FIFO_RAR3 (ETHC_BASE + 0x6c )// RAM Access Register 3 +#define ETH_FIFO_RAR4 (ETHC_BASE + 0x70 )// RAM Access Register 4 +#define ETH_FIFO_RAR5 (ETHC_BASE + 0x74 )// RAM Access Register 5 +#define ETH_FIFO_RAR6 (ETHC_BASE + 0x78 )// RAM Access Register 6 +#define ETH_FIFO_RAR7 (ETHC_BASE + 0x7c )// RAM Access Register 7 + +// Constants for ETH_FIFO_CR0 register +#define FTF_EN_RPLY (1 << 20) // Indicate whether mmiitfif_fab module is enabled +#define STF_EN_RPLY (1 << 19) // Indicate whether mmiitfif_sys module is enabled +#define FRF_EN_RPLY (1 << 18) // Indicate whether mmiirfif_fab module is enabled +#define SRF_EN_RPLY (1 << 17) // Indicate whether mmiirfif_sys module is enabled +#define WTM_EN_RPLY (1 << 16) // Indicate whether mmiitfif_wtm module is enabled +#define ALL_EN_RPLY (FTF_EN_RPLY | STF_EN_RPLY | FRF_EN_RPLY | SRF_EN_RPLY | WTM_EN_RPLY) + +#define FTF_EN_REQ (1 << 12) // Request enable/disable -ing the mmiitfif_fab module +#define STF_EN_REQ (1 << 11) // Request enable/disable -ing the mmiitfif_sys module +#define FRF_EN_REQ (1 << 10) // Request enable/disable -ing the mmiirfif_fab module +#define SRF_EN_REQ (1 << 9) // Request enable/disable -ing the mmiirfif_sys module +#define WTM_EN_REQ (1 << 8) // Request enable/disable -ing the mmiitfif_wtm module +#define ALL_EN_REQ (FTF_EN_REQ | STF_EN_REQ | FRF_EN_REQ | SRF_EN_REQ | WTM_EN_REQ) + +#define FTF_RST (1 << 4) // Reset mmiitfif_fab module +#define STF_RST (1 << 3) // Reset mmiitfif_sys module +#define FRT_RST (1 << 2) // Reset mmiirfif_fab module +#define SRF_RST (1 << 1) // Reset mmiirfif_sys module +#define WTM_RST (1 << 0) // Reset mmiitfif_wtm module +#define ALL_RST (FTF_RST | STF_RST | FRT_RST | SRF_RST | WTM_RST) + +// Constants for ETH_FIFO_CR1 register +#define CFG_FR_TH_MASK (0x0fff << 16) // Fabric Receive Threshold mask +#define CFG_XOFF_RTX_MASK 0xffff // ?????????????? + +// Constants for ETH_FIFO_CR2 register +#define CFG_H_WM_MASK (0x1fff << 16) // Receive RAM high watermark mask +#define CFG_L_WM_MASK 0x1fff // Receive RAM low watermark mask + +// Constants for ETH_FIFO_CR3 register +#define CFG_H_WM_FT_MASK (0x0fff << 16) // ?????????????? +#define CFG_FT_TH_MASK 0xffff // Fabric Transmit Threshold mask + +// Constants for ETH_FIFO_CR4 register +#define HST_FLT_RFRM_MASK 0xffff // Indicate drop condition + +// Constants for ETH_FIFO_CR5 register +#define CFG_H_DPLX (1 << 22) // Enable Half-duplex backpressure as flow control mchm +#define CFG_SR_FULL (1 << 21) // Indicate whether FIFO storage has been met or exceeded +#define CFG_SR_FULL_CLR (1 << 20) // Clear CFG_SR_FULL bit +#define CLK_EN_MODE (1 << 19) // +#define HST_DR_LT_64 (1 << 18) // Drop the frame which less than 16 bit length +#define HST_FLT_RFRMDC_MASK (0xffff) // Indicate drop condition ... which don't care + +// Constants for ETH_FIFO_RAR0 register +#define RAR0_HT_W_REQ (1 << 31) // Host Tx RAM write request +#define RAR0_HT_W_ACK (1 << 30) // Host Tx RAM write acknowledge +#define RAR0_HT_W_CD_MASK (0xff << 16) // Host Tx RAM write control data +#define RAR0_HT_W_ADDR_MASK (0x3ff << 0) // Host Tx RAM write address, [9:0] 10 bit, (4k RAM / 4 = 1024) + +// Constants for ETH_FIFO_RAR2 register +#define RAR2_HT_R_REQ (1 << 31) // Host Tx RAM read request +#define RAR2_HT_R_ACK (1 << 30) // Host Tx RAM read acknowledge +#define RAR2_HT_R_CD_MASK (0xff << 16) // Host Tx RAM read control data +#define RAR2_HT_R_ADDR_MASK (0x3ff << 0) // Host Tx RAM read address, [9:0] 10 bit + +// Constants for ETH_FIFO_RAR4 register +#define RAR4_HR_W_REQ (1 << 31) // Host Rx RAM write request +#define RAR4_HR_W_ACK (1 << 30) // Host Rx RAM write acknowledge +#define RAR4_HR_W_CD_MASK (0xf << 16) // Host Rx RAM write control data +#define RAR4_HR_W_ADDR_MASK (0x3ff << 0) // Host Rx RAM write address + +// Constants for ETH_FIFO_RAR6 register +#define RAR4_HR_R_REQ (1 << 31) // Host Rx RAM read request +#define RAR4_HR_R_ACK (1 << 30) // Host Rx RAM read acknowledge +#define RAR4_HR_R_CD_MASK (0xf << 16) // Host Rx RAM read control data +#define RAR4_HR_R_ADDR_MASK (0x3ff << 0) // Host Rx RAM read address + +// ---------------------------------------------------------------------------------- +// PE-MSTAT registers (32-bit) +// ---------------------------------------------------------------------------------- + +// Several control signal +#define ETH_STAT_CR ETH_DMA_IMR // Use high 3 bits of ETH_DMA_IMR +#define STAT_EN (1 << 31) // Enable PE-MSTAT module +#define STAT_CL (1 << 30) // Clear counters, need voltage jump +#define STAT_AZ (1 << 29) // Enable Auto-Zero after read + +// Combined transmit and receive counters. [17 : 0] available +#define ETH_STAT_TR64 (ETHC_BASE + 0x80 )// Tx & Rx 64 bytes frame counter +#define ETH_STAT_TR127 (ETHC_BASE + 0x84 )// Tx & Rx 65 ~ 127 bytes frame counter +#define ETH_STAT_TR255 (ETHC_BASE + 0x88 )// Tx & Rx 128 ~ 255 bytes frame counter +#define ETH_STAT_TR511 (ETHC_BASE + 0x8c )// Tx & Rx 256 ~ 511 bytes frame counter +#define ETH_STAT_TR1K (ETHC_BASE + 0x90 )// Tx & Rx 512 ~ 1023 bytes frame counter +#define ETH_STAT_TRMAX (ETHC_BASE + 0x94 )// Tx & Rx 1024 ~ 1518 bytes frame counter +#define ETH_STAT_TRMGV (ETHC_BASE + 0x98 )// Tx & Rx 1519 ~ 1522 bytes good VLAN frame counter + +// Receive counters +#define ETH_STAT_RBYT (ETHC_BASE + 0x9c )// Rx Byte counter [23 : 0] +#define ETH_STAT_RPKT (ETHC_BASE + 0xa0 )// Rx Packet counter [17 : 0] +#define ETH_STAT_RFCS (ETHC_BASE + 0xa4 )// Rx FCS Error counter [11 : 0] +#define ETH_STAT_RMCA (ETHC_BASE + 0xa8 )// Rx Multicast packet counter [17 : 0] +#define ETH_STAT_RBCA (ETHC_BASE + 0xac )// Rx Broadcast packet counter [21 : 0] +#define ETH_STAT_RXCF (ETHC_BASE + 0xb0 )// Rx Control frame packet counter [17 : 0] +#define ETH_STAT_RXPF (ETHC_BASE + 0xb4 )// Rx PAUSE frame packet counter [11 : 0] +#define ETH_STAT_RXUO (ETHC_BASE + 0xb8 )// Rx Unkown OP code counter [11 : 0] +#define ETH_STAT_RALN (ETHC_BASE + 0xbc )// Rx Alignment Error counter [11 : 0] +#define ETH_STAT_RFLR (ETHC_BASE + 0xc0 )// Rx Frame Length Error counter [15 : 0] +#define ETH_STAT_RCDE (ETHC_BASE + 0xc4 )// Rx Code Error counter [11 : 0] +#define ETH_STAT_RCSE (ETHC_BASE + 0xc8 )// Rx Carrier Sense Error counter [11 : 0] +#define ETH_STAT_RUND (ETHC_BASE + 0xcc )// Rx Undersize packet counter [11 : 0] +#define ETH_STAT_ROVR (ETHC_BASE + 0xd0 )// Rx Oversize packet counter [11 : 0] +#define ETH_STAT_RFRG (ETHC_BASE + 0xd4 )// Rx Fragments counter [11 : 0] +#define ETH_STAT_RJBR (ETHC_BASE + 0xd8 )// Rx Jabber counter [11 : 0] +#define ETH_STAT_RDRP (ETHC_BASE + 0xdc )// Rx Drop [11 : 0] + +// Transmit counters +#define ETH_STAT_TBYT (ETHC_BASE + 0xe0 )// Tx Byte counter [23 : 0] +#define ETH_STAT_TPKT (ETHC_BASE + 0xe4 )// Tx Packet counter [17 : 0] +#define ETH_STAT_TMCA (ETHC_BASE + 0xe8 )// Tx Multicast packet counter [17 : 0] +#define ETH_STAT_TBCA (ETHC_BASE + 0xec )// Tx Broadcast packet counter [17 : 0] +#define ETH_STAT_TXPF (ETHC_BASE + 0xf0 )// Tx PAUSE frame packet counter [11 : 0] +#define ETH_STAT_TDFR (ETHC_BASE + 0xf4 )// Tx Deferral packet counter [11 : 0] +#define ETH_STAT_TEDF (ETHC_BASE + 0xf8 )// Tx Excessive Deferral packet counter [11 : 0] +#define ETH_STAT_TSCL (ETHC_BASE + 0xfc )// Tx Single Collision packet counter [11 : 0] +#define ETH_STAT_TMCL (ETHC_BASE + 0x100)// Tx Multiple Collision packet counte [11 : 0] +#define ETH_STAT_TLCL (ETHC_BASE + 0x104)// Tx Late Collision packet counter [11 : 0] +#define ETH_STAT_TXCL (ETHC_BASE + 0x108)// Tx Excessive Collision packet counter [11 : 0] +#define ETH_STAT_TNCL (ETHC_BASE + 0x10c)// Tx Total Collision packet counter [12 : 0] +#define ETH_STAT_TPFH (ETHC_BASE + 0x110)// Tx PAUSE frames Honored counter [11 : 0] +#define ETH_STAT_TDRP (ETHC_BASE + 0x114)// Tx Drop frame counter [11 : 0] +#define ETH_STAT_TJBR (ETHC_BASE + 0x118)// Tx Jabber frame counter [11 : 0] +#define ETH_STAT_TFCS (ETHC_BASE + 0x11c)// Tx FCS Error counter [11 : 0] +#define ETH_STAT_TXCF (ETHC_BASE + 0x120)// Tx Control frame counter [11 : 0] +#define ETH_STAT_TOVR (ETHC_BASE + 0x124)// Tx Oversize frame counter [11 : 0] +#define ETH_STAT_TUND (ETHC_BASE + 0x128)// Tx Undersize frame counter [11 : 0] +#define ETH_STAT_TFRG (ETHC_BASE + 0x12c)// Tx Fragments frame counter [11 : 0] + +// Carry registers +#define ETH_STAT_CAR1 (ETHC_BASE + 0x130)// Carry Register 1 +#define ETH_STAT_CAR2 (ETHC_BASE + 0x134)// Carry Register 2 +#define ETH_STAT_CARM1 (ETHC_BASE + 0x138)// Carry Mask Register 1 +#define ETH_STAT_CARM2 (ETHC_BASE + 0x13c)// Carry Mask Register 2 + +// Constants for ETH_STAT_CAR* +#define CAR1_TR64 (1 << 31) +#define CAR1_TR127 (1 << 30) +#define CAR1_TR255 (1 << 29) +#define CAR1_TR511 (1 << 28) +#define CAR1_TR1K (1 << 27) +#define CAR1_TRMAX (1 << 26) +#define CAR1_TRMGV (1 << 25) +#define CAR1_RBY (1 << 16) +#define CAR1_RPK (1 << 15) +#define CAR1_RFC (1 << 14) +#define CAR1_RMC (1 << 13) +#define CAR1_RBC (1 << 12) +#define CAR1_RXC (1 << 11) +#define CAR1_RXP (1 << 10) +#define CAR1_RXU (1 << 9) +#define CAR1_RAL (1 << 8) +#define CAR1_RFL (1 << 7) +#define CAR1_RCD (1 << 6) +#define CAR1_RCS (1 << 5) +#define CAR1_RUN (1 << 4) +#define CAR1_ROV (1 << 3) +#define CAR1_RFR (1 << 2) +#define CAR1_RJB (1 << 1) +#define CAR1_RDR (1 << 0) + +#define CAR2_TJB (1 << 19) +#define CAR2_TFC (1 << 18) +#define CAR2_TCF (1 << 17) +#define CAR2_TOV (1 << 16) +#define CAR2_TUN (1 << 15) +#define CAR2_TFG (1 << 14) +#define CAR2_TBY (1 << 13) +#define CAR2_TPK (1 << 12) +#define CAR2_TMC (1 << 11) +#define CAR2_TBC (1 << 10) +#define CAR2_TPF (1 << 9) +#define CAR2_TDF (1 << 8) +#define CAR2_TED (1 << 7) +#define CAR2_TSC (1 << 6) +#define CAR2_TMA (1 << 5) +#define CAR2_TLC (1 << 4) +#define CAR2_TXC (1 << 3) +#define CAR2_TNC (1 << 2) +#define CAR2_TPH (1 << 1) +#define CAR2_TDP (1 << 0) + +#define CARM1_TR64 (1 << 31) +#define CARM1_TR127 (1 << 30) +#define CARM1_TR255 (1 << 29) +#define CARM1_TR511 (1 << 28) +#define CARM1_TR1K (1 << 27) +#define CARM1_TRMAX (1 << 26) +#define CARM1_TRMGV (1 << 25) +#define CARM1_RBY (1 << 16) +#define CARM1_RPK (1 << 15) +#define CARM1_RFC (1 << 14) +#define CARM1_RMC (1 << 13) +#define CARM1_RBC (1 << 12) +#define CARM1_RXC (1 << 11) +#define CARM1_RXP (1 << 10) +#define CARM1_RXU (1 << 9) +#define CARM1_RAL (1 << 8) +#define CARM1_RFL (1 << 7) +#define CARM1_RCD (1 << 6) +#define CARM1_RCS (1 << 5) +#define CARM1_RUN (1 << 4) +#define CARM1_ROV (1 << 3) +#define CARM1_RFR (1 << 2) +#define CARM1_RJB (1 << 1) +#define CARM1_RDR (1 << 0) + +#define CARM2_TJB (1 << 19) +#define CARM2_TFC (1 << 18) +#define CARM2_TCF (1 << 17) +#define CARM2_TOV (1 << 16) +#define CARM2_TUN (1 << 15) +#define CARM2_TFG (1 << 14) +#define CARM2_TBY (1 << 13) +#define CARM2_TPK (1 << 12) +#define CARM2_TMC (1 << 11) +#define CARM2_TBC (1 << 10) +#define CARM2_TPF (1 << 9) +#define CARM2_TDF (1 << 8) +#define CARM2_TED (1 << 7) +#define CARM2_TSC (1 << 6) +#define CARM2_TMA (1 << 5) +#define CARM2_TLC (1 << 4) +#define CARM2_TXC (1 << 3) +#define CARM2_TNC (1 << 2) +#define CARM2_TPH (1 << 1) +#define CARM2_TDP (1 << 0) + +// ---------------------------------------------------------------------------------- +// PE-SAL registers (32-bit) +// ---------------------------------------------------------------------------------- + +#define ETH_SAL_AFR (ETHC_BASE + 0x1a0)// Address Filter Register +#define ETH_SAL_HT1 (ETHC_BASE + 0x1a4)// Hash Table [64 : 32] +#define ETH_SAL_HT2 (ETHC_BASE + 0x1a8)// Hash Table [31 : 0 ] + +// Constants for ETH_SAL_AFR +#define AFR_PRO (1 << 3) // Promiscuous mode +#define AFR_PRM (1 << 2) // Accept Multicast +#define AFR_AMC (1 << 1) // Accept Multicast qualified +#define AFR_ABC (1 << 0) // Accept Broadcast + +// ---------------------------------------------------------------------------------- +// MISC definition +// ---------------------------------------------------------------------------------- + +// Receive Status Vector +#define RSV_RVTD (1 << 30) // Receive VLAN Type detected +#define RSV_RUO (1 << 29) // Receive Unsupported Op-code +#define RSV_RPCF (1 << 28) // Receive Pause Control Frame +#define RSV_RCF (1 << 27) // Receive Control Frame +#define RSV_DN (1 << 26) // Dribble Nibble +#define RSV_BP (1 << 25) // Broadcast Packet +#define RSV_MP (1 << 24) // Multicast Packet +#define RSV_OK (1 << 23) // Receive OK +#define RSV_LOR (1 << 22) // Length Out of Range +#define RSV_LCE (1 << 21) // Length Check Error +#define RSV_CRCE (1 << 20) // CRC Error +#define RSV_RCV (1 << 19) // Receive Code Violation +#define RSV_CEPS (1 << 18) // Carrier Event Previously Seen +#define RSV_REPS (1 << 17) // RXDV Event Previously Seen +#define RSV_PPI (1 << 16) // Packet Previously Ignored + +// ---------------------------------------------------------------------------------- +// MII Registers and Definitions +// ---------------------------------------------------------------------------------- + +#define MII_BMCR 0x00 /* MII Management Control Register */ +#define MII_BMSR 0x01 /* MII Management Status Register */ +#define MII_ID1 0x02 /* PHY Identifier Register 0 */ +#define MII_ID2 0x03 /* PHY Identifier Register 1 */ +#define MII_ANAR 0x04 /* Auto Negotiation Advertisement */ +#define MII_ANLPAR 0x05 /* Auto Negotiation Link Partner Ability */ +#define MII_ANER 0x06 /* Auto Negotiation Expansion */ +#define MII_ANP 0x07 /* Auto Negotiation Next Page TX */ +#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_10 0x0000 /* Set 10Mb/s */ +#define MII_CR_100 0x2000 /* Set 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_ANAR_TAF 0x03e0 /* Technology Ability Field */ +#define MII_ANAR_T4AM 0x0200 /* T4 Technology Ability Mask */ +#define MII_ANAR_TXAM 0x0180 /* TX Technology Ability Mask */ +#define MII_ANAR_FDAM 0x0140 /* Full Duplex Technology Ability Mask */ +#define MII_ANAR_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */ +#define MII_ANAR_100M 0x0380 /* 100Mb Technology Ability Mask */ +#define MII_ANAR_10M 0x0060 /* 10Mb Technology Ability Mask */ +#define MII_ANAR_CSMA 0x0001 /* CSMA-CD Capable */ + +// MII Management Auto Negotiation Remote End Register +#define MII_ANLPAR_NP 0x8000 /* Next Page (Enable) */ +#define MII_ANLPAR_ACK 0x4000 /* Remote Acknowledge */ +#define MII_ANLPAR_RF 0x2000 /* Remote Fault */ +#define MII_ANLPAR_TAF 0x03e0 /* Technology Ability Field */ +#define MII_ANLPAR_T4AM 0x0200 /* T4 Technology Ability Mask */ +#define MII_ANLPAR_TXAM 0x0180 /* TX Technology Ability Mask */ +#define MII_ANLPAR_FDAM 0x0140 /* Full Duplex Technology Ability Mask */ +#define MII_ANLPAR_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */ +#define MII_ANLPAR_100M 0x0380 /* 100Mb Technology Ability Mask */ +#define MII_ANLPAR_10M 0x0060 /* 10Mb Technology Ability Mask */ +#define MII_ANLPAR_CSMA 0x0001 /* CSMA-CD Capable */ + +// Media / mode state machine definitions +// User selectable: +#define TP 0x0040 /* 10Base-T (now equiv to _10Mb) */ +#define TP_NW 0x0002 /* 10Base-T with Nway */ +#define BNC 0x0004 /* Thinwire */ +#define AUI 0x0008 /* Thickwire */ +#define BNC_AUI 0x0010 /* BNC/AUI on DC21040 indistinguishable */ +#define _10Mb 0x0040 /* 10Mb/s Ethernet */ +#define _100Mb 0x0080 /* 100Mb/s Ethernet */ +#define AUTO 0x4000 /* Auto sense the media or speed */ + +// Internal states +#define NC 0x0000 /* No Connection */ +#define ANS 0x0020 /* Intermediate AutoNegotiation State */ +#define SPD_DET 0x0100 /* Parallel speed detection */ +#define INIT 0x0200 /* Initial state */ +#define EXT_SIA 0x0400 /* External SIA for motherboard chip */ +#define ANS_SUSPECT 0x0802 /* Suspect the ANS (TP) port is down */ +#define TP_SUSPECT 0x0803 /* Suspect the TP port is down */ +#define BNC_AUI_SUSPECT 0x0804 /* Suspect the BNC or AUI port is down */ +#define EXT_SIA_SUSPECT 0x0805 /* Suspect the EXT SIA port is down */ +#define BNC_SUSPECT 0x0806 /* Suspect the BNC port is down */ +#define AUI_SUSPECT 0x0807 /* Suspect the AUI port is down */ +#define MII 0x1000 /* MII on the 21143 */ + +// ---------------------------------------------------------------------------------- +// Device data and structure +// ---------------------------------------------------------------------------------- + +#define READ_COMMAND (SIOCDEVPRIVATE+4) +#define WRITE_COMMAND (SIOCDEVPRIVATE+5) +#define GETDRIVERINFO (SIOCDEVPRIVATE+6) + +#define ETH_TX_TIMEOUT (6*HZ) + +#define RX_BUF_SIZE (1536 + 64) + +#define NUM_RX_DESCS 64 +#define NUM_TX_DESCS 16 + +#define MAX_WAIT 2000 + +#define STAT_INTERVAL HZ * 3 + +// Constants for DMA descriptor +#define EMPTY_FLAG_MASK (1 << 31) +#define FTPP_FLAGS_MASK (0x1f << 16) +#define FTCFRM_MASK (1 << 20) +#define FTPP_PADMODE_MASK (0x3 << 18) +#define FTPP_GENFCS_MASK (1 << 17) +#define FTPP_EN_MASK (1 << 16) + +#define PKT_SIZE_MASK (0x0FFF) + +/* +static const char *media_types[] = { + "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", + "100baseTx-FD", "100baseT4", 0 +}; +*/ + +typedef struct { + unsigned int pkt_addr; // phy addr + unsigned int pkt_size; // include empty flag + unsigned int next_desc; // phy addr + + unsigned int for_align; // for 4-word alignment +} jz_desc_t; + + +enum counters{ +// CNT_TR64, +// CNT_TR127, +// CNT_TR255, +// CNT_TR511, +// CNT_TR1K, +// CNT_TRMAX, +// CNT_TRMGV, + CNT_RBYT, + CNT_RPKT, + CNT_RFCS, + CNT_RMCA, +// CNT_RBCA, +// CNT_RXCF, +// CNT_RXPF, +// CNT_RXUO, +// CNT_RALN, +// CNT_RFLR, +// CNT_RCDE, +// CNT_RCSE, +// CNT_RUND, +// CNT_ROVR, +// CNT_RFRG, +// CNT_RJBR, + CNT_RDRP, + CNT_TBYT, + CNT_TPKT, +// CNT_TMCA, +// CNT_TBCA, +// CNT_TXPF, +// CNT_TDFR, +// CNT_TEDF, +// CNT_TSCL, +// CNT_TMCL, +// CNT_TLCL, +// CNT_TXCL, + CNT_TNCL, +// CNT_TPFH, + CNT_TDRP, +// CNT_TJBR, + CNT_TFCS, +// CNT_TXCF, +// CNT_TOVR, +// CNT_TUND, +// CNT_TFRG, + + STAT_CNT_NUM +}; + + +/* Allocate by alloc_etherdev, which could ensure the struct was 32-byte align */ +struct jz_eth_private { + + jz_desc_t tx_ring[NUM_TX_DESCS]; /* transmit descriptors, 4-word align */ + jz_desc_t rx_ring[NUM_RX_DESCS]; /* receive descriptors, 4-word align */ + + 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; + unsigned int carry_counters[STAT_CNT_NUM]; + + 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 */ + + struct task_struct *thread; /* Link cheak thread */ + int thread_die; + struct completion thr_exited; + wait_queue_head_t thr_wait; + + struct pm_dev *pmdev; +}; + +// ---------------------------------------------------------------------------------- +// Operation defination +// ---------------------------------------------------------------------------------- + +// Operations of ETH DMA +#define __eth_dma_tx_enable() \ +do { \ + REG32(ETH_DMA_TCR) |= TCR_ENABLE; \ +} while(0) + +#define __eth_dma_tx_disable() \ +do { \ + REG32(ETH_DMA_TCR) &= ~TCR_ENABLE; \ +} while(0) + +#define __eth_dma_set_burst_len(len_macro) \ +do { \ + REG32(ETH_DMA_IMR) &= ~(BURST_LEN_LO | BURST_LEN_HI); \ + REG32(ETH_DMA_IMR) |= (len_macro); \ +} while(0) + +#define __eth_set_tx_desc_addr(desc_addr) \ +do { \ + REG32(ETH_DMA_TDR) = desc_addr; \ +} while(0) + +#define __eth_get_flag_pkt_sent() (REG32(ETH_DMA_TSR) & TSR_PKTSENT) +#define __eth_get_flag_underrun() (REG32(ETH_DMA_TSR) & TSR_UNDERRUN) +#define __eth_get_flag_tx_bus_err() (REG32(ETH_DMA_TSR) & TSR_BUSERR) +#define __eth_get_tx_pkt_cnt() ((REG32(ETH_DMA_TSR) & TSR_PKTCNT_MASK) >> 0x10) + +#define __eth_reduce_pkt_sent_cnt() (REG32(ETH_DMA_TSR) |= TSR_PKTSENT) +#define __eth_clear_flag_underrun() (REG32(ETH_DMA_TSR) |= TSR_UNDERRUN) +#define __eth_clear_flag_tx_bus_err() (REG32(ETH_DMA_TSR) |= TSR_BUSERR) +#define __eth_clear_tx_pkt_cnt() \ +do { \ + unsigned int tmp_cnt = __eth_get_tx_pkt_cnt(); \ + for (; tmp_cnt > 0; tmp_cnt--) \ + __eth_reduce_pkt_sent_cnt(); \ +} while(0) + + + +#define __eth_dma_rx_enable() \ +do { \ + REG32(ETH_DMA_RCR) |= RCR_ENABLE; \ +} while(0) + +#define __eth_dma_rx_disable() \ +do { \ + REG32(ETH_DMA_RCR) &= ~RCR_ENABLE; \ +} while(0) + +#define __eth_set_rx_desc_addr(desc_addr) \ +do { \ + REG32(ETH_DMA_RDR) = desc_addr; \ +} while(0) + +#define __eth_get_flag_pkt_recv() (REG32(ETH_DMA_RSR) & RSR_PKTRECV) +#define __eth_get_flag_overflow() (REG32(ETH_DMA_RSR) & RSR_OVERFLOW) +#define __eth_get_flag_rx_bus_err() (REG32(ETH_DMA_RSR) & RSR_BUSERR) +#define __eth_get_rx_pkt_cnt() ((REG32(ETH_DMA_RSR) & RSR_PKTCNT_MASK) >> 0x10) + +#define __eth_reduce_pkt_recv_cnt() (REG32(ETH_DMA_RSR) |= RSR_PKTRECV) +#define __eth_clear_flag_overflow() (REG32(ETH_DMA_RSR) |= RSR_OVERFLOW) +#define __eth_clear_flag_rx_bus_err() (REG32(ETH_DMA_RSR) |= RSR_BUSERR) +#define __eth_clear_rx_pkt_cnt() \ +do { \ + unsigned int tmp_cnt = __eth_get_rx_pkt_cnt(); \ + for (; tmp_cnt > 0; tmp_cnt--) \ + __eth_reduce_pkt_recv_cnt(); \ +} while(0) + +#define __eth_clear_rx_flags() \ +do { \ + /*__eth_clear_rx_pkt_cnt();*/ \ + REG32(ETH_DMA_RSR) = RSR_OVERFLOW | RSR_BUSERR; \ +} while(0) + +#define __eth_clear_tx_flags() \ +do { \ + /*__eth_clear_tx_pkt_cnt();*/ \ + REG32(ETH_DMA_TSR) = TSR_UNDERRUN | TSR_BUSERR; \ +} while(0) + +#define __eth_enable_irq() \ +do { \ + REG32(ETH_DMA_IMR) |= IMR_ALL_IRQ; \ +} while(0) + +#define __eth_disable_irq() \ +do { \ + REG32(ETH_DMA_IMR) &= ~IMR_ALL_IRQ; \ +} while(0) + +#define __eth_enable() \ +do { \ + __eth_dma_tx_enable(); \ + __eth_dma_rx_enable(); \ +} while(0) + +#define __eth_disable() \ +do { \ + __eth_dma_tx_disable(); \ + __eth_dma_rx_disable(); \ +} while(0) + +#define __eth_set_mac_address(b1, b2, b3, b4, b5, b6) \ +do { \ + REG16(ETH_MAC_SA0) = ((b1) << 8) | ((b2) & 0xff); \ + REG16(ETH_MAC_SA1) = ((b3) << 8) | ((b4) & 0xff); \ + REG16(ETH_MAC_SA2) = ((b5) << 8) | ((b6) & 0xff); \ +} while(0) + + +// Operations of ETH MAC registers +#define __mac_reset() \ +do { \ + REG16(ETH_MAC_MCR1) |= MCR1_SOFTRST; \ + udelay(1000); \ + REG16(ETH_MAC_MCR1) &= ~MCR1_SOFTRST; \ +} while(0) + +#define __mac_get_IPGR() (REG16(ETH_MAC_IPGR) & IPGR_MASK) + +#define __mac_set_IPGR(ipgt) \ +do { \ + REG16(ETH_MAC_IPGR) = ipgt; \ +} while(0) + +#define __mac_get_NIPGR1() ((REG16(ETH_MAC_NIPGR) & NIPGR_P1_MASK) >> 8) + +#define __mac_set_NIPGR1(v1) \ +do { \ + REG16(ETH_MAC_NIPGR) |= ((v1) << 8) & NIPGR_P1_MASK; \ +} while(0) + +#define __mac_get_NIPGR2() (REG16(ETH_MAC_NIPGR) & NIPGR_P2_MASK) + +#define __mac_set_NIPGR2(v2) \ +do { \ + REG16(ETH_MAC_NIPGR) |= (v2) & NIPGR_P2_MASK; \ +} while(0) + +#define __mac_get_collision_window() ((REG16(ETH_MAC_CWR) & CWR_CW_MASK) >> 8) + +#define __mac_set_collision_window(cw) \ +do { \ + REG16(ETH_MAC_CWR) |= ((cw) << 8) & CWR_CW_MASK; \ +} while(0) + +#define __mac_get_retx_maximum() (REG16(ETH_MAC_CWR) & CWR_RM_MASK) + +#define __mac_set_retx_maximum(rm) \ +do { \ + REG16(ETH_MAC_CWR) |= (rm) & CWR_RM_MASK; \ +} while(0) + +#define __mac_get_max_frame_length() (REG16(ETH_MAC_MFR)) + +#define __mac_set_max_frame_length(len) \ +do { \ + REG16(ETH_MAC_MFR) = len; \ +} while(0) + +#define __mac_set_mii_clk(_clkdiv) \ +do { \ + REG16(ETH_MAC_MCFGR) |= ((_clkdiv) << 2) & MCFGR_CS_MASK; \ +} while(0) + +#define __mac_set_mii_address(pa, ra) \ +do { \ + REG16(ETH_MAC_MADRR) = \ + (((pa) << 8)& MADRR_PA_MASK)|((ra) & MADRR_RA_MASK); \ +} while(0) + + +#define __mac_send_mii_read_cmd(pa, ra, scan) \ +do { \ + __mac_set_mii_address(pa, ra); \ + REG16(ETH_MAC_MCMDR) &= ~MCMDR_SCAN & ~MCMDR_READ; \ + REG16(ETH_MAC_MCMDR) |= MCMDR_READ | ((scan) & MCMDR_SCAN); \ +} while(0) + +#define __mac_send_mii_write_cmd(pa, ra, wdata) \ +do { \ + __mac_set_mii_address(pa, ra); \ + REG16(ETH_MAC_MCMDR) &= ~MCMDR_SCAN & ~MCMDR_READ; \ + __mac_mii_write_data(wdata); \ +} while(0) + +#define __mac_mii_write_data(_2byte) (REG16(ETH_MAC_MWTDR) = _2byte) + +#define __mac_mii_read_data() REG16(ETH_MAC_MRDDR) + +#define __mac_mii_is_busy() (REG16(ETH_MAC_MINDR) & MINDR_BUSY) + +// Operations of ETH FIFO registers +#define __fifo_enable_all_modules() \ +do { \ + REG32(ETH_FIFO_CR0) |= ALL_EN_REQ; \ +} while(0) + +#define __fifo_enable_all_modules_finish() \ +do { \ + REG32(ETH_FIFO_CR0) &= ~ALL_EN_REQ; \ +} while(0) + +// All enabled mean all reply bits were set except SRF_EN_RPLY... +#define __fifo_all_enabled() ((REG32(ETH_FIFO_CR0) & (ALL_EN_RPLY & ~SRF_EN_RPLY)) == (ALL_EN_RPLY & ~SRF_EN_RPLY)) + +#define __fifo_reset_all() \ +do { \ + REG32(ETH_FIFO_CR0) |= ALL_RST; \ + REG32(ETH_FIFO_CR0) &= ~ALL_RST; \ +} while(0) + +#define __fifo_set_fr_threshold(_th) \ +do { \ + REG32(ETH_FIFO_CR1) &= ~CFG_FR_TH_MASK; \ + REG32(ETH_FIFO_CR1) |= ((_th) << 16) & CFG_FR_TH_MASK; \ +} while(0) + +#define __fifo_set_XOFF_RTX(_th) \ +do { \ + REG32(ETH_FIFO_CR1) &= ~CFG_XOFF_RTX_MASK; \ + REG32(ETH_FIFO_CR1) |= (_th) & CFG_XOFF_RTX_MASK; \ +} while(0) + +#define __fifo_set_high_wm(_th) \ +do { \ + REG32(ETH_FIFO_CR2) &= ~CFG_H_WM_MASK; \ + REG32(ETH_FIFO_CR2) |= ((_th) << 16) & CFG_H_WM_MASK; \ +} while(0) + +#define __fifo_set_low_wm(_th) \ +do { \ + REG32(ETH_FIFO_CR2) &= ~CFG_L_WM_MASK; \ + REG32(ETH_FIFO_CR2) |= (_th) & CFG_L_WM_MASK; \ +} while(0) + +#define __fifo_set_ft_high_wm(_th) \ +do { \ + REG32(ETH_FIFO_CR3) &= ~CFG_H_WM_FT_MASK; \ + REG32(ETH_FIFO_CR3) |= ((_th) << 16) & CFG_H_WM_FT_MASK; \ +} while(0) + +#define __fifo_set_ft_threshold(_th) \ +do { \ + REG32(ETH_FIFO_CR3) &= ~CFG_FT_TH_MASK; \ + REG32(ETH_FIFO_CR3) |= (_th) & CFG_FT_TH_MASK; \ +} while(0) + +#define __fifo_set_drop_cond(_cdt) \ +do { \ + REG32(ETH_FIFO_CR4) |= ((_cdt) >> 16) & HST_FLT_RFRM_MASK; \ +} while(0) + +#define __fifo_set_dropdc_cond(_cdt) \ +do { \ + REG32(ETH_FIFO_CR5) &= ~(((_cdt)>>16) & HST_FLT_RFRMDC_MASK); \ +} while(0) + +#define __fifo_set_pause_control() \ +do { \ + REG32(ETH_FIFO_CR5) &= ~CFG_H_DPLX; \ +} while(0) + +#define __fifo_set_clk_enable_mode() \ +do { \ + REG32(ETH_FIFO_CR5) |= CLK_EN_MODE; \ +} while(0) + +#define __fifo_set_half_duplex() \ +do { \ + REG32(ETH_FIFO_CR5) |= CFG_H_DPLX; \ +} while(0) + +#define __fifo_drop_lt64_frame() \ +do { \ + REG32(ETH_FIFO_CR5) |= HST_DR_LT_64; \ +} while(0) + +// Operations of ETH STAT registers +#define __stat_enable() \ +do { \ + REG32(ETH_STAT_CR) |= STAT_EN; \ +} while(0) + +#define __stat_disable() \ +do { \ + REG32(ETH_STAT_CR) &= ~STAT_EN; \ +} while(0) + +#define __stat_clear_counters() \ +do { \ + REG32(ETH_STAT_CR) &= ~STAT_CL; \ + REG32(ETH_STAT_CR) |= STAT_CL; \ +} while(0) + +#define __stat_enable_auto_zero() \ +do { \ + REG32(ETH_STAT_CR) |= STAT_AZ; \ +} while(0) + +#define __stat_disable_auto_zero() \ +do { \ + REG32(ETH_STAT_CR) &= ~STAT_AZ; \ +} while(0) + +#define __stat_enable_carry_irq() \ +do { \ + __stat_unmask1(CARM1_RPK | CARM1_RBY | CARM1_RFC | CARM1_RDR | CARM1_RMC);\ + __stat_unmask2(CARM2_TPK | CARM2_TBY | CARM2_TFC | CARM2_TDP | CARM2_TNC);\ +} while(0) + +#define __stat_disable_carry_irq() \ +do { \ + __stat_unmask1(0); \ + __stat_unmask2(0); \ +} while(0) + +#define __stat_unmask1(_counter) \ +do { \ + REG32(ETH_STAT_CARM1) = ~(_counter); \ +} while(0) + +#define __stat_unmask2(_counter) \ +do { \ + REG32(ETH_STAT_CARM2) = ~(_counter); \ +} while(0) + +// Operations of ETH SAL registers + +// Anyhow, enable broadcast ... +#define __sal_set_mode(_mode) \ +do { \ + REG32(ETH_SAL_AFR) = (_mode) | AFR_ABC; \ +} while(0) + +#define __sal_set_hash_table(_hi32, _lo32) \ +do { \ + REG32(ETH_SAL_HT1) = _hi32; \ + REG32(ETH_SAL_HT2) = _lo32; \ +} while(0) + +#define __sal_get_hash_table(_hi32, _lo32) \ +do { \ + _hi32 = REG32(ETH_SAL_HT1); \ + _lo32 = REG32(ETH_SAL_HT2); \ +} while(0) + +// Operations of DMA descripter +#define __desc_get_empty_flag(pktsize) (pktsize & EMPTY_FLAG_MASK) +#define __desc_get_FTPP_flags(pktsize) ((pktsize & FTPP_FLAGS_MASK) >> 16) +#define __desc_get_FTCFRM_flag(pktsize) (pktsize & FTCFRM_MASK) +#define __desc_get_FTPP_PADMODE_flag(pktsize) ((pktsize & FTPP_PADMODE_MASK) >> 18) +#define __desc_get_FTPP_GENFCS_flag(pktsize) (pktsize & FTPP_GENFCS_MASK) +#define __desc_get_FTPP_enable_flag(pktsize) (pktsize & FTPP_EN_MASK) +#define __desc_get_pkt_size(pktsize) (pktsize & PKT_SIZE_MASK) + + + +#endif diff --git a/target/linux/xburst/files-2.6.27/drivers/net/jz_eth.c b/target/linux/xburst/files-2.6.27/drivers/net/jz_eth.c new file mode 100644 index 000000000..6dbbaf4eb --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/net/jz_eth.c @@ -0,0 +1,1290 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 " +#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 *)dev->priv; + struct task_struct *t; + + np->thread_die = 0; + init_waitqueue_head(&np->thr_wait); + init_completion (&np->thr_exited); + + t = kthread_create(link_check_thread,(void *)dev, + dev->name); + if (IS_ERR(t)) + errprintk("%s: unable to start kernel thread\n",dev->name); + np->thread = t; +} + +static int close_check(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + int ret = 0; + + if (np->thread != NULL) { + np->thread_die = 1; + wmb(); + send_sig(SIGTERM, np->thread, 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; + unsigned char current_link; + unsigned long timeout; + + daemonize("%s", dev->name); + spin_lock_irq(¤t->sighand->siglock); + sigemptyset(¤t->blocked); + recalc_sigpending(); + spin_unlock_irq(¤t->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(¤t->sighand->siglock); + flush_signals(current); + spin_unlock_irq(¤t->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 && idata[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 *)dev->priv; + 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;jdmi_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 *)dev->priv; + 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 *)dev->priv; + 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 *)dev->priv; + 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 *)dev->priv; + 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 *)dev->priv; + 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<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 *)dev->priv; + 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 *)dev->priv; + 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 = dev->priv; + 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 *)dev->priv; + 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*)dev->priv; + 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 *)dev->priv; + + 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*)dev->priv; + 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 *)dev->priv; + 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 *)dev->priv; + u32 length; + + if (np->tx_full) { + return 0; + } + udelay(500); /* FIXME: can we remove this delay ? */ + 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 = dev->priv; + 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 *)dev->priv; + 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 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 = (struct jz_eth_private *)P2ADDR(dev->priv); + dev->priv = np; + 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); + + ether_setup(dev); + dev->irq = IRQ_ETH; + dev->open = jz_eth_open; + dev->stop = jz_eth_close; + dev->hard_start_xmit = jz_eth_send_packet; + dev->get_stats = jz_eth_get_stats; + dev->set_multicast_list = jz_set_multicast_list; + dev->do_ioctl = jz_eth_ioctl; + dev->tx_timeout = jz_eth_tx_timeout; + dev->watchdog_timeo = ETH_TX_TIMEOUT; + + /* 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 = dev->priv; + + 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/target/linux/xburst/files-2.6.27/drivers/net/jz_eth.h b/target/linux/xburst/files-2.6.27/drivers/net/jz_eth.h new file mode 100644 index 000000000..3475d2eac --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 */ + + struct task_struct *thread; /* Link cheak thread */ + int thread_die; + struct completion thr_exited; + wait_queue_head_t thr_wait; + + struct pm_dev *pmdev; +}; + +#endif /* __JZ_ETH_H__ */ diff --git a/target/linux/xburst/files-2.6.27/drivers/net/jzcs8900a.c b/target/linux/xburst/files-2.6.27/drivers/net/jzcs8900a.c new file mode 100644 index 000000000..af2dccc3b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/net/jzcs8900a.c @@ -0,0 +1,652 @@ +/* + * linux/drivers/net/jzcs8900a.c + * + * Author: Lucifer + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "jzcs8900a.h" + +#define FULL_DUPLEX +#define INT_PIN 0 + +/* + * IO address and irq pin + */ +#ifdef CONFIG_SOC_JZ4740 +#define GPIO_NET_INT (32*1+27) /* GPB27 */ +#define CIRRUS_DEFAULT_IO 0xa8000000 +#define CIRRUS_DEFAULT_IRQ (GPIO_NET_INT + IRQ_GPIO_0) +#endif /* CONFIG_SOC_JZ4740*/ + +#ifdef CONFIG_SOC_JZ4750 +#define CIRRUS_DEFAULT_IO 0xac000000 +#define CIRRUS_DEFAULT_IRQ (GPIO_NET_INT + IRQ_GPIO_0) +#endif /* CONFIG_SOC_JZ4750 */ + +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 + /* We use CS4 with 16-bit data width */ + __gpio_as_func0(60); /* CS4# */ + __gpio_as_func0(61); /* RD# */ + __gpio_as_func0(62); /* WR# */ + + REG_EMC_SMCR4 &= ~EMC_SMCR_BW_MASK; /* 16bit */ + REG_EMC_SMCR4 |= EMC_SMCR_BW_16BIT; /* 16bit */ + +#endif /* CONFIG_SOC_JZ4740 */ + +#ifdef CONFIG_SOC_JZ4750 + /* We use CS3 with 16-bit data width */ + __gpio_as_func0(32*2+23); /* CS3# */ + __gpio_as_func0(32*2+25); /* RD# */ + __gpio_as_func0(32*2+26); /* WR# */ + + REG_EMC_SMCR3 &= ~EMC_SMCR_BW_MASK; + REG_EMC_SMCR3 |= EMC_SMCR_BW_16BIT; +#endif /* CONFIG_SOC_JZ4750 */ + + __gpio_as_irq_high_level(GPIO_NET_INT); /* irq */ + __gpio_disable_pull(GPIO_NET_INT); /* disable pull */ +} + +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 = (cirrus_t *) dev->priv; + 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 = (cirrus_t *) dev->priv; + 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; + + if (dev->priv == NULL) { + return IRQ_NONE; + } + + priv = (cirrus_t *) dev->priv; + + 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 = (cirrus_t *) dev->priv; + 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); + + /* enable irq */ + __gpio_unmask_irq(GPIO_NET_INT); + + //MOD_INC_USE_COUNT; + return (0); +} + +static int cirrus_stop (struct net_device *dev) +{ + /* disable irq */ + __gpio_mask_irq(GPIO_NET_INT); + + /* 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 = (cirrus_t *) dev->priv; + 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 + */ + +/* + * Driver initialization routines + */ + +int __init cirrus_probe(void) +{ + static cirrus_t priv; + int i; + u16 value; + + printk ("Jz CS8900A driver for Linux (V0.02)\n"); + + /* Init hardware for PAVO board */ + gpio_init_cs8900(); + + /* Allocate ethernet device */ + dev = alloc_etherdev(sizeof(struct net_device)); + + memset (&priv,0,sizeof (cirrus_t)); + + ether_setup (dev); + + dev->open = cirrus_start; + dev->stop = cirrus_stop; + dev->hard_start_xmit = cirrus_send_start; + dev->get_stats = cirrus_get_stats; + dev->set_multicast_list = cirrus_set_receive_mode; + dev->set_mac_address = cirrus_set_mac_address; + dev->tx_timeout = cirrus_transmit_timeout; + dev->watchdog_timeo = 5 * HZ; + + 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] = 0x9c; + dev->dev_addr[3] = 0x61; + dev->dev_addr[4] = 0xcf; + dev->dev_addr[5] = 0x16; + } + dev->if_port = IF_PORT_10BASET; + dev->priv = (void *) &priv; + + dev->base_addr = CIRRUS_DEFAULT_IO; + dev->irq = CIRRUS_DEFAULT_IRQ; + + + /* 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 "); +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/target/linux/xburst/files-2.6.27/drivers/net/jzcs8900a.h b/target/linux/xburst/files-2.6.27/drivers/net/jzcs8900a.h new file mode 100644 index 000000000..68d76bb0b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/net/jzcs8900a.h @@ -0,0 +1,235 @@ +#ifndef JZCS8900A_H +#define JZCS8900A_H + +/* + * linux/drivers/net/jzcs8900a.h + * + * Author: Lucifer + * + * 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/target/linux/xburst/files-2.6.27/drivers/power/jz_battery.c b/target/linux/xburst/files-2.6.27/drivers/power/jz_battery.c new file mode 100755 index 000000000..80b37472e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/power/jz_battery.c @@ -0,0 +1,298 @@ +/* + * linux/drivers/power/jz_battery + * + * Battery measurement code for Ingenic JZ SOC. + * + * based on tosa_battery.c + * + * Copyright (C) 2008 Marek Vasut + * + * 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 +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_POWER_SUPPLY_DEBUG +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) while(0){} +#endif + +#define JZ_BAT_MAX_VOLTAGE 4200000 // uV +#define JZ_BAT_MIN_VOLTAGE 3600000 + +static DEFINE_MUTEX(bat_lock); +struct workqueue_struct *monitor_wqueue; +struct delayed_work bat_work; +struct mutex work_lock; + +int bat_status = POWER_SUPPLY_STATUS_DISCHARGING; + +extern unsigned int jz_read_battery(void); + + +/********************************************************************* + * Power + *********************************************************************/ + +static int jz_get_power_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + if (psy->type == POWER_SUPPLY_TYPE_MAINS) + val->intval = !__gpio_get_pin(GPIO_DC_DETE_N); + else + val->intval = __gpio_get_pin(GPIO_USB_DETE); + break; + default: + return -EINVAL; + } + + return 0; +} + +static enum power_supply_property jz_power_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static struct power_supply jz_ac = { + .name = "ac", + .type = POWER_SUPPLY_TYPE_MAINS, + .properties = jz_power_props, + .num_properties = ARRAY_SIZE(jz_power_props), + .get_property = jz_get_power_prop, +}; + +static struct power_supply jz_usb = { + .name = "usb", + .type = POWER_SUPPLY_TYPE_USB, + .properties = jz_power_props, + .num_properties = ARRAY_SIZE(jz_power_props), + .get_property = jz_get_power_prop, +}; + + +/********************************************************************* + * Battery properties + *********************************************************************/ + +static unsigned long jz_read_bat(struct power_supply *bat_ps) +{ + unsigned long val; + if (CFG_PBAT_DIV == 1) + val = (((unsigned long long)jz_read_battery() * 7500000)) >> 12; + else + val = (((unsigned long long)jz_read_battery() * CFG_PBAT_DIV * 2500000)) >> 12; + dprintk("--raw_batter_vol=%d uV\n", val); + return val; +} + +static int jz_bat_get_property(struct power_supply *bat_ps, + enum power_supply_property psp, + union power_supply_propval *val) +{ + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = bat_status; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; + break; + case POWER_SUPPLY_PROP_HEALTH: + if(jz_read_bat(bat_ps) < 3600000) { + dprintk("--battery dead\n"); + val->intval = POWER_SUPPLY_HEALTH_DEAD; + } else { + dprintk("--battery good\n"); + val->intval = POWER_SUPPLY_HEALTH_GOOD; + } + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = (jz_read_bat(bat_ps) - 3600000) * 100 / (4200000 - 3600000); + if (val->intval > 100) + val->intval = 100; + dprintk("--battery_capacity=%d\%\n",val->intval); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = jz_read_bat(bat_ps); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = JZ_BAT_MAX_VOLTAGE; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = JZ_BAT_MIN_VOLTAGE; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = 1; + break; + case POWER_SUPPLY_PROP_TEMP: + case POWER_SUPPLY_PROP_VOL: + val->intval = 0; // reading TEMP and VOL aren't supported + break; + default: + return -EINVAL; + } + return 0; +} + +static void jz_bat_external_power_changed(struct power_supply *bat_ps) +{ + cancel_delayed_work(&bat_work); + queue_delayed_work(monitor_wqueue, &bat_work, HZ/10); +} + +static char *status_text[] = { + [POWER_SUPPLY_STATUS_UNKNOWN] = "Unknown", + [POWER_SUPPLY_STATUS_CHARGING] = "Charging", + [POWER_SUPPLY_STATUS_DISCHARGING] = "Discharging", + [POWER_SUPPLY_STATUS_NOT_CHARGING] = "Not charging", +}; + +static void jz_bat_update(struct power_supply *bat_ps) +{ + int old_status = bat_status; + static unsigned long old_batt_vol = 0; + unsigned long batt_vol = jz_read_bat(bat_ps); + mutex_lock(&work_lock); + + if(!__gpio_get_pin(GPIO_CHARG_STAT_N)) + bat_status = POWER_SUPPLY_STATUS_CHARGING; + else { + bat_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + } + + dprintk("--battery status=%s\n", status_text[bat_status]); + if ((old_status != bat_status) || + (old_batt_vol - batt_vol > 50000)) { + pr_debug("%s %s -> %s\n", bat_ps->name, + status_text[old_status], + status_text[bat_status]); + power_supply_changed(bat_ps); + } + + old_batt_vol = batt_vol; + mutex_unlock(&work_lock); +} + +static enum power_supply_property jz_bat_main_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_CAPACITY, /* in percents! */ + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_VOL, +}; + +struct power_supply bat_ps = { + .name = "battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = jz_bat_main_props, + .num_properties = ARRAY_SIZE(jz_bat_main_props), + .get_property = jz_bat_get_property, + .external_power_changed = jz_bat_external_power_changed, + .use_for_apm = 1, +}; + +static void jz_bat_work(struct work_struct *work) +{ + const int interval = HZ * 6; + + jz_bat_update(&bat_ps); + queue_delayed_work(monitor_wqueue, &bat_work, interval); +} + +#ifdef CONFIG_PM +static int jz_bat_suspend(struct platform_device *dev, pm_message_t state) +{ + bat_status = POWER_SUPPLY_STATUS_UNKNOWN; + + return 0; +} + +static int jz_bat_resume(struct platform_device *dev) +{ + bat_status = POWER_SUPPLY_STATUS_UNKNOWN; + cancel_delayed_work(&bat_work); + queue_delayed_work(monitor_wqueue, &bat_work, HZ/10); + + return 0; +} +#else +#define jz_bat_suspend NULL +#define jz_bat_resume NULL +#endif + +static int __devinit jz_bat_probe(struct platform_device *dev) +{ + int ret = 0; + printk("JZ battery init.\n"); + mutex_init(&work_lock); + + INIT_DELAYED_WORK(&bat_work, jz_bat_work); + + __gpio_disable_pull(GPIO_USB_DETE); + + power_supply_register(&dev->dev, &jz_ac); + power_supply_register(&dev->dev, &jz_usb); + + ret = power_supply_register(&dev->dev, &bat_ps); + if (!ret) { + monitor_wqueue = create_singlethread_workqueue("jz_battery"); + if (!monitor_wqueue) { + return -ESRCH; + } + queue_delayed_work(monitor_wqueue, &bat_work, HZ * 1); + } + + return ret; +} + +static int __devexit jz_bat_remove(struct platform_device *dev) +{ + power_supply_unregister(&bat_ps); + return 0; +} + +static struct platform_driver jz_bat_driver = { + .driver.name = "jz-battery", + .driver.owner = THIS_MODULE, + .probe = jz_bat_probe, + .remove = __devexit_p(jz_bat_remove), + .suspend = jz_bat_suspend, + .resume = jz_bat_resume, +}; + +static int __init jz_bat_init(void) +{ + platform_device_register_simple("jz-battery", 0, NULL, 0); + return platform_driver_register(&jz_bat_driver); +} + +static void __exit jz_bat_exit(void) +{ + platform_driver_unregister(&jz_bat_driver); +} + +module_init(jz_bat_init); +module_exit(jz_bat_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marek Vasut "); +MODULE_DESCRIPTION("Palm T|X battery driver"); diff --git a/target/linux/xburst/files-2.6.27/drivers/rtc/alarm.c b/target/linux/xburst/files-2.6.27/drivers/rtc/alarm.c new file mode 100755 index 000000000..c20ebffb8 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/rtc/alarm.c @@ -0,0 +1,574 @@ +/* drivers/rtc/alarm.c + * + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ANDROID_ALARM_PRINT_ERRORS (1U << 0) +#define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1) +#define ANDROID_ALARM_PRINT_INFO (1U << 2) +#define ANDROID_ALARM_PRINT_IO (1U << 3) +#define ANDROID_ALARM_PRINT_INT (1U << 4) +#define ANDROID_ALARM_PRINT_FLOW (1U << 5) + +#if 0 +#define ANDROID_ALARM_DPRINTF_MASK (~0) +#define ANDROID_ALARM_DPRINTF(debug_level_mask, args...) \ + do { \ + if (ANDROID_ALARM_DPRINTF_MASK & debug_level_mask) { \ + printk(args); \ + } \ + } while (0) +#else +#define ANDROID_ALARM_DPRINTF(args...) +#endif + +#define ANDROID_ALARM_WAKEUP_MASK ( \ + ANDROID_ALARM_RTC_WAKEUP_MASK | \ + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK) + +/* support old usespace code */ +#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */ +#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t) + +static struct rtc_device *alarm_rtc_dev; +static int alarm_opened; +static DEFINE_SPINLOCK(alarm_slock); +static DEFINE_MUTEX(alarm_setrtc_mutex); +static struct wake_lock alarm_wake_lock; +static struct wake_lock alarm_rtc_wake_lock; +static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue); +static uint32_t alarm_pending; +static uint32_t alarm_enabled; +static uint32_t wait_pending; +static struct platform_device *alarm_platform_dev; +static struct hrtimer alarm_timer[ANDROID_ALARM_TYPE_COUNT]; +static struct timespec alarm_time[ANDROID_ALARM_TYPE_COUNT]; +static struct timespec elapsed_rtc_delta; + +static void alarm_start_hrtimer(enum android_alarm_type alarm_type) +{ + struct timespec hr_alarm_time; + if (!(alarm_enabled & (1U << alarm_type))) + return; + hr_alarm_time = alarm_time[alarm_type]; + if (alarm_type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP || + alarm_type == ANDROID_ALARM_ELAPSED_REALTIME) + set_normalized_timespec(&hr_alarm_time, + hr_alarm_time.tv_sec + elapsed_rtc_delta.tv_sec, + hr_alarm_time.tv_nsec + elapsed_rtc_delta.tv_nsec); + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_FLOW, + "alarm start hrtimer %d at %ld.%09ld\n", + alarm_type, hr_alarm_time.tv_sec, hr_alarm_time.tv_nsec); + hrtimer_start(&alarm_timer[alarm_type], + timespec_to_ktime(hr_alarm_time), HRTIMER_MODE_ABS); +} + +static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int rv = 0; + unsigned long flags; + int i; + struct timespec new_alarm_time; + struct timespec new_rtc_time; + struct timespec tmp_time; + struct rtc_time rtc_new_rtc_time; + enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd); + uint32_t alarm_type_mask = 1U << alarm_type; + + if (alarm_type >= ANDROID_ALARM_TYPE_COUNT) + return -EINVAL; + + if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) { + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + return -EPERM; + if (file->private_data == NULL && + cmd != ANDROID_ALARM_SET_RTC) { + spin_lock_irqsave(&alarm_slock, flags); + if (alarm_opened) { + spin_unlock_irqrestore(&alarm_slock, flags); + return -EBUSY; + } + alarm_opened = 1; + file->private_data = (void *)1; + spin_unlock_irqrestore(&alarm_slock, flags); + } + } + + switch (ANDROID_ALARM_BASE_CMD(cmd)) { + case ANDROID_ALARM_CLEAR(0): + spin_lock_irqsave(&alarm_slock, flags); + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_IO, + "alarm %d clear\n", alarm_type); + hrtimer_try_to_cancel(&alarm_timer[alarm_type]); + if (alarm_pending) { + alarm_pending &= ~alarm_type_mask; + if (!alarm_pending && !wait_pending) + wake_unlock(&alarm_wake_lock); + } + alarm_enabled &= ~alarm_type_mask; + spin_unlock_irqrestore(&alarm_slock, flags); + break; + + case ANDROID_ALARM_SET_OLD: + case ANDROID_ALARM_SET_AND_WAIT_OLD: + if (get_user(new_alarm_time.tv_sec, (int __user *)arg)) { + rv = -EFAULT; + goto err1; + } + new_alarm_time.tv_nsec = 0; + goto from_old_alarm_set; + + case ANDROID_ALARM_SET_AND_WAIT(0): + case ANDROID_ALARM_SET(0): + if (copy_from_user(&new_alarm_time, (void __user *)arg, + sizeof(new_alarm_time))) { + rv = -EFAULT; + goto err1; + } +from_old_alarm_set: + spin_lock_irqsave(&alarm_slock, flags); + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_IO, + "alarm %d set %ld.%09ld\n", alarm_type, + new_alarm_time.tv_sec, new_alarm_time.tv_nsec); + alarm_time[alarm_type] = new_alarm_time; + alarm_enabled |= alarm_type_mask; + alarm_start_hrtimer(alarm_type); + spin_unlock_irqrestore(&alarm_slock, flags); + if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0) + && cmd != ANDROID_ALARM_SET_AND_WAIT_OLD) + break; + /* fall though */ + case ANDROID_ALARM_WAIT: + spin_lock_irqsave(&alarm_slock, flags); + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_IO, "alarm wait\n"); + if (!alarm_pending && wait_pending) { + wake_unlock(&alarm_wake_lock); + wait_pending = 0; + } + spin_unlock_irqrestore(&alarm_slock, flags); + rv = wait_event_interruptible(alarm_wait_queue, alarm_pending); + if (rv) + goto err1; + spin_lock_irqsave(&alarm_slock, flags); + rv = alarm_pending; + wait_pending = 1; + alarm_pending = 0; + if (rv & ANDROID_ALARM_WAKEUP_MASK) + wake_unlock(&alarm_rtc_wake_lock); + spin_unlock_irqrestore(&alarm_slock, flags); + break; + case ANDROID_ALARM_SET_RTC: + if (copy_from_user(&new_rtc_time, (void __user *)arg, + sizeof(new_rtc_time))) { + rv = -EFAULT; + goto err1; + } + rtc_time_to_tm(new_rtc_time.tv_sec, &rtc_new_rtc_time); + + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_IO, + "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n", + new_rtc_time.tv_sec, new_rtc_time.tv_nsec, + rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min, + rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1, + rtc_new_rtc_time.tm_mday, + rtc_new_rtc_time.tm_year + 1900); + + mutex_lock(&alarm_setrtc_mutex); + spin_lock_irqsave(&alarm_slock, flags); + for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) + hrtimer_try_to_cancel(&alarm_timer[i]); + getnstimeofday(&tmp_time); + elapsed_rtc_delta = timespec_sub(elapsed_rtc_delta, + timespec_sub(tmp_time, new_rtc_time)); + spin_unlock_irqrestore(&alarm_slock, flags); + rv = do_settimeofday(&new_rtc_time); + spin_lock_irqsave(&alarm_slock, flags); + for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) + alarm_start_hrtimer(i); + spin_unlock_irqrestore(&alarm_slock, flags); + if (rv < 0) { + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_ERRORS, + "Failed to set time\n"); + mutex_unlock(&alarm_setrtc_mutex); + goto err1; + } + rv = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time); + spin_lock_irqsave(&alarm_slock, flags); + alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK; + wake_up(&alarm_wait_queue); + spin_unlock_irqrestore(&alarm_slock, flags); + mutex_unlock(&alarm_setrtc_mutex); + if (rv < 0) { + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_ERRORS, + "Failed to set RTC, time will be lost on reboot\n"); + goto err1; + } + break; + case ANDROID_ALARM_GET_TIME(0): + mutex_lock(&alarm_setrtc_mutex); + spin_lock_irqsave(&alarm_slock, flags); + if (alarm_type != ANDROID_ALARM_SYSTEMTIME) { + getnstimeofday(&tmp_time); + if (alarm_type >= ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP) + tmp_time = timespec_sub(tmp_time, + elapsed_rtc_delta); + } else + ktime_get_ts(&tmp_time); + spin_unlock_irqrestore(&alarm_slock, flags); + mutex_unlock(&alarm_setrtc_mutex); + if (copy_to_user((void __user *)arg, &tmp_time, + sizeof(tmp_time))) { + rv = -EFAULT; + goto err1; + } + break; + + default: + rv = -EINVAL; + goto err1; + } +err1: + return rv; +} + +static int alarm_open(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + return 0; +} + +static int alarm_release(struct inode *inode, struct file *file) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&alarm_slock, flags); + if (file->private_data != 0) { + for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) { + uint32_t alarm_type_mask = 1U << i; + if (alarm_enabled & alarm_type_mask) { + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO, + "alarm_release: clear alarm, " + "pending %d\n", + !!(alarm_pending & alarm_type_mask)); + alarm_enabled &= ~alarm_type_mask; + } + spin_unlock_irqrestore(&alarm_slock, flags); + hrtimer_cancel(&alarm_timer[i]); + spin_lock_irqsave(&alarm_slock, flags); + } + if (alarm_pending | wait_pending) { + if (alarm_pending) + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO, + "alarm_release: clear pending alarms " + "%x\n", alarm_pending); + wake_unlock(&alarm_wake_lock); + wait_pending = 0; + alarm_pending = 0; + } + alarm_opened = 0; + } + spin_unlock_irqrestore(&alarm_slock, flags); + return 0; +} + +static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer) +{ + unsigned long flags; + enum android_alarm_type alarm_type = (timer - alarm_timer); + uint32_t alarm_type_mask = 1U << alarm_type; + + + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INT, + "alarm_timer_triggered type %d\n", alarm_type); + spin_lock_irqsave(&alarm_slock, flags); + if (alarm_enabled & alarm_type_mask) { + wake_lock_timeout(&alarm_wake_lock, 5 * HZ); + alarm_enabled &= ~alarm_type_mask; + alarm_pending |= alarm_type_mask; + wake_up(&alarm_wait_queue); + } + spin_unlock_irqrestore(&alarm_slock, flags); + return HRTIMER_NORESTART; +} + +static void alarm_triggered_func(void *p) +{ + struct rtc_device *rtc = alarm_rtc_dev; + if (!(rtc->irq_data & RTC_AF)) + return; + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INT, "rtc alarm triggered\n"); + wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ); +} + +void save_time_delta(struct timespec *delta, struct timespec *rtc) +{ + set_normalized_timespec(delta, + xtime.tv_sec - rtc->tv_sec, + xtime.tv_nsec - rtc->tv_nsec); +} + +int alarm_suspend(struct platform_device *pdev, pm_message_t state) +{ + int err = 0; + unsigned long flags; + struct rtc_wkalrm rtc_alarm; + struct rtc_time rtc_current_rtc_time; + unsigned long rtc_current_time; + unsigned long rtc_alarm_time; + struct timespec rtc_current_timespec; + struct timespec rtc_delta; + struct timespec elapsed_realtime_alarm_time; + + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_FLOW, + "alarm_suspend(%p, %d)\n", pdev, state.event); + spin_lock_irqsave(&alarm_slock, flags); + if (alarm_pending && !wake_lock_active(&alarm_wake_lock)) { + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO, + "alarm pending\n"); + err = -EBUSY; + goto err1; + } + if (alarm_enabled & ANDROID_ALARM_WAKEUP_MASK) { + spin_unlock_irqrestore(&alarm_slock, flags); + if (alarm_enabled & ANDROID_ALARM_RTC_WAKEUP_MASK) + hrtimer_cancel(&alarm_timer[ANDROID_ALARM_RTC_WAKEUP]); + if (alarm_enabled & ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK) + hrtimer_cancel(&alarm_timer[ + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP]); + + rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time); + rtc_current_timespec.tv_nsec = 0; + rtc_tm_to_time(&rtc_current_rtc_time, + &rtc_current_timespec.tv_sec); + save_time_delta(&rtc_delta, &rtc_current_timespec); + set_normalized_timespec(&elapsed_realtime_alarm_time, + alarm_time[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP] + .tv_sec + elapsed_rtc_delta.tv_sec, + alarm_time[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP] + .tv_nsec + elapsed_rtc_delta.tv_nsec); + if ((alarm_enabled & ANDROID_ALARM_RTC_WAKEUP_MASK) && + (!(alarm_enabled & + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK) || + timespec_compare(&alarm_time[ANDROID_ALARM_RTC_WAKEUP], + &elapsed_realtime_alarm_time) < 0)) + rtc_alarm_time = timespec_sub( + alarm_time[ANDROID_ALARM_RTC_WAKEUP], + rtc_delta).tv_sec; + else + rtc_alarm_time = timespec_sub( + elapsed_realtime_alarm_time, rtc_delta).tv_sec; + rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time); + rtc_alarm.enabled = 1; + rtc_set_alarm(alarm_rtc_dev, &rtc_alarm); + rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time); + rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time); + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO, + "rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n", + rtc_alarm_time, rtc_current_time, + rtc_delta.tv_sec, rtc_delta.tv_nsec); + if (rtc_current_time + 1 >= rtc_alarm_time) { + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO, + "alarm about to go off\n"); + memset(&rtc_alarm, 0, sizeof(rtc_alarm)); + rtc_alarm.enabled = 0; + rtc_set_alarm(alarm_rtc_dev, &rtc_alarm); + + spin_lock_irqsave(&alarm_slock, flags); + wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ); + alarm_start_hrtimer(ANDROID_ALARM_RTC_WAKEUP); + alarm_start_hrtimer( + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP); + err = -EBUSY; + spin_unlock_irqrestore(&alarm_slock, flags); + } + } else { +err1: + spin_unlock_irqrestore(&alarm_slock, flags); + } + return err; +} + +int alarm_resume(struct platform_device *pdev) +{ + struct rtc_wkalrm alarm; + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_FLOW, + "alarm_resume(%p)\n", pdev); + if (alarm_enabled & ANDROID_ALARM_WAKEUP_MASK) { + memset(&alarm, 0, sizeof(alarm)); + alarm.enabled = 0; + rtc_set_alarm(alarm_rtc_dev, &alarm); + alarm_start_hrtimer(ANDROID_ALARM_RTC_WAKEUP); + alarm_start_hrtimer(ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP); + } + return 0; +} + +static struct rtc_task alarm_rtc_task = { + .func = alarm_triggered_func +}; + +static struct file_operations alarm_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = alarm_ioctl, + .open = alarm_open, + .release = alarm_release, +}; + +static struct miscdevice alarm_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "alarm", + .fops = &alarm_fops, +}; + +static int rtc_alarm_add_device(struct device *dev, + struct class_interface *class_intf) +{ + int err; + struct rtc_device *rtc = to_rtc_device(dev); + + mutex_lock(&alarm_setrtc_mutex); + + if (alarm_rtc_dev) { + err = -EBUSY; + goto err1; + } + + err = misc_register(&alarm_device); + if (err) + goto err1; + alarm_platform_dev = + platform_device_register_simple("alarm", -1, NULL, 0); + if (IS_ERR(alarm_platform_dev)) { + err = PTR_ERR(alarm_platform_dev); + goto err2; + } + err = rtc_irq_register(rtc, &alarm_rtc_task); + if (err) + goto err3; + alarm_rtc_dev = rtc; + mutex_unlock(&alarm_setrtc_mutex); + + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO, "alarm: parent %p\n", + alarm_platform_dev->dev.power.pm_parent); + return 0; + +err3: + platform_device_unregister(alarm_platform_dev); +err2: + misc_deregister(&alarm_device); +err1: + mutex_unlock(&alarm_setrtc_mutex); + return err; +} + +static void rtc_alarm_remove_device(struct device *dev, + struct class_interface *class_intf) +{ + if (dev == &alarm_rtc_dev->dev) { + rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task); + platform_device_unregister(alarm_platform_dev); + misc_deregister(&alarm_device); + alarm_rtc_dev = NULL; + } +} + +static struct class_interface rtc_alarm_interface = { + .add_dev = &rtc_alarm_add_device, + .remove_dev = &rtc_alarm_remove_device, +}; + +static struct platform_driver alarm_driver = { + .suspend = alarm_suspend, + .resume = alarm_resume, + .driver = { + .name = "alarm" + } +}; + +static int __init alarm_late_init(void) +{ + unsigned long flags; + struct timespec system_time; + + /* this needs to run after the rtc is read at boot */ + spin_lock_irqsave(&alarm_slock, flags); + /* We read the current rtc and system time so we can later calulate + * elasped realtime to be (boot_systemtime + rtc - boot_rtc) == + * (rtc - (boot_rtc - boot_systemtime)) + */ + getnstimeofday(&elapsed_rtc_delta); + ktime_get_ts(&system_time); + elapsed_rtc_delta = timespec_sub(elapsed_rtc_delta, system_time); + spin_unlock_irqrestore(&alarm_slock, flags); + + ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO, + "alarm_late_init: rtc to elapsed realtime delta %ld.%09ld\n", + elapsed_rtc_delta.tv_sec, elapsed_rtc_delta.tv_nsec); + return 0; +} + +static int __init alarm_init(void) +{ + int err; + int i; + + for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { + hrtimer_init(&alarm_timer[i], CLOCK_REALTIME, HRTIMER_MODE_ABS); + alarm_timer[i].function = alarm_timer_triggered; + } + hrtimer_init(&alarm_timer[ANDROID_ALARM_SYSTEMTIME], + CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + alarm_timer[ANDROID_ALARM_SYSTEMTIME].function = alarm_timer_triggered; + err = platform_driver_register(&alarm_driver); + if (err < 0) + goto err1; + wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm"); + wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc"); + rtc_alarm_interface.class = rtc_class; + err = class_interface_register(&rtc_alarm_interface); + if (err < 0) + goto err2; + + return 0; + +err2: + wake_lock_destroy(&alarm_rtc_wake_lock); + wake_lock_destroy(&alarm_wake_lock); + platform_driver_unregister(&alarm_driver); +err1: + return err; +} + +static void __exit alarm_exit(void) +{ + class_interface_unregister(&rtc_alarm_interface); + wake_lock_destroy(&alarm_rtc_wake_lock); + wake_lock_destroy(&alarm_wake_lock); + platform_driver_unregister(&alarm_driver); +} + +late_initcall(alarm_late_init); +module_init(alarm_init); +module_exit(alarm_exit); + diff --git a/target/linux/xburst/files-2.6.27/drivers/rtc/rtc-jz4750.c b/target/linux/xburst/files-2.6.27/drivers/rtc/rtc-jz4750.c new file mode 100755 index 000000000..2d84d2c50 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/rtc/rtc-jz4750.c @@ -0,0 +1,542 @@ +/* + * Real Time Clock interface for Jz4750/Jz4755. + * + * Copyright (C) 2005-2009, Ingenic Semiconductor Inc. + * + * Author: Richard Feng + * Regen Huang + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TIMER_FREQ CLOCK_TICK_RATE + +/* The divider is decided by the RTC clock frequency. */ +#define RTC_FREQ_DIVIDER (32768 - 1) + +/* Default time for the first-time power on */ +static struct rtc_time default_tm = { + .tm_year = (2009 - 1900), // year 2009 + .tm_mon = (10 - 1), // month 10 + .tm_mday = 1, // day 1 + .tm_hour = 12, + .tm_min = 0, + .tm_sec = 0 +}; + +static unsigned long rtc_freq = 1024; +static struct rtc_time rtc_alarm; +static DEFINE_SPINLOCK(jz4750_rtc_lock); + +static inline int rtc_periodic_alarm(struct rtc_time *tm) +{ + return (tm->tm_year == -1) || + ((unsigned)tm->tm_mon >= 12) || + ((unsigned)(tm->tm_mday - 1) >= 31) || + ((unsigned)tm->tm_hour > 23) || + ((unsigned)tm->tm_min > 59) || + ((unsigned)tm->tm_sec > 59); +} + +/* + * Calculate the next alarm time given the requested alarm time mask + * and the current time. + */ +static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm) +{ + unsigned long next_time; + unsigned long now_time; + + next->tm_year = now->tm_year; + next->tm_mon = now->tm_mon; + next->tm_mday = now->tm_mday; + next->tm_hour = alrm->tm_hour; + next->tm_min = alrm->tm_min; + next->tm_sec = alrm->tm_sec; + + rtc_tm_to_time(now, &now_time); + rtc_tm_to_time(next, &next_time); + + if (next_time < now_time) { + /* Advance one day */ + next_time += 60 * 60 * 24; + rtc_time_to_tm(next_time, next); + } +} + +static int rtc_update_alarm(struct rtc_time *alrm) +{ + struct rtc_time alarm_tm, now_tm; + unsigned long now, time; + int ret; + + do { + now = REG_RTC_RSR; + rtc_time_to_tm(now, &now_tm); + rtc_next_alarm_time(&alarm_tm, &now_tm, alrm); + ret = rtc_tm_to_time(&alarm_tm, &time); + if (ret != 0) + break; + while ( !__rtc_write_ready()); + REG_RTC_RCR = REG_RTC_RCR & ~( RTC_RCR_1HZIE | RTC_RCR_1HZ | RTC_RCR_AIE | RTC_RCR_AF | RTC_RCR_AE); + while ( !__rtc_write_ready()); + REG_RTC_RSAR = time; + while ( !__rtc_write_ready()); + } while (now != REG_RTC_RSR); + return ret; +} + +static irqreturn_t jz4750_rtc_interrupt(int irq, void *dev_id) +{ + struct platform_device *pdev = to_platform_device(dev_id); + struct rtc_device *rtc = platform_get_drvdata(pdev); + unsigned int rtsr; + unsigned long events = 0; + + spin_lock(&jz4750_rtc_lock); + rtsr = REG_RTC_RCR; + + if ((rtsr & (RTC_RCR_1HZIE | RTC_RCR_AE | RTC_RCR_AIE)) == (RTC_RCR_1HZIE | RTC_RCR_AE | RTC_RCR_AIE)) { + //printk("1Hz&alarm!\n"); + while ( !__rtc_write_ready()); + REG_RTC_RCR = rtsr & ~(RTC_RCR_1HZ | RTC_RCR_1HZIE | RTC_RCR_AF | RTC_RCR_AIE); + while ( !__rtc_write_ready()); + if (rtsr & RTC_RCR_AF) { + rtsr &= ~RTC_RCR_AIE; + while ( !__rtc_write_ready()); + __rtc_disable_alarm_irq(); + while ( !__rtc_write_ready()); + __rtc_clear_alarm_flag(); + while ( !__rtc_write_ready()); + __rtc_disable_alarm(); + } + + /* update irq data & counter */ + if (rtsr & RTC_RCR_AF) + events |= RTC_AF | RTC_IRQF; + if (rtsr & RTC_RCR_1HZ) + events |= RTC_UF | RTC_IRQF; + rtc_update_irq(rtc, 1, events); + if ((rtsr & RTC_RCR_AF) && rtc_periodic_alarm(&rtc_alarm)) + rtc_update_alarm(&rtc_alarm); + if (rtsr & RTC_RCR_1HZ) { + if ((rtsr & RTC_RCR_AF) == 0) { + while ( !__rtc_write_ready()); + __rtc_enable_alarm_irq(); + } + while ( !__rtc_write_ready()); + __rtc_enable_1Hz_irq(); + while ( !__rtc_write_ready()); + } + + } else if ((rtsr & (RTC_RCR_1HZ | RTC_RCR_1HZIE)) == (RTC_RCR_1HZ | RTC_RCR_1HZIE)) { + //printk("1Hz!\n"); + while ( !__rtc_write_ready()); + REG_RTC_RCR = rtsr & ~(RTC_RCR_1HZ | RTC_RCR_1HZIE | RTC_RCR_AF | RTC_RCR_AIE); + while ( !__rtc_write_ready()); + REG_RTC_RCR |= RTC_RCR_1HZIE; + if (rtsr & RTC_RCR_1HZ) + events |= RTC_UF | RTC_IRQF; + rtc_update_irq(rtc, 1, events); + } else if ((rtsr & (RTC_RCR_AE | RTC_RCR_AIE | RTC_RCR_AF)) == (RTC_RCR_AE | RTC_RCR_AIE | RTC_RCR_AF)) { + //printk("alarm!\n"); + while ( !__rtc_write_ready()); + REG_RTC_RCR = rtsr & ~(RTC_RCR_1HZ | RTC_RCR_1HZIE | RTC_RCR_AF | RTC_RCR_AIE); + /* clear alarm interrupt if it has occurred */ + rtsr &= ~RTC_RCR_AIE; + events |= RTC_AF | RTC_IRQF; + rtc_update_irq(rtc, 1, events); + if (rtsr & RTC_RCR_AF && rtc_periodic_alarm(&rtc_alarm)) + rtc_update_alarm(&rtc_alarm); + } + spin_unlock(&jz4750_rtc_lock); + + return IRQ_HANDLED; +} + +#if 0 +static int rtc_timer1_count; +static irqreturn_t timer1_interrupt(int irq, void *dev_id) +{ + struct platform_device *pdev = to_platform_device(dev_id); + struct rtc_device *rtc = platform_get_drvdata(pdev); + + /* + * If we match for the first time, rtc_timer1_count will be 1. + * Otherwise, we wrapped around (very unlikely but + * still possible) so compute the amount of missed periods. + * The match reg is updated only when the data is actually retrieved + * to avoid unnecessary interrupts. + */ + OSSR = OSSR_M1; /* clear match on timer1 */ + + rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF); + + if (rtc_timer1_count == 1) + rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))); + + return IRQ_HANDLED; +} +#endif + +#if 0 +static int jz4750_rtc_read_callback(struct device *dev, int data) +{ + if (data & RTC_PF) { + /* interpolate missed periods and set match for the next */ + unsigned long period = TIMER_FREQ/rtc_freq; + unsigned long oscr = OSCR; + unsigned long osmr1 = OSMR1; + unsigned long missed = (oscr - osmr1)/period; + data += missed << 8; + OSSR = OSSR_M1; /* clear match on timer 1 */ + OSMR1 = osmr1 + (missed + 1)*period; + /* Ensure we didn't miss another match in the mean time. + * Here we compare (match - OSCR) 8 instead of 0 -- + * see comment in pxa_timer_interrupt() for explanation. + */ + while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) { + data += 0x100; + OSSR = OSSR_M1; /* clear match on timer 1 */ + OSMR1 = osmr1 + period; + } + } + return data; +} +#endif + +static int jz4750_rtc_open(struct device *dev) +{ + int ret; + + ret = request_irq(IRQ_RTC, jz4750_rtc_interrupt, IRQF_DISABLED, + "rtc 1Hz and alarm", dev); + if (ret) { + dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC); + goto fail_ui; + } + + /*ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED, + "rtc timer", dev); + if (ret) { + dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1); + goto fail_pi; + }*/ + + return 0; + + fail_ui: + free_irq(IRQ_RTC, dev); + return ret; +} + +static void jz4750_rtc_release(struct device *dev) +{ + spin_lock_irq(&jz4750_rtc_lock); + + spin_unlock_irq(&jz4750_rtc_lock); + //free_irq(IRQ_OST1, dev); + free_irq(IRQ_RTC, dev); +} + + +static int jz4750_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + switch(cmd) { + case RTC_AIE_OFF: + spin_lock_irq(&jz4750_rtc_lock); + while ( !__rtc_write_ready()); + __rtc_disable_alarm_irq(); + while ( !__rtc_write_ready()); + __rtc_disable_alarm(); + while ( !__rtc_write_ready()); + spin_unlock_irq(&jz4750_rtc_lock); + return 0; + case RTC_AIE_ON: + spin_lock_irq(&jz4750_rtc_lock); + while ( !__rtc_write_ready()); + __rtc_enable_alarm(); + while ( !__rtc_write_ready()); + __rtc_enable_alarm_irq(); + while ( !__rtc_write_ready()); + spin_unlock_irq(&jz4750_rtc_lock); + return 0; + case RTC_UIE_OFF: + spin_lock_irq(&jz4750_rtc_lock); + while ( !__rtc_write_ready()); + __rtc_disable_1Hz_irq(); + while ( !__rtc_write_ready()); + spin_unlock_irq(&jz4750_rtc_lock); + return 0; + case RTC_UIE_ON: + spin_lock_irq(&jz4750_rtc_lock); + while ( !__rtc_write_ready()); + __rtc_clear_1Hz_flag(); + while ( !__rtc_write_ready()); + __rtc_clear_alarm_flag(); + while ( !__rtc_write_ready()); + __rtc_enable_1Hz_irq(); + while ( !__rtc_write_ready()); + spin_unlock_irq(&jz4750_rtc_lock); + return 0; + case RTC_PIE_OFF: + spin_lock_irq(&jz4750_rtc_lock); + printk("no implement!\n"); + spin_unlock_irq(&jz4750_rtc_lock); + return 0; + case RTC_PIE_ON: + spin_lock_irq(&jz4750_rtc_lock); + printk("no implement!\n"); + spin_unlock_irq(&jz4750_rtc_lock); + return 0; + case RTC_IRQP_READ: + return put_user(rtc_freq, (unsigned long *)arg); + case RTC_IRQP_SET: + if (arg < 1 || arg > TIMER_FREQ) + return -EINVAL; + rtc_freq = arg; + return 0; + } + return -ENOIOCTLCMD; +} + +static int jz4750_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long time; + int ret; + + ret = rtc_tm_to_time(tm, &time); + if (ret == 0) { + while ( !__rtc_write_ready()); + REG_RTC_RSR = time; + while ( !__rtc_write_ready()); + } + return ret; +} + +static int jz4750_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + rtc_time_to_tm(REG_RTC_RSR, tm); + + if (rtc_valid_tm(tm) < 0) { + /* Set the default time */ + jz4750_rtc_set_time(dev, &default_tm); + + rtc_time_to_tm(REG_RTC_RSR, tm); + } + + return 0; +} + +static int jz4750_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + u32 rtc_rcr; + + rtc_time_to_tm(REG_RTC_RSAR, &rtc_alarm); + memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time)); + rtc_rcr = REG_RTC_RCR; + + alrm->enabled = (rtc_rcr & RTC_RCR_AIE) ? 1 : 0; + alrm->pending = (rtc_rcr & RTC_RCR_AF) ? 1 : 0; + return 0; +} + +static int jz4750_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + int ret; + + spin_lock_irq(&jz4750_rtc_lock); + ret = rtc_update_alarm(&alrm->time); + if (ret == 0) { + if (alrm->enabled) { + while ( !__rtc_write_ready()); + __rtc_enable_alarm(); + while ( !__rtc_write_ready()); + __rtc_enable_alarm_irq(); + while ( !__rtc_write_ready()); + } else { + while ( !__rtc_write_ready()); + __rtc_disable_alarm_irq(); + while ( !__rtc_write_ready()); + __rtc_disable_alarm(); + while ( !__rtc_write_ready()); + } + } + spin_unlock_irq(&jz4750_rtc_lock); + + return ret; +} + +static int jz4750_rtc_proc(struct device *dev, struct seq_file *seq) +{ + seq_printf(seq, "RTC regulator\t: 0x%08x\n", (u32) REG_RTC_RGR); + seq_printf(seq, "update_IRQ\t: %s\n", + (REG_RTC_RCR & RTC_RCR_1HZIE) ? "yes" : "no"); + /*seq_printf(seq, "periodic_IRQ\t: %s\n", + (OIER & OIER_E1) ? "yes" : "no");*/ + seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq); + + return 0; +} + +static const struct rtc_class_ops jz4750_rtc_ops = { + .open = jz4750_rtc_open, + //.read_callback = jz4750_rtc_read_callback, + .release = jz4750_rtc_release, + .ioctl = jz4750_rtc_ioctl, + .read_time = jz4750_rtc_read_time, + .set_time = jz4750_rtc_set_time, + .read_alarm = jz4750_rtc_read_alarm, + .set_alarm = jz4750_rtc_set_alarm, + .proc = jz4750_rtc_proc, +}; + +static int jz4750_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + + /* + * When we are powered on for the first time, init the rtc and reset time. + * + * For other situations, we remain the rtc status unchanged. + */ + if (__rtc_status_ppr_reset_occur()) { + /* We are powered on for the first time !!! */ + + printk("jz4750-rtc: rtc status reset by power-on\n"); + + /* select external 32K crystal as RTC clock */ + __cpm_select_rtcclk_rtc(); + + /* init rtc status */ + while ( !__rtc_write_ready()); + __rtc_disable_1Hz_irq(); + while ( !__rtc_write_ready()); + __rtc_disable_alarm_irq(); + while ( !__rtc_write_ready()); + __rtc_clear_alarm_flag(); + while ( !__rtc_write_ready()); + __rtc_clear_1Hz_flag(); + while ( !__rtc_write_ready()); + __rtc_disable_alarm(); + while ( !__rtc_write_ready()); + + /* Set 32768 rtc clocks per seconds */ + REG_RTC_RGR = RTC_FREQ_DIVIDER; + while ( !__rtc_write_ready()); + + /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */ + REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT); + while ( !__rtc_write_ready()); + + /* Set reset pin low-level assertion time after wakeup: must > 60ms */ + REG_RTC_HRCR = (60 << RTC_HRCR_BIT); + while ( !__rtc_write_ready()); + + /* Reset to the default time */ + jz4750_rtc_set_time(NULL, &default_tm); + while ( !__rtc_write_ready()); + + /* start rtc */ + __rtc_enabled(); + while ( !__rtc_write_ready()); + } + + /* clear all rtc flags */ + __rtc_clear_hib_stat_all(); + while ( !__rtc_write_ready()); + + device_init_wakeup(&pdev->dev, 1); + + rtc = rtc_device_register(pdev->name, &pdev->dev, &jz4750_rtc_ops, + THIS_MODULE); + + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + platform_set_drvdata(pdev, rtc); + + return 0; +} + +static int jz4750_rtc_remove(struct platform_device *pdev) +{ + struct rtc_device *rtc = platform_get_drvdata(pdev); + + while ( !__rtc_write_ready()); + __rtc_disable_1Hz_irq(); + while ( !__rtc_write_ready()); + __rtc_disable_alarm_irq(); + while ( !__rtc_write_ready()); + __rtc_disabled(); + + if (rtc) + rtc_device_unregister(rtc); + + return 0; +} + +#ifdef CONFIG_PM +static int jz4750_rtc_suspend(struct platform_device *pdev, pm_message_t state) +{ +// if (device_may_wakeup(&pdev->dev)) +// enable_irq_wake(IRQ_RTC); + return 0; +} + +static int jz4750_rtc_resume(struct platform_device *pdev) +{ +// if (device_may_wakeup(&pdev->dev)) +// disable_irq_wake(IRQ_RTC); + return 0; +} +#else +#define jz4750_rtc_suspend NULL +#define jz4750_rtc_resume NULL +#endif + +static struct platform_driver jz4750_rtc_driver = { + .probe = jz4750_rtc_probe, + .remove = jz4750_rtc_remove, + .suspend = jz4750_rtc_suspend, + .resume = jz4750_rtc_resume, + .driver = { + .name = "jz4750-rtc", + }, +}; + +static int __init jz4750_rtc_init(void) +{ + return platform_driver_register(&jz4750_rtc_driver); +} + +static void __exit jz4750_rtc_exit(void) +{ + platform_driver_unregister(&jz4750_rtc_driver); +} + +module_init(jz4750_rtc_init); +module_exit(jz4750_rtc_exit); + +MODULE_AUTHOR("Richard Feng "); +MODULE_DESCRIPTION("JZ4750 Realtime Clock Driver (RTC)"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:jz4750-rtc"); diff --git a/target/linux/xburst/files-2.6.27/drivers/usb/gadget/android.c b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/android.c new file mode 100755 index 000000000..d078d3dd2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/android.c @@ -0,0 +1,431 @@ +/* + * Gadget Driver for Android + * + * Copyright (C) 2008 Google, Inc. + * Author: Mike Lockwood + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +/* #define DEBUG */ +/* #define VERBOSE_DEBUG */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "f_mass_storage.h" +#include "f_adb.h" + +#include "gadget_chips.h" + +MODULE_AUTHOR("Mike Lockwood"); +MODULE_DESCRIPTION("Android Composite USB Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); + +static char *g_android_function = "mass"; +module_param_named(function, g_android_function, charp, S_IRUGO); + +static const char longname[] = "Gadget Android"; + +/* Default vendor and product IDs, overridden by platform data */ +#define VENDOR_ID 0x0BB4 +#define PRODUCT_ID 0x0001 +#define ADB_PRODUCT_ID 0x0C01 + +/* Platform data */ +static struct android_usb_platform_data android_platform_data = { + .vendor_id = 0x18D1, + .product_id = 0x0001, + .adb_product_id = 0x0002, + .version = 0x1, + .product_name = "USB Mass Storage", + .manufacturer_name = "Ingenic", + .serial_number = "01234567890ABCDEF", +}; + +/* LUN attribute table - Which also decides the amount of LUN */ +static lun_attr_t lun_attr_table[] = { + { /* LUN 0 */ + "Ingenic", /* LUN 0 - Vendor */ + "USB Disk", /* LUN 0 - Product */ + 0, + }, + { /* LUN 1 */ + "Ingenic", /* LUN 1 - Vendor */ + "SD Card Reader", /* LUN 1 - Product */ + 0, + }, +}; + +struct android_dev { + struct usb_gadget *gadget; + struct usb_composite_dev *cdev; + + int product_id; + int adb_product_id; + int version; + + int adb_enabled; + int nluns; +}; + +static atomic_t adb_enable_excl; +static struct android_dev *_android_dev; + +/* string IDs are assigned dynamically */ + +#define STRING_MANUFACTURER_IDX 0 +#define STRING_PRODUCT_IDX 1 +#define STRING_SERIAL_IDX 2 +#define STRING_MS_OS_IDX 3 + +#define STRING_MS_OS_ID 0xee + +/* String Table */ +static struct usb_string strings_dev[] = { + /* These dummy values should be overridden by platform data */ + [STRING_MANUFACTURER_IDX].s = "Android", + [STRING_PRODUCT_IDX].s = "Android", + [STRING_SERIAL_IDX].s = "0123456789ABCDEF", + [STRING_MS_OS_IDX].s = "Microsoft", + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab_dev = { + .language = 0x0409, /* en-us */ + .strings = strings_dev, +}; + +static struct usb_gadget_strings *dev_strings[] = { + &stringtab_dev, + NULL, +}; + +static struct usb_device_descriptor device_desc = { + .bLength = sizeof(device_desc), + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .idVendor = __constant_cpu_to_le16(VENDOR_ID), + .idProduct = __constant_cpu_to_le16(PRODUCT_ID), + .bcdDevice = __constant_cpu_to_le16(0xffff), + .bNumConfigurations = 1, +}; + +static int android_bind_config(struct usb_configuration *c) +{ + int ret; + + printk(KERN_DEBUG "android_bind_config\n"); + + if (!strcmp(g_android_function, "adb")) { + printk(KERN_INFO"Andorid Gadget: Function -> adb.\n"); + + ret = adb_function_add(c); + if (ret) + return ret; + }else{ + printk(KERN_INFO"Android Gadget: Function -> USB Mass storage.\n"); + + ret = mass_storage_function_add(c, lun_attr_table, sizeof(lun_attr_table) / sizeof(lun_attr_t)); + if (ret) + return ret; + } + + return 0; +} + +static struct usb_configuration android_config = { + .label = "android", + .bind = android_bind_config, + .bConfigurationValue = 1, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 0x80, /* 250ma */ +}; + + +static int android_bind(struct usb_composite_dev *cdev) +{ + struct android_dev *dev = _android_dev; + struct usb_gadget *gadget = cdev->gadget; + int gcnum; + int id; + int ret; + + printk(KERN_INFO "android_bind\n"); + + /* Allocate string descriptor numbers ... note that string + * contents can be overridden by the composite_dev glue. + */ + id = usb_string_id(cdev); + if (id < 0) + return id; + strings_dev[STRING_MANUFACTURER_IDX].id = id; + device_desc.iManufacturer = id; + + id = usb_string_id(cdev); + if (id < 0) + return id; + strings_dev[STRING_PRODUCT_IDX].id = id; + device_desc.iProduct = id; + + id = usb_string_id(cdev); + if (id < 0) + return id; + strings_dev[STRING_SERIAL_IDX].id = id; + device_desc.iSerialNumber = id; + + strings_dev[STRING_MS_OS_IDX].id = STRING_MS_OS_ID; + + /* register our configuration */ + ret = usb_add_config(cdev, &android_config); + if (ret) { + printk(KERN_ERR "usb_add_config failed\n"); + return ret; + } + + gcnum = usb_gadget_controller_number(gadget); + if (gcnum >= 0) + device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); + else { + /* gadget zero is so simple (for now, no altsettings) that + * it SHOULD NOT have problems with bulk-capable hardware. + * so just warn about unrcognized controllers -- don't panic. + * + * things like configuration and altsetting numbering + * can need hardware-specific attention though. + */ + pr_warning("%s: controller '%s' not recognized\n", + longname, gadget->name); + device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); + } + + usb_gadget_set_selfpowered(gadget); + dev->cdev = cdev; + + return 0; +} + +static struct usb_composite_driver android_usb_driver = { + .name = "android_usb", + .dev = &device_desc, + .strings = dev_strings, + .bind = android_bind, +}; + +static void enable_adb(struct android_dev *dev, int enable) +{ + if (enable != dev->adb_enabled) { + dev->adb_enabled = enable; + adb_function_enable(enable); + + /* set product ID to the appropriate value */ + if (enable) + device_desc.idProduct = + __constant_cpu_to_le16(dev->adb_product_id); + else + device_desc.idProduct = + __constant_cpu_to_le16(dev->product_id); + if (dev->cdev) + dev->cdev->desc.idProduct = device_desc.idProduct; + + /* force reenumeration */ + if (dev->cdev && dev->cdev->gadget && + dev->cdev->gadget->speed != USB_SPEED_UNKNOWN) { + usb_gadget_disconnect(dev->cdev->gadget); + msleep(10); + usb_gadget_connect(dev->cdev->gadget); + } + } +} + +static int adb_enable_open(struct inode *ip, struct file *fp) +{ + if (atomic_inc_return(&adb_enable_excl) != 1) { + atomic_dec(&adb_enable_excl); + return -EBUSY; + } + + if (!strcmp(g_android_function, "adb")) { + printk(KERN_INFO "enabling adb\n"); + enable_adb(_android_dev, 1); + return 0; + }else + return -ENODEV; + +} + +static int adb_enable_release(struct inode *ip, struct file *fp) +{ + printk(KERN_INFO "disabling adb\n"); + enable_adb(_android_dev, 0); + atomic_dec(&adb_enable_excl); + return 0; +} + +static struct file_operations adb_enable_fops = { + .owner = THIS_MODULE, + .open = adb_enable_open, + .release = adb_enable_release, +}; + +static struct miscdevice adb_enable_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "android_adb_enable", + .fops = &adb_enable_fops, +}; + +static int __init android_probe(struct platform_device *pdev) +{ + struct android_usb_platform_data *pdata = pdev->dev.platform_data; + struct android_dev *dev = _android_dev; + + printk(KERN_INFO "android_probe:%s, pdata: %p\n", pdev->name, pdata); + + if (pdata) { + if (pdata->vendor_id) + device_desc.idVendor = + __constant_cpu_to_le16(pdata->vendor_id); + if (pdata->product_id) { + dev->product_id = pdata->product_id; + device_desc.idProduct = + __constant_cpu_to_le16(pdata->product_id); + } + if (pdata->adb_product_id) + dev->adb_product_id = pdata->adb_product_id; + if (pdata->version) + dev->version = pdata->version; + + if (pdata->product_name) + strings_dev[STRING_PRODUCT_IDX].s = pdata->product_name; + if (pdata->manufacturer_name) + strings_dev[STRING_MANUFACTURER_IDX].s = + pdata->manufacturer_name; + if (pdata->serial_number) + strings_dev[STRING_SERIAL_IDX].s = pdata->serial_number; + dev->nluns = pdata->nluns; + } + + return 0; +} + +static void android_platform_device_release(struct device *dev) { + return; +}; + +static struct platform_device android_platform_device = { + .name = "android_usb", + .id = -1, + .dev = { + .platform_data = &android_platform_data, + .release = android_platform_device_release, + }, +}; + +static struct platform_driver android_platform_driver = { + .driver = { .name = "android_usb", }, + .probe = android_probe, +}; + +static int __init init(void) +{ + struct android_dev *dev; + + unsigned long status = 0; + + int ret; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + set_bit(0, &status); + + /* set default values, which should be overridden by platform data */ + dev->product_id = PRODUCT_ID; + dev->adb_product_id = ADB_PRODUCT_ID; + _android_dev = dev; + + ret = platform_device_register(&android_platform_device); + if (ret) { + goto err; + } + + set_bit(1, &status); + + ret = platform_driver_register(&android_platform_driver); + if (ret) { + goto err; + } + + set_bit(2, &status); + + ret = misc_register(&adb_enable_device); + if (ret) { + goto err; + } + + set_bit(3, &status); + + ret = usb_composite_register(&android_usb_driver); + if (ret) { + goto err; + } + + printk(KERN_INFO "Android Gadget Initialized.\n"); + + return 0; + +err: + if (test_bit(3, &status)) { + misc_deregister(&adb_enable_device); + } + + if (test_bit(2, &status)) { + platform_driver_unregister(&android_platform_driver); + } + + if (test_bit(1, &status)) { + platform_device_unregister(&android_platform_device); + } + + if (test_bit(0, &status)) { + kfree(dev); + dev = NULL; + } + + return ret; +} +module_init(init); + +static void __exit cleanup(void) +{ + usb_composite_unregister(&android_usb_driver); + misc_deregister(&adb_enable_device); + platform_device_unregister(&android_platform_device); + platform_driver_unregister(&android_platform_driver); + kfree(_android_dev); + _android_dev = NULL; +} +module_exit(cleanup); diff --git a/target/linux/xburst/files-2.6.27/drivers/usb/gadget/f_mass_storage.c b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/f_mass_storage.c new file mode 100755 index 000000000..7b81b8845 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/f_mass_storage.c @@ -0,0 +1,3350 @@ +/* + * drivers/usb/gadget/f_mass_storage.c + * + * Function Driver for USB Mass Storage + * + * Copyright (C) 2008 Google, Inc. + * Author: Mike Lockwood + * + * Based heavily on the file_storage gadget driver in + * drivers/usb/gadget/file_storage.c and licensed under the same terms: + * + * Copyright (C) 2003-2007 Alan Stern + * 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, + * without modification. + * 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. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * ALTERNATIVELY, this software may be 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. + * + * 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 COPYRIGHT OWNER 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. + */ + +/* #define DEBUG */ +/* #define VERBOSE_DEBUG */ +/* #define DUMP_MSGS */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "f_mass_storage.h" +#include "gadget_chips.h" +#include "udc_hotplug.h" + +#if defined (CONFIG_UDC_USE_LB_CACHE) +#define GHOST +#endif + +#ifdef GHOST +extern unsigned long udc_read(unsigned int offset, unsigned int len, unsigned char *); +extern unsigned long udc_write(unsigned int 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 BULK_BUFFER_SIZE (32 * 1024) + +/*-------------------------------------------------------------------------*/ + +#define DRIVER_NAME "usb_mass_storage" +#define MAX_LUNS 8 + +static const char shortname[] = DRIVER_NAME; + +#ifdef DEBUG +#define LDBG(lun, fmt, args...) \ + dev_dbg(&(lun)->dev , fmt , ## args) +#define MDBG(fmt,args...) \ + printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) +#else +#define LDBG(lun, fmt, args...) \ + do { } while (0) +#define MDBG(fmt,args...) \ + do { } while (0) +#undef VERBOSE_DEBUG +#undef DUMP_MSGS +#endif /* DEBUG */ + +#ifdef VERBOSE_DEBUG +#define VLDBG LDBG +#else +#define VLDBG(lun, fmt, args...) \ + do { } while (0) +#endif /* VERBOSE_DEBUG */ + +#define LERROR(lun, fmt, args...) \ +dev_err(&(lun)->dev , fmt , ## args) +#define LWARN(lun, fmt, args...) \ + dev_warn(&(lun)->dev , fmt , ## args) +#define LINFO(lun, fmt, args...) \ + dev_info(&(lun)->dev , fmt , ## args) + +#define MINFO(fmt,args...) \ + printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) + +#undef DBG +#undef VDBG +#undef ERROR +#undef WARNING +#undef INFO +#define DBG(d, fmt, args...) \ + dev_dbg(&(d)->function.config->cdev->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) \ + dev_vdbg(&(d)->function.config->cdev->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) \ + dev_err(&(d)->function.config->cdev->gadget->dev , fmt , ## args) +#define WARNING(d, fmt, args...) \ + dev_warn(&(d)->function.config->cdev->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) \ + dev_info(&(d)->function.config->cdev->gadget->dev , fmt , ## args) + + +/*-------------------------------------------------------------------------*/ + +/* Bulk-only data structures */ + +/* Command Block Wrapper */ +struct bulk_cb_wrap { + __le32 Signature; /* Contains 'USBC' */ + u32 Tag; /* Unique per command id */ + __le32 DataTransferLength; /* Size of the data */ + u8 Flags; /* Direction in bit 7 */ + u8 Lun; /* LUN (normally 0) */ + u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */ + u8 CDB[16]; /* Command Data Block */ +}; + +#define USB_BULK_CB_WRAP_LEN 31 +#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */ +#define USB_BULK_IN_FLAG 0x80 + +/* Command Status Wrapper */ +struct bulk_cs_wrap { + __le32 Signature; /* Should = 'USBS' */ + u32 Tag; /* Same as original command */ + __le32 Residue; /* Amount not transferred */ + u8 Status; /* See below */ +}; + +#define USB_BULK_CS_WRAP_LEN 13 +#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */ +#define USB_STATUS_PASS 0 +#define USB_STATUS_FAIL 1 +#define USB_STATUS_PHASE_ERROR 2 + +/* Bulk-only class specific requests */ +#define USB_BULK_RESET_REQUEST 0xff +#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe + +/* Length of a SCSI Command Data Block */ +#define MAX_COMMAND_SIZE 16 + +/* SCSI commands that we recognize */ +#define SC_FORMAT_UNIT 0x04 +#define SC_INQUIRY 0x12 +#define SC_MODE_SELECT_6 0x15 +#define SC_MODE_SELECT_10 0x55 +#define SC_MODE_SENSE_6 0x1a +#define SC_MODE_SENSE_10 0x5a +#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define SC_READ_6 0x08 +#define SC_READ_10 0x28 +#define SC_READ_12 0xa8 +#define SC_READ_CAPACITY 0x25 +#define SC_READ_FORMAT_CAPACITIES 0x23 +#define SC_RELEASE 0x17 +#define SC_REQUEST_SENSE 0x03 +#define SC_RESERVE 0x16 +#define SC_SEND_DIAGNOSTIC 0x1d +#define SC_START_STOP_UNIT 0x1b +#define SC_SYNCHRONIZE_CACHE 0x35 +#define SC_TEST_UNIT_READY 0x00 +#define SC_VERIFY 0x2f +#define SC_WRITE_6 0x0a +#define SC_WRITE_10 0x2a +#define SC_WRITE_12 0xaa + +/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ +#define SS_NO_SENSE 0 +#define SS_COMMUNICATION_FAILURE 0x040800 +#define SS_INVALID_COMMAND 0x052000 +#define SS_INVALID_FIELD_IN_CDB 0x052400 +#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 +#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 +#define SS_MEDIUM_NOT_PRESENT 0x023a00 +#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 +#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 +#define SS_RESET_OCCURRED 0x062900 +#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 +#define SS_UNRECOVERED_READ_ERROR 0x031100 +#define SS_WRITE_ERROR 0x030c02 +#define SS_WRITE_PROTECTED 0x072700 + +#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */ +#define ASC(x) ((u8) ((x) >> 8)) +#define ASCQ(x) ((u8) (x)) + + +/*-------------------------------------------------------------------------*/ + +/* LUN Flags */ +enum { + BIT_NAND_LB_ENABLE, + BIT_BACKING_FILE_MTD, +}; + +struct lun { + struct file *filp; + loff_t file_length; + loff_t num_sectors; + + unsigned int ro : 1; + unsigned int prevent_medium_removal : 1; + unsigned int registered : 1; + unsigned int info_valid : 1; + u32 sense_data; + u32 sense_data_info; + u32 unit_attention_data; + + struct device dev; + + /* LUN Attribute - Added by River */ + lun_attr_t *attr; + unsigned long flags; + /* End added */ +}; + +/* Big enough to hold our biggest descriptor */ +#define EP0_BUFSIZE 256 +#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ + +/* Number of buffers we will use. 2 is enough for double-buffering */ +#define NUM_BUFFERS 2 + +enum fsg_buffer_state { + BUF_STATE_EMPTY = 0, + BUF_STATE_FULL, + BUF_STATE_BUSY +}; + +struct fsg_buffhd { + void *buf; + enum fsg_buffer_state state; + struct fsg_buffhd *next; + + /* The NetChip 2280 is faster, and handles some protocol faults + * better, if we don't submit any short bulk-out read requests. + * So we will record the intended request length here. */ + unsigned int bulk_out_intended_length; + + struct usb_request *inreq; + int inreq_busy; + struct usb_request *outreq; + int outreq_busy; +}; + +enum fsg_state { + /* This one isn't used anywhere */ + FSG_STATE_COMMAND_PHASE = -10, + + FSG_STATE_DATA_PHASE, + FSG_STATE_STATUS_PHASE, + + FSG_STATE_IDLE = 0, + FSG_STATE_ABORT_BULK_OUT, + FSG_STATE_RESET, + FSG_STATE_CONFIG_CHANGE, + FSG_STATE_EXIT, + FSG_STATE_TERMINATED +}; + +enum data_direction { + DATA_DIR_UNKNOWN = 0, + DATA_DIR_FROM_HOST, + DATA_DIR_TO_HOST, + DATA_DIR_NONE +}; + +struct fsg_dev { + struct usb_function function; + + /* lock protects: state and all the req_busy's */ + spinlock_t lock; + + /* filesem protects: backing files in use */ + struct rw_semaphore filesem; + + /* reference counting: wait until all LUNs are released */ + struct kref ref; + + unsigned int bulk_out_maxpacket; + enum fsg_state state; /* For exception handling */ + + u8 config, new_config; + + unsigned int running : 1; + unsigned int bulk_in_enabled : 1; + unsigned int bulk_out_enabled : 1; + unsigned int phase_error : 1; + unsigned int short_packet_received : 1; + unsigned int bad_lun_okay : 1; + + unsigned long atomic_bitflags; +#define REGISTERED 0 +#define CLEAR_BULK_HALTS 1 +#define SUSPENDED 2 +#define USB_CABLE_ONLINE 3 +#define USB_GADGET_CONNECTED 4 +#define USB_GADGET_NEED_RECONNECT 5 + struct usb_ep *bulk_in; + struct usb_ep *bulk_out; + + struct fsg_buffhd *next_buffhd_to_fill; + struct fsg_buffhd *next_buffhd_to_drain; + struct fsg_buffhd buffhds[NUM_BUFFERS]; + + int thread_wakeup_needed; + struct completion thread_notifier; + struct task_struct *thread_task; + + int cmnd_size; + u8 cmnd[MAX_COMMAND_SIZE]; + enum data_direction data_dir; + u32 data_size; + u32 data_size_from_cmnd; + u32 tag; + unsigned int lun; + u32 residue; + u32 usb_amount_left; + + unsigned int nluns; + struct lun *luns; + struct lun *curlun; + + u32 buf_size; + + struct switch_dev sdev; + struct wake_lock wake_lock; + + /* Added by River. */ + lun_attr_t *lun_attr_table; + struct notifier_block nb; + /* End added. */ +}; + +static struct fsg_dev *the_fsg; + +/* ------------------------------------------------------------------------ */ +/* Common Rountines Start */ + +#define backing_file_is_open(curlun) ((curlun)->filp != NULL) + +static inline struct lun *dev_to_lun(struct device *dev) +{ + return container_of(dev, struct lun, dev); +} + +static inline struct fsg_dev *func_to_dev(struct usb_function *f) +{ + return container_of(f, struct fsg_dev, function); +} + +static inline int exception_in_progress(struct fsg_dev *fsg) +{ + return (fsg->state > FSG_STATE_IDLE); +} + +/* Make bulk-out requests be divisible by the maxpacket size */ +static void set_bulk_out_req_length(struct fsg_dev *fsg, + struct fsg_buffhd *bh, unsigned int length) +{ + unsigned int rem; + + bh->bulk_out_intended_length = length; + rem = length % fsg->bulk_out_maxpacket; + if (rem > 0) + length += fsg->bulk_out_maxpacket - rem; + bh->outreq->length = length; +} + +static void close_backing_file(struct fsg_dev *fsg, struct lun *curlun); +static void close_all_backing_files(struct fsg_dev *fsg); + +/* Connect gadget - Added by River */ +static void fsg_gadget_do_connect(struct fsg_dev *fsg) +{ + struct usb_gadget *gadget = fsg->function.config->cdev->gadget; + + if (!test_bit(USB_GADGET_CONNECTED, &fsg->atomic_bitflags)) { +// printk(KERN_ERR "%s(): USB Gadget connect.\n", __func__); + usb_gadget_connect(gadget); + + /* Start keep alive */ + udc_hotplug_start_keep_alive(0, 0); + + set_bit(USB_GADGET_CONNECTED, &fsg->atomic_bitflags); + } + + return; +} + +/* Disconnect gadget - Added by River */ +static void fsg_gadget_disconnect(struct fsg_dev *fsg) +{ + struct usb_gadget *gadget = fsg->function.config->cdev->gadget; + + if (test_bit(USB_GADGET_CONNECTED, &fsg->atomic_bitflags)) { +// printk(KERN_ERR "%s(): USB Gadget disconnect.\n", __func__); + usb_gadget_disconnect(gadget); + + /* Stop keep alive */ + udc_hotplug_stop_keep_alive(); + + clear_bit(USB_GADGET_CONNECTED, &fsg->atomic_bitflags); + } + + return; +} + +/* Connect / Reconnect gadget - Added by River */ +static void inline fsg_gadget_connect(struct fsg_dev *fsg) +{ + if (test_and_clear_bit(USB_GADGET_NEED_RECONNECT, &fsg->atomic_bitflags)) { +// printk(KERN_ERR "%s(): USB Gadget reconnect.\n", __func__); + + fsg_gadget_disconnect(fsg); + + udelay(5); + + fsg_gadget_do_connect(fsg); + }else + fsg_gadget_do_connect(fsg); + + return; +} + +#ifdef GHOST +/* Nand LB Cache functions - Added by River */ +static inline void lb_enable(struct lun *l) +{ + NAND_LB_Init(); + set_bit(BIT_NAND_LB_ENABLE, &l->flags); + + return; +} + +static inline void lb_disable(struct lun *l) +{ + clear_bit(BIT_NAND_LB_ENABLE, &l->flags); + + /* Flush cache when disabled. */ + NAND_LB_FLASHCACHE(); + NAND_MTD_FLASHCACHE(); + + return; +} + +static inline int lb_is_enable(struct lun *l) +{ + return test_bit(BIT_NAND_LB_ENABLE, &l->flags); +} + +static inline int lb_is_active(struct fsg_dev *fsg) +{ + struct lun *l; + + int i; + + for (i = 0; i < fsg->nluns; i++) { + l = fsg->luns + i; + + if (lb_is_enable(l)) + return 1; + } + + return 0; +} + +static inline void lun_set_type_mtd(struct lun *l) +{ + set_bit(BIT_BACKING_FILE_MTD, &l->flags); + + return; +} + +static inline void lun_set_type_normal(struct lun *l) +{ + clear_bit(BIT_BACKING_FILE_MTD, &l->flags); + + return; +} + +static inline int lun_is_type_mtd(struct lun *l) +{ + return test_bit(BIT_BACKING_FILE_MTD, &l->flags); +} + +/* End added */ +#endif +/*-------------------------------------------------------------------------*/ + +#ifdef DUMP_MSGS + +static void dump_msg(struct fsg_dev *fsg, const char *label, + const u8 *buf, unsigned int length) +{ + if (length < 512) { + DBG(fsg, "%s, length %u:\n", label, length); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, + 16, 1, buf, length, 0); + } +} + +static void dump_cdb(struct fsg_dev *fsg) +{} + +#else + +static void dump_msg(struct fsg_dev *fsg, const char *label, + const u8 *buf, unsigned int length) +{} + +#ifdef VERBOSE_DEBUG + +static void dump_cdb(struct fsg_dev *fsg) +{ + print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, + 16, 1, fsg->cmnd, fsg->cmnd_size, 0); +} + +#else + +static void dump_cdb(struct fsg_dev *fsg) +{} + +#endif /* VERBOSE_DEBUG */ +#endif /* DUMP_MSGS */ + +/*-------------------------------------------------------------------------*/ + +/* Routines for unaligned data access */ + +static u16 get_be16(u8 *buf) +{ + return ((u16) buf[0] << 8) | ((u16) buf[1]); +} + +static u32 get_be32(u8 *buf) +{ + return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | + ((u32) buf[2] << 8) | ((u32) buf[3]); +} + +static void put_be16(u8 *buf, u16 val) +{ + buf[0] = val >> 8; + buf[1] = val; +} + +static void put_be32(u8 *buf, u32 val) +{ + buf[0] = val >> 24; + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val & 0xff; +} + +/*-------------------------------------------------------------------------*/ + +/* + * DESCRIPTORS ... most are static, but strings and (full) configuration + * descriptors are built on demand. Also the (static) config and interface + * descriptors are adjusted during fsg_bind(). + */ + +/* There is only one interface. */ + +static struct usb_interface_descriptor +intf_desc = { + .bLength = sizeof intf_desc, + .bDescriptorType = USB_DT_INTERFACE, + + .bNumEndpoints = 2, /* Adjusted during fsg_bind() */ + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = US_SC_SCSI, + .bInterfaceProtocol = US_PR_BULK, +}; + +/* Three full-speed endpoint descriptors: bulk-in, bulk-out, + * and interrupt-in. */ + +static struct usb_endpoint_descriptor +fs_bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + /* wMaxPacketSize set by autoconfiguration */ +}; + +static struct usb_endpoint_descriptor +fs_bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + /* wMaxPacketSize set by autoconfiguration */ +}; + +static struct usb_descriptor_header *fs_function[] = { + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &fs_bulk_in_desc, + (struct usb_descriptor_header *) &fs_bulk_out_desc, + NULL, +}; +#define FS_FUNCTION_PRE_EP_ENTRIES 2 + + +static struct usb_endpoint_descriptor +hs_bulk_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor +hs_bulk_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), + .bInterval = 1, /* NAK every 1 uframe */ +}; + + +static struct usb_descriptor_header *hs_function[] = { + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &hs_bulk_in_desc, + (struct usb_descriptor_header *) &hs_bulk_out_desc, + NULL, +}; + +/* Maxpacket and other transfer characteristics vary by speed. */ +static struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} + +/*-------------------------------------------------------------------------*/ + +/* These routines may be called in process context or in_irq */ + +/* Caller must hold fsg->lock */ +static void wakeup_thread(struct fsg_dev *fsg) +{ + /* Tell the main thread that something has happened */ + fsg->thread_wakeup_needed = 1; + if (fsg->thread_task) + wake_up_process(fsg->thread_task); +} + + +static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) +{ + unsigned long flags; + + DBG(fsg, "raise_exception %d\n", (int)new_state); + /* Do nothing if a higher-priority exception is already in progress. + * If a lower-or-equal priority exception is in progress, preempt it + * and notify the main thread by sending it a signal. */ + spin_lock_irqsave(&fsg->lock, flags); + if (fsg->state <= new_state) { + fsg->state = new_state; + if (fsg->thread_task) + send_sig_info(SIGUSR1, SEND_SIG_FORCED, + fsg->thread_task); + } + spin_unlock_irqrestore(&fsg->lock, flags); +} + + +/*-------------------------------------------------------------------------*/ + +/* Bulk and interrupt endpoint completion handlers. + * These always run in_irq. */ + +static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; + + if (req->status || req->actual != req->length) + DBG(fsg, "%s --> %d, %u/%u\n", __func__, + req->status, req->actual, req->length); + + /* Hold the lock while we update the request and buffer states */ + smp_wmb(); + spin_lock(&fsg->lock); + bh->inreq_busy = 0; + bh->state = BUF_STATE_EMPTY; + wakeup_thread(fsg); + spin_unlock(&fsg->lock); +} + +static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; + + dump_msg(fsg, "bulk-out", req->buf, req->actual); + if (req->status || req->actual != bh->bulk_out_intended_length) + DBG(fsg, "%s --> %d, %u/%u\n", __func__, + req->status, req->actual, + bh->bulk_out_intended_length); + + /* Hold the lock while we update the request and buffer states */ + smp_wmb(); + spin_lock(&fsg->lock); + bh->outreq_busy = 0; + bh->state = BUF_STATE_FULL; + wakeup_thread(fsg); + spin_unlock(&fsg->lock); +} + +static int fsg_function_setup(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) +{ + struct fsg_dev *fsg = func_to_dev(f); + struct usb_composite_dev *cdev = fsg->function.config->cdev; + struct usb_request *req = cdev->req; + + int value = -EOPNOTSUPP; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + + DBG(fsg, "fsg_function_setup\n"); + /* Handle Bulk-only class-specific requests */ + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) { + DBG(fsg, "USB_TYPE_CLASS\n"); + switch (ctrl->bRequest) { + case USB_BULK_RESET_REQUEST: + if (ctrl->bRequestType != (USB_DIR_OUT | + USB_TYPE_CLASS | USB_RECIP_INTERFACE)) + break; + if (w_index != 0 || w_value != 0) { + value = -EDOM; + break; + } + + /* Raise an exception to stop the current operation + * and reinitialize our state. */ + DBG(fsg, "bulk reset request\n"); + raise_exception(fsg, FSG_STATE_RESET); + value = DELAYED_STATUS; + break; + + case USB_BULK_GET_MAX_LUN_REQUEST: + if (ctrl->bRequestType != (USB_DIR_IN | + USB_TYPE_CLASS | USB_RECIP_INTERFACE)) + break; + if (w_index != 0 || w_value != 0) { + value = -EDOM; + break; + } + + VDBG(fsg, "get max LUN\n"); + *(u8 *)cdev->req->buf = fsg->nluns - 1; + value = 1; + break; + } + } + + if (value == -EOPNOTSUPP) + VDBG(fsg, + "unknown class-specific control req " + "%02x.%02x v%04x i%04x l%u\n", + ctrl->bRequestType, ctrl->bRequest, + le16_to_cpu(ctrl->wValue), w_index, w_length); + + /* See notes in composite_setup() / composite.c - Added by River */ + + /* respond with data transfer before status phase? */ + if (value >= 0) { + req->length = value; + req->zero = value < w_length; + value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + } + + /* End Added */ + + return value; +} + +/*-------------------------------------------------------------------------*/ + +/* All the following routines run in process context */ + + +/* Use this for bulk or interrupt transfers, not ep0 */ +static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, + struct usb_request *req, int *pbusy, + enum fsg_buffer_state *state) +{ + int rc; + + DBG(fsg, "start_transfer req: %p, req->buf: %p\n", req, req->buf); + if (ep == fsg->bulk_in) + dump_msg(fsg, "bulk-in", req->buf, req->length); + + spin_lock_irq(&fsg->lock); + *pbusy = 1; + *state = BUF_STATE_BUSY; + spin_unlock_irq(&fsg->lock); + rc = usb_ep_queue(ep, req, GFP_KERNEL); + if (rc != 0) { + *pbusy = 0; + *state = BUF_STATE_EMPTY; + + /* We can't do much more than wait for a reset */ + + /* Note: currently the net2280 driver fails zero-length + * submissions if DMA is enabled. */ + if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP && + req->length == 0)) + WARN(fsg, "error in submission: %s --> %d\n", + (ep == fsg->bulk_in ? "bulk-in" : "bulk-out"), + rc); + } +} + + +static int sleep_thread(struct fsg_dev *fsg) +{ + int rc = 0; + + /* Wait until a signal arrives or we are woken up */ + for (;;) { + try_to_freeze(); + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + rc = -EINTR; + break; + } + if (fsg->thread_wakeup_needed) + break; + schedule(); + } + __set_current_state(TASK_RUNNING); + fsg->thread_wakeup_needed = 0; + return rc; +} + + +/*-------------------------------------------------------------------------*/ + +static int do_read(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + u32 lba; + struct fsg_buffhd *bh; + int rc; + u32 amount_left; + loff_t file_offset, file_offset_tmp; + unsigned int amount; + unsigned int partial_page; + ssize_t nread; + + /* Get the starting Logical Block Address and check that it's + * not too big */ + if (fsg->cmnd[0] == SC_READ_6) + lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]); + else { + lba = get_be32(&fsg->cmnd[2]); + + /* We allow DPO (Disable Page Out = don't save data in the + * cache) and FUA (Force Unit Access = don't read from the + * cache), but we don't implement them. */ + if ((fsg->cmnd[1] & ~0x18) != 0) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + } + if (lba >= curlun->num_sectors) { + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; + } + file_offset = ((loff_t) lba) << 9; + + /* Carry out the file reads */ + amount_left = fsg->data_size_from_cmnd; + if (unlikely(amount_left == 0)) + return -EIO; /* No default reply */ + + for (;;) { + + /* Figure out how much we need to read: + * Try to read the remaining amount. + * But don't read more than the buffer size. + * And don't try to read past the end of the file. + * Finally, if we're not at a page boundary, don't read past + * the next page. + * If this means reading 0 then we were asked to read past + * the end of file. */ + amount = min((unsigned int) amount_left, + (unsigned int)fsg->buf_size); + amount = min((loff_t) amount, + curlun->file_length - file_offset); + partial_page = file_offset & (PAGE_CACHE_SIZE - 1); + if (partial_page > 0) + amount = min(amount, (unsigned int) PAGE_CACHE_SIZE - + partial_page); + + /* Wait for the next buffer to become available */ + bh = fsg->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(fsg); + if (rc) + return rc; + } + + /* If we were asked to read past the end of file, + * end with an empty buffer. */ + if (amount == 0) { + curlun->sense_data = + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; + bh->inreq->length = 0; + bh->state = BUF_STATE_FULL; + break; + } + + /* Perform the read */ + file_offset_tmp = file_offset; +#ifdef GHOST + if (lun_is_type_mtd(curlun)) + 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); + if (signal_pending(current)) + return -EINTR; + + if (nread < 0) { + LDBG(curlun, "error in file read: %d\n", + (int) nread); + nread = 0; + } else if (nread < amount) { + LDBG(curlun, "partial file read: %d/%u\n", + (int) nread, amount); + nread -= (nread & 511); /* Round down to a block */ + } + file_offset += nread; + amount_left -= nread; + fsg->residue -= nread; + bh->inreq->length = nread; + bh->state = BUF_STATE_FULL; + + /* If an error occurred, report it and its position */ + if (nread < amount) { + curlun->sense_data = SS_UNRECOVERED_READ_ERROR; + curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; + break; + } + + if (amount_left == 0) + break; /* No more left to read */ + + + /* Send this buffer and go read some more */ + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; + } + + return -EIO; /* No default reply */ +} + + +/*-------------------------------------------------------------------------*/ + +static int do_write(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + u32 lba; + struct fsg_buffhd *bh; + int get_some_more; + u32 amount_left_to_req, amount_left_to_write; + loff_t usb_offset, file_offset, file_offset_tmp; + unsigned int amount; + unsigned int partial_page; + ssize_t nwritten; + int rc; + + if (curlun->ro) { + curlun->sense_data = SS_WRITE_PROTECTED; + return -EINVAL; + } + curlun->filp->f_flags &= ~O_SYNC; /* Default is not to wait */ + + /* Get the starting Logical Block Address and check that it's + * not too big */ + if (fsg->cmnd[0] == SC_WRITE_6) + lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]); + else { + lba = get_be32(&fsg->cmnd[2]); + + /* We allow DPO (Disable Page Out = don't save data in the + * cache) and FUA (Force Unit Access = write directly to the + * medium). We don't implement DPO; we implement FUA by + * performing synchronous output. */ + if ((fsg->cmnd[1] & ~0x18) != 0) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + if (fsg->cmnd[1] & 0x08) /* FUA */ + curlun->filp->f_flags |= O_SYNC; + } + if (lba >= curlun->num_sectors) { + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; + } + + /* Carry out the file writes */ + get_some_more = 1; + file_offset = usb_offset = ((loff_t) lba) << 9; + amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; + + while (amount_left_to_write > 0) { + + /* Queue a request for more data from the host */ + bh = fsg->next_buffhd_to_fill; + if (bh->state == BUF_STATE_EMPTY && get_some_more) { + + /* Figure out how much we want to get: + * Try to get the remaining amount. + * But don't get more than the buffer size. + * And don't try to go past the end of the file. + * If we're not at a page boundary, + * don't go past the next page. + * If this means getting 0, then we were asked + * to write past the end of file. + * Finally, round down to a block boundary. */ + amount = min(amount_left_to_req, (u32)fsg->buf_size); + amount = min((loff_t) amount, curlun->file_length - + usb_offset); + partial_page = usb_offset & (PAGE_CACHE_SIZE - 1); + if (partial_page > 0) + amount = min(amount, + (unsigned int) PAGE_CACHE_SIZE - partial_page); + + if (amount == 0) { + get_some_more = 0; + curlun->sense_data = + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + curlun->sense_data_info = usb_offset >> 9; + curlun->info_valid = 1; + continue; + } + amount -= (amount & 511); + if (amount == 0) { + + /* Why were we were asked to transfer a + * partial block? */ + get_some_more = 0; + continue; + } + + /* Get the next buffer */ + usb_offset += amount; + fsg->usb_amount_left -= amount; + amount_left_to_req -= amount; + if (amount_left_to_req == 0) + get_some_more = 0; + + /* amount is always divisible by 512, hence by + * the bulk-out maxpacket size */ + bh->outreq->length = bh->bulk_out_intended_length = + amount; + + start_transfer(fsg, fsg->bulk_out, bh->outreq, + &bh->outreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; + continue; + } + + /* Write the received data to the backing file */ + bh = fsg->next_buffhd_to_drain; + if (bh->state == BUF_STATE_EMPTY && !get_some_more) + break; /* We stopped early */ + if (bh->state == BUF_STATE_FULL) { + smp_rmb(); + fsg->next_buffhd_to_drain = bh->next; + bh->state = BUF_STATE_EMPTY; + + /* Did something go wrong with the transfer? */ + if (bh->outreq->status != 0) { + curlun->sense_data = SS_COMMUNICATION_FAILURE; + curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; + break; + } + + amount = bh->outreq->actual; + if (curlun->file_length - file_offset < amount) { + LERROR(curlun, + "write %u @ %llu beyond end %llu\n", + amount, (unsigned long long) file_offset, + (unsigned long long) curlun->file_length); + amount = curlun->file_length - file_offset; + } + + /* Perform the write */ + file_offset_tmp = file_offset; +#ifdef GHOST + if (lun_is_type_mtd(curlun)) + 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 + if (signal_pending(current)) + return -EINTR; /* Interrupted! */ + + if (nwritten < 0) { + LDBG(curlun, "error in file write: %d\n", + (int) nwritten); + nwritten = 0; + } else if (nwritten < amount) { + LDBG(curlun, "partial file write: %d/%u\n", + (int) nwritten, amount); + nwritten -= (nwritten & 511); + /* Round down to a block */ + } + file_offset += nwritten; + amount_left_to_write -= nwritten; + fsg->residue -= nwritten; + + /* If an error occurred, report it and its position */ + if (nwritten < amount) { + curlun->sense_data = SS_WRITE_ERROR; + curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; + break; + } + + /* Did the host decide to stop early? */ + if (bh->outreq->actual != bh->outreq->length) { + fsg->short_packet_received = 1; + break; + } + continue; + } + + /* Wait for something to happen */ + rc = sleep_thread(fsg); + if (rc) + return rc; + } + + return -EIO; /* No default reply */ +} + + +/*-------------------------------------------------------------------------*/ + +/* Sync the file data, don't bother with the metadata. + * The caller must own fsg->filesem. + * This code was copied from fs/buffer.c:sys_fdatasync(). */ +static int fsync_sub(struct lun *curlun) +{ + struct file *filp = curlun->filp; + struct inode *inode; + int rc, err; + + if (curlun->ro || !filp) + return 0; + if (!filp->f_op->fsync) + return -EINVAL; + + inode = filp->f_path.dentry->d_inode; + mutex_lock(&inode->i_mutex); + rc = filemap_fdatawrite(inode->i_mapping); + err = filp->f_op->fsync(filp, filp->f_path.dentry, 1); + if (!rc) + rc = err; + err = filemap_fdatawait(inode->i_mapping); + if (!rc) + rc = err; + mutex_unlock(&inode->i_mutex); + VLDBG(curlun, "fdatasync -> %d\n", rc); + return rc; +} + +static void fsync_all(struct fsg_dev *fsg) +{ + int i; + + for (i = 0; i < fsg->nluns; ++i) + fsync_sub(&fsg->luns[i]); +} + +static int do_synchronize_cache(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + int rc; + + /* We ignore the requested LBA and write out all file's + * dirty data buffers. */ + rc = fsync_sub(curlun); + if (rc) + curlun->sense_data = SS_WRITE_ERROR; + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +static void invalidate_sub(struct lun *curlun) +{ + struct file *filp = curlun->filp; + struct inode *inode = filp->f_path.dentry->d_inode; + unsigned long rc; + + rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); + VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc); +} + +static int do_verify(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + u32 lba; + u32 verification_length; + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; + loff_t file_offset, file_offset_tmp; + u32 amount_left; + unsigned int amount; + ssize_t nread; + + /* Get the starting Logical Block Address and check that it's + * not too big */ + lba = get_be32(&fsg->cmnd[2]); + if (lba >= curlun->num_sectors) { + curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; + } + + /* We allow DPO (Disable Page Out = don't save data in the + * cache) but we don't implement it. */ + if ((fsg->cmnd[1] & ~0x10) != 0) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + verification_length = get_be16(&fsg->cmnd[7]); + if (unlikely(verification_length == 0)) + return -EIO; /* No default reply */ + + /* Prepare to carry out the file verify */ + amount_left = verification_length << 9; + file_offset = ((loff_t) lba) << 9; + + /* Write out all the dirty buffers before invalidating them */ + fsync_sub(curlun); + if (signal_pending(current)) + return -EINTR; + + invalidate_sub(curlun); + if (signal_pending(current)) + return -EINTR; + + /* Just try to read the requested blocks */ + while (amount_left > 0) { + + /* Figure out how much we need to read: + * Try to read the remaining amount, but not more than + * the buffer size. + * And don't try to read past the end of the file. + * If this means reading 0 then we were asked to read + * past the end of file. */ + amount = min((unsigned int) amount_left, + (unsigned int)fsg->buf_size); + amount = min((loff_t) amount, + curlun->file_length - file_offset); + if (amount == 0) { + curlun->sense_data = + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; + break; + } + + /* Perform the read */ + file_offset_tmp = file_offset; +#ifdef GHOST + if (lun_is_type_mtd(curlun)) + 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); + if (signal_pending(current)) + return -EINTR; + + if (nread < 0) { + LDBG(curlun, "error in file verify: %d\n", + (int) nread); + nread = 0; + } else if (nread < amount) { + LDBG(curlun, "partial file verify: %d/%u\n", + (int) nread, amount); + nread -= (nread & 511); /* Round down to a sector */ + } + if (nread == 0) { + curlun->sense_data = SS_UNRECOVERED_READ_ERROR; + curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; + break; + } + file_offset += nread; + amount_left -= nread; + } + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + u8 *buf = (u8 *) bh->buf; + + if (!fsg->curlun) { /* Unsupported LUNs are okay */ + fsg->bad_lun_okay = 1; + memset(buf, 0, 36); + buf[0] = 0x7f; /* Unsupported, no device-type */ + return 36; + } + + memset(buf, 0, 8); /* Non-removable, direct-access device */ + + buf[1] = 0x80; /* set removable bit */ + buf[2] = 2; /* ANSI SCSI level 2 */ + buf[3] = 2; /* SCSI-2 INQUIRY data format */ + buf[4] = 31; /* Additional length */ + /* No special options */ + + sprintf(buf + 8, "%-8s%-16s%04x", fsg->curlun->attr->vendor, + fsg->curlun->attr->product, fsg->curlun->attr->release); + + return 36; +} + + +static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + u8 *buf = (u8 *) bh->buf; + u32 sd, sdinfo; + int valid; + + /* + * From the SCSI-2 spec., section 7.9 (Unit attention condition): + * + * If a REQUEST SENSE command is received from an initiator + * with a pending unit attention condition (before the target + * generates the contingent allegiance condition), then the + * target shall either: + * a) report any pending sense data and preserve the unit + * attention condition on the logical unit, or, + * b) report the unit attention condition, may discard any + * pending sense data, and clear the unit attention + * condition on the logical unit for that initiator. + * + * FSG normally uses option a); enable this code to use option b). + */ +#if 0 + if (curlun && curlun->unit_attention_data != SS_NO_SENSE) { + curlun->sense_data = curlun->unit_attention_data; + curlun->unit_attention_data = SS_NO_SENSE; + } +#endif + + if (!curlun) { /* Unsupported LUNs are okay */ + fsg->bad_lun_okay = 1; + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; + sdinfo = 0; + valid = 0; + } else { + sd = curlun->sense_data; + sdinfo = curlun->sense_data_info; + valid = curlun->info_valid << 7; + curlun->sense_data = SS_NO_SENSE; + curlun->sense_data_info = 0; + curlun->info_valid = 0; + } + + memset(buf, 0, 18); + buf[0] = valid | 0x70; /* Valid, current error */ + buf[2] = SK(sd); + put_be32(&buf[3], sdinfo); /* Sense information */ + buf[7] = 18 - 8; /* Additional sense length */ + buf[12] = ASC(sd); + buf[13] = ASCQ(sd); + return 18; +} + + +static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + u32 lba = get_be32(&fsg->cmnd[2]); + int pmi = fsg->cmnd[8]; + u8 *buf = (u8 *) bh->buf; + + /* Check the PMI and LBA fields */ + if (pmi > 1 || (pmi == 0 && lba != 0)) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + put_be32(&buf[0], curlun->num_sectors - 1); /* Max logical block */ + put_be32(&buf[4], 512); /* Block length */ + return 8; +} + + +static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + int mscmnd = fsg->cmnd[0]; + u8 *buf = (u8 *) bh->buf; + u8 *buf0 = buf; + int pc, page_code; + int changeable_values, all_pages; + int valid_page = 0; + int len, limit; + + if ((fsg->cmnd[1] & ~0x08) != 0) { /* Mask away DBD */ + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + pc = fsg->cmnd[2] >> 6; + page_code = fsg->cmnd[2] & 0x3f; + if (pc == 3) { + curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; + return -EINVAL; + } + changeable_values = (pc == 1); + all_pages = (page_code == 0x3f); + + /* Write the mode parameter header. Fixed values are: default + * medium type, no cache control (DPOFUA), and no block descriptors. + * The only variable value is the WriteProtect bit. We will fill in + * the mode data length later. */ + memset(buf, 0, 8); + if (mscmnd == SC_MODE_SENSE_6) { + buf[2] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ + buf += 4; + limit = 255; + } else { /* SC_MODE_SENSE_10 */ + buf[3] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ + buf += 8; + limit = 65535; + } + + /* No block descriptors */ + + /* Disabled to workaround USB reset problems with a Vista host. + */ +#if 0 + /* The mode pages, in numerical order. The only page we support + * is the Caching page. */ + if (page_code == 0x08 || all_pages) { + valid_page = 1; + buf[0] = 0x08; /* Page code */ + buf[1] = 10; /* Page length */ + memset(buf+2, 0, 10); /* None of the fields are changeable */ + + if (!changeable_values) { + buf[2] = 0x04; /* Write cache enable, */ + /* Read cache not disabled */ + /* No cache retention priorities */ + put_be16(&buf[4], 0xffff); /* Don't disable prefetch */ + /* Minimum prefetch = 0 */ + put_be16(&buf[8], 0xffff); /* Maximum prefetch */ + /* Maximum prefetch ceiling */ + put_be16(&buf[10], 0xffff); + } + buf += 12; + } +#else + valid_page = 1; +#endif + + /* Check that a valid page was requested and the mode data length + * isn't too long. */ + len = buf - buf0; + if (!valid_page || len > limit) { + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + /* Store the mode data length */ + if (mscmnd == SC_MODE_SENSE_6) + buf0[0] = len - 1; + else + put_be16(buf0, len - 2); + return len; +} + +static int do_start_stop(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + int loej, start; + + /* int immed = fsg->cmnd[1] & 0x01; */ + loej = fsg->cmnd[4] & 0x02; + start = fsg->cmnd[4] & 0x01; + + if (loej) { + /* eject request from the host */ + if (backing_file_is_open(curlun)) { + close_backing_file(fsg, curlun); + curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; + } + } + + return 0; +} + +static int do_prevent_allow(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + int prevent; + + prevent = fsg->cmnd[4] & 0x01; + if ((fsg->cmnd[4] & ~0x01) != 0) { /* Mask away Prevent */ + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + return -EINVAL; + } + + if (curlun->prevent_medium_removal && !prevent) + fsync_sub(curlun); + curlun->prevent_medium_removal = prevent; + return 0; +} + + +static int do_read_format_capacities(struct fsg_dev *fsg, + struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + u8 *buf = (u8 *) bh->buf; + + buf[0] = buf[1] = buf[2] = 0; + buf[3] = 8; /* Only the Current/Maximum Capacity Descriptor */ + buf += 4; + + put_be32(&buf[0], curlun->num_sectors); /* Number of blocks */ + put_be32(&buf[4], 512); /* Block length */ + buf[4] = 0x02; /* Current capacity */ + return 12; +} + + +static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct lun *curlun = fsg->curlun; + + /* We don't support MODE SELECT */ + curlun->sense_data = SS_INVALID_COMMAND; + return -EINVAL; +} + + +/*-------------------------------------------------------------------------*/ +#if 0 +static int write_zero(struct fsg_dev *fsg) +{ + struct fsg_buffhd *bh; + int rc; + + DBG(fsg, "write_zero\n"); + /* Wait for the next buffer to become available */ + bh = fsg->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(fsg); + if (rc) + return rc; + } + + bh->inreq->length = 0; + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + + fsg->next_buffhd_to_fill = bh->next; + return 0; +} +#endif + +static int throw_away_data(struct fsg_dev *fsg) +{ + struct fsg_buffhd *bh; + u32 amount; + int rc; + + DBG(fsg, "throw_away_data\n"); + while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY || + fsg->usb_amount_left > 0) { + + /* Throw away the data in a filled buffer */ + if (bh->state == BUF_STATE_FULL) { + smp_rmb(); + bh->state = BUF_STATE_EMPTY; + fsg->next_buffhd_to_drain = bh->next; + + /* A short packet or an error ends everything */ + if (bh->outreq->actual != bh->outreq->length || + bh->outreq->status != 0) { + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); + return -EINTR; + } + continue; + } + + /* Try to submit another request if we need one */ + bh = fsg->next_buffhd_to_fill; + if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) { + amount = min(fsg->usb_amount_left, (u32) fsg->buf_size); + + /* amount is always divisible by 512, hence by + * the bulk-out maxpacket size */ + bh->outreq->length = bh->bulk_out_intended_length = + amount; + + start_transfer(fsg, fsg->bulk_out, bh->outreq, + &bh->outreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; + fsg->usb_amount_left -= amount; + continue; + } + + /* Otherwise wait for something to happen */ + rc = sleep_thread(fsg); + if (rc) + return rc; + } + return 0; +} + +static int pad_with_zeros(struct fsg_dev *fsg) +{ + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; + u32 nkeep = bh->inreq->length; + u32 nsend; + int rc; + + bh->state = BUF_STATE_EMPTY; // For the first iteration + fsg->usb_amount_left = nkeep + fsg->residue; + while (fsg->usb_amount_left > 0) { + + /* Wait for the next buffer to be free */ + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(fsg); + if (rc) + return rc; + } + + nsend = min(fsg->usb_amount_left, fsg->buf_size); + memset(bh->buf + nkeep, 0, nsend - nkeep); + bh->inreq->length = nsend; + bh->inreq->zero = 0; + + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + bh = fsg->next_buffhd_to_fill = bh->next; + fsg->usb_amount_left -= nsend; + nkeep = 0; + } + return 0; +} + +static int finish_reply(struct fsg_dev *fsg) +{ + struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; + int rc = 0; + + switch (fsg->data_dir) { + case DATA_DIR_NONE: + break; /* Nothing to send */ + + case DATA_DIR_UNKNOWN: + rc = -EINVAL; + break; + + /* All but the last buffer of data must have already been sent */ + case DATA_DIR_TO_HOST: + if (fsg->data_size == 0) + ; /* Nothing to send */ + + /* If there's no residue, simply send the last buffer */ + else if (fsg->residue == 0) { + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; + } else { + + pad_with_zeros(fsg); +#if 0 + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + fsg->next_buffhd_to_fill = bh->next; + /* this is unnecessary, and was causing problems with MacOS */ + if (bh->inreq->length > 0) + write_zero(fsg); +#endif + } + break; + + /* We have processed all we want from the data the host has sent. + * There may still be outstanding bulk-out requests. */ + case DATA_DIR_FROM_HOST: + if (fsg->residue == 0) + ; /* Nothing to receive */ + + /* Did the host stop sending unexpectedly early? */ + else if (fsg->short_packet_received) { + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); + rc = -EINTR; + } + + /* We haven't processed all the incoming data. Even though + * we may be allowed to stall, doing so would cause a race. + * The controller may already have ACK'ed all the remaining + * bulk-out packets, in which case the host wouldn't see a + * STALL. Not realizing the endpoint was halted, it wouldn't + * clear the halt -- leading to problems later on. */ +#if 0 + fsg_set_halt(fsg, fsg->bulk_out); + raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); + rc = -EINTR; +#endif + + /* We can't stall. Read in the excess data and throw it + * all away. */ + else + rc = throw_away_data(fsg); + break; + } + return rc; +} + + +static int send_status(struct fsg_dev *fsg) +{ + struct lun *curlun = fsg->curlun; + struct fsg_buffhd *bh; + int rc; + u8 status = USB_STATUS_PASS; + u32 sd, sdinfo = 0; + struct bulk_cs_wrap *csw; + + DBG(fsg, "send_status\n"); + /* Wait for the next buffer to become available */ + bh = fsg->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(fsg); + if (rc) + return rc; + } + + if (curlun) { + sd = curlun->sense_data; + sdinfo = curlun->sense_data_info; + } else if (fsg->bad_lun_okay) + sd = SS_NO_SENSE; + else + sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; + + if (fsg->phase_error) { + DBG(fsg, "sending phase-error status\n"); + status = USB_STATUS_PHASE_ERROR; + sd = SS_INVALID_COMMAND; + } else if (sd != SS_NO_SENSE) { + DBG(fsg, "sending command-failure status\n"); + status = USB_STATUS_FAIL; + VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" + " info x%x\n", + SK(sd), ASC(sd), ASCQ(sd), sdinfo); + } + + csw = bh->buf; + + /* Store and send the Bulk-only CSW */ + csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG); + csw->Tag = fsg->tag; + csw->Residue = cpu_to_le32(fsg->residue); + csw->Status = status; + + bh->inreq->length = USB_BULK_CS_WRAP_LEN; + + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + + fsg->next_buffhd_to_fill = bh->next; + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +/* Check whether the command is properly formed and whether its data size + * and direction agree with the values we already have. */ +static int check_command(struct fsg_dev *fsg, int cmnd_size, + enum data_direction data_dir, unsigned int mask, + int needs_medium, const char *name) +{ + int i; + int lun = fsg->cmnd[1] >> 5; + static const char dirletter[4] = {'u', 'o', 'i', 'n'}; + char hdlen[20]; + struct lun *curlun; + + hdlen[0] = 0; + if (fsg->data_dir != DATA_DIR_UNKNOWN) + sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir], + fsg->data_size); +/* + printk(KERN_ERR "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", + name, cmnd_size, dirletter[(int) data_dir], + fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen); +*/ + + VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", + name, cmnd_size, dirletter[(int) data_dir], + fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen); + + /* We can't reply at all until we know the correct data direction + * and size. */ + if (fsg->data_size_from_cmnd == 0) + data_dir = DATA_DIR_NONE; + if (fsg->data_dir == DATA_DIR_UNKNOWN) { /* CB or CBI */ + fsg->data_dir = data_dir; + fsg->data_size = fsg->data_size_from_cmnd; + + } else { /* Bulk-only */ + if (fsg->data_size < fsg->data_size_from_cmnd) { + + /* Host data size < Device data size is a phase error. + * Carry out the command, but only transfer as much + * as we are allowed. */ + DBG(fsg, "phase error 1\n"); + fsg->data_size_from_cmnd = fsg->data_size; + fsg->phase_error = 1; + } + } + fsg->residue = fsg->usb_amount_left = fsg->data_size; + + /* Conflicting data directions is a phase error */ + if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { + fsg->phase_error = 1; + DBG(fsg, "phase error 2\n"); + return -EINVAL; + } + + /* Verify the length of the command itself */ + if (cmnd_size != fsg->cmnd_size) { + + /* Special case workaround: MS-Windows issues REQUEST SENSE + * with cbw->Length == 12 (it should be 6). */ + if (fsg->cmnd[0] == SC_REQUEST_SENSE && fsg->cmnd_size == 12) + cmnd_size = fsg->cmnd_size; + else { + fsg->phase_error = 1; + return -EINVAL; + } + } + + /* Check that the LUN values are consistent */ + if (fsg->lun != lun) + DBG(fsg, "using LUN %d from CBW, " + "not LUN %d from CDB\n", + fsg->lun, lun); + + /* Check the LUN */ + if (fsg->lun >= 0 && fsg->lun < fsg->nluns) { + fsg->curlun = curlun = &fsg->luns[fsg->lun]; + if (fsg->cmnd[0] != SC_REQUEST_SENSE) { + curlun->sense_data = SS_NO_SENSE; + curlun->sense_data_info = 0; + curlun->info_valid = 0; + } + } else { + fsg->curlun = curlun = NULL; + fsg->bad_lun_okay = 0; + + /* INQUIRY and REQUEST SENSE commands are explicitly allowed + * to use unsupported LUNs; all others may not. */ + if (fsg->cmnd[0] != SC_INQUIRY && + fsg->cmnd[0] != SC_REQUEST_SENSE) { + DBG(fsg, "unsupported LUN %d\n", fsg->lun); + return -EINVAL; + } + } + + /* If a unit attention condition exists, only INQUIRY and + * REQUEST SENSE commands are allowed; anything else must fail. */ + if (curlun && curlun->unit_attention_data != SS_NO_SENSE && + fsg->cmnd[0] != SC_INQUIRY && + fsg->cmnd[0] != SC_REQUEST_SENSE) { + curlun->sense_data = curlun->unit_attention_data; + curlun->unit_attention_data = SS_NO_SENSE; + return -EINVAL; + } + + /* Check that only command bytes listed in the mask are non-zero */ + fsg->cmnd[1] &= 0x1f; /* Mask away the LUN */ + for (i = 1; i < cmnd_size; ++i) { + if (fsg->cmnd[i] && !(mask & (1 << i))) { + if (curlun) + curlun->sense_data = SS_INVALID_FIELD_IN_CDB; + DBG(fsg, "SS_INVALID_FIELD_IN_CDB\n"); + return -EINVAL; + } + } + + /* If the medium isn't mounted and the command needs to access + * it, return an error. */ + if (curlun && !backing_file_is_open(curlun) && needs_medium) { + curlun->sense_data = SS_MEDIUM_NOT_PRESENT; + DBG(fsg, "SS_MEDIUM_NOT_PRESENT\n"); + return -EINVAL; + } + + return 0; +} + + +static int do_scsi_command(struct fsg_dev *fsg) +{ + struct fsg_buffhd *bh; + int rc; + int reply = -EINVAL; + int i; + static char unknown[16]; + + dump_cdb(fsg); + + /* Wait for the next buffer to become available for data or status */ + bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(fsg); + if (rc) + return rc; + } + fsg->phase_error = 0; + fsg->short_packet_received = 0; + + down_read(&fsg->filesem); /* We're using the backing file */ + switch (fsg->cmnd[0]) { + + case SC_INQUIRY: + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (1<<4), 0, + "INQUIRY")) == 0) + reply = do_inquiry(fsg, bh); + break; + + case SC_MODE_SELECT_6: + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, + (1<<1) | (1<<4), 0, + "MODE SELECT(6)")) == 0) + reply = do_mode_select(fsg, bh); + break; + + case SC_MODE_SELECT_10: + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, + (1<<1) | (3<<7), 0, + "MODE SELECT(10)")) == 0) + reply = do_mode_select(fsg, bh); + break; + + case SC_MODE_SENSE_6: + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (1<<1) | (1<<2) | (1<<4), 0, + "MODE SENSE(6)")) == 0) + reply = do_mode_sense(fsg, bh); + break; + + case SC_MODE_SENSE_10: + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (1<<1) | (1<<2) | (3<<7), 0, + "MODE SENSE(10)")) == 0) + reply = do_mode_sense(fsg, bh); + break; + + case SC_PREVENT_ALLOW_MEDIUM_REMOVAL: + fsg->data_size_from_cmnd = 0; + if ((reply = check_command(fsg, 6, DATA_DIR_NONE, + (1<<4), 0, + "PREVENT-ALLOW MEDIUM REMOVAL")) == 0) + reply = do_prevent_allow(fsg); + break; + + case SC_READ_6: + i = fsg->cmnd[4]; + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (7<<1) | (1<<4), 1, + "READ(6)")) == 0) + reply = do_read(fsg); + break; + + case SC_READ_10: + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9; + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (1<<1) | (0xf<<2) | (3<<7), 1, + "READ(10)")) == 0) + reply = do_read(fsg); + break; + + case SC_READ_12: + fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9; + if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, + (1<<1) | (0xf<<2) | (0xf<<6), 1, + "READ(12)")) == 0) + reply = do_read(fsg); + break; + + case SC_READ_CAPACITY: + fsg->data_size_from_cmnd = 8; + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (0xf<<2) | (1<<8), 1, + "READ CAPACITY")) == 0) + reply = do_read_capacity(fsg, bh); + break; + + case SC_READ_FORMAT_CAPACITIES: + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); + if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + (3<<7), 1, + "READ FORMAT CAPACITIES")) == 0) + reply = do_read_format_capacities(fsg, bh); + break; + + case SC_REQUEST_SENSE: + fsg->data_size_from_cmnd = fsg->cmnd[4]; + if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + (1<<4), 0, + "REQUEST SENSE")) == 0) + reply = do_request_sense(fsg, bh); + break; + + case SC_START_STOP_UNIT: + fsg->data_size_from_cmnd = 0; + if ((reply = check_command(fsg, 6, DATA_DIR_NONE, + (1<<1) | (1<<4), 0, + "START-STOP UNIT")) == 0) + reply = do_start_stop(fsg); + break; + + case SC_SYNCHRONIZE_CACHE: + fsg->data_size_from_cmnd = 0; + if ((reply = check_command(fsg, 10, DATA_DIR_NONE, + (0xf<<2) | (3<<7), 1, + "SYNCHRONIZE CACHE")) == 0) + reply = do_synchronize_cache(fsg); + break; + + case SC_TEST_UNIT_READY: + fsg->data_size_from_cmnd = 0; + 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 + * support a minimal version: BytChk must be 0. */ + case SC_VERIFY: + fsg->data_size_from_cmnd = 0; + if ((reply = check_command(fsg, 10, DATA_DIR_NONE, + (1<<1) | (0xf<<2) | (3<<7), 1, + "VERIFY")) == 0) + reply = do_verify(fsg); + break; + + case SC_WRITE_6: + i = fsg->cmnd[4]; + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, + (7<<1) | (1<<4), 1, + "WRITE(6)")) == 0) + reply = do_write(fsg); + break; + + case SC_WRITE_10: + fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9; + if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, + (1<<1) | (0xf<<2) | (3<<7), 1, + "WRITE(10)")) == 0) + reply = do_write(fsg); + break; + + case SC_WRITE_12: + fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9; + if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, + (1<<1) | (0xf<<2) | (0xf<<6), 1, + "WRITE(12)")) == 0) + reply = do_write(fsg); + break; + + /* Some mandatory commands that we recognize but don't implement. + * They don't mean much in this setting. It's left as an exercise + * for anyone interested to implement RESERVE and RELEASE in terms + * of Posix locks. */ + case SC_FORMAT_UNIT: + case SC_RELEASE: + case SC_RESERVE: + case SC_SEND_DIAGNOSTIC: + /* Fall through */ + + default: + fsg->data_size_from_cmnd = 0; + sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]); + if ((reply = check_command(fsg, fsg->cmnd_size, + DATA_DIR_UNKNOWN, 0xff, 0, unknown)) == 0) { + fsg->curlun->sense_data = SS_INVALID_COMMAND; + reply = -EINVAL; + } + break; + } + up_read(&fsg->filesem); + + VDBG(fsg, "reply: %d, fsg->data_size_from_cmnd: %d\n", + reply, fsg->data_size_from_cmnd); + if (reply == -EINTR || signal_pending(current)) + return -EINTR; + + /* Set up the single reply buffer for finish_reply() */ + if (reply == -EINVAL) + reply = 0; /* Error reply length */ + if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) { + reply = min((u32) reply, fsg->data_size_from_cmnd); + bh->inreq->length = reply; + bh->state = BUF_STATE_FULL; + fsg->residue -= reply; + } /* Otherwise it's already set */ + + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{ + struct usb_request *req = bh->outreq; + struct bulk_cb_wrap *cbw = req->buf; + + /* Was this a real packet? */ + if (req->status) + return -EINVAL; + + /* Is the CBW valid? */ + if (req->actual != USB_BULK_CB_WRAP_LEN || + cbw->Signature != __constant_cpu_to_le32( + USB_BULK_CB_SIG)) { + DBG(fsg, "invalid CBW: len %u sig 0x%x\n", + req->actual, + le32_to_cpu(cbw->Signature)); + return -EINVAL; + } + + /* Is the CBW meaningful? */ + if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { + DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " + "cmdlen %u\n", + cbw->Lun, cbw->Flags, cbw->Length); + return -EINVAL; + } + + /* Save the command for later */ + fsg->cmnd_size = cbw->Length; + memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size); + if (cbw->Flags & USB_BULK_IN_FLAG) + fsg->data_dir = DATA_DIR_TO_HOST; + else + fsg->data_dir = DATA_DIR_FROM_HOST; + fsg->data_size = le32_to_cpu(cbw->DataTransferLength); + if (fsg->data_size == 0) + fsg->data_dir = DATA_DIR_NONE; + + fsg->lun = cbw->Lun; + fsg->tag = cbw->Tag; + return 0; +} + + +static int get_next_command(struct fsg_dev *fsg) +{ + struct fsg_buffhd *bh; + int rc = 0; + + /* Wait for the next buffer to become available */ + bh = fsg->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(fsg); + if (rc) + return rc; + } + + /* Queue a request to read a Bulk-only CBW */ + set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); + + start_transfer(fsg, fsg->bulk_out, bh->outreq, + &bh->outreq_busy, &bh->state); + + /* We will drain the buffer in software, which means we + * can reuse it for the next filling. No need to advance + * next_buffhd_to_fill. */ + + /* Wait for the CBW to arrive */ + while (bh->state != BUF_STATE_FULL) { + rc = sleep_thread(fsg); + if (rc) + return rc; + } + smp_rmb(); + + rc = received_cbw(fsg, bh); + bh->state = BUF_STATE_EMPTY; + + return rc; +} + + +/*-------------------------------------------------------------------------*/ + +static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep, + const struct usb_endpoint_descriptor *d) +{ + int rc; + + DBG(fsg, "usb_ep_enable %s\n", ep->name); + ep->driver_data = fsg; + rc = usb_ep_enable(ep, d); + if (rc) + ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc); + return rc; +} + +static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep, + struct usb_request **preq) +{ + *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); + if (*preq) + return 0; + ERROR(fsg, "can't allocate request for %s\n", ep->name); + return -ENOMEM; +} + +/* + * Reset interface setting and re-init endpoint state (toggle etc). + * Call with altsetting < 0 to disable the interface. The only other + * available altsetting is 0, which enables the interface. + */ +static int do_set_interface(struct fsg_dev *fsg, int altsetting) +{ + struct usb_composite_dev *cdev = fsg->function.config->cdev; + int rc = 0; + int i; + const struct usb_endpoint_descriptor *d; + + if (fsg->running) + DBG(fsg, "reset interface\n"); + +reset: + /* Deallocate the requests */ + for (i = 0; i < NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + + if (bh->inreq) { + usb_ep_free_request(fsg->bulk_in, bh->inreq); + bh->inreq = NULL; + } + if (bh->outreq) { + usb_ep_free_request(fsg->bulk_out, bh->outreq); + bh->outreq = NULL; + } + } + + /* Disable the endpoints */ + if (fsg->bulk_in_enabled) { + DBG(fsg, "usb_ep_disable %s\n", fsg->bulk_in->name); + usb_ep_disable(fsg->bulk_in); + fsg->bulk_in_enabled = 0; + } + if (fsg->bulk_out_enabled) { + DBG(fsg, "usb_ep_disable %s\n", fsg->bulk_out->name); + usb_ep_disable(fsg->bulk_out); + fsg->bulk_out_enabled = 0; + } + + fsg->running = 0; + if (altsetting < 0 || rc != 0) + return rc; + + DBG(fsg, "set interface %d\n", altsetting); + + /* Enable the endpoints */ + d = ep_desc(cdev->gadget, &fs_bulk_in_desc, &hs_bulk_in_desc); + if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0) + goto reset; + fsg->bulk_in_enabled = 1; + + d = ep_desc(cdev->gadget, &fs_bulk_out_desc, &hs_bulk_out_desc); + if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) + goto reset; + fsg->bulk_out_enabled = 1; + fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); + + /* Allocate the requests */ + for (i = 0; i < NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + + rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq); + if (rc != 0) + goto reset; + rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq); + if (rc != 0) + goto reset; + bh->inreq->buf = bh->outreq->buf = bh->buf; + bh->inreq->context = bh->outreq->context = bh; + bh->inreq->complete = bulk_in_complete; + bh->outreq->complete = bulk_out_complete; + } + + fsg->running = 1; + for (i = 0; i < fsg->nluns; ++i) + fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; + + return rc; +} + +static void adjust_wake_lock(struct fsg_dev *fsg) +{ + int ums_active = 0; + int i; + + spin_lock_irq(&fsg->lock); + + if (fsg->config) { + for (i = 0; i < fsg->nluns; ++i) { + if (backing_file_is_open(&fsg->luns[i])) + ums_active = 1; + } + } + + if (ums_active) + wake_lock(&fsg->wake_lock); + else + wake_unlock(&fsg->wake_lock); + + spin_unlock_irq(&fsg->lock); +} + +/* + * Change our operational configuration. This code must agree with the code + * that returns config descriptors, and with interface altsetting code. + * + * It's also responsible for power management interactions. Some + * configurations might not work with our current power sources. + * For now we just assume the gadget is always self-powered. + */ +static int do_set_config(struct fsg_dev *fsg, u8 new_config) +{ + int rc = 0; + + /* Disable the single interface */ + if (fsg->config != 0) { + DBG(fsg, "reset config\n"); + fsg->config = 0; + rc = do_set_interface(fsg, -1); + } + + /* Enable the interface */ + if (new_config != 0) { + fsg->config = new_config; + rc = do_set_interface(fsg, 0); + if (rc != 0) + fsg->config = 0; /* Reset on errors */ + else + INFO(fsg, "config #%d\n", fsg->config); + + switch_set_state(&fsg->sdev, STATE_USB_DEVICE_ONLINE); + } + + adjust_wake_lock(fsg); + + return rc; +} + + +/*-------------------------------------------------------------------------*/ + +static void handle_exception(struct fsg_dev *fsg) +{ + siginfo_t info; + int sig; + int i; + struct fsg_buffhd *bh; + enum fsg_state old_state; + u8 new_config; + struct lun *curlun; + int rc; + int num_active; + + DBG(fsg, "handle_exception state: %d\n", (int)fsg->state); + /* Clear the existing signals. Anything but SIGUSR1 is converted + * into a high-priority EXIT exception. */ + for (;;) { + sig = dequeue_signal_lock(current, ¤t->blocked, &info); + if (!sig) + break; + if (sig != SIGUSR1) { + if (fsg->state < FSG_STATE_EXIT) + DBG(fsg, "Main thread exiting on signal\n"); + raise_exception(fsg, FSG_STATE_EXIT); + } + } + + /* Added by River from file_storage.c */ + /* Pending request will not be free without these processes. + It will cause an "bulk-out -22" error when plug in / out the cable. */ + + /* Cancel all the pending transfers */ + for (i = 0; i < NUM_BUFFERS; ++i) { + bh = &fsg->buffhds[i]; + if (bh->inreq_busy) + usb_ep_dequeue(fsg->bulk_in, bh->inreq); + if (bh->outreq_busy) + usb_ep_dequeue(fsg->bulk_out, bh->outreq); + } + + /* Wait until everything is idle */ + for (;;) { + num_active = 0; + for (i = 0; i < NUM_BUFFERS; ++i) { + bh = &fsg->buffhds[i]; + num_active += bh->inreq_busy + bh->outreq_busy; + } + if (num_active == 0) + break; + if (sleep_thread(fsg)) + return; + } + /* End Added */ + + /* Clear out the controller's fifos */ + if (fsg->bulk_in_enabled) + usb_ep_fifo_flush(fsg->bulk_in); + if (fsg->bulk_out_enabled) + usb_ep_fifo_flush(fsg->bulk_out); + + /* Reset the I/O buffer states and pointers, the SCSI + * state, and the exception. Then invoke the handler. */ + spin_lock_irq(&fsg->lock); + + for (i = 0; i < NUM_BUFFERS; ++i) { + bh = &fsg->buffhds[i]; + bh->state = BUF_STATE_EMPTY; + } + fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain = + &fsg->buffhds[0]; + + new_config = fsg->new_config; + old_state = fsg->state; + + if (old_state == FSG_STATE_ABORT_BULK_OUT) + fsg->state = FSG_STATE_STATUS_PHASE; + else { + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; + curlun->prevent_medium_removal = 0; + curlun->sense_data = curlun->unit_attention_data = + SS_NO_SENSE; + curlun->sense_data_info = 0; + curlun->info_valid = 0; + } + fsg->state = FSG_STATE_IDLE; + } + spin_unlock_irq(&fsg->lock); + + /* Carry out any extra actions required for the exception */ + switch (old_state) { + default: + break; + + case FSG_STATE_ABORT_BULK_OUT: + spin_lock_irq(&fsg->lock); + if (fsg->state == FSG_STATE_STATUS_PHASE) + fsg->state = FSG_STATE_IDLE; + spin_unlock_irq(&fsg->lock); + break; + + case FSG_STATE_RESET: + /* really not much to do here */ + break; + + case FSG_STATE_CONFIG_CHANGE: + rc = do_set_config(fsg, new_config); + if (new_config == 0) { + /* We're using the backing file */ + down_read(&fsg->filesem); + fsync_all(fsg); + up_read(&fsg->filesem); + } + break; + + case FSG_STATE_EXIT: + case FSG_STATE_TERMINATED: + do_set_config(fsg, 0); /* Free resources */ + spin_lock_irq(&fsg->lock); + fsg->state = FSG_STATE_TERMINATED; /* Stop the thread */ + spin_unlock_irq(&fsg->lock); + break; + } +} + +/* Handle USB device state - Added by River */ +static inline void fsg_handle_usb_state(struct fsg_dev *fsg) +{ + + if ((test_bit(SUSPENDED, &fsg->atomic_bitflags))) + { + +#ifdef GHOST + /* Flush NAND LB Cache when it's active. */ + if (lb_is_active(fsg)) { + printk(KERN_ERR "%s(): NAND LB Cache Flush.\n", __func__); + NAND_LB_FLASHCACHE(); + NAND_MTD_FLASHCACHE(); + } +#endif + + /* Sync file when suspended */ + down_read(&fsg->filesem); + fsync_all(fsg); + up_read(&fsg->filesem); + + /* Using fsg_function_resume() to clear this bit is inaccurate. So we clear it ourself. */ + clear_bit(SUSPENDED, &fsg->atomic_bitflags); + } + + return; +} + +/*-------------------------------------------------------------------------*/ + +static int fsg_main_thread(void *fsg_) +{ + struct fsg_dev *fsg = fsg_; + + /* Allow the thread to be killed by a signal, but set the signal mask + * to block everything but INT, TERM, KILL, and USR1. */ + allow_signal(SIGINT); + allow_signal(SIGTERM); + allow_signal(SIGKILL); + allow_signal(SIGUSR1); + + /* Allow the thread to be frozen */ + set_freezable(); + + /* Arrange for userspace references to be interpreted as kernel + * pointers. That way we can pass a kernel pointer to a routine + * that expects a __user pointer and it will work okay. */ + set_fs(get_ds()); + + /* The main loop */ + while (fsg->state != FSG_STATE_TERMINATED) { + + /* Handle USB state first - Added by River */ + fsg_handle_usb_state(fsg); + + if (exception_in_progress(fsg) || signal_pending(current)) { + handle_exception(fsg); + continue; + } + + if (!fsg->running) { + sleep_thread(fsg); + continue; + } + + if (get_next_command(fsg)) + continue; + + spin_lock_irq(&fsg->lock); + if (!exception_in_progress(fsg)) + fsg->state = FSG_STATE_DATA_PHASE; + spin_unlock_irq(&fsg->lock); + + if (do_scsi_command(fsg) || finish_reply(fsg)) + continue; + + spin_lock_irq(&fsg->lock); + if (!exception_in_progress(fsg)) + fsg->state = FSG_STATE_STATUS_PHASE; + spin_unlock_irq(&fsg->lock); + + if (send_status(fsg)) + continue; + + spin_lock_irq(&fsg->lock); + if (!exception_in_progress(fsg)) + fsg->state = FSG_STATE_IDLE; + spin_unlock_irq(&fsg->lock); + } + + spin_lock_irq(&fsg->lock); + fsg->thread_task = NULL; + spin_unlock_irq(&fsg->lock); + + /* In case we are exiting because of a signal, unregister the + * gadget driver and close the backing file. */ + if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) + close_all_backing_files(fsg); + + /* Let the unbind and cleanup routines know the thread has exited */ + complete_and_exit(&fsg->thread_notifier, 0); +} + + +/*-------------------------------------------------------------------------*/ + +/* If the next two routines are called while the gadget is registered, + * the caller must own fsg->filesem for writing. */ + +static int open_backing_file(struct fsg_dev *fsg, struct lun *curlun, + const char *filename) +{ + int ro; + struct file *filp = NULL; + int rc = -EINVAL; + struct inode *inode = NULL; + loff_t size; + loff_t num_sectors; + + /* R/W if we can, R/O if we must */ + ro = curlun->ro; + if (!ro) { + filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0); + if (-EROFS == PTR_ERR(filp)) + ro = 1; + } + if (ro) + filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0); + if (IS_ERR(filp)) { + LINFO(curlun, "unable to open backing file: %s\n", filename); + return PTR_ERR(filp); + } + + if (!(filp->f_mode & FMODE_WRITE)) + ro = 1; + + if (filp->f_path.dentry) + inode = filp->f_path.dentry->d_inode; + if (inode && S_ISBLK(inode->i_mode)) { + if (bdev_read_only(inode->i_bdev)) + ro = 1; + } else if (!inode || !S_ISREG(inode->i_mode)) { + LINFO(curlun, "invalid file type: %s\n", filename); + goto out; + } + + /* If we can't read the file, it's no good. + * If we can't write the file, use it read-only. */ + if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) { + LINFO(curlun, "file not readable: %s\n", filename); + goto out; + } + if (!(filp->f_op->write || filp->f_op->aio_write)) + ro = 1; + + size = i_size_read(inode->i_mapping->host); + if (size < 0) { + LINFO(curlun, "unable to find file size: %s\n", filename); + rc = (int) size; + goto out; + } + num_sectors = size >> 9; /* File size in 512-byte sectors */ + if (num_sectors == 0) { + LINFO(curlun, "file too small: %s\n", filename); + rc = -ETOOSMALL; + goto out; + } + + get_file(filp); + curlun->ro = ro; + curlun->filp = filp; + curlun->file_length = size; + curlun->num_sectors = num_sectors; + LDBG(curlun, "open backing file: %s size: %lld num_sectors: %lld\n", + filename, size, num_sectors); + rc = 0; + +#ifdef GHOST + if (lun_is_type_mtd(curlun)) { + lb_enable(curlun); + } +#endif + + adjust_wake_lock(fsg); + +out: + filp_close(filp, current->files); + return rc; +} + + +static void close_backing_file(struct fsg_dev *fsg, struct lun *curlun) +{ + if (curlun->filp) { + int rc; + + /* + * XXX: San: Ugly hack here added to ensure that + * our pages get synced to disk. + * Also drop caches here just to be extra-safe + */ + rc = do_fsync(curlun->filp, 1); + if (rc < 0) + printk(KERN_ERR "ums: Error syncing data (%d)\n", rc); + /* drop_pagecache and drop_slab are no longer available */ + /* drop_pagecache(); */ + /* drop_slab(); */ + + LDBG(curlun, "close backing file\n"); +#ifdef GHOST + if (lun_is_type_mtd(curlun)) + lb_disable(curlun); +#endif + fput(curlun->filp); + curlun->filp = NULL; + adjust_wake_lock(fsg); + } +} + +static void close_all_backing_files(struct fsg_dev *fsg) +{ + int i; + + for (i = 0; i < fsg->nluns; ++i) + close_backing_file(fsg, &fsg->luns[i]); +} + +static ssize_t show_file(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct lun *curlun = dev_to_lun(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); + char *p; + ssize_t rc; + + down_read(&fsg->filesem); + if (backing_file_is_open(curlun)) { /* Get the complete pathname */ + p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1); + if (IS_ERR(p)) + rc = PTR_ERR(p); + else { + rc = strlen(p); + memmove(buf, p, rc); + buf[rc] = '\n'; /* Add a newline */ + buf[++rc] = 0; + } + } else { /* No file, return 0 bytes */ + *buf = 0; + rc = 0; + } + up_read(&fsg->filesem); + return rc; +} + +static ssize_t store_file(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lun *curlun = dev_to_lun(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); + int rc = 0; + + DBG(fsg, "store_file: \"%s\"\n", buf); + +#if 0 + /* disabled because we need to allow closing the backing file if the media was removed */ + if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) { + LDBG(curlun, "eject attempt prevented\n"); + return -EBUSY; /* "Door is locked" */ + } +#endif + + /* Remove a trailing newline */ + if (count > 0 && buf[count-1] == '\n') + ((char *) buf)[count-1] = 0; + + /* Eject current medium */ + down_write(&fsg->filesem); + if (backing_file_is_open(curlun)) { + close_backing_file(fsg, curlun); + curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; + } + +#ifdef GHOST + strstr(buf, "mtdblock") ? lun_set_type_mtd(curlun) : lun_set_type_normal(curlun); +#endif + + /* Load new medium */ + if (count > 0 && buf[0]) { + rc = open_backing_file(fsg, curlun, buf); + if (rc == 0) + curlun->unit_attention_data = + SS_NOT_READY_TO_READY_TRANSITION; + } + + if (backing_file_is_open(curlun)) { + if (test_bit(USB_CABLE_ONLINE, &fsg->atomic_bitflags)) + fsg_gadget_connect(fsg); + } + + up_write(&fsg->filesem); + return (rc < 0 ? rc : count); +} + + +static DEVICE_ATTR(file, 0444, show_file, store_file); + +/*-------------------------------------------------------------------------*/ + +static void fsg_release(struct kref *ref) +{ + struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref); + + kfree(fsg->luns); + kfree(fsg); +} + +static void lun_release(struct device *dev) +{ + struct fsg_dev *fsg = dev_get_drvdata(dev); + + kref_put(&fsg->ref, fsg_release); +} + + +/*-------------------------------------------------------------------------*/ + +static int __init fsg_alloc(void) +{ + struct fsg_dev *fsg; + + fsg = kzalloc(sizeof *fsg, GFP_KERNEL); + if (!fsg) + return -ENOMEM; + spin_lock_init(&fsg->lock); + init_rwsem(&fsg->filesem); + kref_init(&fsg->ref); + init_completion(&fsg->thread_notifier); + + the_fsg = fsg; + return 0; +} + +static ssize_t print_switch_name(struct switch_dev *sdev, char *buf) +{ + return sprintf(buf, "%s\n", DRIVER_NAME); +} + + +static ssize_t print_switch_state(struct switch_dev *sdev, char *buf) +{ + /* Result decided by the state of switch_device - Fixed by River */ + return sprintf(buf, "%s\n", ((switch_get_state(sdev) == STATE_USB_DEVICE_ONLINE) ? "online" : "offline")); +} + + +static void +fsg_function_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct fsg_dev *fsg = func_to_dev(f); + int i; + struct lun *curlun; + + DBG(fsg, "fsg_function_unbind\n"); + clear_bit(REGISTERED, &fsg->atomic_bitflags); + + /* Unregister the sysfs attribute files and the LUNs */ + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; + + if (curlun->registered) { + device_remove_file(&curlun->dev, &dev_attr_file); + device_unregister(&curlun->dev); + curlun->registered = 0; + } + } + + /* If the thread isn't already dead, tell it to exit now */ + if (fsg->state != FSG_STATE_TERMINATED) { + raise_exception(fsg, FSG_STATE_EXIT); + wait_for_completion(&fsg->thread_notifier); + + /* The cleanup routine waits for this completion also */ + complete(&fsg->thread_notifier); + } + + /* Free the data buffers */ + for (i = 0; i < NUM_BUFFERS; ++i) + kfree(fsg->buffhds[i].buf); + + /* Unregister switch_device - Added by River */ + switch_dev_unregister(&fsg->sdev); + + return; +} + +/* Event notifier - Added by River */ +static int have_open_lun(struct fsg_dev *fsg) +{ + int i; + + for (i = 0; i < fsg->nluns; ++i) + if (backing_file_is_open(&fsg->luns[i])) + return 1; /* A Lun have open file. */ + + return 0; +} + + +static int fsg_event_notifier(struct notifier_block *n, unsigned long val, void *data) +{ + struct fsg_dev *fsg = the_fsg; + + udc_hotplug_event_t *e = (udc_hotplug_event_t *)data; + + switch (e->type) { + case EVENT_TYPE_CABLE: + if (e->state == EVENT_STATE_OFFLINE) { + printk(KERN_ERR "%s(): Cable Offline. \n", __func__); + /* Disconnect gadget when cable is offline. */ + fsg_gadget_disconnect(fsg); + + clear_bit(USB_CABLE_ONLINE, &fsg->atomic_bitflags); + } + break; + + case EVENT_TYPE_USB: + switch (e->state) { + case EVENT_STATE_OFFLINE: + printk(KERN_ERR "%s(): USB Offline.\n", __func__); + + switch_set_state(&fsg->sdev, STATE_USB_DEVICE_OFFLINE); + + clear_bit(USB_CABLE_ONLINE, &fsg->atomic_bitflags); + + /* Stop keep alive. */ + udc_hotplug_stop_keep_alive(); + + break; + + case EVENT_STATE_ONLINE: + printk(KERN_ERR "%s(): USB Online.\n", __func__); + + set_bit(USB_CABLE_ONLINE, &fsg->atomic_bitflags); + + if (test_bit(EVENT_FLAG_UDC_PHY_TOUCHED, &e->flags)) { + set_bit(USB_GADGET_NEED_RECONNECT, &fsg->atomic_bitflags); + } + + if (have_open_lun(fsg)) { + /* Have open LUN -> if gadget is not connected, connect it now.*/ + fsg_gadget_connect(fsg); + } + + switch_set_state(&fsg->sdev, STATE_USB_DEVICE_ONLINE); + + break; + } + break; + + } + + return 0; +} +/* End Added */ + +static int __init +fsg_function_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct usb_composite_dev *cdev = c->cdev; + struct fsg_dev *fsg = func_to_dev(f); + int rc; + int i; + int id; + struct lun *curlun; + struct usb_ep *ep; + char *pathbuf, *p; + + DBG(fsg, "fsg_function_bind\n"); + + /* Register switch device - Moved from mass_storage_function_add() - Added by River */ + fsg->sdev.name = DRIVER_NAME; + fsg->sdev.print_name = print_switch_name; + fsg->sdev.print_state = print_switch_state; + + rc = switch_dev_register(&fsg->sdev); + if (rc < 0) + goto out; + + dev_attr_file.attr.mode = 0644; + /* End Added */ + + /* Leave gadget disconnected - Wait UDC hotplug event - Added by River */ + usb_gadget_disconnect(cdev->gadget); + + clear_bit(USB_CABLE_ONLINE, &fsg->atomic_bitflags); + clear_bit(USB_GADGET_CONNECTED, &fsg->atomic_bitflags); + + switch_set_state(&fsg->sdev, STATE_USB_DEVICE_OFFLINE); + /* End Added */ + + /* Find out how many LUNs there should be */ + + i = fsg->nluns; + + if (i == 0) + i = 1; + if (i > MAX_LUNS) { + ERROR(fsg, "invalid number of LUNs: %d\n", i); + rc = -EINVAL; + goto out; + } + + /* Create the LUNs, open their backing files, and register the + * LUN devices in sysfs. */ + fsg->luns = kzalloc(i * sizeof(struct lun), GFP_KERNEL); + if (!fsg->luns) { + rc = -ENOMEM; + goto out; + } + + fsg->nluns = i; + + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; + curlun->ro = 0; + curlun->dev.release = lun_release; + curlun->dev.parent = &cdev->gadget->dev; + dev_set_drvdata(&curlun->dev, fsg); + snprintf(curlun->dev.bus_id, BUS_ID_SIZE, + "lun%d", i); + + rc = device_register(&curlun->dev); + if (rc != 0) { + INFO(fsg, "failed to register LUN%d: %d\n", i, rc); + goto out; + } + rc = device_create_file(&curlun->dev, &dev_attr_file); + if (rc != 0) { + ERROR(fsg, "device_create_file failed: %d\n", rc); + device_unregister(&curlun->dev); + goto out; + } + + /* Initialize LUN attribute - Added by River */ + curlun->attr = &fsg->lun_attr_table[i]; + + curlun->registered = 1; + kref_get(&fsg->ref); + } + + /* allocate interface ID(s) */ + id = usb_interface_id(c, f); + if (id < 0) + return id; + intf_desc.bInterfaceNumber = id; + + ep = usb_ep_autoconfig(cdev->gadget, &fs_bulk_in_desc); + if (!ep) + goto autoconf_fail; + ep->driver_data = fsg; /* claim the endpoint */ + fsg->bulk_in = ep; + + ep = usb_ep_autoconfig(cdev->gadget, &fs_bulk_out_desc); + if (!ep) + goto autoconf_fail; + ep->driver_data = fsg; /* claim the endpoint */ + fsg->bulk_out = ep; + + rc = -ENOMEM; + + if (gadget_is_dualspeed(cdev->gadget)) { + /* Assume endpoint addresses are the same for both speeds */ + hs_bulk_in_desc.bEndpointAddress = + fs_bulk_in_desc.bEndpointAddress; + hs_bulk_out_desc.bEndpointAddress = + fs_bulk_out_desc.bEndpointAddress; + + f->hs_descriptors = hs_function; + } + + /* Allocate the data buffers */ + for (i = 0; i < NUM_BUFFERS; ++i) { + struct fsg_buffhd *bh = &fsg->buffhds[i]; + + /* Allocate for the bulk-in endpoint. We assume that + * the buffer will also work with the bulk-out (and + * interrupt-in) endpoint. */ + bh->buf = kmalloc(fsg->buf_size, GFP_KERNEL); + if (!bh->buf) + goto out; + bh->next = bh + 1; + } + fsg->buffhds[NUM_BUFFERS - 1].next = &fsg->buffhds[0]; + + fsg->thread_task = kthread_create(fsg_main_thread, fsg, + shortname); + if (IS_ERR(fsg->thread_task)) { + rc = PTR_ERR(fsg->thread_task); + ERROR(fsg, "kthread_create failed: %d\n", rc); + goto out; + } + + INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); + +#ifdef GHOST + INFO(fsg, "NAND LB Cache is on.\n"); +#endif + + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); + for (i = 0; i < fsg->nluns; ++i) { + curlun = &fsg->luns[i]; + if (backing_file_is_open(curlun)) { + p = NULL; + if (pathbuf) { + p = d_path(&curlun->filp->f_path, + pathbuf, PATH_MAX); + if (IS_ERR(p)) + p = NULL; + } + LINFO(curlun, "ro=%d, file: %s\n", + curlun->ro, (p ? p : "(error)")); + } + } + kfree(pathbuf); + + set_bit(REGISTERED, &fsg->atomic_bitflags); + + /* Tell the thread to start working */ + wake_up_process(fsg->thread_task); + + /* Request current state when being registered. - Added by River. */ + fsg->nb.notifier_call = fsg_event_notifier; + if (udc_hotplug_register_notifier(&fsg->nb, 1)) + goto out; + /* End added */ + + return 0; + +autoconf_fail: + ERROR(fsg, "unable to autoconfigure all endpoints\n"); + rc = -ENOTSUPP; + +out: + DBG(fsg, "fsg_function_bind failed: %d\n", rc); + fsg->state = FSG_STATE_TERMINATED; /* The thread is dead */ + fsg_function_unbind(c, f); + close_all_backing_files(fsg); + return rc; +} + +static int fsg_function_set_alt(struct usb_function *f, + unsigned intf, unsigned alt) +{ + struct fsg_dev *fsg = func_to_dev(f); + DBG(fsg, "fsg_function_set_alt intf: %d alt: %d\n", intf, alt); + fsg->new_config = 1; + raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); + return 0; +} + +static void fsg_function_disable(struct usb_function *f) +{ + struct fsg_dev *fsg = func_to_dev(f); + + DBG(fsg, "fsg_function_disable\n"); + fsg->new_config = 0; + raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); +} + +/* Added by River */ +static void fsg_function_suspend(struct usb_function *f) +{ + struct fsg_dev *fsg = func_to_dev(f); + + DBG(fsg, "suspend\n"); + set_bit(SUSPENDED, &fsg->atomic_bitflags); +} + +static void fsg_function_resume(struct usb_function *f) +{ + struct fsg_dev *fsg = func_to_dev(f); + + DBG(fsg, "resume\n"); + clear_bit(SUSPENDED, &fsg->atomic_bitflags); +} +/* End added */ + +/* Add lun_attr_table parameter - Added by River */ +int __init mass_storage_function_add(struct usb_configuration *c, lun_attr_t *lun_attr_table, int nluns) +{ + int rc; + struct fsg_dev *fsg; + + printk(KERN_INFO "mass_storage_function_add\n"); + rc = fsg_alloc(); + if (rc) + return rc; + fsg = the_fsg; + + fsg->nluns = nluns; + + /* Save LUN attribute table pointer - Added by River */ + fsg->lun_attr_table = lun_attr_table; + + spin_lock_init(&fsg->lock); + init_rwsem(&fsg->filesem); + kref_init(&fsg->ref); + init_completion(&fsg->thread_notifier); + + the_fsg->buf_size = BULK_BUFFER_SIZE; + wake_lock_init(&the_fsg->wake_lock, WAKE_LOCK_SUSPEND, + "usb_mass_storage"); + + fsg->function.name = shortname; + fsg->function.descriptors = fs_function; + fsg->function.bind = fsg_function_bind; + fsg->function.unbind = fsg_function_unbind; + fsg->function.setup = fsg_function_setup; + fsg->function.set_alt = fsg_function_set_alt; + fsg->function.disable = fsg_function_disable; + + /* NAND_LB needs these routines - Added by River */ + fsg->function.suspend = fsg_function_suspend; + fsg->function.resume = fsg_function_resume; + + rc = usb_add_function(c, &fsg->function); + if (rc != 0) + goto err_usb_add_function; + + return 0; + +err_usb_add_function: + kref_put(&the_fsg->ref, fsg_release); + + return rc; +} + diff --git a/target/linux/xburst/files-2.6.27/drivers/usb/gadget/f_mass_storage.h b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/f_mass_storage.h new file mode 100644 index 000000000..c51f3e0f1 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/f_mass_storage.h @@ -0,0 +1,65 @@ +/* + * drivers/usb/gadget/f_mass_storage.h + * + * Function Driver for USB Mass Storage + * + * Copyright (C) 2008 Google, Inc. + * Author: Mike Lockwood + * + * Based heavily on the file_storage gadget driver in + * drivers/usb/gadget/file_storage.c and licensed under the same terms: + * + * Copyright (C) 2003-2007 Alan Stern + * 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, + * without modification. + * 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. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * ALTERNATIVELY, this software may be 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. + * + * 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 COPYRIGHT OWNER 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. + */ + +#ifndef __F_MASS_STORAGE_H +#define __F_MASS_STORAGE_H + +/* USB device state - solve switch_device uevent notification BUG - River */ +enum { + STATE_USB_DEVICE_OFFLINE = 0, + STATE_USB_DEVICE_ONLINE, +}; + +/* LUN Attribute */ +typedef struct { + char *vendor; + char *product; + int release; +}lun_attr_t; + +/* Add lun_attr_table parameter - River */ +int mass_storage_function_add(struct usb_configuration *c, lun_attr_t *lun_attr_table, int nluns); + +#endif /* __F_MASS_STORAGE_H */ diff --git a/target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4730_udc.c b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4730_udc.c new file mode 100755 index 000000000..fb182a668 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 "); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4730_udc.h b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4730_udc.h new file mode 100755 index 000000000..6ea368b32 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4740_udc.c b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4740_udc.c new file mode 100755 index 000000000..4946ae8cc --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4740_udc.c @@ -0,0 +1,2297 @@ +/* + * linux/drivers/usb/gadget/jz4740_udc.c + * + * Ingenic JZ4740 on-chip high speed USB device controller + * + * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. + * 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "jz4740_udc.h" + +#include "udc_hotplug.h" + +//#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 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 or power type"); + +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 [] = "ingenic_hsusb"; + +struct jz4740_udc *the_controller; + +static const char driver_name [] = "ingenic_hsusb"; +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); +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); + +#if 0 + /* UDC state is incorrect. - Added by River */ + if (dev->state != UDC_STATE_DISABLE) + return; +#endif + 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) + REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE; +#endif + + dev->ep0state = WAIT_FOR_SETUP; + dev->gadget.speed = USB_SPEED_UNKNOWN; + + return; +} + +/* + * 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); + + /* UDC state is incorrect - Added by River */ + if (dev->state != UDC_STATE_ENABLE) + return; + + 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) + 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); + + return; +} + +/*-------------------------------------------------------------------------*/ + +/* 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-EBUSY"); + 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; + } + + /* then enable host detection and ep0; and we're ready + * for set_configuration as well as eventual disconnect. + */ + udc_enable(dev); + 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; + + 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 */ + list_add_tail(&req->queue, &ep->queue); + jz4740_ep0_kick(dev, ep); + req = 0; + } 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); + + 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); + + 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; +} + +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; + 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; + + 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--; + } + } + + /* 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) { + if (req->req.length == 0) { + DEBUG_EP0("ZERO LENGTH OUT!\n"); +/* usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); */ + usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY)); + dev->ep0state = WAIT_FOR_SETUP; + return; + } + 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 == 0) { + usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); + dev->ep0state = WAIT_FOR_SETUP; + return 1; + } + + 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 1 +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; + + 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; + +#if 1 + case USB_REQ_GET_STATUS: + if (jz4740_handle_get_status(dev, &ctrl) == 0) + return; +#endif + + 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; + } + + /* 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); + if (!ctrl.wLength) { + usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY); + } + } + } +} + +/* + * 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) +{ + u32 csr; + + usb_set_index(0); + csr = usb_readb(USB_REG_CSR0); + + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + /* Clear "out packet ready" */ + usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY); + + if (ep_is_in(ep)) { + dev->ep0state = DATA_STATE_XMIT; + jz4740_ep0_in(dev, csr); + } else { + dev->ep0state = DATA_STATE_RECV; + jz4740_ep0_out(dev, csr); + } +} + +/** Handle USB RESET interrupt + */ +static void jz4740_reset_irq(struct jz4740_udc *dev) +{ + 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" ); +} + +/* + * jz4740 usb device interrupt handler. + */ +static irqreturn_t jz4740_udc_irq(int irq, void *_dev) +{ + struct jz4740_udc *dev = _dev; + + 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"); + dev->driver->resume(&dev->gadget); /* We have suspend(), so we must have resume() too. */ + } + + /* Check for system interrupts */ + if (intr_usb & USB_INTR_RESET) { + DEBUG("USB reset\n"); +#ifdef CONFIG_USB_JZ_UDC_HOTPLUG + udc_hotplug_do_keep_alive(); +#endif + if (udc_debug) { + /* We have tested the cable type, disable module and + * disconnect from host right now. + */ + udc_disable(dev); + spin_unlock(&dev->lock); + return IRQ_HANDLED; + } + jz4740_reset_irq(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"); + dev->driver->suspend(&dev->gadget); + /* Host unloaded from us, can do something, such as flushing + the NAND block cache etc. */ + } + +#ifdef CONFIG_USB_JZ_UDC_HOTPLUG + udc_hotplug_do_keep_alive(); +#endif + + spin_unlock(&dev->lock); + return IRQ_HANDLED; +} + + + +/*-------------------------------------------------------------------------*/ + +/* Common functions - Added by River */ +static struct jz4740_udc udc_dev; + +static inline struct jz4740_udc *gadget_to_udc(struct usb_gadget *gadget) +{ + return container_of(gadget, struct jz4740_udc, gadget); +} +/* End added */ + +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 int jz4740_udc_pullup(struct usb_gadget *_gadget, int on) +{ + + struct jz4740_udc *udc = gadget_to_udc(_gadget); + + unsigned long flags; + + local_irq_save(flags); + + if (on) { + udc->state = UDC_STATE_ENABLE; + udc_enable(udc); + }else{ + udc->state = UDC_STATE_DISABLE; + udc_disable(udc); + } + + local_irq_restore(flags); + + return 0; +} + +static const struct usb_gadget_ops jz4740_udc_ops = { + .get_frame = jz4740_udc_get_frame, + .wakeup = jz4740_udc_wakeup, + .pullup = jz4740_udc_pullup, + /* 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 = { + .bus_id = "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; +// device_initialize(&dev->gadget.dev); /* device_register() will do this. In Linux-2.6.27 re-initializing a kobject will cause a warning. */ + 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"); + + 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 UDC_PROC_FILE + remove_proc_entry(proc_node_name, NULL); +#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 "); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4740_udc.h b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4740_udc.h new file mode 100755 index 000000000..88e04a7b9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/jz4740_udc.h @@ -0,0 +1,121 @@ +/* + * linux/drivers/usb/gadget/jz4740_udc.h + * + * Ingenic JZ4740 on-chip high speed USB device controller + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * 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. + */ + +#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 */ +}; + +/* For function binding with UDC Disable - Added by River */ +typedef enum { + UDC_STATE_ENABLE = 0, + UDC_STATE_DISABLE, +}udc_state_t; + +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; + + /* UDC state - Added by River */ + udc_state_t state; +}; + +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 + +#ifndef IRQ_NONE +typedef void irqreturn_t; +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_RETVAL(x) +#endif + +#endif /* __USB_GADGET_JZ4740_H__ */ diff --git a/target/linux/xburst/files-2.6.27/drivers/usb/gadget/udc_hotplug.h b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/udc_hotplug.h new file mode 100644 index 000000000..b7cb81e36 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/udc_hotplug.h @@ -0,0 +1,50 @@ +/* + * Ingenic USB Device Contoller Hotplug External Interfaces + */ + +#ifndef __UDC_HOTPLUG_H__ +#define __UDC_HOTPLUG_H__ + +#include + +typedef enum { + BROADCAST_TYPE_STATE = 0, + BROADCAST_TYPE_EVENT, +}udc_hotplug_broadcast_type_t; + +typedef enum { + EVENT_STATE_OFFLINE = 0, + EVENT_STATE_ONLINE, +}udc_hotplug_event_state_t; + +typedef enum { + EVENT_TYPE_USB = 0, + EVENT_TYPE_CABLE, +}udc_hotplug_event_type_t; + +enum { + EVENT_FLAG_UDC_PHY_TOUCHED = 0, +}; + +typedef struct { + udc_hotplug_event_type_t type; + udc_hotplug_event_state_t state; + unsigned long flags; +}udc_hotplug_event_t; + +/* Register notifier */ +int udc_hotplug_register_notifier(struct notifier_block *n, int request_state); + +/* Unregister notifier */ +int udc_hotplug_unregister_notifier(struct notifier_block *n); + +/* Start keep alive */ +int udc_hotplug_start_keep_alive(unsigned long timer_interval_in_jiffies, unsigned long counter_limit); + +/* Do keep alive */ +void udc_hotplug_do_keep_alive(void); + +/* Stop keep alive */ +void udc_hotplug_stop_keep_alive(void); + +#endif /* Define __UDC_HOTPLUG_H__ */ diff --git a/target/linux/xburst/files-2.6.27/drivers/usb/gadget/udc_hotplug_core.c b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/udc_hotplug_core.c new file mode 100644 index 000000000..e4e324da6 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/usb/gadget/udc_hotplug_core.c @@ -0,0 +1,836 @@ +/* + * Ingenic USB Device Controller Hotplug Core Function + * Detection mechanism and code are based on the old version of udc_hotplug.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "udc_hotplug.h" + +#define PFX "jz_hotplug_udc" + +#define D(msg, fmt...) \ +// printk(KERN_ERR PFX": %s(): "msg, __func__, ##fmt); + +/* HAVE_DETECT_SYNC + Provide a lock like seqlock keep the synchronization between the start and the end of a detection, + If the lock seems not synchronous(new interrupt comes, when doing our detection) in the end of a detection, + the result of the detection is discarded. No event will be broadcast, and the detection will be restarted. + + Use to filter out more significant events when the interrupt is too noisy. +*/ + +//#define HAVE_DETECT_SYNC 1 + +#if defined (HAVE_DETECT_SYNC) +#define NR_RESTART_TIMES 3 +#define NR_JIFFIES_SLEEP_BEFORE_RESTART 7 +#endif + +#define NR_GPIO_STABLE_TIMES 50 +#define NR_JIFFIES_USB_DETECT_WAIT 11 + +#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) + +/* UDC State bits */ +enum { + /* Online state. */ + BIT_CABLE_ONLINE = 0, + BIT_USB_ONLINE, + + /* State changed ?*/ + BIT_CABLE_CHANGE, + BIT_USB_CHANGE, + + /* What detection will be done ? */ + BIT_DO_CABLE_DETECT, + BIT_DO_USB_DETECT, + + /* What detection is requested ? */ + BIT_REQUEST_CABLE_DETECT, + BIT_REQUEST_USB_DETECT, + + /* Indicate whether a detection is finisned. */ + BIT_USB_DETECT_DONE, + BIT_CABLE_DETECT_DONE, + + BIT_UDC_PHY_TOUCHED, + + /* Keep alive */ + BIT_KEEP_ALIVE, + BIT_KEEP_ALIVE_TIMEOUT, +}; + +struct uh_data { + /* Notifier */ + struct blocking_notifier_head notifier_head; + + /* Thread */ + struct task_struct *kthread; + + /* Wait queue */ + wait_queue_head_t kthread_wq; /* Kernel thread sleep here. */ + wait_queue_head_t wq; /* Others sleep here. */ + + /* UDC State */ + unsigned long state; + + /* Current Event */ + udc_hotplug_event_t cur_uh_event; + +#if defined (HAVE_DETECT_SYNC) + /* Sync seq */ + unsigned long irq_sync_seq; + unsigned long our_sync_seq; +#endif + + /* Keep alive */ + struct timer_list keep_alive_timer; + + unsigned long keep_alive_counter_limit; + unsigned long keep_alive_timer_interval; + unsigned long keep_alive_counter; +}; + +static struct uh_data *g_puh_data = NULL; + +#if defined (HAVE_DETECT_SYNC) +/* Seq sync function */ + +static inline int is_seq_sync(struct uh_data *uh) +{ + return (uh->our_sync_seq == uh->irq_sync_seq); +} + +static inline void reset_seq(struct uh_data *uh) +{ + uh->our_sync_seq = uh->irq_sync_seq = 0; + + return; +} + +static inline void sync_seq(struct uh_data *uh) +{ + uh->our_sync_seq = uh->irq_sync_seq; + + return; +} +#endif + +/* Call kernel thread to detect. */ +static inline void start_detect(struct uh_data *uh) +{ + D("called.\n"); + +#if defined (HAVE_DETECT_SYNC) + uh->irq_sync_seq ++; +#endif + + wake_up_process(uh->kthread); + + return; +} + +static void wait_gpio_pin_stable(struct uh_data *uh) +{ + unsigned long pin = 0; + int i = 1; + + pin = __gpio_get_pin(UDC_HOTPLUG_PIN); + + while (i < NR_GPIO_STABLE_TIMES) { + if (__gpio_get_pin(UDC_HOTPLUG_PIN) != pin) { + pin = __gpio_get_pin(UDC_HOTPLUG_PIN); + i = 1; + }else + i++; + + sleep_on_timeout(&uh->wq, 1); + } + + return; +} + +/* Do cable detection */ +static void cable_detect(struct uh_data *uh) +{ + D("Wait pin stable.\n"); + + /* Wait GPIO pin stable first. */ + wait_gpio_pin_stable(uh); + + if (__gpio_get_pin(UDC_HOTPLUG_PIN)) { + D("Cable online.\n"); + + if (!test_and_set_bit(BIT_CABLE_ONLINE, &uh->state)) { + D("Cable state change to online.\n"); + + set_bit(BIT_CABLE_CHANGE, &uh->state); + } + }else { + D("Cable offline.\n"); + + /* Clear keep alive bit. */ + clear_bit(BIT_KEEP_ALIVE, &uh->state); + + if (test_and_clear_bit(BIT_CABLE_ONLINE, &uh->state)) { + D("Cable state change to offline.\n"); + + set_bit(BIT_CABLE_CHANGE, &uh->state); + } + } + + set_bit(BIT_CABLE_DETECT_DONE, &uh->state); + + return; +} + +/* Really do USB detection */ +static int do_usb_detect(struct uh_data *uh) +{ + u32 intr_usb; + 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; + + D("enable phy! %x %x %x %x %x\n", + REG8(USB_REG_POWER), + REG_CPM_OPCR, + REG16(USB_REG_INTRINE), + REG16(USB_REG_INTROUTE), + REG8(USB_REG_INTRUSBE)); + + /* Wait a moment. */ + sleep_on_timeout(&uh->wq, NR_JIFFIES_USB_DETECT_WAIT); + + intr_usb = REG8(USB_REG_INTRUSB); + if ((intr_usb & USB_INTR_RESET) || + (intr_usb & USB_INTR_RESUME) || + (intr_usb & USB_INTR_SUSPEND)) + { + rv = 1; + } + else + { + rv = 0; + } + + /* 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); + + mdelay(1); + + 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 (test_bit(BIT_CABLE_ONLINE, &uh->state)) { + + D("Do real detection.\n"); + + rv = do_usb_detect(uh); + set_bit(BIT_UDC_PHY_TOUCHED, &uh->state); + }else{ + clear_bit(BIT_UDC_PHY_TOUCHED, &uh->state); + D("No need to do real detection.\n"); + } + + if (rv) { + if (!test_and_set_bit(BIT_USB_ONLINE, &uh->state)) + set_bit(BIT_USB_CHANGE, &uh->state); + }else{ + /* Clear keep alive bit. */ + clear_bit(BIT_KEEP_ALIVE, &uh->state); + + if (test_and_clear_bit(BIT_USB_ONLINE, &uh->state)) + set_bit(BIT_USB_CHANGE, &uh->state); + } + + set_bit(BIT_USB_DETECT_DONE, &uh->state); + return; +} + +/* USB is active ? */ +static int usb_is_active(void) +{ + unsigned long tmp; + + tmp = REG16(USB_REG_FRAME); + + mdelay(2); /* USB 1.1 Frame length is 1ms, USB 2.0 HS Frame length is 125us */ + + rmb(); + + return tmp == REG16(USB_REG_FRAME) ? 0 : 1; +} + +/* Broadcast event to notifier */ +static void do_broadcast_event(struct uh_data *uh) +{ + udc_hotplug_event_t *e = &uh->cur_uh_event; + + /* Collect Information */ + if (test_and_clear_bit(BIT_CABLE_CHANGE, &uh->state)) { + e->type = EVENT_TYPE_CABLE; + e->state = (test_bit(BIT_CABLE_ONLINE, &uh->state)) ? EVENT_STATE_ONLINE: EVENT_STATE_OFFLINE; + e->flags = 0; + + D("Broadcast cable event -> State: %s.\n", (e->state == EVENT_STATE_ONLINE ? "Online" : "Offline")); + + /* Kick chain. */ + blocking_notifier_call_chain(&uh->notifier_head, BROADCAST_TYPE_EVENT, e); + } + + if (test_and_clear_bit(BIT_USB_CHANGE, &uh->state)) { + e->type = EVENT_TYPE_USB; + e->state = (test_bit(BIT_USB_ONLINE, &uh->state)) ? EVENT_STATE_ONLINE : EVENT_STATE_OFFLINE; + e->flags = 0; + + if (test_bit(BIT_UDC_PHY_TOUCHED, &uh->state)) { + set_bit(EVENT_FLAG_UDC_PHY_TOUCHED, &e->flags); + } + + D("Broadcast USB event -> State: %s.\n", (e->state == EVENT_STATE_ONLINE ? "Online" : "Offline")); + + /* Kick chain. */ + blocking_notifier_call_chain(&uh->notifier_head, BROADCAST_TYPE_EVENT, e); + } + + return; +} + +/* Handle pending request */ +static inline void handle_request(struct uh_data *uh) +{ + if (test_and_clear_bit(BIT_REQUEST_CABLE_DETECT, &uh->state)) + set_bit(BIT_DO_CABLE_DETECT, &uh->state); + + if (test_and_clear_bit(BIT_REQUEST_USB_DETECT, &uh->state)) + set_bit(BIT_DO_USB_DETECT, &uh->state); + + return; +} + +/* Have pending request ? */ +static inline int pending_request(struct uh_data *uh) +{ + if (test_bit(BIT_REQUEST_CABLE_DETECT, &uh->state) || test_bit(BIT_REQUEST_USB_DETECT, &uh->state)) + return 1; + else + return 0; +} + +#if defined (HAVE_DETECT_SYNC) +static void prepare_restart(struct uh_data *uh, wait_queue_head_t *wq) +{ + + D("Called.\n"); + + if (test_bit(BIT_CABLE_DETECT_DONE, &uh->state)) + set_bit(BIT_DO_CABLE_DETECT, &uh->state); + + if (test_bit(BIT_USB_DETECT_DONE, &uh->state)) + set_bit(BIT_DO_USB_DETECT, &uh->state); + + sleep_on_timeout(wq, NR_JIFFIES_SLEEP_BEFORE_RESTART); + + sync_seq(uh); + + return; +} + +/* Called from kernel thread */ +static void udc_pnp_detect(struct uh_data *uh) +{ + int nr_restart = 0; + + D("Do UDC detection.\n"); + + while (nr_restart != NR_RESTART_TIMES) { + /* Do cable detection ? */ + if (test_bit(BIT_DO_CABLE_DETECT, &uh->state)) { + D("Do cable detection.\n"); + + cable_detect(uh); + } + + /* Need restart ? */ + if (!is_seq_sync(uh)) { + nr_restart ++; + + prepare_restart(uh, &uh->wq); + continue; + } + + /* Do USB detection ? */ + if (test_bit(BIT_DO_USB_DETECT, &uh->state)) { + D("Do USB detection.\n"); + + usb_detect(uh); + } + + /* Need restart ? */ + if (!is_seq_sync(uh)) { + nr_restart ++; + + prepare_restart(uh, &uh->wq); + continue; + } + + /* Done */ + D("Done.\n"); + + clear_bit(BIT_DO_CABLE_DETECT, &uh->state); + clear_bit(BIT_DO_USB_DETECT, &uh->state); + + break; + } + + return; +} + +static inline void broadcast_event(struct uh_data *uh) +{ + /* Sync ? */ + if (is_seq_sync(uh)) { + D("Sync -> Broadcast event.\n"); + + do_broadcast_event(uh); + }else{ + D("Not sync -> Prepare restarting.\n"); + + prepare_restart(uh, &uh->kthread_wq); + } +} + +static inline void udc_pnp_thread_sleep(struct uh_data *uh) +{ + /* Sync ? -> Sleep. */ + if ( !pending_request(uh) || is_seq_sync(uh)) { + D("Sleep.\n"); + + sleep_on(&uh->kthread_wq); + } + + return; +} + +#else /* !HAVE_DETECT_SYNC */ + +/* Called from kernel thread */ +static void udc_pnp_detect(struct uh_data *uh) +{ + D("Do UDC detection.\n"); + + /* Do cable detection ? */ + if (test_bit(BIT_DO_CABLE_DETECT, &uh->state)) { + D("Do cable detection.\n"); + + cable_detect(uh); + } + + /* Do USB detection ? */ + if (test_bit(BIT_DO_USB_DETECT, &uh->state)) { + D("Do USB detection.\n"); + + usb_detect(uh); + } + + /* Done */ + D("Done.\n"); + + clear_bit(BIT_DO_CABLE_DETECT, &uh->state); + clear_bit(BIT_DO_USB_DETECT, &uh->state); + + return; +} + +static inline void broadcast_event(struct uh_data *uh) +{ + D("Broadcast event.\n"); + + do_broadcast_event(uh); + + return; +} + +static inline void udc_pnp_thread_sleep(struct uh_data *uh) +{ + if (!pending_request(uh)) { + D("Sleep.\n"); + + sleep_on(&uh->kthread_wq); + } + + return; +} +#endif /* HAVE_DETECT_SYNC */ + +/* Kernel thread */ +static int udc_pnp_thread(void *data) +{ + struct uh_data *uh = (struct uh_data *)data; + + while (!kthread_should_stop()) { + /* Sleep. */ + udc_pnp_thread_sleep(uh); + + D("Running.\n"); + + if (kthread_should_stop()) + break; + +#if defined (HAVE_DETECT_SYNC) + /* Sync */ + sync_seq(uh); +#endif + + D("Will do UDC detection.\n"); + + handle_request(uh); + + /* Do detect */ + udc_pnp_detect(uh); + + D("Done.\n"); + + /* Broadcast event. */ + broadcast_event(uh); + } + + D("Exit.\n"); + + return 0; +} + +static irqreturn_t udc_pnp_irq(int irq, void *dev_id) +{ + struct uh_data *uh = (struct uh_data *)dev_id; + + D("called.\n"); + + /* clear interrupt pending status */ + __gpio_ack_irq(UDC_HOTPLUG_PIN); + + set_bit(BIT_REQUEST_CABLE_DETECT, &uh->state); + set_bit(BIT_REQUEST_USB_DETECT, &uh->state); + + start_detect(uh); + + return IRQ_HANDLED; +} + +static void __init init_gpio(struct uh_data *uh) +{ + /* get current pin level */ + __gpio_disable_pull(UDC_HOTPLUG_PIN); + __gpio_as_input(UDC_HOTPLUG_PIN); + udelay(1); + + cable_detect(uh); + + /* 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); + + if (test_bit(BIT_CABLE_ONLINE, &uh->state)) { + D("Cable Online -> Do start detection.\n"); + + set_bit(BIT_REQUEST_CABLE_DETECT, &uh->state); + set_bit(BIT_REQUEST_USB_DETECT, &uh->state); + + start_detect(uh); + }else{ + D("Cable Offline.\n"); + } + + return; +} + +/* ---------------------------------------------------------------------------------- */ +/* Export routines */ +static void udc_hotplug_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->state) && !(--uh->keep_alive_counter)) { + + if (!usb_is_active()) { + D("Timeout.\n"); + + set_bit(BIT_KEEP_ALIVE_TIMEOUT, &uh->state); + + clear_bit(BIT_USB_ONLINE, &uh->state); + set_bit(BIT_USB_CHANGE, &uh->state); + + /* No detection needed. We just want to broadcast our event. */ + start_detect(uh); + } + } + + /* Set next active time. */ + if (test_bit(BIT_KEEP_ALIVE, &uh->state) && !test_bit(BIT_KEEP_ALIVE_TIMEOUT, &uh->state)) + mod_timer(&uh->keep_alive_timer, uh->keep_alive_timer_interval + jiffies); + else + D("Timer will stop.\n"); + + return; +} + +int udc_hotplug_register_notifier(struct notifier_block *n, int request_state) +{ + struct uh_data *uh = g_puh_data; + + udc_hotplug_event_t e; + + D("Register notifier: 0x%p.\n", (void *)n); + + /* Notifer will be registered is requesting current state. */ + if (request_state) { + + BUG_ON(!n->notifier_call); + + /* Cable State */ + e.type = EVENT_TYPE_CABLE; + e.state = (test_bit(BIT_CABLE_ONLINE, &uh->state)) ? EVENT_STATE_ONLINE: EVENT_STATE_OFFLINE; + + n->notifier_call(n, BROADCAST_TYPE_STATE, &e); + + /* USB State */ + e.type = EVENT_TYPE_USB; + e.state = (test_bit(BIT_CABLE_ONLINE, &uh->state)) ? EVENT_STATE_ONLINE: EVENT_STATE_OFFLINE; + + n->notifier_call(n, BROADCAST_TYPE_STATE, &e); + } + + return blocking_notifier_chain_register(&uh->notifier_head, n); + +}EXPORT_SYMBOL(udc_hotplug_register_notifier); + +int udc_hotplug_unregister_notifier(struct notifier_block *n) +{ + struct uh_data *uh = g_puh_data; + + D("Unregister notifier: 0x%p.\n", (void *)n); + + return blocking_notifier_chain_unregister(&uh->notifier_head, n); + +}EXPORT_SYMBOL(udc_hotplug_unregister_notifier); + +/* Start keep alive, 0 - Use default value */ +int udc_hotplug_start_keep_alive(unsigned long timer_interval_in_jiffies, unsigned long counter_limit) +{ + struct uh_data *uh = g_puh_data; + + /* Already started. */ + if (test_and_set_bit(BIT_KEEP_ALIVE, &uh->state)) + return 0; + + if (timer_interval_in_jiffies) + uh->keep_alive_timer_interval = timer_interval_in_jiffies; + else + uh->keep_alive_timer_interval = DEFAULT_KEEP_ALIVE_TIMER_INTERVAL; + + if (counter_limit) + uh->keep_alive_counter_limit = counter_limit; + else + uh->keep_alive_counter_limit = DEFAULT_KEEP_ALIVE_COUNTER_LIMIT; + + uh->keep_alive_counter = uh->keep_alive_counter_limit; + + /* Active our timer. */ + return mod_timer(&uh->keep_alive_timer, 3 + jiffies); + +}EXPORT_SYMBOL(udc_hotplug_start_keep_alive); + +void udc_hotplug_do_keep_alive(void) +{ + struct uh_data *uh = g_puh_data; + + D("Keep alive.\n"); + + /* Reset counter */ + uh->keep_alive_counter = uh->keep_alive_counter_limit; + + /* We are alive again. */ + if (test_and_clear_bit(BIT_KEEP_ALIVE_TIMEOUT, &uh->state)) { + D("Reactive timer.\n"); + + /* Active timer. */ + set_bit(BIT_KEEP_ALIVE, &uh->state); + mod_timer(&uh->keep_alive_timer, 3 + jiffies); + } + + return; +}EXPORT_SYMBOL(udc_hotplug_do_keep_alive); + +void udc_hotplug_stop_keep_alive(void) +{ + struct uh_data *uh = g_puh_data; + + clear_bit(BIT_KEEP_ALIVE, &uh->state); + + return; + +}EXPORT_SYMBOL(udc_hotplug_stop_keep_alive); + +/* ----------------------------------------------------------------------------- */ + +/* + * Module init and exit + */ +static int __init udc_hotplug_init(void) +{ + 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 PFX": Failed to allocate memory.\n"); + return -ENOMEM; + } + + uh = g_puh_data; + + set_bit(1, &status); + + BLOCKING_INIT_NOTIFIER_HEAD(&uh->notifier_head); + + init_waitqueue_head(&uh->kthread_wq); + init_waitqueue_head(&uh->wq); + + init_timer(&uh->keep_alive_timer); + + uh->keep_alive_timer.function = udc_hotplug_keep_alive_timer_func; + uh->keep_alive_timer.expires = jiffies - 1; /* Add a stopped timer */ + uh->keep_alive_timer.data = (unsigned long)uh; + + add_timer(&uh->keep_alive_timer); + +#if defined (HAVE_DETECT_SYNC) + reset_seq(uh); +#endif + + /* Create pnp thread and register IRQ */ + uh->kthread = kthread_run(udc_pnp_thread, uh, "kudcd"); + if (IS_ERR(uh->kthread)) { + printk(KERN_ERR PFX": Failed to create system monitor thread.\n"); + rv = PTR_ERR(uh->kthread); + goto err; + } + + set_bit(2, &status); + + rv = request_irq(UDC_HOTPLUG_IRQ, udc_pnp_irq, IRQF_DISABLED, "udc_pnp", uh); + if (rv) { + printk(KERN_ERR PFX": Could not get udc hotplug irq %d\n", UDC_HOTPLUG_IRQ); + goto err; + } + + init_gpio(uh); + +#if defined (HAVE_DETECT_SYNC) + printk(KERN_ERR PFX": Registered(HAVE_DETECT_SYNC).\n"); +#else + printk(KERN_ERR PFX": Registered.\n"); +#endif + return 0; + +err: + if (test_bit(2, &status)) { + kthread_stop(uh->kthread); + } + + if (test_bit(1, &status)) { + kfree(g_puh_data); + } + + return rv; +} + +static void __exit udc_hotplug_exit(void) +{ + free_irq(UDC_HOTPLUG_IRQ, g_puh_data); + + kthread_stop(g_puh_data->kthread); + + kfree(g_puh_data); + + return; +} + +module_init(udc_hotplug_init); +module_exit(udc_hotplug_exit); + +MODULE_AUTHOR("River Wang "); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/drivers/usb/host/ohci-jz.c b/target/linux/xburst/files-2.6.27/drivers/usb/host/ohci-jz.c new file mode 100755 index 000000000..8a3b973dc --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/usb/host/ohci-jz.c @@ -0,0 +1,260 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2002 Hewlett-Packard Company + * + * Bus Glue for Ingenic Jz47xx. + * + * Written by Christopher Hoover + * Based on fragments of previous driver by Rusell King et al. + * + * Modified for LH7A404 from ohci-sa1111.c + * by Durgesh Pattamatta + * Modified for AMD Alchemy Au1xxx + * by Matt Porter + * Modified for Jz47xx from ohci-au1xxx.c + * by Peter + * + * This file is licenced under the GPL. + */ + +#include +#include + +#include + +extern int usb_disabled(void); + +/*-------------------------------------------------------------------------*/ + +static void jz_start_ohc(struct platform_device *dev) +{ + printk(KERN_DEBUG __FILE__ + ": starting JZ OHCI USB Controller\n"); + + /* enable host controller */ + __cpm_start_uhc(); + +#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) + __cpm_enable_uhcphy(); +#endif + + 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"); + +#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) + __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/target/linux/xburst/files-2.6.27/drivers/usb/musb/jz4760.c b/target/linux/xburst/files-2.6.27/drivers/usb/musb/jz4760.c new file mode 100644 index 000000000..2ad292555 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/usb/musb/jz4760.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2005-2007 by Texas Instruments + * Some code has been taken from tusb6010.c + * Copyrights for that are attributable to: + * Copyright (C) 2006 Nokia Corporation + * Jarkko Nikula + * Tony Lindgren + * + * This file is part of the Inventra Controller Driver for Linux. + * + * The Inventra Controller Driver for Linux 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. + * + * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not, + * write to the Free Software Foundation, Inc., 59 Temple Place, + * Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "musb_core.h" + +#define MUSB_TIMEOUT_A_WAIT_BCON 1100 + +/* Hooks we hasn't used yet. */ +void musb_platform_enable(struct musb *musb) +{ + return; +} + +void musb_platform_disable(struct musb *musb) +{ + return; +} + +void musb_platform_set_mode(struct musb *musb, u8 musb_mode) +{ + return; +} + +/* Code copied form omap2430.c */ +static void jz4760_set_vbus(struct musb *musb, int is_on) +{ + u8 devctl; + /* HDRC controls CPEN, but beware current surges during device + * connect. They can trigger transient overcurrent conditions + * that must be ignored. + */ + + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + + if (is_on) { + musb->is_active = 1; + musb->xceiv.default_a = 1; + musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; + devctl |= MUSB_DEVCTL_SESSION; + + MUSB_HST_MODE(musb); + } else { + musb->is_active = 0; + + /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and + * jumping right to B_IDLE... + */ + + musb->xceiv.default_a = 0; + musb->xceiv.state = OTG_STATE_B_IDLE; + devctl &= ~MUSB_DEVCTL_SESSION; + + MUSB_DEV_MODE(musb); + } + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + + DBG(1, "VBUS %s, devctl %02x " + /* otg %3x conf %08x prcm %08x */ "\n", + otg_state_string(musb), + musb_readb(musb->mregs, MUSB_DEVCTL)); +} + +int __init musb_platform_init(struct musb *musb) +{ + if (is_host_enabled(musb)) + musb->board_set_vbus = jz4760_set_vbus; + + musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON; + + return 0; +} + +int musb_platform_exit(struct musb *musb) +{ + return 0; +} diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jz4740_slcd.c b/target/linux/xburst/files-2.6.27/drivers/video/jz4740_slcd.c new file mode 100755 index 000000000..41f092848 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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(®_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/target/linux/xburst/files-2.6.27/drivers/video/jz4740_slcd.h b/target/linux/xburst/files-2.6.27/drivers/video/jz4740_slcd.h new file mode 100644 index 000000000..84754f654 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/drivers/video/jz4750_android_lcd.c b/target/linux/xburst/files-2.6.27/drivers/video/jz4750_android_lcd.c new file mode 100644 index 000000000..9ebf0e21b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz4750_android_lcd.c @@ -0,0 +1,3041 @@ + +/* + * linux/drivers/video/jz4750_android_lcd.c -- Ingenic Jz4750 LCD frame buffer device + * + * Copyright (C) 2005-2009, 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "console/fbcon.h" +#include "jz4750_android_lcd.h" +#include "jz4750_tve.h" + +#define DRIVER_NAME "jz-lcd" + +MODULE_DESCRIPTION("Jz4750 LCD Controller driver"); +MODULE_AUTHOR("Wolfgang Wang , Lemon Liu , Emily Feng "); +MODULE_LICENSE("GPL"); + +#define LCD_DEBUG +//#undef LCD_DEBUG + +#ifdef CONFIG_JZSOC_BOOT_LOGO +extern int load_565_image(char *filename); +#ifdef CONFIG_FB_565RLE_LOGO +#define INIT_IMAGE_FILE "/logo.rle" +#endif +#ifdef CONFIG_FB_565RGB_LOGO +#define INIT_IMAGE_FILE "/logo.rgb565" +#endif +#endif /* CONFIG_JZSOC_BOOT_LOGO */ + +#ifdef LCD_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) + +#define JZ_LCD_ID "jz-lcd" +#define ANDROID_NUMBER_OF_BUFFERS 2 + +struct lcd_cfb_info { + struct fb_info fb0; /* foreground 0 */ + struct fb_info fb; /* foreground 1 */ + struct display_switch *dispsw; + signed int currcon; + int func_use_count; + spinlock_t update_lock; + unsigned frame_requested; + unsigned frame_done; + wait_queue_head_t frame_wq; + struct early_suspend earlier_suspend; + struct early_suspend early_suspend; + struct { + u16 red, green, blue; + } palette[NR_PALETTE]; +}; + +static struct lcd_cfb_info *jz4750fb_info; +static int current_dma0_id, current_dma1_id; +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; +static struct jz4750_lcd_dma_desc *dma0_desc0_change, *dma1_desc0_change, *dma0_desc1_change, *dma1_desc1_change; + +#define DMA_DESC_NUM 9 +//#define IMEM_MAX_ORDER 12 /*16M*/ + +static unsigned char *lcd_palette; +static unsigned char *lcd_frame0; +static unsigned char *lcd_frame; + +/* APP */ +static void jz4750fb_set_mode(struct jz4750lcd_osd_t * lcd_osd_info ); +static void jz4750fb_deep_set_mode( struct jz4750lcd_info * lcd_info ); +static void print_lcdc_registers(void); + +static void jz4750lcd_info_switch_to_TVE(int mode); +static void jz4750lcd_info_switch_to_lcd(void); + +static int jz4750fb0_foreground_resize(struct jz4750lcd_osd_t *lcd_osd_info); +static int jz4750fb0_foreground_move(struct jz4750lcd_osd_t *lcd_osd_info); + +static int jz4750fb_foreground_resize(struct jz4750lcd_osd_t *lcd_osd_info); +static int jz4750fb_foreground_move(struct jz4750lcd_osd_t *lcd_osd_info); + +static struct jz4750lcd_info jz4750_lcd_panel = { +#if defined(CONFIG_JZ4750_ANDROID_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_BST_16, /* 16words burst, enable out FIFO underrun irq */ + 480, 272, 60, 41, 10, 8, 4, 4, 2, + }, + .osd = { + .osd_cfg = LCD_OSDC_OSDEN | LCD_OSDC_F0EN| LCD_OSDC_F1EN| + LCD_OSDC_ALPHAEN,// | /* Use OSD mode */ + .osd_ctrl = 0, /* disable ipu, */ + .rgb_ctrl = 0, + .bgcolor = 0x0000ff, /* set background color Black */ + .colorkey0 = 0, /* disable colorkey */ + .colorkey1 = 0, /* disable colorkey */ + .alpha = 0xff, /* alpha value */ + .ipu_restart = 0x80001000, /* ipu restart */ + .fg_change = FG_CHANGE_ALL, /* change all initially */ + .fg0 = {16, 0, 0, 704, 573}, /* bpp, x, y, w, h */ + .fg1 = {16, 0, 0, 480, 272}, /* bpp, x, y, w, h */ + }, +#elif defined(CONFIG_JZ4750_ANDROID_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_BST_16, /* 16words burst, enable out FIFO underrun irq */ + 800, 480, 45, 1, 1, 40, 215, 10, 34, + }, + .osd = { + .osd_cfg = LCD_OSDC_OSDEN | LCD_OSDC_F0EN| LCD_OSDC_F1EN| + LCD_OSDC_ALPHAEN,// | /* Use OSD mode */ + .osd_ctrl = 0, /* disable ipu, */ + .rgb_ctrl = 0, + .bgcolor = 0x0000ff, /* set background color Black */ + .colorkey0 = 0, /* disable colorkey */ + .colorkey1 = 0, /* disable colorkey */ + .alpha = 0xff, /* alpha value */ + .ipu_restart = 0x80001000, /* ipu restart */ + .fg_change = FG_CHANGE_ALL, /* change all initially */ + .fg0 = {16, 0, 0, 800, 573}, /* bpp, x, y, w, h */ + .fg1 = {16, 0, 0, 800, 480}, /* bpp, x, y, w, h */ + }, +#endif +}; + +static 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_BST_16,//LCD_CTRL_OFUM | /* 16words burst */ + TVE_WIDTH_PAL16, TVE_HEIGHT_PAL16, 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 |LCD_OSDC_F1EN, /* enable Foreground0,Foreground1 */ + .osd_ctrl = 0, /* disable ipu, */ + .rgb_ctrl = LCD_RGBC_YCC, /* enable RGB => YUV */ + .bgcolor = 0x000000ff, /* set background color Black */ + .colorkey0 = 0x80000000, /* enable colorkey */ + //.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 = {16,}, /* */ + .fg1 = {16,}, + }, +}; + +static struct jz_android_din_t jz_panel[JZ_ANDROID_PANELNUM]; +static int jz_panel_num = JZ_ANDROID_PANELNUM; +static int jz_panel_index = 0; + +static struct android_display_info_t adi={0}; + +static struct jz4750lcd_info *jz4750_lcd_info = &jz4750_lcd_panel; /* default output to lcd panel */ + + +/*********************************************TVE***********************************************/ +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<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 ); +} + + +void jz4750tve_outfmt_init(unsigned int outfmt) +{ + switch (outfmt) { +#ifdef CONFIG_SOC_JZ4750D + case PANEL_OUT_FMT_YCBCR: + jz4750_tve_info_PAL.ctrl |= TVE_CTRL_EYCBCR; + break; +#endif + case PANEL_OUT_FMT_CVBS: +#ifdef CONFIG_SOC_JZ4750D + /* Disable YCbCr */ + jz4750_tve_info_PAL.ctrl &= ~TVE_CTRL_EYCBCR; +#endif + jz4750_tve_info_PAL.ctrl |= TVE_CTRL_ECVBS; + break; + case PANEL_OUT_FMT_SVIDEO: + default: +#ifdef CONFIG_SOC_JZ4750D + /* Disable YCbCr */ + jz4750_tve_info_PAL.ctrl &= ~TVE_CTRL_EYCBCR; +#endif + jz4750_tve_info_PAL.ctrl &= ~TVE_CTRL_ECVBS; + break; + } +} + +void jzfb_get_panel_size(unsigned int *w, unsigned *h) +{ + *w = jz4750_lcd_info->panel.w; + *h = jz4750_lcd_info->panel.h; +} + +static inline void lcd_display_on(void) +{ + __lcd_display_on(); /* Turn on panel */ + __lcd_set_ena(); /* Enable LCD Controller */ + schedule_timeout_uninterruptible(HZ/5); /* Wait 200ms */ + __lcd_set_backlight_level(255); /* Turn of backlight */ +} + +static inline void lcd_display_off(void) +{ + __lcd_close_backlight(); + __lcd_clr_ena(); /* Quick Disable */ + __lcd_display_off(); +} + +/********************************************************************************************/ + +/************************************ + * Jz475X Framebuffer ops + ************************************/ +static int jz4750fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct fb_info *fb = info; + if (regno >= NR_PALETTE) + return 1; + if (fb->var.bits_per_pixel <= 16) { + red >>= 8; + green >>= 8; + blue >>= 8; + + red &= 0xff; + green &= 0xff; + blue &= 0xff; + } + + switch (fb->var.bits_per_pixel) { + case 15: + if (regno < 16) + ((u32 *)fb->pseudo_palette)[regno] = + ((red >> 3) << 10) | + ((green >> 3) << 5) | + (blue >> 3); + break; + case 16: + if (regno < 16) { + ((u32 *)fb->pseudo_palette)[regno] = + ((red >> 3) << 11) | + ((green >> 2) << 5) | + (blue >> 3); + } + break; + case 17 ... 32: + if (regno < 16) + ((u32 *)fb->pseudo_palette)[regno] = + (red << 16) | + (green << 8) | + (blue << 0); + break; + } + return 0; +} + +static int jz4750fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + int ret = 0, nret = -1; + void __user *argp = (void __user *)arg; + struct jz4750lcd_fg_t fg1; + + struct jz4750tve_mode jz4750_tve_mode; + + switch (cmd) { + case FBIOSETBACKLIGHT: + __lcd_set_backlight_level(arg); /* We support 8 levels here. */ + break; + case FBIODISPON: + REG_LCD_STATE = 0; /* clear lcdc status */ + __lcd_slcd_special_on(); + REG_LCD_DA1 = virt_to_phys(dma1_desc0); + __lcd_clr_dis(); + __lcd_set_ena(); /* enable lcdc */ + __lcd_display_on(); + break; + case FBIODISPOFF: + __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 + __lcd_set_dis(); /* regular disable */ + 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->osd); + 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; + + 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 */ + jz4750tve_enable_tve(); + /* turn off lcd backlight */ + __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 */ + __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; + case FBIODISON_FG: //pass + /*lcdc_enable_fg1();*/ + print_dbg("lcdc_disable_fg1()\n"); + jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_F1EN; + __lcd_enable_f1(); + break; + case FBIODISOFF_FG://pass + /*lcdc_disable_fg1();*/ + jz4750_lcd_info->osd.osd_cfg &= ~LCD_OSDC_F1EN; + __lcd_disable_f1(); + break; + + case FBIO_SET_LCD_TO_TVE: + /*tve PAL NTSC, LCD, */ + //jz4750_tve_info + /* 1. display off 2. enable ipu_restart 3. use ipu as input 4. after run_ipu, display on lcd*/ + if (copy_from_user(&jz4750_tve_mode, argp, sizeof(struct jz4750tve_mode))) + return -EFAULT; + if (jz4750_tve_mode.mode == PANEL_MODE_LCD_PANEL) { + jz4750tve_disable_tve(); + jz4750lcd_info_switch_to_lcd(); + __lcd_display_on(); + } + else { + jz4750lcd_info_switch_to_TVE(jz4750_tve_mode.mode); + jz4750tve_outfmt_init(jz4750_tve_mode.out_fmt); + jz4750tve_init(jz4750_tve_mode.mode); + jz4750tve_enable_tve(); + __lcd_display_off(); + } + jz4750fb_deep_set_mode(jz4750_lcd_info); + break; + + case FBIO_SET_IPU_TO_LCD: + /* 1. display off 2. enable ipu_restart 3. use ipu as input 4. after run_ipu, display on lcd*/ + __lcd_set_dis(); + __lcd_fg1_use_ipu(); + REG_LCD_BGC = jz4750_lcd_info->osd.ipu_restart; + jz4750fb_deep_set_mode(jz4750_lcd_info); + break; + case FBIO_SET_FRM_TO_LCD: + __lcd_fg1_use_dma_chan1(); + jz4750fb_deep_set_mode(jz4750_lcd_info); + break; + case FBIO_CHANGE_SIZE: + /*fg1_change_size();*/ + if(!(REG_LCD_OSDC & LCD_OSDC_F1EN)) + return -EFAULT; + if (copy_from_user(&fg1, argp, sizeof(struct jz4750lcd_fg_t))) + return -EFAULT; + jz4750_lcd_info->osd.fg1.w = fg1.w; + jz4750_lcd_info->osd.fg1.h = fg1.h; + jz4750fb_foreground_resize(&jz4750_lcd_info->osd); + break; + case FBIO_CHANGE_POSITION: + if (copy_from_user(&fg1, argp, sizeof(struct jz4750lcd_fg_t))) + return -EFAULT; + jz4750_lcd_info->osd.fg1.x = fg1.x; + jz4750_lcd_info->osd.fg1.y = fg1.y; + jz4750fb_foreground_move(&jz4750_lcd_info->osd); + break; + case FBIO_SET_BG_COLOR://pass + jz4750_lcd_info->osd.bgcolor = arg; + /*lcdc_set_bgcolor(arg);*/ + REG_LCD_BGC = jz4750_lcd_info->osd.bgcolor; + break; + case FBIO_SET_IPU_RESTART_VAL: + /*lcdc_set_ipu_restart_val(arg);*/ + jz4750_lcd_info->osd.ipu_restart &= ~LCD_IPUR_IPURMASK; + jz4750_lcd_info->osd.ipu_restart |= (arg & LCD_IPUR_IPURMASK); + __lcd_set_ipu_restart_triger(arg); + break; + case FBIO_SET_IPU_RESTART_ON: + /*lcdc_enable_ipu_restart();*/ + __lcd_enable_ipu_restart(); + break; + case FBIO_SET_IPU_RESTART_OFF: + /*lcdc_disable_ipu_restart();*/ + __lcd_disable_ipu_restart(); + break; + case FBIO_ANDROID_CTL: + print_dbg("ANDROID supply!\n"); + if (copy_from_user(&adi, argp, sizeof(struct android_display_info_t))) + return -EFAULT; + switch (adi.flag) { + case ANDROID_SET_FG0_ALPHA: //pass + /*lcdc_set_alpha(arg);*/ + if (adi.fg0_alpha > 0xFF){ + /*lcdc_disable_alpha();*/ + printk("alpha value is to large,so shut down the alpha"); + jz4750_lcd_info->osd.osd_cfg &= ~LCD_OSDC_ALPHAEN; + __lcd_disable_alpha(); + } + else{ + /*lcdc_enable_alpha();*/ + jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_ALPHAEN; + jz4750_lcd_info->osd.alpha = adi.fg0_alpha; + REG_LCD_ALPHA = adi.fg0_alpha; + __lcd_enable_alpha(); + } + break; + case ANDROID_SET_FG0_COLORKEY: + printk("============fg0_colorkey=%x\n",adi.fg0_colorkey); + if (adi.fg0_colorkey > 0xFFFFFF){ + /*lcdc_disable_colorkey0;*/ + jz4750_lcd_info->osd.colorkey0 = 0; + __lcd_disable_colorkey0(); + } + else{ + if ( jz4750_lcd_info->osd.fg0.bpp == 16 ) { // 16bpp + adi.fg0_colorkey &= 0x00f8fcf8; + jz4750_lcd_info->osd.colorkey0 = adi.fg0_colorkey; + } + else if ( jz4750_lcd_info->osd.fg0.bpp == 15 ) { // 15bpp + adi.fg0_colorkey &= 0x00f8f8f8; + jz4750_lcd_info->osd.colorkey0 = adi.fg0_colorkey; + } + else { // > 16bpp + jz4750_lcd_info->osd.colorkey0 = adi.fg0_colorkey; + } + __lcd_set_colorkey0(jz4750_lcd_info->osd.colorkey0); + __lcd_enable_colorkey0(); + } + break; + case ANDROID_SET_FG0_ENABLE://pass + if( adi.fg0_enable ){ + print_dbg("lcdc_enable_fg0()\n"); + jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_F0EN; + __lcd_enable_f0(); + } + else{ + print_dbg("lcdc_disable_fg0()\n"); + jz4750_lcd_info->osd.osd_cfg &= ~LCD_OSDC_F0EN; + __lcd_disable_f0(); + + } + break; + + case ANDROID_SET_FG1_POS://pass + print_dbg("fg1 pos set\n"); + __lcd_clr_ena(); + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN){ + jz4750_lcd_info->osd.fg1.x = adi.fg1_x+8; + jz4750_lcd_info->osd.fg1.y = adi.fg1_y+10; + } + else{ + jz4750_lcd_info->osd.fg1.x = adi.fg1_x; + jz4750_lcd_info->osd.fg1.y = adi.fg1_y; + } + jz4750fb_foreground_move(&jz4750_lcd_info->osd); + __lcd_set_ena(); + break; + case ANDROID_SET_FG1_SIZE: + __lcd_clr_ena(); + if ( REG_LCD_OSDCTRL & LCD_OSDCTRL_IPU){ + printk("fg1_ipu\n"); + if(!(REG_LCD_OSDC & LCD_OSDC_F1EN)) + return -EFAULT; + // __lcd_clr_ena(); + jz4750_lcd_info->osd.fg1.w = ((adi.fg1_w+3)<<2)>>2; + jz4750_lcd_info->osd.fg1.h = adi.fg1_h; + jz4750fb_foreground_resize(&jz4750_lcd_info->osd); + __lcd_enable_ipu_restart(); + jz4750fb_deep_set_mode(jz4750_lcd_info); + } + else{ + printk("fg1_dma1\n"); + if(!(REG_LCD_OSDC & LCD_OSDC_F1EN)) + return -EFAULT; + jz4750_lcd_info->osd.fg1.w = ((adi.fg1_w+3)>>2)<<2; + jz4750_lcd_info->osd.fg1.h = adi.fg1_h; + jz4750fb_foreground_resize(&jz4750_lcd_info->osd); + } + __lcd_set_ena(); + break; + case ANDROID_SET_FG1_ENABLE://pass + if( adi.fg1_enable ){ + print_dbg("lcdc_enable_fg1()\n"); + jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_F1EN; + __lcd_enable_f1(); + } + else{ + print_dbg("lcdc_disable_fg1()\n"); + jz4750_lcd_info->osd.osd_cfg &= ~LCD_OSDC_F1EN; + __lcd_disable_f1(); + } + break; + case ANDROID_SET_FG1_IPU_DIRECT: + print_dbg("fg1 use ipu or dma1\n"); + if( adi.fg1_short_cut){ + printk("fg1 use ipu\n"); + //__lcd_set_dis(); + __lcd_clr_ena(); + jz4750_lcd_info->osd.osd_ctrl |= LCD_OSDCTRL_IPU; + jz4750fb_deep_set_mode(jz4750_lcd_info); + } + else{ printk("fg1 use dma1\n"); + __lcd_set_dis(); + //__lcd_clr_ena(); + jz4750_lcd_info->osd.osd_ctrl &= ~LCD_OSDCTRL_IPU; + jz4750fb_deep_set_mode(jz4750_lcd_info); + } + break; + case ANDROID_GET_PANEL_SIZE: + printk("+++++++++++++++++++++++++++++jz_panel_index = %d\n",jz_panel_index); + adi.fg1_w = jz_panel[jz_panel_index].w; + adi.fg1_h = jz_panel[jz_panel_index].h; + if (copy_to_user(argp, &adi, sizeof(struct android_display_info_t))) + return -EFAULT; + break; + default: + printk("FG1:%s, unknown android command(0x%x)", __FILE__, adi.flag); + return nret; + } + break; + default: + printk("%s, unknown command(0x%x)", __FILE__, cmd); + return nret; + } + + 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 fb_info *fb = 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 = fb->fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + 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 */ + + 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 */ + + 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; +} + /*end of Foreground 1 ops*/ + +static int jz4750fb0_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; + + if (regno >= NR_PALETTE) + return 1; + + cfb->palette[regno].red = red ; + cfb->palette[regno].green = green; + cfb->palette[regno].blue = blue; + if (cfb->fb0.var.bits_per_pixel <= 16) { + red >>= 8; + green >>= 8; + blue >>= 8; + + red &= 0xff; + green &= 0xff; + blue &= 0xff; + } + switch (cfb->fb0.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->fb0.pseudo_palette)[regno] = + ((red >> 3) << 10) | + ((green >> 3) << 5) | + (blue >> 3); + break; + case 16: + if (regno < 16) { + ((u32 *)cfb->fb0.pseudo_palette)[regno] = + ((red >> 3) << 11) | + ((green >> 2) << 5) | + (blue >> 3); + } + break; + case 17 ... 32: + if (regno < 16) + ((u32 *)cfb->fb0.pseudo_palette)[regno] = + (red << 16) | + (green << 8) | + (blue << 0); + + break; + } + return 0; +} + + +static int jz4750fb0_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + int ret = 0, nret = -1; + void __user *argp = (void __user *)arg; + struct jz4750lcd_fg_t fg0; + + switch (cmd) { + case FBIOSETBACKLIGHT: + __lcd_set_backlight_level(arg); /* We support 8 levels here. */ + break; + case FBIODISPON: + REG_LCD_STATE = 0; /* clear lcdc status */ + __lcd_slcd_special_on(); + __lcd_clr_dis(); + __lcd_set_ena(); /* enable lcdc */ + __lcd_display_on(); + break; + case FBIODISPOFF: + __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 + __lcd_set_dis(); /* regular disable */ + 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))) +// if (copy_to_user(argp, &jz4750_lcd_info->osd, sizeof(struct jz4750lcd_osd_t))) + 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))) +// if (copy_to_user(argp, &jz4750_lcd_info->osd, sizeof(struct jz4750lcd_osd_t))) + return -EFAULT; + /* set mode */ + jz4750fb_set_mode(&jz4750_lcd_info->osd); +// 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; + + 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; + + case FBIODISON_FG: //pass + /*lcdc_enable_fg0();*/ + jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_F0EN; + __lcd_enable_f0(); + break; + case FBIODISOFF_FG://pass + /*lcdc_disable_fg0();*/ + print_dbg("lcdc_disable_fg0()\n"); + jz4750_lcd_info->osd.osd_cfg &= ~LCD_OSDC_F0EN; + __lcd_disable_f0(); + break; + case FBIO_CHANGE_SIZE: + /*fg0_change_size();*/ + if(!(REG_LCD_OSDC & LCD_OSDC_F0EN)) + return -EFAULT; + if (copy_from_user(&fg0, argp, sizeof(struct jz4750lcd_fg_t))) + return -EFAULT; + jz4750_lcd_info->osd.fg0.w = fg0.w; + jz4750_lcd_info->osd.fg0.h = fg0.h; + jz4750fb0_foreground_resize(&jz4750_lcd_info->osd); + break; + case FBIO_CHANGE_POSITION: + if (copy_from_user(&fg0, argp, sizeof(struct jz4750lcd_fg_t))) + return -EFAULT; + jz4750_lcd_info->osd.fg0.x = fg0.x; + jz4750_lcd_info->osd.fg0.y = fg0.y; + jz4750fb0_foreground_move(&jz4750_lcd_info->osd); + break; + case FBIO_SET_BG_COLOR://pass + jz4750_lcd_info->osd.bgcolor = arg; + /*lcdc_set_bgcolor(arg);*/ + REG_LCD_BGC = jz4750_lcd_info->osd.bgcolor; + break; + case FBIO_ALPHA_ON://pass + /*lcdc_enable_alpha();*/ + jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_ALPHAEN; + __lcd_enable_alpha(); + break; + case FBIO_ALPHA_OFF://pass + /*lcdc_disable_alpha();*/ + jz4750_lcd_info->osd.osd_cfg &= ~LCD_OSDC_ALPHAEN; + __lcd_disable_alpha(); + break; + case FBIO_SET_ALPHA_VAL://pass + jz4750_lcd_info->osd.alpha = arg; + /*lcdc_set_alpha(arg);*/ + REG_LCD_ALPHA = jz4750_lcd_info->osd.alpha; + break; + case FBIO_ANDROID_CTL: + if (copy_from_user(&adi, argp, sizeof(struct android_display_info_t))) + return -EFAULT; + + switch (adi.flag) { + case ANDROID_GET_DISPLAY_NUM://pass + adi.fg0_number = jz_panel_num; + if (copy_to_user(argp, &adi, sizeof(struct android_display_info_t))) + return -EFAULT; + break; + case ANDROID_GET_DISPLAY_INFO://pass + adi.fg0_w = jz_panel[adi.fg0_index].w; + adi.fg0_h = jz_panel[adi.fg0_index].h; + if (copy_to_user(argp, &adi, sizeof(struct android_display_info_t))) + return -EFAULT; + break; + case ANDROID_SET_DISPLAY_INDEX: //pass + printk("fg0_index=%d\n",adi.fg0_index); + switch (adi.fg0_index) { + case PANEL_MODE_TVE_PAL: /* switch to TVE_PAL mode */ + __lcd_clr_ena(); + jz4750lcd_info_switch_to_TVE(adi.fg0_index); + jz4750tve_init(adi.fg0_index); /* tve controller init */ + jz4750tve_enable_tve(); + /* turn off lcd backlight */ + __lcd_display_off(); + break; + case PANEL_MODE_LCD_PANEL: /* switch to LCD mode */ + /* turn off TVE, turn off DACn... */ + jz4750tve_disable_tve(); + __lcd_clr_ena(); + jz4750_lcd_info = &jz4750_lcd_panel; + /* turn on lcd backlight */ + __lcd_display_on(); + break; + default : + printk("FG0:%s, android has no this style panel(0x%x)", __FILE__, adi.fg0_index); + return nret; + } + jz_panel_index = adi.fg0_index; + jz4750fb_deep_set_mode(jz4750_lcd_info); + //print_lcdc_registers(); + break; + + default: + printk("FG0:%s, unknown android command(0x%x)", __FILE__, adi.flag); + return nret; + } + break; + default: + printk("FG0:%s, unknown command(0x%x)", __FILE__, cmd); + return nret; + } + + return ret; +} + + +static int jz4750fb0_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->fb0.fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb0.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 */ + + 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 */ + + 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; +} + /* end of Foreground 0 ops*/ + + +/* 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) +{ +/* if((var->rotate & 1) != (info->var.rotate & 1)) { + if((var->xres != info->var.yres) || + (var->yres != info->var.xres) || + (var->xres_virtual != info->var.yres) || + (var->yres_virtual > + info->var.xres * ANDROID_NUMBER_OF_BUFFERS) || + (var->yres_virtual < info->var.xres )) { + return -EINVAL; + } + } + else { + if((var->xres != info->var.xres) || + (var->yres != info->var.yres) || + (var->xres_virtual != info->var.xres) || + (var->yres_virtual > + info->var.yres * ANDROID_NUMBER_OF_BUFFERS) || + (var->yres_virtual < info->var.yres )) { + return -EINVAL; + } + } + if((var->xoffset != info->var.xoffset) || + (var->bits_per_pixel != info->var.bits_per_pixel)) {// || +// (var->grayscale != info->var.grayscale)) { + return -EINVAL; + } +*/ + return 0; +} + + +/* + * set the video mode according to info->var + */ +static int jz4750fb_set_par(struct fb_info *info) +{ + //dprintk("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) +{ + 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: + /* Turn off panel */ +#if 0 + __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 fb_info *fb = info; + struct jz4750lcd_info *lcd_info = jz4750_lcd_info; + int dy; + int fg1_line_size; + + if (!var || !fb) { + return -EINVAL; + } + + if (var->xoffset - fb->var.xoffset) { + /* No support for X panning for now! */ + return -EINVAL; + } + + printk("pan frame rect %d %d %d %d\n", + var->reserved[1] & 0xffff, + var->reserved[1] >> 16, var->reserved[2] & 0xffff, + var->reserved[2] >> 16); + + /* TODO: Wait for current frame to finished */ + + dy = var->yoffset;// - fb->var.yoffset; + fg1_line_size = lcd_info->osd.fg1.w * lcd_info->osd.fg1.bpp/8 ; + fg1_line_size = ((fg1_line_size+3)>>2)<<2; + if (dy) { + dma1_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame + (fb->fix.line_length * dy)); + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ + dma1_desc1->databuf = (unsigned int)virt_to_phys((void *)(lcd_frame + fg1_line_size) + (fb->fix.line_length * dy)); + dma_cache_wback((unsigned int)(dma1_desc0), sizeof(struct jz4750_lcd_dma_desc)); + + } + else { + dma1_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame); + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ + dma1_desc1->databuf = (unsigned int)virt_to_phys((void *)(lcd_frame + fg1_line_size)); + dma_cache_wback((unsigned int)(dma1_desc0), sizeof(struct jz4750_lcd_dma_desc)); + } + + return 0; +} + +static int jz4750fb0_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + unsigned long irq_flags; + struct fb_info *fb = info; + struct jz4750lcd_info *lcd_info = jz4750_lcd_info; + struct lcd_cfb_info *cfb = jz4750fb_info; + int fg0_line_size; + int dy; + + if (!(REG_LCD_OSDC & LCD_OSDC_F0EN)) + return 0; + + if (!var || !fb) { + return -EINVAL; + } + if (var->xoffset - fb->var.xoffset) { + /* No support for X panning for now! */ + return -EINVAL; + } + + dy = var->yoffset;// - fb->var.yoffset; + fb->fix.line_length = ( jz4750_lcd_panel.osd.fg0.w * (lcd_info->osd.fg0.bpp) / 8); + fg0_line_size = ( jz4750_lcd_panel.osd.fg0.w * (lcd_info->osd.fg0.bpp) / 8); + fg0_line_size = ((fg0_line_size + 3) >> 2) << 2; + + if (dy) { + dma0_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame0 + (fb->fix.line_length * dy)); + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ + dma0_desc1->databuf = (unsigned int)virt_to_phys((void *)(lcd_frame0 + fg0_line_size) + (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); + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ + dma0_desc1->databuf = (unsigned int)virt_to_phys((void *)(lcd_frame0 + fg0_line_size )); + dma_cache_wback((unsigned int)(dma0_desc0), sizeof(struct jz4750_lcd_dma_desc)); + + } + + /* Wait for current frame to finished */ + + spin_lock_irqsave(cfb->update_lock, irq_flags); + + REG_LCD_STATE &= ~LCD_STATE_EOF; // Clear previous EOF flag + __lcd_enable_eof_intr(); + + cfb->frame_requested++; + + spin_unlock_irqrestore(cfb->update_lock, irq_flags); + + if (cfb->frame_requested != cfb->frame_done) + wait_event_interruptible_timeout( + cfb->frame_wq, cfb->frame_done == cfb->frame_requested, HZ/50); + + __lcd_disable_eof_intr(); + + 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, +}; + +/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ +static struct fb_ops jz4750fb0_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = jz4750fb0_setcolreg, + .fb_check_var = jz4750fb_check_var, + .fb_set_par = jz4750fb_set_par, + .fb_blank = jz4750fb_blank, + .fb_pan_display = jz4750fb0_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = jz4750fb0_mmap, + .fb_ioctl = jz4750fb0_ioctl, +}; + +/***************************************************************/ +extern void show_tlb(void); + +static void jz_lcd_add_wired_entry(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; + + /* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */ + entrylo0 = entrylo0 >> 6; + entrylo0 |= 0x7 | (2 << 3); + entrylo1 = entrylo1 >> 6; + entrylo1 |= 0x7 | (2 << 3); + + 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; +// entryhi |= g_asid; +// entryhi |= old_ctx; + 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 LCD_DEBUG + printk("\nold_ctx=%03ld\n", old_ctx); + show_tlb(); +#endif +} + +static void jz_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 int jz4750fb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct fb_info *fb = info; + struct jz4750lcd_info *lcd_info = jz4750_lcd_info; + int chgvar = 0; + + if (con == 0) { + var->height = lcd_info->osd.fg0.h; + var->width = lcd_info->osd.fg0.w; + var->bits_per_pixel = lcd_info->osd.fg0.bpp; + } + else { + var->height = lcd_info->osd.fg1.h; + var->width = lcd_info->osd.fg1.w; + var->bits_per_pixel = lcd_info->osd.fg1.bpp; + } + + var->vmode = FB_VMODE_NONINTERLACED; +// var->vmode = FB_VMODE_DOUBLE + var->activate = fb->var.activate; + var->xres = var->width; + var->yres = var->height; + var->xres_virtual = var->width; + var->yres_virtual = var->height * ANDROID_NUMBER_OF_BUFFERS; + var->xoffset = 0; + var->yoffset = 0; + var->pixclock = KHZ2PICOS(jz_clocks.pixclk/1000); + + var->left_margin = lcd_info->panel.elw; + var->right_margin = lcd_info->panel.blw; + var->upper_margin = lcd_info->panel.efw; + var->lower_margin = lcd_info->panel.bfw; + var->hsync_len = lcd_info->panel.hsw; + var->vsync_len = lcd_info->panel.vsw; + var->sync = 0; + var->activate = FB_ACTIVATE_NOW; + + /* + * 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 = fb->var.xoffset; + var->yoffset = fb->var.yoffset; + } + + if (var->activate & FB_ACTIVATE_TEST) + return 0; + + if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) + return -EINVAL; + + if (fb->var.xres != var->xres) + chgvar = 1; + if (fb->var.yres != var->yres) + chgvar = 1; + if (fb->var.xres_virtual != var->xres_virtual) + chgvar = 1; + if (fb->var.yres_virtual != var->yres_virtual) + chgvar = 1; + if (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 */ + fb->fix.visual = FB_VISUAL_MONO01; + 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; + + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_DIRECTCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_TRUECOLOR; + 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; + + fb->fix.visual = FB_VISUAL_TRUECOLOR; + 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", + fb->fix.id, var->bits_per_pixel); + break; + } + + fb->var = *var; + 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(&fb->cmap, fb); + 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; + + /* Foreground 1 -- fb */ + strcpy(cfb->fb.fix.id, "jzlcd-fg1"); + cfb->fb.flags = FBINFO_FLAG_DEFAULT; + 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.fg1.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; + } + + /* Foreground 0 -- fb0 */ + strcpy(cfb->fb0.fix.id, "jzlcd-fg0"); + cfb->fb0.fix.type = FB_TYPE_PACKED_PIXELS; + cfb->fb0.fix.type_aux = 0; + cfb->fb0.fix.xpanstep = 1; + cfb->fb0.fix.ypanstep = 1; + cfb->fb0.fix.ywrapstep = 0; + cfb->fb0.fix.accel = FB_ACCEL_NONE; + + cfb->fb0.var.nonstd = 0; + cfb->fb0.var.activate = FB_ACTIVATE_NOW; + cfb->fb0.var.height = -1; + cfb->fb0.var.width = -1; + cfb->fb0.var.accel_flags = FB_ACCELF_TEXT; + + cfb->fb0.fbops = &jz4750fb0_ops; + cfb->fb0.flags = FBINFO_FLAG_DEFAULT; + + cfb->fb0.pseudo_palette = (void *)(cfb + 1); + + switch (jz4750_lcd_info->osd.fg0.bpp) { + case 1: + fb_alloc_cmap(&cfb->fb0.cmap, 4, 0); + break; + case 2: + fb_alloc_cmap(&cfb->fb0.cmap, 8, 0); + break; + case 4: + fb_alloc_cmap(&cfb->fb0.cmap, 32, 0); + break; + case 8: + + default: + fb_alloc_cmap(&cfb->fb0.cmap, 256, 0); + break; + } + dprintk("fb_alloc_cmap, fb.cmap.len:%d, fb0.cmap.len:%d....\n", cfb->fb.cmap.len, cfb->fb0.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 = 0, needroom1=0, bpp, w, h; + unsigned char *fb_palette, *fb_frame; + unsigned long pagemask = 0x3ff << 13; /*4M */ + /* caculate the mem size of Foreground 0 */ + 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 > 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; + + needroom1 = needroom = ((w * bpp + 7) >> 3) * h * ANDROID_NUMBER_OF_BUFFERS; + /* end of alloc Foreground 0 mem */ + + /* Caculate the mem size of Foreground 1 */ + bpp = jz4750_lcd_info->osd.fg1.bpp; + if (bpp == 18 || bpp == 24) + bpp = 32; + if (bpp == 15) + bpp = 16; + + /* The buffer size of FG1 should be large enough, so alloc memory depend of the fg0 args */ + 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; + needroom += ((w * bpp + 7) >> 3) * h; + /* end of alloc Foreground 1 mem */ + + /* Alloc memory */ + for (page_shift = 0; page_shift < 12; page_shift++) + if ((PAGE_SIZE << page_shift) >= needroom) + break; + fb_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); + fb_frame = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); + if ((!fb_palette) || (!fb_frame)) + return -ENOMEM; + memset((void *)fb_palette, 0, PAGE_SIZE); + memset((void *)fb_frame, 0, PAGE_SIZE << page_shift); + + lcd_palette = fb_palette; + dma_desc_base = (struct jz4750_lcd_dma_desc *)((void*)lcd_palette + ((PALETTE_SIZE+3)/4)*4); + + /* + * 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)fb_frame; + page < PAGE_ALIGN((unsigned long)fb_frame + (PAGE_SIZE<fb.fix.smem_start = virt_to_phys((void *)lcd_frame); + cfb->fb.fix.smem_len = needroom - needroom1; /* page_shift/2 ??? */ + cfb->fb.screen_base = + (unsigned char *)(((unsigned int)lcd_frame&0x1fffffff) | 0xa0000000); + if (!cfb->fb.screen_base) { + printk("jz4750fb, %s: unable to map screen memory\n", cfb->fb.fix.id); + return -ENOMEM; + } + + lcd_frame0 = fb_frame; + cfb->fb0.fix.smem_start = virt_to_phys((void *)lcd_frame0); + cfb->fb0.fix.smem_len = needroom1; /* page_shift/2 ??? */ + cfb->fb0.screen_base = + (unsigned char *)(((unsigned int)lcd_frame0&0x1fffffff) | 0xa0000000); + if (!cfb->fb0.screen_base) { + printk("jz4750fb0, %s: unable to map screen memory\n", cfb->fb0.fix.id); + return -ENOMEM; + } + jz_lcd_add_wired_entry((unsigned long)cfb->fb0.fix.smem_start, 0, 0x50000000, pagemask); + //jz_lcd_add_wired_entry((unsigned long)fb_frame, 0, 0x50000000, pagemask); + 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; + + 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; + + 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); + } +} + +/************************************ + * Jz475X Chipset OPS + ************************************/ + +/* + * 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 print_lcdc_registers(void) /* debug */ +{ +#ifdef LCD_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_KEY0:\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++); + } + } + } +#endif +} + +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 = TVE_WIDTH_PAL - 16; + h = TVE_HEIGHT_PAL - 20; + x = (TVE_WIDTH_PAL - w) / 2; + y = (TVE_HEIGHT_PAL - h ) / 2; + + 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 = TVE_WIDTH_PAL - 16; + h = TVE_HEIGHT_PAL - 20; + x = (TVE_WIDTH_PAL-w) / 2; + y = (TVE_HEIGHT_PAL-h)/ 2; + + info->osd.fg1.bpp = 16; /* 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 = TVE_WIDTH_NTSC - 16; + h = TVE_HEIGHT_NTSC - 12; + x = (TVE_WIDTH_NTSC - w) / 2; + y = (TVE_HEIGHT_NTSC - h) / 2; + 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 = TVE_WIDTH_NTSC - 16; + h = TVE_HEIGHT_NTSC - 12; + x = (TVE_WIDTH_NTSC - w) / 2; + y = (TVE_HEIGHT_NTSC - h) / 2; + 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__); + break; + } +} + +/* + * switch to lcd mode from TVE mode + */ + +static void jz4750lcd_info_switch_to_lcd(void) +{ + struct jz4750lcd_info *info; + struct jz4750lcd_osd_t *osd_lcd; + struct jz4750lcd_panel_t *panel_lcd; + int x, y, w, h; + + info = &jz4750_lcd_panel; + + /* set to tve mode */ + info->panel.cfg = jz4750_info_tve.panel.cfg; + info->panel.cfg &= ~(LCD_CFG_TVEN | LCD_CFG_MODE_INTER_CCIR656); /* Interlace CCIR656 mode */ + info->panel.ctrl = jz4750_info_tve.panel.ctrl; + info->osd.rgb_ctrl &= ~LCD_RGBC_YCC; /* enable YUV => RGB*/ + + /* */ + osd_lcd = &jz4750_info_tve.osd; + panel_lcd = &jz4750_info_tve.panel; + + /* set Foreground 0 */ + w = osd_lcd->fg0.w / panel_lcd->w * info->panel.w; + h = osd_lcd->fg0.h / panel_lcd->h * info->panel.h; + x = osd_lcd->fg0.x / panel_lcd->w * info->panel.w; + y = osd_lcd->fg0.y / panel_lcd->h * info->panel.h; + info->osd.fg0.x = x; + info->osd.fg0.y = y; + info->osd.fg0.w = w; + info->osd.fg0.h = h; + + /* set Foreground 1 */ + w = osd_lcd->fg1.w / panel_lcd->w * info->panel.w; + h = osd_lcd->fg1.h / panel_lcd->h * info->panel.h; + x = osd_lcd->fg1.x / panel_lcd->w * info->panel.w; + y = osd_lcd->fg1.y / panel_lcd->h * info->panel.h; + info->osd.fg1.x = x; + info->osd.fg1.y = y; + info->osd.fg1.w = w; + info->osd.fg1.h = h; + + jz4750_lcd_info = &jz4750_lcd_panel; +} + +/* initial dma descriptors */ +static void jz4750fb_descriptor_init( struct jz4750lcd_info * lcd_info ) +{ + unsigned int pal_size; + int fg0_line_size, fg0_frm_size, fg1_line_size, fg1_frm_size; + int buffer_line_size, buffer_frm_size; + int panel_line_size, panel_frm_size; + int size0, size1; + + + 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; + + /* + * 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 --> ... + * DMA Chan1: + * TO LCD Panel: + * dma1_desc0 <<==>> dma1_desc0 + * TO TV Encoder: + * dma1_desc0 <<==>> dma1_desc1 + */ + + dma0_desc_palette = dma_desc_base + 0; + dma0_desc0 = dma_desc_base + 1; + dma0_desc1 = dma_desc_base + 2; + dma0_desc0_change = dma_desc_base + 3; + dma0_desc1_change = dma_desc_base + 4; + + /* Foreground 0, caculate size */ + if ( lcd_info->osd.fg0.x >= lcd_info->panel.w ) + lcd_info->osd.fg0.x = lcd_info->panel.w - 1; + if ( lcd_info->osd.fg0.y >= lcd_info->panel.h ) + lcd_info->osd.fg0.y = lcd_info->panel.h - 1; + + if (lcd_info->panel.cfg & LCD_CFG_TVEN ) { + // if ( lcd_info->osd.fg0.x + lcd_info->osd.fg0.w > lcd_info->panel.w ) + lcd_info->osd.fg0.w = lcd_info->panel.w - 2 * 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 - 2 * lcd_info->osd.fg0.y; + } +/* else{ + if ( lcd_info->osd.fg0.x + lcd_info->osd.fg0.w > lcd_info->panel.w ) + lcd_info->osd.fg0.w = lcd_info->panel.w - 2*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 - 2*lcd_info->osd.fg0.y; + } +*/ + size0 = lcd_info->osd.fg0.h << 16 | lcd_info->osd.fg0.w; + //size0 = lcd_info->panel.h << 16 | lcd_info->panel.w; + /* lcd display area */ + panel_line_size = (lcd_info->panel.w - 2 * lcd_info->osd.fg0.x) * lcd_info->osd.fg0.bpp / 8; + panel_line_size = ((panel_line_size + 3) >> 2) << 2; /* word aligned */ + panel_frm_size= panel_line_size * (lcd_info->panel.h - 2 * lcd_info->osd.fg0.y);//lcd_info->panel.h;// + + /* total fg0 buffer area */ + 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; + +#if 1 + /*total buffer size*/ + buffer_line_size = jz4750_lcd_panel.osd.fg0.w * lcd_info->osd.fg0.bpp / 8; + buffer_line_size = ((buffer_line_size + 3) >> 2) << 2; /* word aligned */ + buffer_frm_size= buffer_line_size * jz4750_lcd_panel.panel.h; +#endif + /* Palette Descriptor */ + 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 */ + /* DMA0 Descriptor */ + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ + /* Next */ + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc1); + 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 + dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc1_change); + dma0_desc1_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + + /* frame phys addr */ + dma0_desc0->databuf = dma0_desc0_change->databuf = virt_to_phys((void *)lcd_frame0); + dma0_desc1->databuf = virt_to_phys((void *)(lcd_frame0 + fg0_line_size)); + + /* frame id */ + dma0_desc0->frame_id = (unsigned int)0x0da00000; /* DMA0'0 */ + dma0_desc1->frame_id = (unsigned int)0x0da00001; /* DMA0'1 */ + dma0_desc0_change->frame_id = (unsigned int)0x0da000c0; /* DMA0'2 */ + dma0_desc1_change->frame_id = (unsigned int)0x0da000c1; + + /* others */ + //dma0_desc0->cmd = dma0_desc1->cmd = LCD_CMD_EOFINT | ((panel_frm_size)/4)/2; + dma0_desc0->cmd = LCD_CMD_EOFINT | ((panel_frm_size+panel_line_size)/4)/2; + dma0_desc1->cmd = LCD_CMD_EOFINT | ((panel_frm_size-panel_line_size)/4)/2; + dma0_desc0->offsize = dma0_desc1->offsize =(buffer_line_size + buffer_line_size - panel_line_size)/4; + dma0_desc0->page_width = dma0_desc1->page_width = panel_line_size/4; + dma0_desc0->desc_size = dma0_desc1->desc_size = size0; + + } + else { /* Normal TFT LCD */ + /* next */ + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + + /* frame phys addr */ + dma0_desc0->databuf = dma0_desc0_change->databuf = virt_to_phys((void *)lcd_frame0); + + /* frame id */ + dma0_desc0->frame_id = (unsigned int)0x0000da00; /* DMA0'0 */ + dma0_desc0_change->frame_id = (unsigned int)0x0da000c0; /* DMA0'2 */ + + /* others */ + dma0_desc0->cmd = LCD_CMD_EOFINT | panel_frm_size/4; +// dma0_desc0->cmd = panel_frm_size/4; + dma0_desc0->offsize = (fg0_line_size - panel_line_size)/4; + dma0_desc0->page_width = panel_line_size/4; + + dma0_desc0->desc_size = size0; + } + + 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_desc0); //tft + REG_LCD_SIZE0 = size0; + current_dma0_id = 0;//dma0_desc0; + + dma1_desc0 = dma_desc_base + 5; + dma1_desc1 = dma_desc_base + 6; + dma1_desc0_change = dma_desc_base + 7; + dma1_desc1_change = dma_desc_base + 8; + +#if 1 /* Foreground 1, caculate size */ + if ( lcd_info->osd.fg1.x >= lcd_info->panel.w ) + lcd_info->osd.fg1.x = lcd_info->panel.w - 1; + if ( lcd_info->osd.fg1.y >= lcd_info->panel.h ) + lcd_info->osd.fg1.y = lcd_info->panel.h - 1; + + if (lcd_info->panel.cfg & LCD_CFG_TVEN ) { + if ( lcd_info->osd.fg1.x + lcd_info->osd.fg1.w > lcd_info->panel.w ) + lcd_info->osd.fg1.w = lcd_info->panel.w - 2 *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 - 2 * lcd_info->osd.fg1.y; + } +/* else{ + if ( lcd_info->osd.fg1.x + lcd_info->osd.fg1.w > lcd_info->panel.w ) + lcd_info->osd.fg1.w = lcd_info->panel.w - 2*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 - 2*lcd_info->osd.fg1.y; + } +*/ +#endif + size1 = lcd_info->osd.fg1.h << 16 | lcd_info->osd.fg1.w; + /* lcd panel display area */ + panel_line_size = lcd_info->panel.w * lcd_info->osd.fg1.bpp / 8; + panel_line_size = ((panel_line_size + 3) >> 2) << 2; /* word aligned */ + panel_frm_size= panel_line_size * lcd_info->panel.h; +#if 0 + /*total buffer size*/ + buffer_line_size = TVE_WIDTH_PAL * lcd_info->osd.fg1.bpp / 8; + buffer_line_size = ((buffer_line_size + 3) >> 2) << 2; /* word aligned */ + buffer_frm_size= buffer_line_size * TVE_HEIGHT_PAL; +#endif + /* lcd display area */ + fg1_line_size = lcd_info->osd.fg1.w*lcd_info->osd.fg1.bpp/8; + fg1_line_size = ((fg1_line_size+3)>>2)<<2; /* word aligned */ + fg1_frm_size = fg1_line_size * lcd_info->osd.fg1.h; + + /* DMA1 Descriptor */ + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) {/* TVE mode */ + /* Next */ + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc1); + dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc1_change); + dma1_desc1_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + + /* frame phys addr */ + dma1_desc0->databuf = dma1_desc0_change->databuf = virt_to_phys((void *)lcd_frame); + dma1_desc1->databuf = virt_to_phys((void *)(lcd_frame + fg1_line_size)); + + /* frame id */ + dma1_desc0->frame_id = (unsigned int)0x0da10000; /* DMA1'0 */ + dma1_desc1->frame_id = (unsigned int)0x0da10001; /* DMA1'1 */ + dma1_desc0_change->frame_id = (unsigned int)0x0da100c0; /* DMA1'C0 */ + dma1_desc1_change->frame_id = (unsigned int)0x0da100c1; /* DMA1'C1 */ + + /* other*/ + if(jz4750_lcd_info->osd.fg1.h % 2 == 0){ + dma1_desc0->cmd = LCD_CMD_EOFINT | ((fg1_frm_size)/4)/2; + dma1_desc1->cmd = LCD_CMD_EOFINT | ((fg1_frm_size)/4)/2; + } + else{ + dma1_desc0->cmd = LCD_CMD_EOFINT | ((fg1_frm_size + fg1_line_size)/4)/2; + dma1_desc1->cmd = LCD_CMD_EOFINT | ((fg1_frm_size - fg1_line_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_desc0->desc_size = dma1_desc1->desc_size = size1; + } + else { /* Normal TFT LCD */ + /* Next */ + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + + /* frame phys addr */ + dma1_desc0->databuf = dma1_desc0_change->databuf = virt_to_phys((void *)lcd_frame); + + /* frame id */ + dma1_desc0->frame_id = (unsigned int)0x0da10000; /* DMA1'0 */ + dma1_desc0_change->frame_id = (unsigned int)0x0da100c0; /* DMA1'C0 */ + + /* other */ + if (panel_line_size >= fg1_line_size){ + dma1_desc0->cmd = LCD_CMD_EOFINT | fg1_frm_size /4; + dma1_desc0->offsize = 0;//(buffer_line_size - fg1_line_size )/4; + dma1_desc0->page_width = 0;//fg1_line_size /4; + } + else{ + dma1_desc0->cmd = LCD_CMD_EOFINT | panel_frm_size/4; + dma1_desc0->offsize = 0;//(fg1_line_size - panel_line_size)/4; + dma1_desc0->page_width = 0;//panel_line_size/4; + } + dma1_desc0->desc_size = size1; + } + + REG_LCD_DA1 = virt_to_phys(dma1_desc0); /* set Dma-chan1's Descripter Addrress */ + REG_LCD_SIZE1 = size1; + current_dma1_id = 0;//dma1_desc0; + + dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc)); +} + +static void jz4750fb_set_panel_mode(struct jz4750lcd_info * lcd_info) +{ + struct jz4750lcd_panel_t *panel = &lcd_info->panel; + + /* 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 */ + + 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_osd_t *lcd_osd_info) +{ + lcd_osd_info->osd_ctrl &= ~(LCD_OSDCTRL_OSDBPP_MASK); + if ( lcd_osd_info->fg1.bpp == 15 ) + lcd_osd_info->osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB555; + else if ( lcd_osd_info->fg1.bpp == 16 ) + lcd_osd_info->osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB565; + else { + lcd_osd_info->fg1.bpp = 32; + lcd_osd_info->osd_ctrl |= LCD_OSDCTRL_OSDBPP_18_24; + } + + REG_LCD_OSDC = lcd_osd_info->osd_cfg; /* F0, F1, alpha, */ + + REG_LCD_OSDCTRL = lcd_osd_info->osd_ctrl; /* IPUEN, bpp */ + REG_LCD_RGBC = lcd_osd_info->rgb_ctrl; + REG_LCD_BGC = lcd_osd_info->bgcolor; + REG_LCD_KEY0 = lcd_osd_info->colorkey0; + REG_LCD_KEY1 = lcd_osd_info->colorkey1; + REG_LCD_ALPHA = lcd_osd_info->alpha; + REG_LCD_IPUR = lcd_osd_info->ipu_restart; + REG_LCD_XYP0 = lcd_osd_info->fg0.y << 16 | lcd_osd_info->fg0.x ; + REG_LCD_XYP1 = lcd_osd_info->fg1.y << 16 | lcd_osd_info->fg1.x; +} + + +/* Change Position of Foreground 0 */ +static int jz4750fb0_foreground_move(struct jz4750lcd_osd_t *lcd_osd_info) +{ + int pos; +#if defined(CONFIG_SOC_JZ4750D) + int j, count = 100000; +#endif + /* + * 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 fg0 position: + * fg0.x + fg0.w <= panel.w; + * fg0.y + fg0.h <= panel.h; + * + * When output is LCD panel, fg.y 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 should be even number always. + * + */ + + /* Foreground 0 */ + if (lcd_osd_info->fg0.x + lcd_osd_info->fg0.w > jz4750_lcd_info->panel.w) + lcd_osd_info->fg0.x = jz4750_lcd_info->panel.w - lcd_osd_info->fg0.w; + if (lcd_osd_info->fg0.y + lcd_osd_info->fg0.h > jz4750_lcd_info->panel.h) + lcd_osd_info->fg0.y = jz4750_lcd_info->panel.h - lcd_osd_info->fg0.h; + + if (lcd_osd_info->fg0.x >= jz4750_lcd_info->panel.w) + lcd_osd_info->fg0.x = jz4750_lcd_info->panel.w - 1; + if (lcd_osd_info->fg0.y >= jz4750_lcd_info->panel.h) + lcd_osd_info->fg0.y = jz4750_lcd_info->panel.h - 1; + + pos = lcd_osd_info->fg0.y << 16 | lcd_osd_info->fg0.x; + if (REG_LCD_XYP0 == pos){ + printk("FG0: same position\n"); + return 0; + } + +#if defined(CONFIG_SOC_JZ4750D) + REG_LCD_XYP0 = pos; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + while(!(REG_LCD_OSDS & LCD_OSDS_READY)); + j = count; + msleep(40); + while((REG_LCD_OSDCTRL & LCD_OSDCTRL_CHANGES) && j--); + if(j == 0) { + printk("Error FG0 Position: Wait change fail.\n"); + return -EFAULT; + } + +#else + /****jz4750****/ +// REG_LCD_OSDC &= ~LCD_OSDC_F0EN; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + REG_LCD_XYP0 = pos; +// REG_LCD_OSDC |= LCD_OSDC_F0EN; + /*********************************************/ + +#endif + return 0; +} +/* Change Window size of Foreground 0 */ +static int jz4750fb0_foreground_resize(struct jz4750lcd_osd_t *lcd_osd_info) +{ + struct lcd_cfb_info *cfb = jz4750fb_info; + int size, fg0_line_size, fg0_frm_size; +// int desc_len = sizeof(struct jz4750_lcd_dma_desc); + /* + * 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_osd_info->fg0.x + lcd_osd_info->fg0.w > jz4750_lcd_info->panel.w) + lcd_osd_info->fg0.w = jz4750_lcd_info->panel.w - lcd_osd_info->fg0.x; + if (lcd_osd_info->fg0.y + lcd_osd_info->fg0.h > jz4750_lcd_info->panel.h) + lcd_osd_info->fg0.h = jz4750_lcd_info->panel.h - lcd_osd_info->fg0.y; + + size = lcd_osd_info->fg0.h << 16 | lcd_osd_info->fg0.w; + + if (REG_LCD_SIZE0 == size) { + printk("FG0: same size\n"); + return 0; + } + + fg0_line_size = lcd_osd_info->fg0.w * lcd_osd_info->fg0.bpp / 8; + fg0_line_size = ((fg0_line_size + 3) >> 2) << 2; /* word aligned */ + fg0_frm_size = fg0_line_size * lcd_osd_info->fg0.h; + + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; +#if 0 // For 4750d + if (current_dma0_id == 0) { + printk("Change to dma0_desc0_change\n"); +// REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma0_desc0_change->cmd = dma0_desc1_change->cmd = (fg0_frm_size/4)/2; + dma0_desc0_change->offsize = dma0_desc1_change->offsize + = fg0_line_size/4; + dma0_desc0_change->page_width = dma0_desc1_change->page_width + = fg0_line_size/4; + dma0_desc1_change->databuf = virt_to_phys((void *)(lcd_frame0 + fg0_line_size)); + dma0_desc0_change->desc_size = dma0_desc1->desc_size = size; + dma_cache_wback_inv((unsigned int)(dma0_desc0_change), desc_len); + dma_cache_wback_inv((unsigned int)(dma0_desc1_change), desc_len); + } + else { + dma0_desc0_change->cmd = fg0_frm_size/4; + dma0_desc0_change->offsize = 0; + dma0_desc0_change->page_width = 0; + dma0_desc0_change->desc_size = size; + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + dma_cache_wback_inv((unsigned int)(dma0_desc0_change),desc_len); + } + REG_LCD_SIZE0 = size; + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + dma_cache_wback_inv((unsigned int)(dma0_desc1_change), desc_len); + } + else { + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + dma_cache_wback_inv((unsigned int)(dma0_desc0_change), desc_len); + } + current_dma0_id = 1;//dma0_desc0_change; + } + else { + printk("Change to dma0_desc0\n"); + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + 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)); + dma0_desc0->desc_size = dma0_desc1->desc_size = size; + } + else { + dma0_desc0->cmd = fg0_frm_size/4; + dma0_desc0->offsize =0; + dma0_desc0->page_width = 0; + dma0_desc0->desc_size = size; + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma_cache_wback_inv((unsigned int)(dma0_desc0), desc_len); + } + REG_LCD_SIZE0 = size; + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma0_desc1_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma_cache_wback_inv((unsigned int)(dma0_desc1_change), desc_len); + } + else { + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma_cache_wback_inv((unsigned int)(dma0_desc0_change), desc_len); + } + current_dma0_id = 0;//dma0_desc0; + } + +#else + /* set change bit */ + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* output to TV */ + dma0_desc0->cmd = dma0_desc1->cmd = LCD_CMD_EOFINT | (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)); + } + else { + dma0_desc0->cmd = dma0_desc1->cmd = LCD_CMD_EOFINT | 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 = size; +// = lcd_osd_info->fg0.h << 16 | lcd_osd_info->fg0.w; + REG_LCD_SIZE0 = size; +// REG_LCD_SIZE0 = (lcd_osd_info->fg0.h << 16) | lcd_osd_info->fg0.w; + + dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc)); +#endif + jz4750fb_set_var(&cfb->fb0.var, 0, &cfb->fb0); + return 0; +} + + +/* Change Position of Foreground 1 */ +static int jz4750fb_foreground_move(struct jz4750lcd_osd_t *lcd_osd_info) +{ + int pos; +#if defined(CONFIG_SOC_JZ4750D) + int j, count = 100000; +#endif + /* + * 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 fg1 position: + * fg1.x + fg1.w <= panel.w; + * fg1.y + fg1.h <= panel.h; + * + * When output is LCD panel, fg.y 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 should be even number always. + * + */ + + /* Foreground 0 */ + if (lcd_osd_info->fg1.x + lcd_osd_info->fg1.w > jz4750_lcd_info->panel.w) + lcd_osd_info->fg1.x = jz4750_lcd_info->panel.w - lcd_osd_info->fg1.w; + if (lcd_osd_info->fg1.y + lcd_osd_info->fg1.h > jz4750_lcd_info->panel.h) + lcd_osd_info->fg1.y = jz4750_lcd_info->panel.h - lcd_osd_info->fg1.h; + + if (lcd_osd_info->fg1.x >= jz4750_lcd_info->panel.w) + lcd_osd_info->fg1.x = jz4750_lcd_info->panel.w - 1; + if (lcd_osd_info->fg1.y >= jz4750_lcd_info->panel.h) + lcd_osd_info->fg1.y = jz4750_lcd_info->panel.h - 1; + + pos = lcd_osd_info->fg1.y << 16 | lcd_osd_info->fg1.x; + + if (REG_LCD_XYP1 == pos){ + printk("FG1: same position\n"); + //return 0; + } + +#if defined(CONFIG_SOC_JZ4750) + /****jz4750****/ +// REG_LCD_OSDC &= ~LCD_OSDC_F0EN; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + REG_LCD_XYP1 = pos; +// REG_LCD_OSDC |= LCD_OSDC_F0EN; + /*********************************************/ +#elif defined(CONFIG_SOC_JZ4750D) + REG_LCD_XYP1 = pos; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + while(!(REG_LCD_OSDS & LCD_OSDS_READY)); + j = count; + msleep(40); + while((REG_LCD_OSDCTRL & LCD_OSDCTRL_CHANGES) && j--); + if(j == 0) { + printk("Error FG1 Position: Wait change fail.\n"); + return -EFAULT; + + } +#endif + return 0; +} + +/* Change window size of Foreground 1 */ +static int jz4750fb_foreground_resize(struct jz4750lcd_osd_t *lcd_osd_info) +{ + struct lcd_cfb_info *cfb = jz4750fb_info; + int size, fg1_line_size, fg1_frm_size; +// int desc_len = sizeof(struct jz4750_lcd_dma_desc); + /* + * 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 1 */ + +/* if (lcd_osd_info->fg1.x + lcd_osd_info->fg1.w > jz4750_lcd_info->panel.w) + lcd_osd_info->fg1.w = jz4750_lcd_info->panel.w - lcd_osd_info->fg1.x; + if (lcd_osd_info->fg1.y + lcd_osd_info->fg1.h > jz4750_lcd_info->panel.h) + lcd_osd_info->fg1.h = jz4750_lcd_info->panel.h - lcd_osd_info->fg1.y; +*/ +// size = lcd_info->osd.fg1.h << 16|lcd_info->osd.fg1.w; + + size = lcd_osd_info->fg1.h << 16|lcd_osd_info->fg1.w; + if (REG_LCD_SIZE1 == size) { + printk("FG1: same size\n"); + return 0;// -EFAULT; + } +// fg1_line_size = lcd_osd_info->fg1.w * ((lcd_osd_info->fg1.bpp + 7) / 8); + fg1_line_size = lcd_osd_info->fg1.w * lcd_osd_info->fg1.bpp / 8; + fg1_line_size = ((fg1_line_size + 3) >> 2) << 2; /* word aligned */ + fg1_frm_size = fg1_line_size * lcd_osd_info->fg1.h; + +#if 0 + if (current_dma1_id == 0) { + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma1_desc0_change->cmd = dma1_desc1_change->cmd = (fg1_frm_size/4)/2; + dma1_desc0_change->offsize = dma1_desc1_change->offsize + = fg1_line_size/4; + dma1_desc0_change->page_width = dma1_desc1_change->page_width + = fg1_line_size/4; + dma1_desc1_change->databuf = virt_to_phys((void *)(lcd_frame + fg1_line_size)); + dma1_desc0_change->desc_size = dma1_desc1->desc_size = size; + dma_cache_wback_inv((unsigned int)(dma1_desc0_change), desc_len); + dma_cache_wback_inv((unsigned int)(dma1_desc1_change), desc_len); + } + else { + dma1_desc0_change->cmd = fg1_frm_size/4; + dma1_desc0_change->offsize = 0; + dma1_desc0_change->page_width = 0; + dma1_desc0_change->desc_size = size; + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + dma_cache_wback_inv((unsigned int)(dma1_desc0_change),desc_len); + } + + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + dma_cache_wback_inv((unsigned int)(dma1_desc1_change), desc_len); + } + else { + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + dma_cache_wback_inv((unsigned int)(dma1_desc0_change), desc_len); + } + REG_LCD_SIZE1 = size; + current_dma1_id = 1;//dma1_desc0_change; + + } + else { + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + 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_frame + fg1_line_size)); + dma1_desc0->desc_size = dma1_desc1->desc_size = size; + } + else { + dma1_desc0->cmd = fg1_frm_size/4; + dma1_desc0->offsize =0; + dma1_desc0->page_width = 0; + dma1_desc0->desc_size = size; + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma_cache_wback_inv((unsigned int)(dma1_desc0), desc_len); + } + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma1_desc1_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma_cache_wback_inv((unsigned int)(dma1_desc1_change), desc_len); + } + else { + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma_cache_wback_inv((unsigned int)(dma1_desc0_change), desc_len); + } + REG_LCD_SIZE1 = size; + current_dma1_id = 0;//dma1_desc0_change; + } + + +#else + /* set change bit */ + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + if ( jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* output to TV */ + if(jz4750_lcd_info->osd.fg1.h % 2 == 0){ + dma1_desc0->cmd = LCD_CMD_EOFINT | (fg1_frm_size/4)/2; + dma1_desc1->cmd = LCD_CMD_EOFINT | (fg1_frm_size/4)/2; + } + else{ + dma1_desc0->cmd = LCD_CMD_EOFINT | (fg1_frm_size/4 + fg1_line_size/4)/2; + dma1_desc1->cmd = LCD_CMD_EOFINT | (fg1_frm_size/4 - fg1_line_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_frame + fg1_line_size)); + } + else { + dma1_desc0->cmd = dma1_desc1->cmd = LCD_CMD_EOFINT | fg1_frm_size/4; + dma1_desc0->offsize = dma1_desc1->offsize = 0; + dma1_desc0->page_width = dma1_desc1->page_width = 0;//fg1_line_size; + } + + dma1_desc0->desc_size = dma1_desc1->desc_size = size; + REG_LCD_SIZE1 = size; + + dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc)); +#endif + jz4750fb_set_var(&cfb->fb.var, 1, &cfb->fb); + return 0; +} + + + +/* + * Set lcd pixel clock + */ +static void jz4750fb_change_clock( struct jz4750lcd_info * lcd_info ) +{ + 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 */ + pclk = 27000000; + __cpm_select_pixclk_tve(); + } + else { /* LCDC output to LCD panel */ + __cpm_select_pixclk_lcd(); + } + 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 + __cpm_enable_pll_change(); + + 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); + +} + + +/* + * jz4750fb_set_mode(), set osd configure, resize foreground + * + */ +static void jz4750fb_set_mode(struct jz4750lcd_osd_t * lcd_osd_info) +{ + jz4750fb_set_osd_mode(lcd_osd_info); + jz4750fb_foreground_resize(lcd_osd_info); + jz4750fb0_foreground_resize(lcd_osd_info); +} + +/* + * 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. + */ + struct lcd_cfb_info *cfb = jz4750fb_info; + + __lcd_clr_ena(); /* Quick Disable */ + lcd_info->osd.fg_change = FG_CHANGE_ALL; /* change FG0, FG1 size, postion??? */ + jz4750fb_set_osd_mode(&lcd_info->osd); + jz4750fb_set_panel_mode(lcd_info); + jz4750fb_descriptor_init(lcd_info); + jz4750fb_change_clock(lcd_info); + + jz4750fb_set_var(&cfb->fb0.var, 0, &cfb->fb0); + jz4750fb_set_var(&cfb->fb.var, 1, &cfb->fb); + __lcd_set_ena(); /* enable lcdc */ +} + + +static irqreturn_t jz4750fb_interrupt_handler(int irq, void *dev_id) +{ + unsigned long irq_flags; + unsigned int state;//, osdstate; + struct lcd_cfb_info *cfb = jz4750fb_info; + static int irqcnt = 0; + + spin_lock_irqsave(cfb->update_lock, irq_flags); +// dprintk("Lcd irq, state=0x%08x, osdstate=0x%08x\n", state, osdstate); + state = REG_LCD_STATE; +// osdstate = REG_LCD_OSDS; + if (state & LCD_STATE_EOF) {/* End of frame */ + REG_LCD_STATE = state & ~LCD_STATE_EOF; +// dprintk("lcd dma eof interrupt\n"); + } +/****************************************************************/ +#if 0 + 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; + } + +#endif + if (state & LCD_STATE_OFU) { + 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__); + } +/****************************************************************/ + cfb->frame_done = cfb->frame_requested; + spin_unlock_irqrestore(cfb->update_lock, irq_flags); + wake_up(&cfb->frame_wq); + + return IRQ_HANDLED; +} + + +#ifdef CONFIG_HAS_EARLYSUSPEND + +static void jz4750fb_earlier_suspend(struct early_suspend *h) +{ + lcd_display_off(); + __cpm_stop_lcd(); +} + +static void jz4750fb_earlier_resume(struct early_suspend *h) +{ + __cpm_start_lcd(); + lcd_display_on(); +} + +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +/* The following routine is only for test */ + +static void jz4750_lcd_gpio_init(void) +{ + /* 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(); + + /* 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 + __lcd_display_pin_init(); +} + +static void jz4750_lcd_init_cfg(void) +{ + + jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_F0EN; /* only open fg0 */ +// jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_F1EN; /* only open fg1 */ + + /* In special mode, we only need init special pin, + * as general lcd pin has init in uboot */ +#if defined(CONFIG_SOC_JZ4750) + 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: + break; + } +#endif + /* Foreground 0 support bpp = 1, 2, 4, 8, 15, 16, 18, 24 */ + switch ( jz4750_lcd_info->osd.fg0.bpp ) { + case 17 ... 32: + jz4750_lcd_info->osd.fg1.bpp = 32; + break; + default: + break; + } + + /* Foreground 1 support bpp = 15, 16, 18, 24 */ + 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; + } +} + +#ifdef CONFIG_LEDS_CLASS +static void lcd_set_backlight_level(struct led_classdev *led_cdev, enum led_brightness value) +{ + __lcd_set_backlight_level((int)value); +} + +static struct led_classdev lcd_backlight_led = { + .name = "lcd-backlight", + .brightness_set = lcd_set_backlight_level, +}; +#endif + +static int __init jz4750fb_probe(struct platform_device *pdev) +{ + struct lcd_cfb_info *cfb; + int err = 0; + + jz_panel[0].w = jz4750_lcd_panel.panel.w; + jz_panel[0].h = jz4750_lcd_panel.panel.h; + jz_panel[0].index = 0; + + jz_panel[1].w = jz4750_info_tve.panel.w; + jz_panel[1].h = jz4750_info_tve.panel.h; + jz_panel[1].index = 1; + + if (!pdev) + return -EINVAL; + + __lcd_close_backlight(); + jz4750_lcd_gpio_init(); /* gpio init */ + jz4750_lcd_init_cfg(); /* first config of lcd */ + + __lcd_clr_dis(); + __lcd_clr_ena(); + + /* init clock */ + __lcd_slcd_special_on(); + + cfb = jz4750fb_alloc_fb_info(); + if (!cfb) + goto failed; + + err = jz4750fb_map_smem(cfb); + if (err) + goto failed; + + spin_lock_init(&cfb->update_lock); + init_waitqueue_head(&cfb->frame_wq); + cfb->frame_requested = cfb->frame_done = 0; + +#ifdef CONFIG_HAS_EARLYSUSPEND + cfb->earlier_suspend.suspend = jz4750fb_earlier_suspend; + cfb->earlier_suspend.resume = jz4750fb_earlier_resume; + cfb->earlier_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; + register_early_suspend(&cfb->earlier_suspend); +#endif + + jz4750fb_deep_set_mode( jz4750_lcd_info ); + + /* registers frame buffer devices */ + /* register fg0 */ + err = register_framebuffer(&cfb->fb0); + if (err < 0) { + dprintk("jz4750fb_init(): register framebuffer err.\n"); + goto failed; + } + printk("fb%d: %s frame buffer device, using %dK of video memory\n", + cfb->fb0.node, cfb->fb0.fix.id, cfb->fb0.fix.smem_len>>10); + + /* register fg1 */ + err = register_framebuffer(&cfb->fb); + if (err < 0) { + dprintk("jz4750fb_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_JZSOC_BOOT_LOGO + load_565_image(INIT_IMAGE_FILE); +#endif + if (request_irq(IRQ_LCD, jz4750fb_interrupt_handler, IRQF_DISABLED, + "lcd", 0)) { + err = -EBUSY; + goto failed; + } + + +#ifdef CONFIG_LEDS_CLASS + err = led_classdev_register(&pdev->dev, &lcd_backlight_led); + if (err < 0) + goto failed; +#endif + + lcd_display_on(); + print_lcdc_registers(); + + + return 0; + +failed: + print_dbg(); + jz_del_wired_entry(); + jz4750fb_unmap_smem(cfb); + jz4750fb_free_fb_info(cfb); + + return err; +} + +static int jz4750fb_remove(struct platform_device *pdev) +{ + struct lcd_cfb_info *cfb = platform_get_drvdata(pdev); + + jz_del_wired_entry(); + jz4750fb_unmap_smem(cfb); + jz4750fb_free_fb_info(cfb); + return 0; +} + +static struct platform_driver jz_lcd_driver = { + .probe = jz4750fb_probe, + .remove = jz4750fb_remove, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init jz4750fb_init(void) +{ + return platform_driver_register(&jz_lcd_driver); +} + +static void __exit jz4750fb_cleanup(void) +{ + platform_driver_unregister(&jz_lcd_driver); +} + +module_init(jz4750fb_init); +module_exit(jz4750fb_cleanup); diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jz4750_android_lcd.h b/target/linux/xburst/files-2.6.27/drivers/video/jz4750_android_lcd.h new file mode 100644 index 000000000..3449a8b53 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz4750_android_lcd.h @@ -0,0 +1,267 @@ + +/* + * 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__ + +/* Please define next in lcd panel header file + * __lcd_special_pin_init() + * __lcd_special_on() + * __lcd_special_off() + */ + +#if defined(CONFIG_JZ4750_ANDROID_LCD_AUO_A043FL01V2) +#include "jz_auo_a043fl01v2.h" +#endif + +#if defined(CONFIG_JZ4750_ANDROID_LCD_TOPPOLY_TD043MGEB1) +#include "jz_toppoly_td043mgeb1.h" +#endif + +//#include + + +#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; +}; + + +/***********************Emily****************************/ + +#define JZ_ANDROID_PANELNUM 2 +struct jz_android_din_t{ + unsigned int w; + unsigned int h; + unsigned int index; +}; + +struct android_display_info_t { + unsigned int flag; + unsigned int fg0_number; /**/ + unsigned int fg0_index; + unsigned int fg0_alpha; /* */ + unsigned int fg0_colorkey;/**/ + unsigned int fg0_enable;/**/ + unsigned int fg0_x; /*fg0 start position x*/ + unsigned int fg0_y; /*fg0 start position y*/ + unsigned int fg0_w; /*the weight of fg0*/ + unsigned int fg0_h; /*the height of fg0*/ + unsigned int fg1_x; /*fg1 start position x*/ + unsigned int fg1_y; /*fg1 start position y*/ + unsigned int fg1_w; /*the weight of fg1*/ + unsigned int fg1_h; /*the height of fg1*/ + unsigned int fg1_enable; /*start or stop fg1*/ + unsigned int fg1_short_cut;/*IPU direct*/ +}; + +#define FBIO_ANDROID_CTL 0xad10 + +#define ANDROID_GET_DISPLAY_NUM 0x00000001 +#define ANDROID_GET_DISPLAY_INFO 0x00000002 +#define ANDROID_SET_DISPLAY_INDEX 0x00000004 +#define ANDROID_SET_FG0_ALPHA 0x00000008 +#define ANDROID_SET_FG0_COLORKEY 0x00000010 +#define ANDROID_SET_FG0_ENABLE 0x00000020 +#define ANDROID_SET_FG1_POS 0x00000040 +#define ANDROID_SET_FG1_SIZE 0x00000080 +#define ANDROID_SET_FG1_ENABLE 0x00000100 +#define ANDROID_SET_FG1_IPU_DIRECT 0x00000200 +#define ANDROID_GET_PANEL_SIZE 0x00000400 + +#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ + "nop; nop; nop; nop; nop; nop;\n\t" \ + ".set reorder\n\t") +extern void local_flush_tlb_all(void); + +/******************************Emily**************************************/ + +/* 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 */ +#define FBIODISON_FG 0x46a8 /* FG display on */ +#define FBIODISOFF_FG 0x46a9 /* FG display on */ +#define FBIO_SET_LCD_TO_TVE 0x46b0 /* set lcd to tve mode */ +#define FBIO_SET_FRM_TO_LCD 0x46b1 /* set framebuffer to lcd */ +#define FBIO_SET_IPU_TO_LCD 0x46b2 /* set ipu to lcd directly */ +#define FBIO_CHANGE_SIZE 0x46b3 /* change FG size */ +#define FBIO_CHANGE_POSITION 0x46b4 /* change FG starts position */ +#define FBIO_SET_BG_COLOR 0x46b5 /* set background color */ +#define FBIO_SET_IPU_RESTART_VAL 0x46b6 /* set ipu restart value */ +#define FBIO_SET_IPU_RESTART_ON 0x46b7 /* set ipu restart on */ +#define FBIO_SET_IPU_RESTART_OFF 0x46b8 /* set ipu restart off */ +#define FBIO_ALPHA_ON 0x46b9 /* enable alpha */ +#define FBIO_ALPHA_OFF 0x46c0 /* disable alpha */ +#define FBIO_SET_ALPHA_VAL 0x46c1 /* set alpha value */ + +/* + * Platform specific definition + */ +#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) + +#if 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(); \ +} while (0) + +#define __lcd_display_off() \ +do { \ + __lcd_special_off(); \ +} while (0) +#endif /* APUS */ +#endif /* CONFIG_SOC_JZ4750 */ + + +/***************************************************************************** + * LCD display pin dummy macros + *****************************************************************************/ +#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 + +#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/target/linux/xburst/files-2.6.27/drivers/video/jz4750_lcd.c b/target/linux/xburst/files-2.6.27/drivers/video/jz4750_lcd.c new file mode 100644 index 000000000..f3df5921e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz4750_lcd.c @@ -0,0 +1,3013 @@ +/* + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "console/fbcon.h" + +#include "jz4750_lcd.h" + +#include "jz4750_tve.h" + +#define DRIVER_NAME "jz-lcd" + +#ifdef CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A +#include "jz_kgm_spfd5420a.h" +#endif + +MODULE_DESCRIPTION("Jz4750 LCD Controller driver"); +MODULE_AUTHOR("Wolfgang Wang , Lemon Liu "); +MODULE_LICENSE("GPL"); + + +//#define LCD_DEBUG +#undef LCD_DEBUG + +#ifdef LCD_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) + +#define JZ_LCD_ID "jz-lcd" +#define ANDROID_NUMBER_OF_BUFFERS 2 + +struct lcd_cfb_info { + struct fb_info fb0; /* foreground 0 */ + struct fb_info fb; /* foreground 1 */ + 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 +}; + +static struct lcd_cfb_info *jz4750fb_info; +static int current_dma0_id, current_dma1_id; +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; +static struct jz4750_lcd_dma_desc *dma0_desc0_change, *dma1_desc0_change, *dma0_desc1_change, *dma1_desc1_change; + +#define DMA_DESC_NUM 9 + +static unsigned char *lcd_palette; +static unsigned char *lcd_frame0; +static unsigned char *lcd_frame; + +/* APP */ +static void jz4750fb_set_mode(struct jz4750lcd_osd_t * lcd_osd_info ); +static void jz4750fb_deep_set_mode( struct jz4750lcd_info * lcd_info ); +static void print_lcdc_registers(void); +#ifdef CONFIG_FB_JZ4750_TVE +static void jz4750lcd_info_switch_to_TVE(int mode); +static void jz4750lcd_info_switch_to_lcd(void); +#endif +#if defined(CONFIG_JZ4750_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) +static int jz4750fb0_foreground_resize(struct jz4750lcd_osd_t *lcd_osd_info); +static int jz4750fb0_foreground_move(struct jz4750lcd_osd_t *lcd_osd_info); +#endif + +#if defined(CONFIG_JZ4750_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) +static int jz4750fb_foreground_resize(struct jz4750lcd_osd_t *lcd_osd_info); +static int jz4750fb_foreground_move(struct jz4750lcd_osd_t *lcd_osd_info); +#endif + +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 */ + .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, 480, 272}, /* 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 | LCD_OSDC_ALPHAEN,// | /* Use OSD mode */ + .osd_ctrl = 0, /* disable ipu, */ + .rgb_ctrl = 0, + .bgcolor = 0x000000, /* set background color Black */ + .colorkey0 = 0x80000000, /* disable colorkey */ +// .colorkey0 = 0, /* disable colorkey */ + .colorkey1 = 0, /* disable colorkey */ + .alpha = 0xff, /* alpha value */ +// .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, 480, 272}, /* 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 */ + .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_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 */ + .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 */ + .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 | /* 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 */ + .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 */ + .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 +}; + +#ifdef CONFIG_FB_JZ4750_TVE +struct jz4750lcd_info jz4750_info_tve = { + .panel = { + .w = TVE_WIDTH_PAL, TVE_HEIGHT_PAL, TVE_FREQ_PAL, 0, 0, 0, 0, 0, 0, + }, + .osd = { + .rgb_ctrl = LCD_RGBC_YCC, /* enable RGB => YUV */ + .fg0 = {32,}, /* */ + .fg1 = {32,}, + }, +}; +#endif + +struct jz4750lcd_info *jz4750_lcd_info = &jz4750_lcd_panel; /* default output to lcd panel */ + + + +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 void display_v_color_bar(void *frame, int w, int h, int bpp) { + int i, j, wpl, bpl, data = 0; + int *ptr; + printk("frame_v = 0x%08x\n", (unsigned int)frame); + if(w == 0 || h == 0) + return; + ptr = (int *)frame; + wpl = w*bpp/32; + bpl = w*bpp/8; + + 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: + #ifndef CONFIG_FB_JZ4750_LCD_USE_COMPRESS_24BPP + #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 + #else + #if 1 + ptrc = (unsigned char *)lcd_frame1; + for (j = 0;j < h; j++) + for (i = 0;i < bpl; i+=3) { + if (i < bpl/8*1 ) { + *ptrc++ = 0xff; + *ptrc++ = 0x0; + *ptrc++ = 0x0; + } + else if (i < bpl/8*2) { + *ptrc++ = 0x00; + *ptrc++ = 0xff; + *ptrc++ = 0x00; + } + else if (i < bpl/8*3) { + *ptrc++ = 0x00; + *ptrc++ = 0x00; + *ptrc++ = 0xff; + } + else if (i < bpl/8*4) { + *ptrc++ = 0xff; + *ptrc++ = 0x00; + *ptrc++ = 0x00; + } + else if (i < bpl/8*5) { + *ptrc++ = 0x00; + *ptrc++ = 0xff; + *ptrc++ = 0x00; + } + else if (i < bpl/8*6) { + *ptrc++ = 0x00; + *ptrc++ = 0x00; + *ptrc++ = 0xff; + } + else if (i < bpl/8*7) { + *ptrc++ = 0xff; + *ptrc++ = 0x00; + *ptrc++ = 0x00; + } + else if (i < bpl) { + *ptrc++ = 0x00; + *ptrc++ = 0xff; + *ptrc++ = 0x00; + } + } + #endif + #endif + break; + } + } + dma_cache_wback_inv((unsigned int)(frame), w*h*bpp/8); + } +static void display_h_color_bar(void *frame, int w, int h, int bpp) { + int i, data = 0; + int *ptr; + int wpl; //word_per_line + printk("frame_h = 0x%08x\n", (unsigned int)frame); + if(w == 0 || h == 0) + return; + ptr = (int *)frame; + 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; + } + + } + dma_cache_wback_inv((unsigned int)(frame), w*h*bpp/8); + } +/************************************ + * Jz475X Framebuffer ops + ************************************/ +#if defined(CONFIG_JZ4750_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) +static int jz4750fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct fb_info *fb = info; + if (regno >= NR_PALETTE) + return 1; + if (fb->var.bits_per_pixel <= 16) { + red >>= 8; + green >>= 8; + blue >>= 8; + + red &= 0xff; + green &= 0xff; + blue &= 0xff; + } + + switch (fb->var.bits_per_pixel) { + case 15: + if (regno < 16) + ((u32 *)fb->pseudo_palette)[regno] = + ((red >> 3) << 10) | + ((green >> 3) << 5) | + (blue >> 3); + break; + case 16: + if (regno < 16) { + ((u32 *)fb->pseudo_palette)[regno] = + ((red >> 3) << 11) | + ((green >> 2) << 5) | + (blue >> 3); + } + break; + case 17 ... 32: + if (regno < 16) + ((u32 *)fb->pseudo_palette)[regno] = + (red << 16) | + (green << 8) | + (blue << 0); + +/* if (regno < 16) { + unsigned val; + val = chan_to_field(red, &fb->var.red); + val |= chan_to_field(green, &fb->var.green); + val |= chan_to_field(blue, &fb->var.blue); + ((u32 *)fb->pseudo_palette)[regno] = val; + } +*/ + + break; + } + return 0; +} +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_fg_t fg1; +#ifdef CONFIG_FB_JZ4750_TVE + struct jz4750tve_mode jz4750_tve_mode; +#endif + + switch (cmd) { + case FBIOSETBACKLIGHT: + __lcd_set_backlight_level(arg); /* We support 8 levels here. */ + break; + case FBIODISPON: + REG_LCD_STATE = 0; /* clear lcdc status */ + __lcd_slcd_special_on(); + REG_LCD_DA1 = virt_to_phys(dma1_desc0); + __lcd_clr_dis(); + __lcd_set_ena(); /* enable lcdc */ + __lcd_display_on(); + break; + case FBIODISPOFF: + __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 + __lcd_set_dis(); /* regular disable */ + 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->osd); + 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 */ + jz4750tve_enable_tve(); + /* turn off lcd backlight */ + __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 */ + __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 +#if 1 + case FBIODISON_FG: //pass + /*lcdc_enable_fg1();*/ + print_dbg("lcdc_disable_fg1()\n"); + jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_F1EN; + __lcd_enable_f1(); + break; + case FBIODISOFF_FG://pass + /*lcdc_disable_fg1();*/ + jz4750_lcd_info->osd.osd_cfg &= ~LCD_OSDC_F1EN; + __lcd_disable_f1(); + break; +#ifdef CONFIG_FB_JZ4750_TVE + case FBIO_SET_LCD_TO_TVE: + /*tve PAL NTSC, LCD, */ + //jz4750_tve_info + /* 1. display off 2. enable ipu_restart 3. use ipu as input 4. after run_ipu, display on lcd*/ + if (copy_from_user(&jz4750_tve_mode, argp, sizeof(struct jz4750tve_mode))) + return -EFAULT; + if (jz4750_tve_mode.mode == PANEL_MODE_LCD_PANEL) { + jz4750tve_disable_tve(); + jz4750lcd_info_switch_to_lcd(); + __lcd_display_on(); + } + else { + jz4750lcd_info_switch_to_TVE(jz4750_tve_mode.mode); + jz4750tve_outfmt_init(jz4750_tve_mode.out_fmt); + jz4750tve_init(jz4750_tve_mode.mode); + jz4750tve_enable_tve(); + __lcd_display_off(); + } + jz4750fb_deep_set_mode(jz4750_lcd_info); + break; +#endif + case FBIO_SET_IPU_TO_LCD: + /* 1. display off 2. enable ipu_restart 3. use ipu as input 4. after run_ipu, display on lcd*/ + __lcd_set_dis(); + __lcd_fg1_use_ipu(); + REG_LCD_BGC = jz4750_lcd_info->osd.ipu_restart; + jz4750fb_deep_set_mode(jz4750_lcd_info); + break; + case FBIO_SET_FRM_TO_LCD: + __lcd_fg1_use_dma_chan1(); + jz4750fb_deep_set_mode(jz4750_lcd_info); + break; + case FBIO_CHANGE_SIZE: + /*fg1_change_size();*/ + if(!(REG_LCD_OSDC & LCD_OSDC_F1EN)) + return -EFAULT; + if (copy_from_user(&fg1, argp, sizeof(struct jz4750lcd_fg_t))) + return -EFAULT; + jz4750_lcd_info->osd.fg1.w = fg1.w; + jz4750_lcd_info->osd.fg1.h = fg1.h; + jz4750fb_foreground_resize(&jz4750_lcd_info->osd); + break; + case FBIO_CHANGE_POSITION: + if (copy_from_user(&fg1, argp, sizeof(struct jz4750lcd_fg_t))) + return -EFAULT; + jz4750_lcd_info->osd.fg1.x = fg1.x; + jz4750_lcd_info->osd.fg1.y = fg1.y; + jz4750fb_foreground_move(&jz4750_lcd_info->osd); + break; + case FBIO_SET_BG_COLOR://pass + jz4750_lcd_info->osd.bgcolor = arg; + /*lcdc_set_bgcolor(arg);*/ + REG_LCD_BGC = jz4750_lcd_info->osd.bgcolor; + break; + case FBIO_SET_IPU_RESTART_VAL: + /*lcdc_set_ipu_restart_val(arg);*/ + jz4750_lcd_info->osd.ipu_restart &= ~LCD_IPUR_IPURMASK; + jz4750_lcd_info->osd.ipu_restart |= (arg & LCD_IPUR_IPURMASK); + __lcd_set_ipu_restart_triger(arg); + break; + case FBIO_SET_IPU_RESTART_ON: + /*lcdc_enable_ipu_restart();*/ + __lcd_enable_ipu_restart(); + break; + case FBIO_SET_IPU_RESTART_OFF: + /*lcdc_disable_ipu_restart();*/ + __lcd_disable_ipu_restart(); + 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 fb_info *fb = 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 = fb->fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + 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; +} + +#endif /*end of Foreground 1 ops*/ + +#if defined(CONFIG_JZ4750_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) +static int jz4750fb0_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; + + if (regno >= NR_PALETTE) + return 1; + + cfb->palette[regno].red = red ; + cfb->palette[regno].green = green; + cfb->palette[regno].blue = blue; + if (cfb->fb0.var.bits_per_pixel <= 16) { + red >>= 8; + green >>= 8; + blue >>= 8; + + red &= 0xff; + green &= 0xff; + blue &= 0xff; + } + switch (cfb->fb0.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->fb0.pseudo_palette)[regno] = + ((red >> 3) << 10) | + ((green >> 3) << 5) | + (blue >> 3); + break; + case 16: + if (regno < 16) { + ((u32 *)cfb->fb0.pseudo_palette)[regno] = + ((red >> 3) << 11) | + ((green >> 2) << 5) | + (blue >> 3); + } + break; + case 17 ... 32: + if (regno < 16) + ((u32 *)cfb->fb0.pseudo_palette)[regno] = + (red << 16) | + (green << 8) | + (blue << 0); + +/* if (regno < 16) { + unsigned val; + val = chan_to_field(red, &cfb->fb0.var.red); + val |= chan_to_field(green, &cfb->fb0.var.green); + val |= chan_to_field(blue, &cfb->fb0.var.blue); + ((u32 *)cfb->fb.pseudo_palette)[regno] = val; + } +*/ + + break; + } + return 0; +} + + + +static int jz4750fb0_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + void __user *argp = (void __user *)arg; + struct jz4750lcd_fg_t fg0; + + switch (cmd) { + case FBIOSETBACKLIGHT: + __lcd_set_backlight_level(arg); /* We support 8 levels here. */ + break; + case FBIODISPON: + REG_LCD_STATE = 0; /* clear lcdc status */ + __lcd_slcd_special_on(); + __lcd_clr_dis(); + __lcd_set_ena(); /* enable lcdc */ + __lcd_display_on(); + break; + case FBIODISPOFF: + __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 + __lcd_set_dis(); /* regular disable */ + 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))) +// if (copy_to_user(argp, &jz4750_lcd_info->osd, sizeof(struct jz4750lcd_osd_t))) + 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))) +// if (copy_to_user(argp, &jz4750_lcd_info->osd, sizeof(struct jz4750lcd_osd_t))) + return -EFAULT; + /* set mode */ + jz4750fb_set_mode(&jz4750_lcd_info->osd); +// 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 */ + jz4750tve_enable_tve(); + /* turn off lcd backlight */ + __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 */ + __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 +#if 1 + case FBIODISON_FG: //pass + /*lcdc_enable_fg0();*/ + jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_F0EN; + __lcd_enable_f0(); + break; + case FBIODISOFF_FG://pass + /*lcdc_disable_fg0();*/ + print_dbg("lcdc_disable_fg0()\n"); + jz4750_lcd_info->osd.osd_cfg &= ~LCD_OSDC_F0EN; + __lcd_disable_f0(); + break; + case FBIO_CHANGE_SIZE: + /*fg0_change_size();*/ + if(!(REG_LCD_OSDC & LCD_OSDC_F0EN)) + return -EFAULT; + if (copy_from_user(&fg0, argp, sizeof(struct jz4750lcd_fg_t))) + return -EFAULT; + jz4750_lcd_info->osd.fg0.w = fg0.w; + jz4750_lcd_info->osd.fg0.h = fg0.h; + jz4750fb0_foreground_resize(&jz4750_lcd_info->osd); + break; + case FBIO_CHANGE_POSITION: + if (copy_from_user(&fg0, argp, sizeof(struct jz4750lcd_fg_t))) + return -EFAULT; + jz4750_lcd_info->osd.fg0.x = fg0.x; + jz4750_lcd_info->osd.fg0.y = fg0.y; + jz4750fb0_foreground_move(&jz4750_lcd_info->osd); + break; + case FBIO_SET_BG_COLOR://pass + jz4750_lcd_info->osd.bgcolor = arg; + /*lcdc_set_bgcolor(arg);*/ + REG_LCD_BGC = jz4750_lcd_info->osd.bgcolor; + break; + case FBIO_ALPHA_ON://pass + /*lcdc_enable_alpha();*/ + jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_ALPHAEN; + __lcd_enable_alpha(); + break; + case FBIO_ALPHA_OFF://pass + /*lcdc_disable_alpha();*/ + jz4750_lcd_info->osd.osd_cfg &= ~LCD_OSDC_ALPHAEN; + __lcd_disable_alpha(); + break; + case FBIO_SET_ALPHA_VAL://pass + jz4750_lcd_info->osd.alpha = arg; + /*lcdc_set_alpha(arg);*/ + REG_LCD_ALPHA = jz4750_lcd_info->osd.alpha; + break; +#endif + default: + printk("FG0:%s, unknown command(0x%x)", __FILE__, cmd); + break; + } + + return ret; +} + + +static int jz4750fb0_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->fb0.fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb0.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; +} +#endif /* end of Foreground 0 ops*/ + +/* 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) +{ + + if((var->rotate & 1) != (info->var.rotate & 1)) { + if((var->xres != info->var.yres) || + (var->yres != info->var.xres) || + (var->xres_virtual != info->var.yres) || + (var->yres_virtual > + info->var.xres * ANDROID_NUMBER_OF_BUFFERS) || + (var->yres_virtual < info->var.xres )) { + return -EINVAL; + } + } + else { + if((var->xres != info->var.xres) || + (var->yres != info->var.yres) || + (var->xres_virtual != info->var.xres) || + (var->yres_virtual > + info->var.yres * ANDROID_NUMBER_OF_BUFFERS) || + (var->yres_virtual < info->var.yres )) { + return -EINVAL; + } + } + if((var->xoffset != info->var.xoffset) || + (var->bits_per_pixel != info->var.bits_per_pixel)) {// || +// (var->grayscale != info->var.grayscale)) { + return -EINVAL; + } + return 0; +} + + +/* + * set the video mode according to info->var + */ +static int jz4750fb_set_par(struct fb_info *info) +{ + dprintk("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) +{ + printk("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(); + __lcd_display_on(); + break; + + case FB_BLANK_NORMAL: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + /* Turn off panel */ +#if 0 + __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 fb_info *fb = info; + int dy; + if (!var || !fb) { + return -EINVAL; + } + + if (var->xoffset - fb->var.xoffset) { + /* No support for X panning for now! */ + return -EINVAL; + } + /* TODO: Wait for current frame to finished */ + dy = var->yoffset;// - fb->var.yoffset; +#if defined(CONFIG_JZ4750_LCD_USE_FG1_ONLY) + if (dy) { + dma1_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame + (fb->fix.line_length * dy)); + dma_cache_wback((unsigned int)(dma1_desc0), sizeof(struct jz4750_lcd_dma_desc)); + + } + else { + dma1_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame); + dma_cache_wback((unsigned int)(dma1_desc0), sizeof(struct jz4750_lcd_dma_desc)); + } +#else + if (dy) { + dma0_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame0 + (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)); + } +#endif + return 0; +} + + +/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ +#if defined(CONFIG_JZ4750_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) +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, +}; +#endif +#if defined(CONFIG_JZ4750_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) +/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ +static struct fb_ops jz4750fb0_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = jz4750fb0_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 = jz4750fb0_mmap, + .fb_ioctl = jz4750fb0_ioctl, +}; +#endif + +static int jz4750fb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + + struct fb_info *fb = info; + struct jz4750lcd_info *lcd_info = jz4750_lcd_info; + int chgvar = 0; + + if (con == 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; + } + else { + var->height = lcd_info->osd.fg1.h; + var->width = lcd_info->osd.fg1.w; + var->bits_per_pixel = lcd_info->osd.fg1.bpp; + } + + var->vmode = FB_VMODE_NONINTERLACED; +// var->vmode = FB_VMODE_DOUBLE + var->activate = fb->var.activate; + var->xres = var->width; + var->yres = var->height; + var->xres_virtual = var->width; + var->yres_virtual = var->height * ANDROID_NUMBER_OF_BUFFERS; + var->xoffset = 0; + var->yoffset = 0; + var->pixclock = KHZ2PICOS(jz_clocks.pixclk/1000); + + var->left_margin = lcd_info->panel.elw; + var->right_margin = lcd_info->panel.blw; + var->upper_margin = lcd_info->panel.efw; + var->lower_margin = lcd_info->panel.bfw; + var->hsync_len = lcd_info->panel.hsw; + var->vsync_len = lcd_info->panel.vsw; + var->sync = 0; + var->activate = FB_ACTIVATE_NOW; + + + /* + * 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 = fb->var.xoffset; + var->yoffset = fb->var.yoffset; + } + + if (var->activate & FB_ACTIVATE_TEST) + return 0; + + if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) + return -EINVAL; + + if (fb->var.xres != var->xres) + chgvar = 1; + if (fb->var.yres != var->yres) + chgvar = 1; + if (fb->var.xres_virtual != var->xres_virtual) + chgvar = 1; + if (fb->var.yres_virtual != var->yres_virtual) + chgvar = 1; + if (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 */ + fb->fix.visual = FB_VISUAL_MONO01; + 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; + + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_DIRECTCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_TRUECOLOR; + 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; + + fb->fix.visual = FB_VISUAL_TRUECOLOR; + 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", + fb->fix.id, var->bits_per_pixel); + break; + } + + fb->var = *var; + 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(&fb->cmap, fb); + 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; + +#if defined(CONFIG_JZ4750_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + /* Foreground 1 -- fb */ + strcpy(cfb->fb.fix.id, "jzlcd-fg1"); + cfb->fb.flags = FBINFO_FLAG_DEFAULT; + 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.fg1.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; + } +#endif + +#if defined(CONFIG_JZ4750_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + /* Foreground 0 -- fb0 */ + strcpy(cfb->fb0.fix.id, "jzlcd-fg0"); + cfb->fb0.fix.type = FB_TYPE_PACKED_PIXELS; + cfb->fb0.fix.type_aux = 0; + cfb->fb0.fix.xpanstep = 1; + cfb->fb0.fix.ypanstep = 1; + cfb->fb0.fix.ywrapstep = 0; + cfb->fb0.fix.accel = FB_ACCEL_NONE; + + cfb->fb0.var.nonstd = 0; + cfb->fb0.var.activate = FB_ACTIVATE_NOW; + cfb->fb0.var.height = -1; + cfb->fb0.var.width = -1; + cfb->fb0.var.accel_flags = FB_ACCELF_TEXT; + + cfb->fb0.fbops = &jz4750fb0_ops; + cfb->fb0.flags = FBINFO_FLAG_DEFAULT; + + cfb->fb0.pseudo_palette = (void *)(cfb + 1); + + switch (jz4750_lcd_info->osd.fg0.bpp) { + case 1: + fb_alloc_cmap(&cfb->fb0.cmap, 4, 0); + break; + case 2: + fb_alloc_cmap(&cfb->fb0.cmap, 8, 0); + break; + case 4: + fb_alloc_cmap(&cfb->fb0.cmap, 32, 0); + break; + case 8: + + default: + fb_alloc_cmap(&cfb->fb0.cmap, 256, 0); + break; + } +#endif + dprintk("fb_alloc_cmap, fb.cmap.len:%d, fb0.cmap.len:%d....\n", cfb->fb.cmap.len, cfb->fb0.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 = 0, needroom1=0, bpp, w, h; + unsigned char *fb_palette, *fb_frame; + /* caculate the mem size of Foreground 1 */ +#if defined(CONFIG_JZ4750_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + 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 /* CONFIG_FB_JZ4750_TVE */ + 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 + needroom1 = needroom = ((w * bpp + 7) >> 3) * h * ANDROID_NUMBER_OF_BUFFERS; + +#endif /* end of alloc Foreground 1 mem */ + + + /* caculate the mem size of Foreground 1 */ +#if defined(CONFIG_JZ4750_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + 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 +// needroom += ((w * bpp + 7) >> 3) * h; + needroom += ((w * bpp + 7) >> 3) * h * ANDROID_NUMBER_OF_BUFFERS; +#endif /* end of alloc Foreground 1 mem */ + + + /* Alloc memory */ + for (page_shift = 0; page_shift < 12; page_shift++) + if ((PAGE_SIZE << page_shift) >= needroom) + break; + fb_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); + fb_frame = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); + if ((!fb_palette) || (!fb_frame)) + return -ENOMEM; + memset((void *)fb_palette, 0, PAGE_SIZE); + memset((void *)fb_frame, 0, PAGE_SIZE << page_shift); + + lcd_palette = fb_palette; + 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 +*/ + + /* + * 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)); +#if 1 + for (page = (unsigned long)fb_frame; + page < PAGE_ALIGN((unsigned long)fb_frame + (PAGE_SIZE<fb.fix.smem_start = virt_to_phys((void *)lcd_frame); + cfb->fb.fix.smem_len = needroom - needroom1; /* page_shift/2 ??? */ + cfb->fb.screen_base = + (unsigned char *)(((unsigned int)lcd_frame&0x1fffffff) | 0xa0000000); + if (!cfb->fb.screen_base) { + printk("jz4750fb, %s: unable to map screen memory\n", cfb->fb.fix.id); + return -ENOMEM; + } +#endif + +#if defined(CONFIG_JZ4750_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + lcd_frame0 = fb_frame; + cfb->fb0.fix.smem_start = virt_to_phys((void *)lcd_frame0); + cfb->fb0.fix.smem_len = needroom1; /* page_shift/2 ??? */ + cfb->fb0.screen_base = + (unsigned char *)(((unsigned int)lcd_frame0&0x1fffffff) | 0xa0000000); + if (!cfb->fb0.screen_base) { + printk("jz4750fb0, %s: unable to map screen memory\n", cfb->fb0.fix.id); + return -ENOMEM; + } +#endif + + 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(JZ4750_LCD_USE_2LAYER_FG) + 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); + } +} + +/************************************ + * Jz475X Chipset OPS + ************************************/ + +/* + * 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 print_lcdc_registers(void) /* debug */ +{ +#ifdef 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++); + } + } + } +#endif +} + +#ifdef CONFIG_FB_JZ4750_TVE +static void jz4750lcd_info_switch_to_TVE(int mode) +{ + struct jz4750lcd_info *info; + struct jz4750lcd_osd_t *osd_lcd; + struct jz4750lcd_panel_t *panel_lcd; + int x, y, w, h; + + info = &jz4750_info_tve; + + /* Set to tve mode */ + info->panel.cfg = jz4750_lcd_panel.panel.cfg; + info->panel.cfg |= LCD_CFG_TVEN | LCD_CFG_MODE_INTER_CCIR656; /* Interlace CCIR656 mode */ + info->panel.ctrl = jz4750_lcd_panel.panel.ctrl; + info->osd.rgb_ctrl = LCD_RGBC_YCC; /* enable RGB => YUV */ + + /* Copy current to keep the old style */ + osd_lcd = &jz4750_lcd_panel.osd; + panel_lcd = &jz4750_lcd_panel.panel; + + 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; + + /* set Foreground 0 */ + w = osd_lcd->fg0.w / panel_lcd->w * TVE_WIDTH_PAL; + h = osd_lcd->fg0.h / panel_lcd->h * TVE_HEIGHT_PAL; + x = osd_lcd->fg0.x / panel_lcd->w * TVE_WIDTH_PAL; + y = osd_lcd->fg0.y / panel_lcd->h * TVE_HEIGHT_PAL; + 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; + + /* set Foreground 1 */ + w = osd_lcd->fg1.w / panel_lcd->w * TVE_WIDTH_PAL; + h = osd_lcd->fg1.h / panel_lcd->h * TVE_HEIGHT_PAL; + x = osd_lcd->fg1.x / panel_lcd->w * TVE_WIDTH_PAL; + y = osd_lcd->fg1.y / panel_lcd->h * TVE_HEIGHT_PAL; + 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 / panel_lcd->w * TVE_WIDTH_PAL; + h = osd_lcd->fg0.h / panel_lcd->h * TVE_HEIGHT_NTSC; + x = osd_lcd->fg0.x / panel_lcd->w * TVE_WIDTH_NTSC; + y = osd_lcd->fg0.y / panel_lcd->h * TVE_HEIGHT_NTSC; + 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 / panel_lcd->w * TVE_WIDTH_PAL; + h = osd_lcd->fg1.h / panel_lcd->h * TVE_HEIGHT_NTSC; + x = osd_lcd->fg1.x / panel_lcd->w * TVE_WIDTH_NTSC; + y = osd_lcd->fg1.y / panel_lcd->h * TVE_HEIGHT_NTSC; + 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__); + } + jz4750_lcd_info = &jz4750_info_tve; +} + +/* + * switch to lcd mode from TVE mode + */ + +static void jz4750lcd_info_switch_to_lcd(void) +{ + struct jz4750lcd_info *info; + struct jz4750lcd_osd_t *osd_lcd; + struct jz4750lcd_panel_t *panel_lcd; + int x, y, w, h; + + info = &jz4750_lcd_panel; + + /* set to tve mode */ + info->panel.cfg = jz4750_info_tve.panel.cfg; + info->panel.cfg &= ~(LCD_CFG_TVEN | LCD_CFG_MODE_INTER_CCIR656); /* Interlace CCIR656 mode */ + info->panel.ctrl = jz4750_info_tve.panel.ctrl; + info->osd.rgb_ctrl &= ~LCD_RGBC_YCC; /* enable YUV => RGB*/ + + /* */ + osd_lcd = &jz4750_info_tve.osd; + panel_lcd = &jz4750_info_tve.panel; + + /* set Foreground 0 */ + w = osd_lcd->fg0.w / panel_lcd->w * info->panel.w; + h = osd_lcd->fg0.h / panel_lcd->h * info->panel.h; + x = osd_lcd->fg0.x / panel_lcd->w * info->panel.w; + y = osd_lcd->fg0.y / panel_lcd->h * info->panel.h; + info->osd.fg0.x = x; + info->osd.fg0.y = y; + info->osd.fg0.w = w; + info->osd.fg0.h = h; + + /* set Foreground 1 */ + w = osd_lcd->fg1.w / panel_lcd->w * info->panel.w; + h = osd_lcd->fg1.h / panel_lcd->h * info->panel.h; + x = osd_lcd->fg1.x / panel_lcd->w * info->panel.w; + y = osd_lcd->fg1.y / panel_lcd->h * info->panel.h; + info->osd.fg1.x = x; + info->osd.fg1.y = y; + info->osd.fg1.w = w; + info->osd.fg1.h = h; + + jz4750_lcd_info = &jz4750_lcd_panel; +} +#endif +/* initial dma descriptors */ +static void jz4750fb_descriptor_init( struct jz4750lcd_info * lcd_info ) +{ + unsigned int pal_size; + int fg0_line_size, fg0_frm_size, fg1_line_size, fg1_frm_size; + int size0, size1; + + 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; + + /* + * 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 --> ... + * DMA Chan1: + * TO LCD Panel: + * dma1_desc0 <<==>> dma1_desc0 + * TO TV Encoder: + * dma1_desc0 <<==>> dma1_desc1 + */ + + dma0_desc_palette = dma_desc_base + 0; +#if 1//defined(CONFIG_JZ4750_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + dma0_desc0 = dma_desc_base + 1; + dma0_desc1 = dma_desc_base + 2; + dma0_desc0_change = dma_desc_base + 3; + dma0_desc1_change = dma_desc_base + 4; + + /* Foreground 0, caculate size */ + if ( lcd_info->osd.fg0.x >= lcd_info->panel.w ) + lcd_info->osd.fg0.x = lcd_info->panel.w - 1; + if ( lcd_info->osd.fg0.y >= lcd_info->panel.h ) + lcd_info->osd.fg0.y = lcd_info->panel.h - 1; + 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; + + size0 = lcd_info->osd.fg0.h << 16 | lcd_info->osd.fg0.w; + 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; + + /* Palette Descriptor */ + 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 */ + + /* DMA0 Descriptor */ + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ + /* Next */ + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc1); + 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 + dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc1_change); + dma0_desc1_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + + /* frame phys addr */ + dma0_desc0->databuf = dma0_desc0_change->databuf = virt_to_phys((void *)lcd_frame0); + dma0_desc1->databuf = virt_to_phys((void *)(lcd_frame0 + fg0_line_size)); + + /* frame id */ + dma0_desc0->frame_id = (unsigned int)0x0da00000; /* DMA0'0 */ + dma0_desc1->frame_id = (unsigned int)0x0da00001; /* DMA0'1 */ + dma0_desc0_change->frame_id = (unsigned int)0x0da000c0; /* DMA0'2 */ + dma0_desc1_change->frame_id = (unsigned int)0x0da000c1; + + /* others */ + 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_desc0->desc_size = dma0_desc1->desc_size = size0; + + } + else { /* Normal TFT LCD */ + /* next */ + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + + /* frame phys addr */ + dma0_desc0->databuf = dma0_desc0_change->databuf = virt_to_phys((void *)lcd_frame0); + + /* frame id */ + dma0_desc0->frame_id = (unsigned int)0x0000da00; /* DMA0'0 */ + dma0_desc0_change->frame_id = (unsigned int)0x0da000c0; /* DMA0'2 */ + + /* others */ + dma0_desc0->cmd = fg0_frm_size/4; + dma0_desc0->offsize =0; + dma0_desc0->page_width = 0; + dma0_desc0->desc_size = size0; + } + + 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_desc0); //tft + REG_LCD_SIZE0 = size0; + current_dma0_id = 0;//dma0_desc0; + + +#endif + +#if 1//defined(CONFIG_JZ4750_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + dma1_desc0 = dma_desc_base + 5; + dma1_desc1 = dma_desc_base + 6; + dma1_desc0_change = dma_desc_base + 7; + dma1_desc1_change = dma_desc_base + 8; + + /* Foreground 1, caculate size */ + if ( lcd_info->osd.fg1.x >= lcd_info->panel.w ) + lcd_info->osd.fg1.x = lcd_info->panel.w - 1; + if ( lcd_info->osd.fg1.y >= lcd_info->panel.h ) + lcd_info->osd.fg1.y = lcd_info->panel.h - 1; + 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; + + + size1 = lcd_info->osd.fg1.h << 16 | lcd_info->osd.fg1.w; + fg1_line_size = lcd_info->osd.fg1.w*lcd_info->osd.fg1.bpp/8; + fg1_line_size = ((fg1_line_size+3)>>2)<<2; /* word aligned */ + fg1_frm_size = fg1_line_size * lcd_info->osd.fg1.h; + + /* DMA1 Descriptor */ + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) {/* TVE mode */ + /* Next */ + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc1); + dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc1_change); + dma1_desc1_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + + /* frame phys addr */ + dma1_desc0->databuf = dma1_desc0_change->databuf = virt_to_phys((void *)lcd_frame); + dma1_desc1->databuf = virt_to_phys((void *)(lcd_frame + fg1_line_size)); + + /* frame id */ + dma1_desc0->frame_id = (unsigned int)0x0da10000; /* DMA1'0 */ + dma1_desc1->frame_id = (unsigned int)0x0da10001; /* DMA1'1 */ + dma1_desc0_change->frame_id = (unsigned int)0x0da100c0; /* DMA1'C0 */ + dma1_desc1_change->frame_id = (unsigned int)0x0da100c1; /* DMA1'C1 */ + + /* other*/ + 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_desc0->desc_size = dma1_desc1->desc_size = size1; + + } + else { /* Normal TFT LCD */ + /* Next */ + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + + /* frame phys addr */ + dma1_desc0->databuf = dma1_desc0_change->databuf = virt_to_phys((void *)lcd_frame); + + /* frame id */ + dma1_desc0->frame_id = (unsigned int)0x0da10000; /* DMA1'0 */ + dma1_desc0_change->frame_id = (unsigned int)0x0da100c0; /* DMA1'C0 */ + + /* other */ + dma1_desc0->cmd = fg1_frm_size/4; + dma1_desc0->offsize = 0; + dma1_desc0->page_width = 0; + dma1_desc0->desc_size = size1; + } + + REG_LCD_DA1 = virt_to_phys(dma1_desc0); /* set Dma-chan1's Descripter Addrress */ + REG_LCD_SIZE1 = size1; + current_dma1_id = 0;//dma1_desc0; +#endif + dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc)); + +} + +static void jz4750fb_set_panel_mode(struct jz4750lcd_info * lcd_info) +{ + struct jz4750lcd_panel_t *panel = &lcd_info->panel; + + /* 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 ) +static void jz4750fb_set_osd_mode(struct jz4750lcd_osd_t *lcd_osd_info) +{ + lcd_osd_info->osd_ctrl &= ~(LCD_OSDCTRL_OSDBPP_MASK); + if ( lcd_osd_info->fg1.bpp == 15 ) + lcd_osd_info->osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB555; + else if ( lcd_osd_info->fg1.bpp == 16 ) + lcd_osd_info->osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB565; + else { + lcd_osd_info->fg1.bpp = 32; + lcd_osd_info->osd_ctrl |= LCD_OSDCTRL_OSDBPP_18_24; + } + + REG_LCD_OSDC = lcd_osd_info->osd_cfg; /* F0, F1, alpha, */ + + REG_LCD_OSDCTRL = lcd_osd_info->osd_ctrl; /* IPUEN, bpp */ + REG_LCD_RGBC = lcd_osd_info->rgb_ctrl; + REG_LCD_BGC = lcd_osd_info->bgcolor; + REG_LCD_KEY0 = lcd_osd_info->colorkey0; + REG_LCD_KEY1 = lcd_osd_info->colorkey1; + REG_LCD_ALPHA = lcd_osd_info->alpha; + REG_LCD_IPUR = lcd_osd_info->ipu_restart; +} + +#if defined(CONFIG_JZ4750_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + +/* Change Position of Foreground 0 */ +static int jz4750fb0_foreground_move(struct jz4750lcd_osd_t *lcd_osd_info) +{ + int pos; +#if defined(CONFIG_SOC_JZ4750D) + int j, count; +#endif + /* + * 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 fg0 position: + * fg0.x + fg0.w <= panel.w; + * fg0.y + fg0.h <= panel.h; + * + * When output is LCD panel, fg.y 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 should be even number always. + * + */ + + /* Foreground 0 */ + if (lcd_osd_info->fg0.x + lcd_osd_info->fg0.w > jz4750_lcd_info->panel.w) + lcd_osd_info->fg0.x = jz4750_lcd_info->panel.w - lcd_osd_info->fg0.w; + if (lcd_osd_info->fg0.y + lcd_osd_info->fg0.h > jz4750_lcd_info->panel.h) + lcd_osd_info->fg0.y = jz4750_lcd_info->panel.h - lcd_osd_info->fg0.h; + + if (lcd_osd_info->fg0.x >= jz4750_lcd_info->panel.w) + lcd_osd_info->fg0.x = jz4750_lcd_info->panel.w - 1; + if (lcd_osd_info->fg0.y >= jz4750_lcd_info->panel.h) + lcd_osd_info->fg0.y = jz4750_lcd_info->panel.h - 1; + + pos = lcd_osd_info->fg0.y << 16 | lcd_osd_info->fg0.x; + if (REG_LCD_XYP0 == pos){ + printk("FG0: same position\n"); + return 0; + } + +#if defined(CONFIG_SOC_JZ4750) + /****jz4750****/ +// REG_LCD_OSDC &= ~LCD_OSDC_F0EN; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + REG_LCD_XYP0 = pos; +// REG_LCD_OSDC |= LCD_OSDC_F0EN; + /*********************************************/ +#elif defined(CONFIG_SOC_JZ4750D) + REG_LCD_XYP0 = pos; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + while(!(REG_LCD_OSDS & LCD_OSDS_READY)); + j = count; + msleep(40); + while((REG_LCD_OSDCTRL & LCD_OSDCTRL_CHANGES) && j--); + if(j == 0) { + printk("Error FG0 Position: Wait change fail.\n"); + return -EFAULT; + } + +#endif + return 0; +} +/* Change Window size of Foreground 0 */ +static int jz4750fb0_foreground_resize(struct jz4750lcd_osd_t *lcd_osd_info) +{ + struct lcd_cfb_info *cfb = jz4750fb_info; + int size, fg0_line_size, fg0_frm_size; +// int desc_len = sizeof(struct jz4750_lcd_dma_desc); + /* + * 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_osd_info->fg0.x + lcd_osd_info->fg0.w > jz4750_lcd_info->panel.w) + lcd_osd_info->fg0.w = jz4750_lcd_info->panel.w - lcd_osd_info->fg0.x; + if (lcd_osd_info->fg0.y + lcd_osd_info->fg0.h > jz4750_lcd_info->panel.h) + lcd_osd_info->fg0.h = jz4750_lcd_info->panel.h - lcd_osd_info->fg0.y; + + size = lcd_osd_info->fg0.h << 16 | lcd_osd_info->fg0.w; + + if (REG_LCD_SIZE0 == size) { + printk("FG0: same size\n"); + return 0; + } + + fg0_line_size = lcd_osd_info->fg0.w * lcd_osd_info->fg0.bpp / 8; + fg0_line_size = ((fg0_line_size + 3) >> 2) << 2; /* word aligned */ + fg0_frm_size = fg0_line_size * lcd_osd_info->fg0.h; + + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; +#if 0 // For 4750d + if (current_dma0_id == 0) { + printk("Change to dma0_desc0_change\n"); +// REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma0_desc0_change->cmd = dma0_desc1_change->cmd = (fg0_frm_size/4)/2; + dma0_desc0_change->offsize = dma0_desc1_change->offsize + = fg0_line_size/4; + dma0_desc0_change->page_width = dma0_desc1_change->page_width + = fg0_line_size/4; + dma0_desc1_change->databuf = virt_to_phys((void *)(lcd_frame0 + fg0_line_size)); + dma0_desc0_change->desc_size = dma0_desc1->desc_size = size; + dma_cache_wback_inv((unsigned int)(dma0_desc0_change), desc_len); + dma_cache_wback_inv((unsigned int)(dma0_desc1_change), desc_len); + } + else { + dma0_desc0_change->cmd = fg0_frm_size/4; + dma0_desc0_change->offsize = 0; + dma0_desc0_change->page_width = 0; + dma0_desc0_change->desc_size = size; + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + dma_cache_wback_inv((unsigned int)(dma0_desc0_change),desc_len); + } + REG_LCD_SIZE0 = size; + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + dma_cache_wback_inv((unsigned int)(dma0_desc1_change), desc_len); + } + else { + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + dma_cache_wback_inv((unsigned int)(dma0_desc0_change), desc_len); + } + current_dma0_id = 1;//dma0_desc0_change; + } + else { + printk("Change to dma0_desc0\n"); + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + 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)); + dma0_desc0->desc_size = dma0_desc1->desc_size = size; + } + else { + dma0_desc0->cmd = fg0_frm_size/4; + dma0_desc0->offsize =0; + dma0_desc0->page_width = 0; + dma0_desc0->desc_size = size; + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma_cache_wback_inv((unsigned int)(dma0_desc0), desc_len); + } + REG_LCD_SIZE0 = size; + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma0_desc1_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma_cache_wback_inv((unsigned int)(dma0_desc1_change), desc_len); + } + else { + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma_cache_wback_inv((unsigned int)(dma0_desc0_change), desc_len); + } + current_dma0_id = 0;//dma0_desc0; + } + +#else + /* set change bit */ + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + + if (jz4750_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)); + } + 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 = size; +// = lcd_osd_info->fg0.h << 16 | lcd_osd_info->fg0.w; + REG_LCD_SIZE0 = size; +// REG_LCD_SIZE0 = (lcd_osd_info->fg0.h << 16) | lcd_osd_info->fg0.w; + + dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc)); +#endif + jz4750fb_set_var(&cfb->fb0.var, 0, &cfb->fb0); + return 0; +} +#endif +#if defined(CONFIG_JZ4750_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + +/* Change Position of Foreground 1 */ +static int jz4750fb_foreground_move(struct jz4750lcd_osd_t *lcd_osd_info) +{ + int pos; +#if defined(CONFIG_SOC_JZ4750D) + int j, count = 100000; +#endif + /* + * 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 fg1 position: + * fg1.x + fg1.w <= panel.w; + * fg1.y + fg1.h <= panel.h; + * + * When output is LCD panel, fg.y 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 should be even number always. + * + */ + + /* Foreground 0 */ + if (lcd_osd_info->fg1.x + lcd_osd_info->fg1.w > jz4750_lcd_info->panel.w) + lcd_osd_info->fg1.x = jz4750_lcd_info->panel.w - lcd_osd_info->fg1.w; + if (lcd_osd_info->fg1.y + lcd_osd_info->fg1.h > jz4750_lcd_info->panel.h) + lcd_osd_info->fg1.y = jz4750_lcd_info->panel.h - lcd_osd_info->fg1.h; + + if (lcd_osd_info->fg1.x >= jz4750_lcd_info->panel.w) + lcd_osd_info->fg1.x = jz4750_lcd_info->panel.w - 1; + if (lcd_osd_info->fg1.y >= jz4750_lcd_info->panel.h) + lcd_osd_info->fg1.y = jz4750_lcd_info->panel.h - 1; + + pos = lcd_osd_info->fg1.y << 16 | lcd_osd_info->fg1.x; + if (REG_LCD_XYP1 == pos){ + printk("FG1: same position\n"); + return 0; + } + +#if defined(CONFIG_SOC_JZ4750) + /****jz4750****/ +// REG_LCD_OSDC &= ~LCD_OSDC_F0EN; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + REG_LCD_XYP1 = pos; +// REG_LCD_OSDC |= LCD_OSDC_F0EN; + /*********************************************/ +#elif defined(CONFIG_SOC_JZ4750D) + REG_LCD_XYP1 = pos; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + while(!(REG_LCD_OSDS & LCD_OSDS_READY)); + j = count; + msleep(40); + while((REG_LCD_OSDCTRL & LCD_OSDCTRL_CHANGES) && j--); + if(j == 0) { + printk("Error FG1 Position: Wait change fail.\n"); + return -EFAULT; + + } +#endif + return 0; +} + +/* Change window size of Foreground 1 */ +static int jz4750fb_foreground_resize(struct jz4750lcd_osd_t *lcd_osd_info) +{ + struct lcd_cfb_info *cfb = jz4750fb_info; + int size, fg1_line_size, fg1_frm_size; +// int desc_len = sizeof(struct jz4750_lcd_dma_desc); + /* + * 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_osd_info->fg1.x + lcd_osd_info->fg1.w > jz4750_lcd_info->panel.w) + lcd_osd_info->fg1.w = jz4750_lcd_info->panel.w - lcd_osd_info->fg1.x; + if (lcd_osd_info->fg1.y + lcd_osd_info->fg1.h > jz4750_lcd_info->panel.h) + lcd_osd_info->fg1.h = jz4750_lcd_info->panel.h - lcd_osd_info->fg1.y; +// size = lcd_info->osd.fg1.h << 16|lcd_info->osd.fg1.w; + size = lcd_osd_info->fg1.h << 16|lcd_osd_info->fg1.w; + if (REG_LCD_SIZE1 == size) { + printk("FG1: same size\n"); + return 0;// -EFAULT; + } + +// fg1_line_size = lcd_osd_info->fg1.w * ((lcd_osd_info->fg1.bpp + 7) / 8); + fg1_line_size = lcd_osd_info->fg1.w * lcd_osd_info->fg1.bpp / 8; + fg1_line_size = ((fg1_line_size + 3) >> 2) << 2; /* word aligned */ + fg1_frm_size = fg1_line_size * lcd_osd_info->fg1.h; + +#if 0 + if (current_dma1_id == 0) { + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma1_desc0_change->cmd = dma1_desc1_change->cmd = (fg1_frm_size/4)/2; + dma1_desc0_change->offsize = dma1_desc1_change->offsize + = fg1_line_size/4; + dma1_desc0_change->page_width = dma1_desc1_change->page_width + = fg1_line_size/4; + dma1_desc1_change->databuf = virt_to_phys((void *)(lcd_frame + fg1_line_size)); + dma1_desc0_change->desc_size = dma1_desc1->desc_size = size; + dma_cache_wback_inv((unsigned int)(dma1_desc0_change), desc_len); + dma_cache_wback_inv((unsigned int)(dma1_desc1_change), desc_len); + } + else { + dma1_desc0_change->cmd = fg1_frm_size/4; + dma1_desc0_change->offsize = 0; + dma1_desc0_change->page_width = 0; + dma1_desc0_change->desc_size = size; + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + dma_cache_wback_inv((unsigned int)(dma1_desc0_change),desc_len); + } + + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + dma_cache_wback_inv((unsigned int)(dma1_desc1_change), desc_len); + } + else { + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + dma_cache_wback_inv((unsigned int)(dma1_desc0_change), desc_len); + } + REG_LCD_SIZE1 = size; + current_dma1_id = 1;//dma1_desc0_change; + + } + else { + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + 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_frame + fg1_line_size)); + dma1_desc0->desc_size = dma1_desc1->desc_size = size; + } + else { + dma1_desc0->cmd = fg1_frm_size/4; + dma1_desc0->offsize =0; + dma1_desc0->page_width = 0; + dma1_desc0->desc_size = size; + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma_cache_wback_inv((unsigned int)(dma1_desc0), desc_len); + } + if (jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma1_desc1_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma_cache_wback_inv((unsigned int)(dma1_desc1_change), desc_len); + } + else { + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma_cache_wback_inv((unsigned int)(dma1_desc0_change), desc_len); + } + REG_LCD_SIZE1 = size; + current_dma1_id = 0;//dma1_desc0_change; + } + + +#else + /* set change bit */ + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + if ( jz4750_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_frame + fg1_line_size)); + } + 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 = size; + REG_LCD_SIZE1 = size; + + dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc)); +#endif + jz4750fb_set_var(&cfb->fb.var, 1, &cfb->fb); + return 0; +} +#endif + + +/* + * Set lcd pixel clock + */ +static void jz4750fb_change_clock( struct jz4750lcd_info * lcd_info ) +{ +#if defined(CONFIG_FPGA) /* FPGA test, pixdiv */ + 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 */ + pclk = 27000000; + __cpm_select_pixclk_tve(); + } + else { /* LCDC output to LCD panel */ + __cpm_select_pixclk_lcd(); + } + 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 + __cpm_enable_pll_change(); + + 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_osd_t * lcd_osd_info) +//static void jz4750fb_set_mode(struct jz4750lcd_info * lcd_info) +{ +// struct jz4750lcd_osd_t * lcd_osd_info = jz4750_lcd_info->osd; +// struct lcd_cfb_info *cfb = jz4750fb_info; + + jz4750fb_set_osd_mode(lcd_osd_info); +#if defined(CONFIG_JZ4750_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + jz4750fb_foreground_resize(lcd_osd_info); +#endif +#if defined(CONFIG_JZ4750_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + jz4750fb0_foreground_resize(lcd_osd_info); +#endif +} + +/* + * 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. + */ + struct lcd_cfb_info *cfb = jz4750fb_info; + + __lcd_clr_ena(); /* Quick Disable */ + lcd_info->osd.fg_change = FG_CHANGE_ALL; /* change FG0, FG1 size, postion??? */ + jz4750fb_set_osd_mode(&lcd_info->osd); + jz4750fb_set_panel_mode(lcd_info); + jz4750fb_descriptor_init(lcd_info); + jz4750fb_change_clock(lcd_info); +#if defined(CONFIG_JZ4750_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + jz4750fb_set_var(&cfb->fb0.var, 0, &cfb->fb0); +#endif +#if defined(CONFIG_JZ4750_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + jz4750fb_set_var(&cfb->fb.var, 1, &cfb->fb); +#endif + __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 jz4750fb_suspend(struct platform_device *pdev, pm_message_t state) +{ + __lcd_clr_ena(); /* Quick Disable */ + __lcd_display_off(); + __cpm_stop_lcd(); + + return 0; +} + +/* + * Resume the LCDC. + */ +static int jz4750fb_resume(struct platform_device *pdev) +{ + __cpm_start_lcd(); + REG_LCD_DA1 = virt_to_phys(dma1_desc0); + __lcd_set_ena(); + __lcd_display_on(); + + return 0; +} +#else +static int jz4750fb_suspend(struct device *dev, pm_message_t state) {return 0;} +static int jz4750fb_resume(struct device *dev) {return 0;} +#endif /* CONFIG_PM */ + +/* The following routine is only for test */ + +static void jz4750_lcd_gpio_init(void) +{ + /* 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(); + + /* 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 + __lcd_display_pin_init(); +} + +static void jz4750_lcd_init_cfg(void) +{ + +#if defined(CONFIG_JZ4750_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_F0EN; /* only open fg0 */ +#endif +// jz4750_lcd_info->osd.osd_cfg |= LCD_OSDC_F1EN; /* only open fg1 */ + + /* In special mode, we only need init special pin, + * as general lcd pin has init in uboot */ +#if defined(CONFIG_SOC_JZ4750) + 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: + break; + } +#endif + /* Foreground 0 support bpp = 1, 2, 4, 8, 15, 16, 18, 24 */ + switch ( jz4750_lcd_info->osd.fg0.bpp ) { + case 17 ... 32: + jz4750_lcd_info->osd.fg1.bpp = 32; + break; + default: + break; + } + + /* Foreground 1 support bpp = 15, 16, 18, 24 */ + 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; + } +} + +#ifdef CONFIG_LEDS_CLASS +static void lcd_set_backlight_level(struct led_classdev *led_cdev, enum led_brightness value) { + __lcd_set_backlight_level((int)value); +} + +static struct led_classdev lcd_backlight_led = { + .name = "lcd-backlight", + .brightness_set = lcd_set_backlight_level, +}; +#endif + +static int __init jz4750fb_probe(struct platform_device *pdev) +{ + struct lcd_cfb_info *cfb; + int err = 0; + __lcd_close_backlight(); + if (!pdev) + return -EINVAL; + jz4750_lcd_gpio_init(); /* gpio init */ + jz4750_lcd_init_cfg(); /* first config of lcd */ + + __lcd_clr_dis(); + __lcd_clr_ena(); + + /* init clock */ + __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 ); + + /* registers frame buffer devices */ + +#if defined(CONFIG_JZ4750_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + /* register fg0 */ + err = register_framebuffer(&cfb->fb0); + if (err < 0) { + dprintk("jz4750fb_init(): register framebuffer err.\n"); + goto failed; + } + printk("fb%d: %s frame buffer device, using %dK of video memory\n", + cfb->fb0.node, cfb->fb0.fix.id, cfb->fb0.fix.smem_len>>10); + +#endif + +#if defined(CONFIG_JZ4750_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4750_LCD_USE_2LAYER_FG) + /* register fg1 */ + err = register_framebuffer(&cfb->fb); + if (err < 0) { + dprintk("jz4750fb_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); +#endif + + if (request_irq(IRQ_LCD, jz4750fb_interrupt_handler, IRQF_DISABLED, + "lcd", 0)) { + err = -EBUSY; + goto failed; + } +// display_h_color_bar((void *)lcd_frame, jz4750_lcd_info->osd.fg1.w, jz4750_lcd_info->osd.fg1.h, jz4750_lcd_info->osd.fg1.bpp); + +#ifdef CONFIG_LEDS_CLASS + err = led_classdev_register(&pdev->dev, &lcd_backlight_led); + if (err < 0) + goto failed; +#endif + + __lcd_set_ena(); /* enalbe LCD Controller */ + __lcd_display_on(); + print_lcdc_registers(); + pm_set_vt_switch(0); /*disable VT switch during suspend/resume*/ + return 0; + +failed: + print_dbg(); + jz4750fb_unmap_smem(cfb); + jz4750fb_free_fb_info(cfb); + + return err; +} + +static int jz4750fb_remove(struct platform_device *pdev) +{ + struct lcd_cfb_info *cfb = platform_get_drvdata(pdev); + + jz4750fb_unmap_smem(cfb); + jz4750fb_free_fb_info(cfb); + return 0; +} + + + +static struct platform_driver jz_lcd_driver = { + .probe = jz4750fb_probe, + .remove = jz4750fb_remove, +#ifdef CONFIG_PM + .suspend = jz4750fb_suspend, + .resume = jz4750fb_resume, +#endif + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init jz4750fb_init(void) +{ + return platform_driver_register(&jz_lcd_driver); +} + +static void __exit jz4750fb_cleanup(void) +{ + platform_driver_unregister(&jz_lcd_driver); +} + +module_init(jz4750fb_init); +module_exit(jz4750fb_cleanup); diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jz4750_lcd.h b/target/linux/xburst/files-2.6.27/drivers/video/jz4750_lcd.h new file mode 100644 index 000000000..bdff54eb9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz4750_lcd.h @@ -0,0 +1,796 @@ +/* + * 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 + + +#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 */ +#define FBIODISON_FG 0x46a8 /* FG display on */ +#define FBIODISOFF_FG 0x46a9 /* FG display on */ +#define FBIO_SET_LCD_TO_TVE 0x46b0 /* set lcd to tve mode */ +#define FBIO_SET_FRM_TO_LCD 0x46b1 /* set framebuffer to lcd */ +#define FBIO_SET_IPU_TO_LCD 0x46b2 /* set ipu to lcd directly */ +#define FBIO_CHANGE_SIZE 0x46b3 /* change FG size */ +#define FBIO_CHANGE_POSITION 0x46b4 /* change FG starts position */ +#define FBIO_SET_BG_COLOR 0x46b5 /* set background color */ +#define FBIO_SET_IPU_RESTART_VAL 0x46b6 /* set ipu restart value */ +#define FBIO_SET_IPU_RESTART_ON 0x46b7 /* set ipu restart on */ +#define FBIO_SET_IPU_RESTART_OFF 0x46b8 /* set ipu restart off */ +#define FBIO_ALPHA_ON 0x46b9 /* enable alpha */ +#define FBIO_ALPHA_OFF 0x46c0 /* disable alpha */ +#define FBIO_SET_ALPHA_VAL 0x46c1 /* set alpha value */ + +/* + * 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) /* 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*5+2) /*LCD_DISP_N use for lcd reset*/ +#elif defined(CONFIG_JZ4750D_CETUS) /* board cetus */ + #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*/ +#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 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_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) + +#if 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(); \ + mdelay(200); \ + __lcd_set_backlight_level(80); \ +} while (0) + +#define __lcd_display_off() \ +do { \ + __lcd_close_backlight(); \ + __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(); \ + __lcd_set_backlight_level(80); \ +} while (0) + +#define __lcd_display_off() \ +do { \ + __lcd_close_backlight(); \ + __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 */ +#endif /* CONFIG_SOC_JZ4750 */ + + +/***************************************************************************** + * 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/target/linux/xburst/files-2.6.27/drivers/video/jz4750_tve.c b/target/linux/xburst/files-2.6.27/drivers/video/jz4750_tve.c new file mode 100644 index 000000000..a1be2db62 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz4750_tve.c @@ -0,0 +1,166 @@ + +/* + * linux/drivers/video/jz4750_tve.c -- Ingenic Jz4750 TVE Controller operation + * interface. + * Copyright (C) 2005-2008, Ingenic Semiconductor Inc. + * Author: Wolfgang Wang, + * + * 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 +#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<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(); +} + + +void jz4750tve_outfmt_init(unsigned int outfmt) +{ + switch (outfmt) { +#ifdef CONFIG_SOC_JZ4750D + case PANEL_OUT_FMT_YCBCR: + jz4750_tve_info_PAL.ctrl |= TVE_CTRL_EYCBCR; + break; +#endif + case PANEL_OUT_FMT_CVBS: +#ifdef CONFIG_SOC_JZ4750D + /* Disable YCbCr */ + jz4750_tve_info_PAL.ctrl &= ~TVE_CTRL_EYCBCR; +#endif + jz4750_tve_info_PAL.ctrl |= TVE_CTRL_ECVBS; + break; + case PANEL_OUT_FMT_SVIDEO: + default: +#ifdef CONFIG_SOC_JZ4750D + /* Disable YCbCr */ + jz4750_tve_info_PAL.ctrl &= ~TVE_CTRL_EYCBCR; +#endif + jz4750_tve_info_PAL.ctrl &= ~TVE_CTRL_ECVBS; + break; + } +} + +#if 0 +void jz4750tve_mode_init(struct jz4750tve_mode * tve_mode) +{ + switch (tve_mode->out_fmt) { + case PANEL_OUT_FMT_YCBCR: + jz4750_tve_info_PAL.ctrl |= TVE_CTRL_EYCBCR; + break; + case PANEL_OUT_FMT_CVBS: +#ifdef CONFIG_SOC_JZ4750D + /* Disable YCbCr */ + jz4750_tve_info_PAL.ctrl &= ~TVE_CTRL_EYCBCR; +#endif + jz4750_tve_info_PAL.ctrl |= TVE_CTRL_ECVBS; + break; + case PANEL_OUT_FMT_SVIDEO: + default: +#ifdef CONFIG_SOC_JZ4750D + /* Disable YCbCr */ + jz4750_tve_info_PAL.ctrl &= ~TVE_CTRL_EYCBCR; +#endif + jz4750_tve_info_PAL.ctrl &= ~TVE_CTRL_ECVBS; + break; + } + switch (tve_mode->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(); +} +#endif diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jz4750_tve.h b/target/linux/xburst/files-2.6.27/drivers/video/jz4750_tve.h new file mode 100644 index 000000000..fefbe803e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz4750_tve.h @@ -0,0 +1,59 @@ +#ifndef __JZ4750_TVE_H__ +#define __JZ4750_TVE_H__ + + +#define PANEL_MODE_TVE_NTSC 2 +#define PANEL_MODE_TVE_PAL 1 +#define PANEL_MODE_LCD_PANEL 0 + +#define PANEL_OUT_FMT_YCBCR 2 +#define PANEL_OUT_FMT_SVIDEO 1 +#define PANEL_OUT_FMT_CVBS 0 + +/* TV parameter */ +#define TVE_WIDTH_PAL 720 +#define TVE_WIDTH_PAL16 704 +#define TVE_HEIGHT_PAL 573 +#define TVE_HEIGHT_PAL16 553 +#define TVE_FREQ_PAL 50 +#define TVE_WIDTH_NTSC 720 +#define TVE_WIDTH_NTSC16 704 +#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; +}; + +struct jz4750tve_mode { + unsigned int mode; /* PAL or NTSC mode, lcd mode*/ + unsigned int out_fmt; /* CVBS, S-video, YCbCr(Jz4750 didn't support)*/ +}; + +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 ); + +extern void jz4750tve_outfmt_init(unsigned int outfmt); + +#endif /* __JZ4750_TVE_H__ */ diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jz4755_android_lcd.c b/target/linux/xburst/files-2.6.27/drivers/video/jz4755_android_lcd.c new file mode 100644 index 000000000..1b9fe3190 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz4755_android_lcd.c @@ -0,0 +1,2841 @@ + +/* + * linux/drivers/video/jz4755_android_lcd.c -- Ingenic Jz4755 LCD frame buffer device + * + * Copyright (C) 2005-2009, 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "console/fbcon.h" +#include "jz4755_android_lcd.h" +#include "jz4755_android_tve.h" + +#define DRIVER_NAME "jz-lcd" + +MODULE_DESCRIPTION("Jz4755 LCD Controller driver"); +MODULE_AUTHOR("Wolfgang Wang , Lemon Liu , Emily Feng "); +MODULE_LICENSE("GPL"); + +#define LCD_DEBUG +//#undef LCD_DEBUG + +#ifdef CONFIG_JZSOC_BOOT_LOGO +extern int load_565_image(char *filename); +#ifdef CONFIG_FB_565RLE_LOGO +#define INIT_IMAGE_FILE "/logo.rle" +#endif +#ifdef CONFIG_FB_565RGB_LOGO +#define INIT_IMAGE_FILE "/logo.rgb565" +#endif +#endif /* CONFIG_JZSOC_BOOT_LOGO */ + +#ifdef LCD_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) + +#define JZ_LCD_ID "jz-lcd" +#define ANDROID_NUMBER_OF_BUFFERS 2 + +struct lcd_cfb_info { + struct fb_info fb0; /* foreground 0 */ + struct fb_info fb1; /* foreground 1 */ + struct display_switch *dispsw; + signed int currcon; + int func_use_count; + spinlock_t update_lock; + unsigned frame_requested; + unsigned frame_done; + wait_queue_head_t frame_wq; + struct early_suspend earlier_suspend; + struct early_suspend early_suspend; + struct { + u16 red, green, blue; + } palette[NR_PALETTE]; +}; + +static struct lcd_cfb_info *jz4755fb_info; +static int current_dma0_id, current_dma1_id; +static struct jz4755_lcd_dma_desc *dma_desc_base; +static struct jz4755_lcd_dma_desc *dma0_desc_palette, *dma0_desc0, *dma0_desc1, *dma1_desc0, *dma1_desc1; +static struct jz4755_lcd_dma_desc *dma0_desc0_change, *dma1_desc0_change, *dma0_desc1_change, *dma1_desc1_change; + +#define DMA_DESC_NUM 9 + +static unsigned char *lcd_palette; +static unsigned char *lcd_frame0; +static unsigned char *lcd_frame; + +/* APP */ +static void jz4755fb_set_mode(struct jz4755lcd_osd_t * lcd_osd_info ); +static void jz4755fb_deep_set_mode( struct jz4755lcd_info * lcd_info ); +static void print_lcdc_registers(void); + +static void jz4755lcd_info_switch_to_TVE(int mode); +//static void jz4755lcd_info_switch_to_lcd(void); + +static int jz4755fb0_foreground_resize(struct jz4755lcd_osd_t *lcd_osd_info); +static int jz4755fb0_foreground_move(struct jz4755lcd_osd_t *lcd_osd_info); + +static int jz4755fb1_foreground_resize(struct jz4755lcd_osd_t *lcd_osd_info); +static int jz4755fb1_foreground_move(struct jz4755lcd_osd_t *lcd_osd_info); + +static struct jz4755lcd_info jz4755_lcd_panel = { +#if defined(CONFIG_JZ4755_ANDROID_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_BST_16, /* 16words burst, enable out FIFO underrun irq */ + 480, 272, 60, 41, 10, 8, 4, 4, 2, + }, + .osd = { + .osd_cfg = LCD_OSDC_OSDEN | LCD_OSDC_F0EN| + LCD_OSDC_ALPHAEN,// | /* Use OSD mode */ + .osd_ctrl = 0, /* disable ipu, */ + .rgb_ctrl = 0, + .bgcolor = 0x0000ff, /* set background color Black */ + .colorkey0 = 0, /* disable colorkey */ + .colorkey1 = 0, /* disable colorkey */ + .alpha = 0xff, /* alpha value */ + .ipu_restart = 0x80001000, /* ipu restart */ + .fg_change = FG_CHANGE_ALL, /* change all initially */ + .fg0 = {16, 0, 0, 720, 573}, /* bpp, x, y, w, h */ + .fg1 = {16, 0, 0, 480, 272}, /* bpp, x, y, w, h */ + }, +#elif defined(CONFIG_JZ4755_ANDROID_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_BST_16, /* 16words burst, enable out FIFO underrun irq */ + 800, 480, 45, 1, 1, 40, 215, 10, 34, + }, + .osd = { + .osd_cfg = LCD_OSDC_OSDEN | LCD_OSDC_F0EN| + LCD_OSDC_ALPHAEN,// | /* Use OSD mode */ + .osd_ctrl = 0, /* disable ipu, */ + .rgb_ctrl = 0, + .bgcolor = 0x0000ff, /* set background color Black */ + .colorkey0 = 0, /* disable colorkey */ + .colorkey1 = 0, /* disable colorkey */ + .alpha = 0xff, /* alpha value */ + .ipu_restart = 0x80001000, /* ipu restart */ + .fg_change = FG_CHANGE_ALL, /* change all initially */ + .fg0 = {16, 0, 0, 800, 573}, /* bpp, x, y, w, h */ + .fg1 = {16, 0, 0, 800, 480}, /* bpp, x, y, w, h */ + }, +#endif +}; + +static struct jz4755lcd_info jz4755_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_BST_16,//LCD_CTRL_OFUM | /* 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 |LCD_OSDC_F1EN, /* enable Foreground0,Foreground1 */ + .osd_ctrl = 0x8000, /* enable ipu, */ + .rgb_ctrl = LCD_RGBC_YCC, /* enable RGB => YUV */ + .bgcolor = 0x00000f0f, /* set background color Black */ + .colorkey0 = 0x80000000, /* enable colorkey */ + //.colorkey0 = 0, /* disable colorkey */ + .colorkey1 = 0, /* disable colorkey */ + .alpha = 0xff, /* alpha value */ + .ipu_restart = 0x80000100, /* ipu restart */ + .fg_change = FG_CHANGE_ALL, /* change all initially */ + .fg0 = {16,}, /* */ + .fg1 = {16,}, + }, +}; + +static struct jz_android_din_t jz_panel[JZ_ANDROID_PANELNUM]; +static int jz_panel_num = JZ_ANDROID_PANELNUM; +static int jz_panel_index = 0; + +static struct android_display_info_t adi={0}; + +static struct jz4755lcd_info *jz4755_lcd_info = &jz4755_lcd_panel; /* default output to lcd panel */ + + +/*********************************************TVE***********************************************/ +struct jz4755tve_info jz4755_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<ctrl = (jz4755_tve_info->ctrl | TVE_CTRL_DAPD) & ( ~( TVE_CTRL_DAPD1 | TVE_CTRL_DAPD2)); + jz4755_tve_info->ctrl &= ~TVE_CTRL_SWRST; + REG_TVE_CTRL = jz4755_tve_info->ctrl; +} + +/* turn off TVE, turn off DACn... */ +void jz4755tve_disable_tve(void) +{ + jz4755_tve_info->ctrl &= ~TVE_CTRL_DAPD;/* DACn disabled??? */ + jz4755_tve_info->ctrl |= TVE_CTRL_SWRST;/* DACn disabled??? */ + REG_TVE_CTRL = jz4755_tve_info->ctrl; +} + +void jz4755tve_set_tve_mode(struct jz4755tve_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 jz4755tve_init( int tve_mode ) +{ + switch ( tve_mode ) { + case PANEL_MODE_TVE_PAL: + jz4755_tve_info = &jz4755_tve_info_PAL; + break; + case PANEL_MODE_TVE_NTSC: + jz4755_tve_info = &jz4755_tve_info_NTSC; + break; + } + + jz4755tve_set_tve_mode( jz4755_tve_info ); +} + + +void jz4755tve_outfmt_init(unsigned int outfmt) +{ + switch (outfmt) { +#ifdef CONFIG_SOC_JZ4755D + case PANEL_OUT_FMT_YCBCR: + jz4755_tve_info_PAL.ctrl |= TVE_CTRL_EYCBCR; + break; +#endif + case PANEL_OUT_FMT_CVBS: +#ifdef CONFIG_SOC_JZ4755D + /* Disable YCbCr */ + jz4755_tve_info_PAL.ctrl &= ~TVE_CTRL_EYCBCR; +#endif + jz4755_tve_info_PAL.ctrl |= TVE_CTRL_ECVBS; + break; + case PANEL_OUT_FMT_SVIDEO: + default: +#ifdef CONFIG_SOC_JZ4755D + /* Disable YCbCr */ + jz4755_tve_info_PAL.ctrl &= ~TVE_CTRL_EYCBCR; +#endif + jz4755_tve_info_PAL.ctrl &= ~TVE_CTRL_ECVBS; + break; + } +} + +void jzfb_get_panel_size(unsigned int *w, unsigned *h) +{ + *w = jz4755_lcd_info->panel.w; + *h = jz4755_lcd_info->panel.h; +} + +static inline void lcd_display_on(void) +{ + __lcd_display_on(); /* Turn on panel */ + __lcd_set_ena(); /* Enable LCD Controller */ + schedule_timeout_uninterruptible(HZ/5); /* Wait 200ms */ + __lcd_set_backlight_level(255); /* Turn off backlight */ +} + +static inline void lcd_display_off(void) +{ + __lcd_close_backlight(); + __lcd_clr_ena(); /* Quick Disable */ + __lcd_display_off(); +} + +/********************************************************************************************/ + +/************************************ + * Jz475X Framebuffer ops + ************************************/ +static int jz4755fb1_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct fb_info *fb = info; + if (regno >= NR_PALETTE) + return 1; + if (fb->var.bits_per_pixel <= 16) { + red >>= 8; + green >>= 8; + blue >>= 8; + + red &= 0xff; + green &= 0xff; + blue &= 0xff; + } + + switch (fb->var.bits_per_pixel) { + case 15: + if (regno < 16) + ((u32 *)fb->pseudo_palette)[regno] = + ((red >> 3) << 10) | + ((green >> 3) << 5) | + (blue >> 3); + break; + case 16: + if (regno < 16) { + ((u32 *)fb->pseudo_palette)[regno] = + ((red >> 3) << 11) | + ((green >> 2) << 5) | + (blue >> 3); + } + break; + case 17 ... 32: + if (regno < 16) + ((u32 *)fb->pseudo_palette)[regno] = + (red << 16) | + (green << 8) | + (blue << 0); + break; + } + return 0; +} + +static int jz4755fb1_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + int ret = 0, nret = -1; + void __user *argp = (void __user *)arg; + + switch (cmd) { + case FBIOSETBACKLIGHT: + __lcd_set_backlight_level(arg); /* We support 8 levels here. */ + break; + case FBIODISPON: + REG_LCD_STATE = 0; /* clear lcdc status */ + __lcd_slcd_special_on(); + REG_LCD_DA1 = virt_to_phys(dma1_desc0); + __lcd_clr_dis(); + __lcd_set_ena(); /* enable lcdc */ + __lcd_display_on(); + break; + case FBIODISPOFF: + __lcd_display_off(); + if ( jz4755_lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD || + jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN ) /* */ + __lcd_clr_ena(); /* Smart lcd and TVE mode only support quick disable */ + else + __lcd_set_dis(); /* regular disable */ + break; + case FBIOPRINT_REG: + print_lcdc_registers(); + break; + case FBIO_GET_MODE: + print_dbg("fbio get mode\n"); + if (copy_to_user(argp, jz4755_lcd_info, sizeof(struct jz4755lcd_info))) + return -EFAULT; + break; + case FBIO_SET_MODE: + print_dbg("fbio set mode\n"); + if (copy_from_user(jz4755_lcd_info, argp, sizeof(struct jz4755lcd_info))) + return -EFAULT; + /* set mode */ + jz4755fb_set_mode(&jz4755_lcd_info->osd); + break; + case FBIO_DEEP_SET_MODE: + print_dbg("fbio deep set mode\n"); + if (copy_from_user(jz4755_lcd_info, argp, sizeof(struct jz4755lcd_info))) + return -EFAULT; + jz4755fb_deep_set_mode(jz4755_lcd_info); + break; + + case FBIO_GET_TVE_MODE: + print_dbg("fbio get TVE mode\n"); + if (copy_to_user(argp, jz4755_tve_info, sizeof(struct jz4755tve_info))) + return -EFAULT; + break; + case FBIO_SET_TVE_MODE: + print_dbg("fbio set TVE mode\n"); + if (copy_from_user(jz4755_tve_info, argp, sizeof(struct jz4755tve_info))) + return -EFAULT; + /* set tve mode */ + jz4755tve_set_tve_mode(jz4755_tve_info); + break; + case FBIODISON_FG: //pass + /*lcdc_enable_fg1();*/ + print_dbg("lcdc_disable_fg1()\n"); + jz4755_lcd_info->osd.osd_cfg |= LCD_OSDC_F1EN; + __lcd_enable_f1(); + break; + case FBIODISOFF_FG://pass + /*lcdc_disable_fg1();*/ + jz4755_lcd_info->osd.osd_cfg &= ~LCD_OSDC_F1EN; + __lcd_disable_f1(); + break; + case FBIO_SET_BG_COLOR://pass + jz4755_lcd_info->osd.bgcolor = arg; + /*lcdc_set_bgcolor(arg);*/ + REG_LCD_BGC = jz4755_lcd_info->osd.bgcolor; + break; + case FBIO_SET_IPU_RESTART_VAL: + /*lcdc_set_ipu_restart_val(arg);*/ + jz4755_lcd_info->osd.ipu_restart &= ~LCD_IPUR_IPURMASK; + jz4755_lcd_info->osd.ipu_restart |= (arg & LCD_IPUR_IPURMASK); + __lcd_set_ipu_restart_triger(arg); + break; + case FBIO_SET_IPU_RESTART_ON: + /*lcdc_enable_ipu_restart();*/ + __lcd_enable_ipu_restart(); + break; + case FBIO_SET_IPU_RESTART_OFF: + /*lcdc_disable_ipu_restart();*/ + __lcd_disable_ipu_restart(); + break; + case FBIO_ANDROID_CTL: + print_dbg("ANDROID supply!\n"); + if (copy_from_user(&adi, argp, sizeof(struct android_display_info_t))) + return -EFAULT; + switch (adi.flag) { + case ANDROID_SET_FG0_ALPHA: //pass + /*lcdc_set_alpha(arg);*/ + if (adi.fg0_alpha > 0xFF){ + /*lcdc_disable_alpha();*/ + printk("alpha value is to large,so shut down the alpha"); + jz4755_lcd_info->osd.osd_cfg &= ~LCD_OSDC_ALPHAEN; + __lcd_disable_alpha(); + } + else{ + /*lcdc_enable_alpha();*/ + jz4755_lcd_info->osd.osd_cfg |= LCD_OSDC_ALPHAEN; + jz4755_lcd_info->osd.alpha = adi.fg0_alpha; + REG_LCD_ALPHA = adi.fg0_alpha; + __lcd_enable_alpha(); + } + break; + case ANDROID_SET_FG0_COLORKEY: + if (adi.fg0_colorkey > 0xFFFFFF){ + /*lcdc_disable_colorkey0;*/ + jz4755_lcd_info->osd.colorkey0 = 0; + __lcd_disable_colorkey0(); + } + else{ + if ( jz4755_lcd_info->osd.fg0.bpp == 16 ) { // 16bpp + adi.fg0_colorkey &= 0x00f8fcf8; + jz4755_lcd_info->osd.colorkey0 = adi.fg0_colorkey; + } + else if ( jz4755_lcd_info->osd.fg0.bpp == 15 ) { // 15bpp + adi.fg0_colorkey &= 0x00f8f8f8; + jz4755_lcd_info->osd.colorkey0 = adi.fg0_colorkey; + } + else { // > 16bpp + jz4755_lcd_info->osd.colorkey0 = adi.fg0_colorkey; + } + __lcd_set_colorkey0(jz4755_lcd_info->osd.colorkey0); + __lcd_enable_colorkey0(); + } + break; + case ANDROID_SET_FG0_ENABLE://pass + printk("------ANDROID_SET_FG0_ENABLE--------\n"); + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN) + __lcd_set_dis();//normal disable + if( adi.fg0_enable ){ + print_dbg("lcdc_enable_fg0()\n"); + jz4755_lcd_info->osd.osd_cfg |= LCD_OSDC_F0EN; + __lcd_enable_f0(); + } + else{ + print_dbg("lcdc_disable_fg0()\n"); + jz4755_lcd_info->osd.osd_cfg &= ~LCD_OSDC_F0EN; + __lcd_disable_f0(); + } + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN){ + while(REG_LCD_STATE & LCD_STATE_LDD); + __lcd_clr_dis();//normal enable + } + break; + + case ANDROID_SET_FG1_POS://pass + printk("fg1 pos set\n"); + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN){ + break; +#if 0 + __lcd_clr_ena(); + jz4755_lcd_info->osd.fg1.x = adi.fg1_x+8; + jz4755_lcd_info->osd.fg1.y = adi.fg1_y+10; + jz4755fb1_foreground_move(&jz4755_lcd_info->osd); + __lcd_set_ena(); +#endif + }else{ + jz4755_lcd_info->osd.fg1.x = adi.fg1_x; + jz4755_lcd_info->osd.fg1.y = adi.fg1_y; + jz4755fb1_foreground_move(&jz4755_lcd_info->osd); + } + //jz4755fb1_foreground_move(&jz4755_lcd_info->osd); + break; + case ANDROID_SET_FG1_SIZE: + if ( REG_LCD_OSDCTRL & LCD_OSDCTRL_IPU){ + printk(" ANDROID_SET_FG1_SIZE:fg1_ipu\n"); + if(!(REG_LCD_OSDC & LCD_OSDC_F1EN)) + return -EFAULT; + __lcd_clr_ena(); + jz4755_lcd_info->osd.fg1.w = adi.fg1_w; + jz4755_lcd_info->osd.fg1.h = adi.fg1_h; + jz4755fb1_foreground_resize(&jz4755_lcd_info->osd); + __lcd_set_ena(); + } + else{ + printk(" ANDROID_SET_FG1_SIZE:fg1_dma1\n"); + if(!(REG_LCD_OSDC & LCD_OSDC_F1EN)) + return -EFAULT; + jz4755_lcd_info->osd.fg1.w = adi.fg1_w; + jz4755_lcd_info->osd.fg1.h = adi.fg1_h; + jz4755fb1_foreground_resize(&jz4755_lcd_info->osd); + } + break; + case ANDROID_SET_FG1_ENABLE://pass +#if 1 + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN){ + REG_LCD_STATE = 0; + break; + //__lcd_clr_ena(); + //__lcd_set_dis();//normal disable + // while(REG_LCD_STATE & LCD_STATE_QD); + //printk("rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr1111111111111\n"); + } +#endif + + if( adi.fg1_enable ){ + print_dbg("lcdc_enable_fg1()\n"); + jz4755_lcd_info->osd.osd_cfg |= LCD_OSDC_F1EN; + __lcd_enable_f1(); + } + else{ + print_dbg("lcdc_disable_fg1()\n"); + jz4755_lcd_info->osd.osd_cfg &= ~LCD_OSDC_F1EN; + __lcd_disable_f1(); + } +#if 0 + if(jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN){ + //__lcd_clr_dis();//normal enable + __lcd_set_ena(); + printk("rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr222222222\n"); + } +#endif + break; + case ANDROID_SET_FG1_IPU_DIRECT: + print_dbg("fg1 use ipu or dma1\n"); + //__lcd_set_dis(); + //while(REG_LCD_STATE & LCD_STATE_LDD); + //__lcd_clr_dis(); + __lcd_clr_ena(); + if( adi.fg1_short_cut){ + printk("rrrrrrrrrrrrrrrrfg1 use ipu\n"); + jz4755_lcd_info->osd.osd_ctrl |= LCD_OSDCTRL_IPU; + REG_LCD_OSDCTRL = jz4755_lcd_info->osd.osd_ctrl; + __lcd_enable_ipu_restart(); + } + else{ printk("rrrrrrrrrrrrrrrrfg1 use dma1\n"); + jz4755_lcd_info->osd.osd_ctrl &= ~LCD_OSDCTRL_IPU; + REG_LCD_OSDCTRL = jz4755_lcd_info->osd.osd_ctrl; + __lcd_disable_ipu_restart(); + + } + REG_LCD_STATE = 0; + __lcd_set_ena(); + //__lcd_clr_dis(); + break; + case ANDROID_GET_PANEL_SIZE: + adi.fg1_w = jz_panel[jz_panel_index].w; + adi.fg1_h = jz_panel[jz_panel_index].h; + if (copy_to_user(argp, &adi, sizeof(struct android_display_info_t))) + return -EFAULT; + break; + default: + printk("FG1:%s, unknown android command(0x%x)", __FILE__, adi.flag); + return nret; + } + break; + default: + printk("%s, unknown command(0x%x)", __FILE__, cmd); + return nret; + } + + return ret; +} + +/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */ +static int jz4755fb1_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + + struct fb_info *fb = 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 = fb->fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + 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 */ + + 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 */ + + 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; +} + /*end of Foreground 1 ops*/ + +static int jz4755fb0_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; + + if (regno >= NR_PALETTE) + return 1; + + cfb->palette[regno].red = red ; + cfb->palette[regno].green = green; + cfb->palette[regno].blue = blue; + if (cfb->fb0.var.bits_per_pixel <= 16) { + red >>= 8; + green >>= 8; + blue >>= 8; + + red &= 0xff; + green &= 0xff; + blue &= 0xff; + } + switch (cfb->fb0.var.bits_per_pixel) { + case 1: + case 2: + case 4: + case 8: + if (((jz4755_lcd_info->panel.cfg & LCD_CFG_MODE_MASK) == LCD_CFG_MODE_SINGLE_MSTN ) || + ((jz4755_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->fb0.pseudo_palette)[regno] = + ((red >> 3) << 10) | + ((green >> 3) << 5) | + (blue >> 3); + break; + case 16: + if (regno < 16) { + ((u32 *)cfb->fb0.pseudo_palette)[regno] = + ((red >> 3) << 11) | + ((green >> 2) << 5) | + (blue >> 3); + } + break; + case 17 ... 32: + if (regno < 16) + ((u32 *)cfb->fb0.pseudo_palette)[regno] = + (red << 16) | + (green << 8) | + (blue << 0); + + break; + } + return 0; +} + + +static int jz4755fb0_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + int ret = 0, nret = -1; + void __user *argp = (void __user *)arg; + struct jz4755lcd_fg_t fg0; + + switch (cmd) { + case FBIOSETBACKLIGHT: + __lcd_set_backlight_level(arg); /* We support 8 levels here. */ + break; + case FBIODISPON: + REG_LCD_STATE = 0; /* clear lcdc status */ + __lcd_slcd_special_on(); + __lcd_clr_dis(); + __lcd_set_ena(); /* enable lcdc */ + __lcd_display_on(); + break; + case FBIODISPOFF: + __lcd_display_off(); + if ( jz4755_lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD || + jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN ) /* */ + __lcd_clr_ena(); /* Smart lcd and TVE mode only support quick disable */ + else + __lcd_set_dis(); /* regular disable */ + break; + case FBIOPRINT_REG: + print_lcdc_registers(); + break; + case FBIO_GET_MODE: + print_dbg("fbio get mode\n"); + if (copy_to_user(argp, jz4755_lcd_info, sizeof(struct jz4755lcd_info))) + return -EFAULT; + break; + case FBIO_SET_MODE: + print_dbg("fbio set mode\n"); + if (copy_from_user(jz4755_lcd_info, argp, sizeof(struct jz4755lcd_info))) + return -EFAULT; + /* set mode */ + jz4755fb_set_mode(&jz4755_lcd_info->osd); + break; + case FBIO_DEEP_SET_MODE: + print_dbg("fbio deep set mode\n"); + if (copy_from_user(jz4755_lcd_info, argp, sizeof(struct jz4755lcd_info))) + return -EFAULT; + jz4755fb_deep_set_mode(jz4755_lcd_info); + break; + + case FBIO_GET_TVE_MODE: + print_dbg("fbio get TVE mode\n"); + if (copy_to_user(argp, jz4755_tve_info, sizeof(struct jz4755tve_info))) + return -EFAULT; + break; + case FBIO_SET_TVE_MODE: + print_dbg("fbio set TVE mode\n"); + if (copy_from_user(jz4755_tve_info, argp, sizeof(struct jz4755tve_info))) + return -EFAULT; + /* set tve mode */ + jz4755tve_set_tve_mode(jz4755_tve_info); + break; + + case FBIODISON_FG: //pass + /*lcdc_enable_fg0();*/ + jz4755_lcd_info->osd.osd_cfg |= LCD_OSDC_F0EN; + __lcd_enable_f0(); + break; + case FBIODISOFF_FG://pass + /*lcdc_disable_fg0();*/ + print_dbg("lcdc_disable_fg0()\n"); + jz4755_lcd_info->osd.osd_cfg &= ~LCD_OSDC_F0EN; + __lcd_disable_f0(); + break; + case FBIO_CHANGE_SIZE: + /*fg0_change_size();*/ + if(!(REG_LCD_OSDC & LCD_OSDC_F0EN)) + return -EFAULT; + if (copy_from_user(&fg0, argp, sizeof(struct jz4755lcd_fg_t))) + return -EFAULT; + jz4755_lcd_info->osd.fg0.w = fg0.w; + jz4755_lcd_info->osd.fg0.h = fg0.h; + jz4755fb0_foreground_resize(&jz4755_lcd_info->osd); + break; + case FBIO_CHANGE_POSITION: + if (copy_from_user(&fg0, argp, sizeof(struct jz4755lcd_fg_t))) + return -EFAULT; + jz4755_lcd_info->osd.fg0.x = fg0.x; + jz4755_lcd_info->osd.fg0.y = fg0.y; + jz4755fb0_foreground_move(&jz4755_lcd_info->osd); + break; + case FBIO_SET_BG_COLOR://pass + jz4755_lcd_info->osd.bgcolor = arg; + /*lcdc_set_bgcolor(arg);*/ + REG_LCD_BGC = jz4755_lcd_info->osd.bgcolor; + break; + case FBIO_ALPHA_ON://pass + /*lcdc_enable_alpha();*/ + jz4755_lcd_info->osd.osd_cfg |= LCD_OSDC_ALPHAEN; + __lcd_enable_alpha(); + break; + case FBIO_ALPHA_OFF://pass + /*lcdc_disable_alpha();*/ + jz4755_lcd_info->osd.osd_cfg &= ~LCD_OSDC_ALPHAEN; + __lcd_disable_alpha(); + break; + case FBIO_SET_ALPHA_VAL://pass + jz4755_lcd_info->osd.alpha = arg; + /*lcdc_set_alpha(arg);*/ + REG_LCD_ALPHA = jz4755_lcd_info->osd.alpha; + break; + case FBIO_ANDROID_CTL: + if (copy_from_user(&adi, argp, sizeof(struct android_display_info_t))) + return -EFAULT; + + switch (adi.flag) { + case ANDROID_GET_DISPLAY_NUM://pass + adi.fg0_number = jz_panel_num; + if (copy_to_user(argp, &adi, sizeof(struct android_display_info_t))) + return -EFAULT; + break; + case ANDROID_GET_DISPLAY_INFO://pass + adi.fg0_w = jz_panel[adi.fg0_index].w; + adi.fg0_h = jz_panel[adi.fg0_index].h; + if (copy_to_user(argp, &adi, sizeof(struct android_display_info_t))) + return -EFAULT; + break; + case ANDROID_SET_DISPLAY_INDEX: //pass + printk("fg0_index=%d\n",adi.fg0_index); + switch (adi.fg0_index) { + case PANEL_MODE_TVE_PAL: /* switch to TVE_PAL mode */ + + __lcd_clr_ena(); +#if 0 + if ( REG_LCD_OSDCTRL & LCD_OSDCTRL_IPU){ + jz4755_lcd_info->osd.osd_ctrl &= ~LCD_OSDCTRL_IPU; + REG_LCD_OSDCTRL = jz4755_lcd_info->osd.osd_ctrl; + __lcd_disable_ipu_restart(); + } +#endif + jz4755lcd_info_switch_to_TVE(adi.fg0_index); +#if 0 + jz4755_lcd_info->osd.osd_ctrl |= LCD_OSDCTRL_IPU; + REG_LCD_OSDCTRL = jz4755_lcd_info->osd.osd_ctrl; + __lcd_enable_ipu_restart(); +#endif + jz4755tve_init(adi.fg0_index); /* tve controller init */ + //ipu_open(); + + jz4755tve_enable_tve(); + /* turn off lcd backlight */ + __lcd_display_off(); + break; + case PANEL_MODE_LCD_PANEL: /* switch to LCD mode */ + /* turn off TVE, turn off DACn... */ + jz4755tve_disable_tve(); + __lcd_clr_ena(); + jz4755_lcd_info = &jz4755_lcd_panel; + /* turn on lcd backlight */ + __lcd_display_on(); + break; + default : + printk("FG0:%s, android has no this style panel(0x%x)", __FILE__, adi.fg0_index); + return nret; + } + jz_panel_index = adi.fg0_index; + jz4755fb_deep_set_mode(jz4755_lcd_info); + //print_lcdc_registers(); + break; + + default: + printk("FG0:%s, unknown android command(0x%x)", __FILE__, adi.flag); + return nret; + } + break; + default: + printk("FG0:%s, unknown command(0x%x)", __FILE__, cmd); + return nret; + } + + return ret; +} + + +static int jz4755fb0_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->fb0.fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb0.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 */ + + 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 */ + + 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; +} + /* end of Foreground 0 ops*/ + + +/* checks var and eventually tweaks it to something supported, + * DO NOT MODIFY PAR */ +static int jz4755fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ +// dprintk("jz4755fb_set_par, not implemented\n"); + return 0; +} + + +/* + * set the video mode according to info->var + */ +static int jz4755fb_set_par(struct fb_info *info) +{ +// dprintk("jz4755fb_set_par, not implemented\n"); + return 0; +} + + +/* + * (Un)Blank the display. + * Fix me: should we use VESA value? + */ +static int jz4755fb_blank(int blank_mode, struct fb_info *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: + /* Turn off panel */ +#if 0 + __lcd_display_off(); + __lcd_set_dis(); +#endif + break; + default: + break; + + } + return 0; +} + +/* + * pan display + */ +static int jz4755fb1_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct fb_info *fb = info; + struct jz4755lcd_info *lcd_info = jz4755_lcd_info; + int dy; + int fg1_line_size; + + if (!var || !fb) { + return -EINVAL; + } + + if (var->xoffset - fb->var.xoffset) { + /* No support for X panning for now! */ + return -EINVAL; + } + + printk("pan frame rect %d %d %d %d\n", + var->reserved[1] & 0xffff, + var->reserved[1] >> 16, var->reserved[2] & 0xffff, + var->reserved[2] >> 16); + + /* TODO: Wait for current frame to finished */ + + dy = var->yoffset;// - fb->var.yoffset; + + fg1_line_size = lcd_info->osd.fg1.w * lcd_info->osd.fg1.bpp/8 ; + fg1_line_size = ((fg1_line_size+3)>>2)<<2; + dma1_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame); + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ + dma1_desc1->databuf = (unsigned int)virt_to_phys((void *)(lcd_frame + fg1_line_size)); + dma_cache_wback((unsigned int)(dma1_desc0), sizeof(struct jz4755_lcd_dma_desc)); + + return 0; +} + +static int jz4755fb0_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + unsigned long irq_flags; + struct fb_info *fb = info; + struct jz4755lcd_info *lcd_info = jz4755_lcd_info; + struct lcd_cfb_info *cfb = jz4755fb_info; + int fg0_line_size; + int dy; + + if (!(REG_LCD_OSDC & LCD_OSDC_F0EN)) + return 0; + + if (!var || !fb) { + return -EINVAL; + } + if (var->xoffset - fb->var.xoffset) { + /* No support for X panning for now! */ + return -EINVAL; + } + + dy = var->yoffset;// - fb->var.yoffset; + fb->fix.line_length = ( jz4755_lcd_panel.osd.fg0.w * (lcd_info->osd.fg0.bpp) / 8); + fg0_line_size = ( jz4755_lcd_panel.osd.fg0.w * (lcd_info->osd.fg0.bpp) / 8); + fg0_line_size = ((fg0_line_size + 3) >> 2) << 2; + + if (dy) { + dma0_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame0 + (fb->fix.line_length * dy)); + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ + dma0_desc1->databuf = (unsigned int)virt_to_phys((void *)(lcd_frame0 + fg0_line_size) + (fb->fix.line_length * dy)); + dma_cache_wback((unsigned int)(dma0_desc0), sizeof(struct jz4755_lcd_dma_desc)); + } + else { + dma0_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame0); + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ + dma0_desc1->databuf = (unsigned int)virt_to_phys((void *)(lcd_frame0 + fg0_line_size )); + dma_cache_wback((unsigned int)(dma0_desc0), sizeof(struct jz4755_lcd_dma_desc)); + } + + /* Wait for current frame to finished */ + spin_lock_irqsave(cfb->update_lock, irq_flags); + + REG_LCD_STATE &= ~LCD_STATE_EOF; // Clear previous EOF flag + __lcd_enable_eof_intr(); + + cfb->frame_requested++; + + spin_unlock_irqrestore(cfb->update_lock, irq_flags); + + if (cfb->frame_requested != cfb->frame_done) + wait_event_interruptible_timeout( + cfb->frame_wq, cfb->frame_done == cfb->frame_requested, HZ/50); + + __lcd_disable_eof_intr(); + + return 0; +} + +/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ +static struct fb_ops jz4755fb1_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = jz4755fb1_setcolreg, + .fb_check_var = jz4755fb_check_var, + .fb_set_par = jz4755fb_set_par, + .fb_blank = jz4755fb_blank, + .fb_pan_display = jz4755fb1_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = jz4755fb1_mmap, + .fb_ioctl = jz4755fb1_ioctl, +}; + +/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ +static struct fb_ops jz4755fb0_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = jz4755fb0_setcolreg, + .fb_check_var = jz4755fb_check_var, + .fb_set_par = jz4755fb_set_par, + .fb_blank = jz4755fb_blank, + .fb_pan_display = jz4755fb0_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = jz4755fb0_mmap, + .fb_ioctl = jz4755fb0_ioctl, +}; + +/***************************************************************/ +extern void show_tlb(void); + +static void jz_lcd_add_wired_entry(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; + + /* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */ + entrylo0 = entrylo0 >> 6; + entrylo0 |= 0x7 | (2 << 3); + entrylo1 = entrylo1 >> 6; + entrylo1 |= 0x7 | (2 << 3); + + 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; + 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 LCD_DEBUG + printk("\nold_ctx=%03ld\n", old_ctx); + show_tlb(); +#endif +} + +static void jz_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 int jz4755fb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + struct fb_info *fb = info; + struct jz4755lcd_info *lcd_info = jz4755_lcd_info; + int chgvar = 0; + + if (con == 0) { + var->height = lcd_info->osd.fg0.h; + var->width = lcd_info->osd.fg0.w; + var->bits_per_pixel = lcd_info->osd.fg0.bpp; + } + else { + var->height = lcd_info->osd.fg1.h; + var->width = lcd_info->osd.fg1.w; + var->bits_per_pixel = lcd_info->osd.fg1.bpp; + } + + var->vmode = FB_VMODE_NONINTERLACED; +// var->vmode = FB_VMODE_DOUBLE + var->activate = fb->var.activate; + var->xres = var->width; + var->yres = var->height; + var->xres_virtual = var->width; + var->yres_virtual = var->height * ANDROID_NUMBER_OF_BUFFERS; + var->xoffset = 0; + var->yoffset = 0; + var->pixclock = KHZ2PICOS(jz_clocks.pixclk/1000); + + var->left_margin = lcd_info->panel.elw; + var->right_margin = lcd_info->panel.blw; + var->upper_margin = lcd_info->panel.efw; + var->lower_margin = lcd_info->panel.bfw; + var->hsync_len = lcd_info->panel.hsw; + var->vsync_len = lcd_info->panel.vsw; + var->sync = 0; + var->activate = FB_ACTIVATE_NOW; + + /* + * 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 = fb->var.xoffset; + var->yoffset = fb->var.yoffset; + } + + if (var->activate & FB_ACTIVATE_TEST) + return 0; + + if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) + return -EINVAL; + + if (fb->var.xres != var->xres) + chgvar = 1; + if (fb->var.yres != var->yres) + chgvar = 1; + if (fb->var.xres_virtual != var->xres_virtual) + chgvar = 1; + if (fb->var.yres_virtual != var->yres_virtual) + chgvar = 1; + if (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 */ + fb->fix.visual = FB_VISUAL_MONO01; + 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; + + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_DIRECTCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_TRUECOLOR; + 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; + + fb->fix.visual = FB_VISUAL_TRUECOLOR; + 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", + fb->fix.id, var->bits_per_pixel); + break; + } + + fb->var = *var; + 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(&fb->cmap, fb); + return 0; +} + +static struct lcd_cfb_info * jz4755fb_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; + + jz4755fb_info = cfb; + + memset(cfb, 0, sizeof(struct lcd_cfb_info) ); + + cfb->currcon = -1; + + /* Foreground 1 -- fb1 */ + strcpy(cfb->fb1.fix.id, "jzlcd-fg1"); + cfb->fb1.flags = FBINFO_FLAG_DEFAULT; + cfb->fb1.fix.type = FB_TYPE_PACKED_PIXELS; + cfb->fb1.fix.type_aux = 0; + cfb->fb1.fix.xpanstep = 1; + cfb->fb1.fix.ypanstep = 1; + cfb->fb1.fix.ywrapstep = 0; + cfb->fb1.fix.accel = FB_ACCEL_NONE; + + cfb->fb1.var.nonstd = 0; + cfb->fb1.var.activate = FB_ACTIVATE_NOW; + cfb->fb1.var.height = -1; + cfb->fb1.var.width = -1; + cfb->fb1.var.accel_flags = FB_ACCELF_TEXT; + + cfb->fb1.fbops = &jz4755fb1_ops; + cfb->fb1.flags = FBINFO_FLAG_DEFAULT; + + cfb->fb1.pseudo_palette = (void *)(cfb + 1); + + switch (jz4755_lcd_info->osd.fg1.bpp) { + case 1: + fb_alloc_cmap(&cfb->fb1.cmap, 4, 0); + break; + case 2: + fb_alloc_cmap(&cfb->fb1.cmap, 8, 0); + break; + case 4: + fb_alloc_cmap(&cfb->fb1.cmap, 32, 0); + break; + case 8: + + default: + fb_alloc_cmap(&cfb->fb1.cmap, 256, 0); + break; + } + + /* Foreground 0 -- fb0 */ + strcpy(cfb->fb0.fix.id, "jzlcd-fg0"); + cfb->fb0.fix.type = FB_TYPE_PACKED_PIXELS; + cfb->fb0.fix.type_aux = 0; + cfb->fb0.fix.xpanstep = 1; + cfb->fb0.fix.ypanstep = 1; + cfb->fb0.fix.ywrapstep = 0; + cfb->fb0.fix.accel = FB_ACCEL_NONE; + + cfb->fb0.var.nonstd = 0; + cfb->fb0.var.activate = FB_ACTIVATE_NOW; + cfb->fb0.var.height = -1; + cfb->fb0.var.width = -1; + cfb->fb0.var.accel_flags = FB_ACCELF_TEXT; + + cfb->fb0.fbops = &jz4755fb0_ops; + cfb->fb0.flags = FBINFO_FLAG_DEFAULT; + + cfb->fb0.pseudo_palette = (void *)(cfb + 1); + + switch (jz4755_lcd_info->osd.fg0.bpp) { + case 1: + fb_alloc_cmap(&cfb->fb0.cmap, 4, 0); + break; + case 2: + fb_alloc_cmap(&cfb->fb0.cmap, 8, 0); + break; + case 4: + fb_alloc_cmap(&cfb->fb0.cmap, 32, 0); + break; + case 8: + + default: + fb_alloc_cmap(&cfb->fb0.cmap, 256, 0); + break; + } + dprintk("fb_alloc_cmap, fb.cmap.len:%d, fb0.cmap.len:%d....\n", cfb->fb1.cmap.len, cfb->fb0.cmap.len); + return cfb; +} + +/* + * Map screen memory + */ +static int jz4755fb_map_smem(struct lcd_cfb_info *cfb) +{ + unsigned long page; + unsigned int page_shift, needroom = 0, needroom1=0, bpp, w, h; + unsigned char *fb_palette, *fb_frame; + unsigned long pagemask = 0x3ff << 13; /*4M */ + /* caculate the mem size of Foreground 0 */ + bpp = jz4755_lcd_info->osd.fg0.bpp; + if (bpp == 18 || bpp == 24) + bpp = 32; + if (bpp == 15) + bpp = 16; + + w = (jz4755_lcd_info->osd.fg0.w > TVE_WIDTH_PAL) ? jz4755_lcd_info->osd.fg0.w : TVE_WIDTH_PAL; + h = (jz4755_lcd_info->osd.fg0.h > TVE_HEIGHT_PAL) ? jz4755_lcd_info->osd.fg0.h : TVE_HEIGHT_PAL; + + needroom1 = needroom = ((w * bpp + 7) >> 3) * h * ANDROID_NUMBER_OF_BUFFERS; + /* end of alloc Foreground 0 mem */ + + /* Caculate the mem size of Foreground 1 */ + bpp = jz4755_lcd_info->osd.fg1.bpp; + if (bpp == 18 || bpp == 24) + bpp = 32; + if (bpp == 15) + bpp = 16; + + /* The buffer size of FG1 should be large enough, so alloc memory depend of the fg0 args */ + w = (jz4755_lcd_info->osd.fg0.w > TVE_WIDTH_PAL) ? jz4755_lcd_info->osd.fg0.w : TVE_WIDTH_PAL; + h = (jz4755_lcd_info->osd.fg0.h > TVE_HEIGHT_PAL) ? jz4755_lcd_info->osd.fg0.h : TVE_HEIGHT_PAL; + needroom += ((w * bpp + 7) >> 3) * h; + /* end of alloc Foreground 1 mem */ + + /* Alloc memory */ + for (page_shift = 0; page_shift < 12; page_shift++) + if ((PAGE_SIZE << page_shift) >= needroom) + break; + fb_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); + fb_frame = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); + if ((!fb_palette) || (!fb_frame)) + return -ENOMEM; + memset((void *)fb_palette, 0, PAGE_SIZE); + memset((void *)fb_frame, 0, PAGE_SIZE << page_shift); + + lcd_palette = fb_palette; + dma_desc_base = (struct jz4755_lcd_dma_desc *)((void*)lcd_palette + ((PALETTE_SIZE+3)/4)*4); + + /* + * 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)fb_frame; + page < PAGE_ALIGN((unsigned long)fb_frame + (PAGE_SIZE<fb1.fix.smem_start = virt_to_phys((void *)lcd_frame); + cfb->fb1.fix.smem_len = needroom - needroom1; /* page_shift/2 ??? */ + cfb->fb1.screen_base = + (unsigned char *)(((unsigned int)lcd_frame&0x1fffffff) | 0xa0000000); + if (!cfb->fb1.screen_base) { + printk("jz4755fb, %s: unable to map screen memory\n", cfb->fb1.fix.id); + return -ENOMEM; + } + + lcd_frame0 = fb_frame; + cfb->fb0.fix.smem_start = virt_to_phys((void *)lcd_frame0); + cfb->fb0.fix.smem_len = needroom1; /* page_shift/2 ??? */ + cfb->fb0.screen_base = + (unsigned char *)(((unsigned int)lcd_frame0&0x1fffffff) | 0xa0000000); + if (!cfb->fb0.screen_base) { + printk("jz4755fb0, %s: unable to map screen memory\n", cfb->fb0.fix.id); + return -ENOMEM; + } + jz_lcd_add_wired_entry((unsigned long)cfb->fb0.fix.smem_start, 0, 0x50000000, pagemask); + + return 0; +} + +static void jz4755fb_free_fb_info(struct lcd_cfb_info *cfb) +{ + if (cfb) { + fb_alloc_cmap(&cfb->fb1.cmap, 0, 0); + kfree(cfb); + } +} + +static void jz4755fb_unmap_smem(struct lcd_cfb_info *cfb) +{ + struct page * map = NULL; + unsigned char *tmp; + unsigned int page_shift, needroom, bpp, w, h; + bpp = jz4755_lcd_info->osd.fg0.bpp; + if ( bpp == 18 || bpp == 24) + bpp = 32; + if ( bpp == 15 ) + bpp = 16; + w = jz4755_lcd_info->osd.fg0.w; + h = jz4755_lcd_info->osd.fg0.h; + needroom = ((w * bpp + 7) >> 3) * h; + + bpp = jz4755_lcd_info->osd.fg1.bpp; + if ( bpp == 18 || bpp == 24) + bpp = 32; + if ( bpp == 15 ) + bpp = 16; + w = jz4755_lcd_info->osd.fg1.w; + h = jz4755_lcd_info->osd.fg1.h; + needroom += ((w * bpp + 7) >> 3) * h; + + for (page_shift = 0; page_shift < 12; page_shift++) + if ((PAGE_SIZE << page_shift) >= needroom) + break; + + if (cfb && cfb->fb1.screen_base) { + iounmap(cfb->fb1.screen_base); + cfb->fb1.screen_base = NULL; + release_mem_region(cfb->fb1.fix.smem_start, + cfb->fb1.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); + } +} + +/************************************ + * Jz475X Chipset OPS + ************************************/ + +/* + * 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 print_lcdc_registers(void) /* debug */ +{ +#ifdef LCD_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_KEY0:\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++); + } + } + } +#endif +} + +static void jz4755lcd_info_switch_to_TVE(int mode) +{ + struct jz4755lcd_info *info; + struct jz4755lcd_osd_t *osd_lcd; + int x, y, w, h; + + info = jz4755_lcd_info = &jz4755_info_tve; + osd_lcd = &jz4755_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 = TVE_WIDTH_PAL - 16; + h = TVE_HEIGHT_PAL - 20; + x = (TVE_WIDTH_PAL - w) / 2; + y = (TVE_HEIGHT_PAL - h ) / 2; + + 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 = TVE_WIDTH_PAL - 16; + h = TVE_HEIGHT_PAL - 20; + x = (TVE_WIDTH_PAL-w) / 2; + y = (TVE_HEIGHT_PAL-h)/ 2; + + info->osd.fg1.bpp = 16; /* 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 = TVE_WIDTH_NTSC - 16; + h = TVE_HEIGHT_NTSC - 12; + x = (TVE_WIDTH_NTSC - w) / 2; + y = (TVE_HEIGHT_NTSC - h) / 2; + 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 = TVE_WIDTH_NTSC - 16; + h = TVE_HEIGHT_NTSC - 12; + x = (TVE_WIDTH_NTSC - w) / 2; + y = (TVE_HEIGHT_NTSC - h) / 2; + 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__); + break; + } + info->osd.osd_ctrl |= (1<<15); //open ipu for tve +} + +/* initial dma descriptors */ +static void jz4755fb_descriptor_init( struct jz4755lcd_info * lcd_info ) +{ + unsigned int pal_size; + int fg0_line_size, fg0_frm_size, fg1_line_size, fg1_frm_size; + int buffer_line_size, buffer_frm_size; + int panel_line_size, panel_frm_size; + int size0, size1; + + + 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; + + /* + * 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 --> ... + * DMA Chan1: + * TO LCD Panel: + * dma1_desc0 <<==>> dma1_desc0 + * TO TV Encoder: + * dma1_desc0 <<==>> dma1_desc1 + */ + + dma0_desc_palette = dma_desc_base + 0; + dma0_desc0 = dma_desc_base + 1; + dma0_desc1 = dma_desc_base + 2; + dma0_desc0_change = dma_desc_base + 3; + dma0_desc1_change = dma_desc_base + 4; + + /* Foreground 0, caculate size */ + if ( lcd_info->osd.fg0.x >= lcd_info->panel.w ) + lcd_info->osd.fg0.x = lcd_info->panel.w - 1; + if ( lcd_info->osd.fg0.y >= lcd_info->panel.h ) + lcd_info->osd.fg0.y = lcd_info->panel.h - 1; + + if (lcd_info->panel.cfg & LCD_CFG_TVEN ) { + // if ( lcd_info->osd.fg0.x + lcd_info->osd.fg0.w > lcd_info->panel.w ) + lcd_info->osd.fg0.w = lcd_info->panel.w - 2 * 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 - 2 * lcd_info->osd.fg0.y; + } + size0 = lcd_info->osd.fg0.h << 16 | lcd_info->osd.fg0.w; + + /* lcd display area */ + panel_line_size = (lcd_info->panel.w - 2 * lcd_info->osd.fg0.x) * lcd_info->osd.fg0.bpp / 8; +// panel_line_size = ((panel_line_size + 3) >> 2) << 2; /* word aligned */ + panel_frm_size= panel_line_size * (lcd_info->panel.h - 2 * lcd_info->osd.fg0.y);//lcd_info->panel.h;// + + /* total fg0 buffer area */ + 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; + + /*total buffer size*/ + buffer_line_size = jz4755_lcd_panel.osd.fg0.w * lcd_info->osd.fg0.bpp / 8; +// buffer_line_size = ((buffer_line_size + 3) >> 2) << 2; /* word aligned */ + buffer_frm_size= buffer_line_size * jz4755_lcd_panel.panel.h; + + /* Palette Descriptor */ + 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 */ + /* DMA0 Descriptor */ + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ + /* Next */ + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc1); + 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 + dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc1_change); + dma0_desc1_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + + /* frame phys addr */ + dma0_desc0->databuf = dma0_desc0_change->databuf = virt_to_phys((void *)lcd_frame0); + dma0_desc1->databuf = virt_to_phys((void *)(lcd_frame0 + fg0_line_size)); + + /* frame id */ + dma0_desc0->frame_id = (unsigned int)0x0da00000; /* DMA0'0 */ + dma0_desc1->frame_id = (unsigned int)0x0da00001; /* DMA0'1 */ + dma0_desc0_change->frame_id = (unsigned int)0x0da000c0; /* DMA0'2 */ + dma0_desc1_change->frame_id = (unsigned int)0x0da000c1; + + /* others */ + dma0_desc0->cmd = LCD_CMD_EOFINT | ((panel_frm_size+panel_line_size)/4)/2; + dma0_desc1->cmd = LCD_CMD_EOFINT | ((panel_frm_size-panel_line_size)/4)/2; + dma0_desc0->offsize = dma0_desc1->offsize =(buffer_line_size + buffer_line_size - panel_line_size)/4; + dma0_desc0->page_width = dma0_desc1->page_width = panel_line_size/4; + dma0_desc0->desc_size = dma0_desc1->desc_size = size0; + + } + else { /* Normal TFT LCD */ + /* next */ + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + + /* frame phys addr */ + dma0_desc0->databuf = dma0_desc0_change->databuf = virt_to_phys((void *)lcd_frame0); + + /* frame id */ + dma0_desc0->frame_id = (unsigned int)0x0000da00; /* DMA0'0 */ + dma0_desc0_change->frame_id = (unsigned int)0x0da000c0; /* DMA0'2 */ + + /* others */ + dma0_desc0->cmd = LCD_CMD_EOFINT | panel_frm_size/4; + dma0_desc0->offsize = (fg0_line_size - panel_line_size)/4; + dma0_desc0->page_width = panel_line_size/4; + + dma0_desc0->desc_size = size0; + } + + 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_desc0); //tft + REG_LCD_SIZE0 = size0; + current_dma0_id = 0;//dma0_desc0; + + dma1_desc0 = dma_desc_base + 5; + dma1_desc1 = dma_desc_base + 6; + dma1_desc0_change = dma_desc_base + 7; + dma1_desc1_change = dma_desc_base + 8; + + /* Foreground 1, caculate size */ + if ( lcd_info->osd.fg1.x >= lcd_info->panel.w ) + lcd_info->osd.fg1.x = lcd_info->panel.w - 1; + if ( lcd_info->osd.fg1.y >= lcd_info->panel.h ) + lcd_info->osd.fg1.y = lcd_info->panel.h - 1; + + if (lcd_info->panel.cfg & LCD_CFG_TVEN ) { + if ( lcd_info->osd.fg1.x + lcd_info->osd.fg1.w > lcd_info->panel.w ) + lcd_info->osd.fg1.w = lcd_info->panel.w - 2 *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 - 2 * lcd_info->osd.fg1.y; + } +/* else{ + if ( lcd_info->osd.fg1.x + lcd_info->osd.fg1.w > lcd_info->panel.w ) + lcd_info->osd.fg1.w = lcd_info->panel.w - 2*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 - 2*lcd_info->osd.fg1.y; + } +*/ + + size1 = lcd_info->osd.fg1.h << 16 | lcd_info->osd.fg1.w; + /* lcd panel display area */ + panel_line_size = lcd_info->panel.w * lcd_info->osd.fg1.bpp / 8; +// panel_line_size = ((panel_line_size + 3) >> 2) << 2; /* word aligned */ + panel_frm_size= panel_line_size * lcd_info->panel.h; + + /* lcd display area */ + fg1_line_size = lcd_info->osd.fg1.w*lcd_info->osd.fg1.bpp/8; +// fg1_line_size = ((fg1_line_size+3)>>2)<<2; /* word aligned */ + fg1_frm_size = fg1_line_size * lcd_info->osd.fg1.h; + + /* DMA1 Descriptor */ + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) {/* TVE mode */ + /* Next */ + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc1); + dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc1_change); + dma1_desc1_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + + /* frame phys addr */ + dma1_desc0->databuf = dma1_desc0_change->databuf = virt_to_phys((void *)lcd_frame); + dma1_desc1->databuf = virt_to_phys((void *)(lcd_frame + fg1_line_size)); + + /* frame id */ + dma1_desc0->frame_id = (unsigned int)0x0da10000; /* DMA1'0 */ + dma1_desc1->frame_id = (unsigned int)0x0da10001; /* DMA1'1 */ + dma1_desc0_change->frame_id = (unsigned int)0x0da100c0; /* DMA1'C0 */ + dma1_desc1_change->frame_id = (unsigned int)0x0da100c1; /* DMA1'C1 */ + + /* other*/ + if(jz4755_lcd_info->osd.fg1.h % 2 == 0){ + dma1_desc0->cmd = LCD_CMD_EOFINT | ((fg1_frm_size)/4)/2; + dma1_desc1->cmd = LCD_CMD_EOFINT | ((fg1_frm_size)/4)/2; + } + else{ + dma1_desc0->cmd = LCD_CMD_EOFINT | ((fg1_frm_size + fg1_line_size)/4)/2; + dma1_desc1->cmd = LCD_CMD_EOFINT | ((fg1_frm_size - fg1_line_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_desc0->desc_size = dma1_desc1->desc_size = size1; + } + else { /* Normal TFT LCD */ + /* Next */ + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + + /* frame phys addr */ + dma1_desc0->databuf = dma1_desc0_change->databuf = virt_to_phys((void *)lcd_frame); + + /* frame id */ + dma1_desc0->frame_id = (unsigned int)0x0da10000; /* DMA1'0 */ + dma1_desc0_change->frame_id = (unsigned int)0x0da100c0; /* DMA1'C0 */ + + /* other */ + if (panel_line_size >= fg1_line_size){ + dma1_desc0->cmd = LCD_CMD_EOFINT | fg1_frm_size /4; + dma1_desc0->offsize = 0; + dma1_desc0->page_width = 0; + } + else{ + dma1_desc0->cmd = LCD_CMD_EOFINT | panel_frm_size/4; + dma1_desc0->offsize = 0; + dma1_desc0->page_width = 0; + } + dma1_desc0->desc_size = size1; + } + + REG_LCD_DA1 = virt_to_phys(dma1_desc0); /* set Dma-chan1's Descripter Addrress */ + REG_LCD_SIZE1 = size1; + current_dma1_id = 0;//dma1_desc0; + + dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4755_lcd_dma_desc)); +} + +static void jz4755fb_set_panel_mode(struct jz4755lcd_info * lcd_info) +{ + struct jz4755lcd_panel_t *panel = &lcd_info->panel; + + /* 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 */ + + 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 jz4755fb_set_osd_mode(struct jz4755lcd_osd_t *lcd_osd_info) +{ + lcd_osd_info->osd_ctrl &= ~(LCD_OSDCTRL_OSDBPP_MASK); + if ( lcd_osd_info->fg1.bpp == 15 ) + lcd_osd_info->osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB555; + else if ( lcd_osd_info->fg1.bpp == 16 ) + lcd_osd_info->osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB565; + else { + lcd_osd_info->fg1.bpp = 32; + lcd_osd_info->osd_ctrl |= LCD_OSDCTRL_OSDBPP_18_24; + } + + REG_LCD_OSDC = lcd_osd_info->osd_cfg; /* F0, F1, alpha, */ + + REG_LCD_OSDCTRL = lcd_osd_info->osd_ctrl; /* IPUEN, bpp */ + REG_LCD_RGBC = lcd_osd_info->rgb_ctrl; + REG_LCD_BGC = lcd_osd_info->bgcolor; + REG_LCD_KEY0 = lcd_osd_info->colorkey0; + REG_LCD_KEY1 = lcd_osd_info->colorkey1; + REG_LCD_ALPHA = lcd_osd_info->alpha; + REG_LCD_IPUR = lcd_osd_info->ipu_restart; + REG_LCD_XYP0 = lcd_osd_info->fg0.y << 16 | lcd_osd_info->fg0.x ; + REG_LCD_XYP1 = lcd_osd_info->fg1.y << 16 | lcd_osd_info->fg1.x; +} + + /* + * 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; + * f1.x + f1.w <= panel.w; + * f1.y + f1.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. + * + */ + +/* Change Position of Foreground 0 */ +static int jz4755fb0_foreground_move(struct jz4755lcd_osd_t *lcd_osd_info) +{ + int pos; + int j, count = 100000; + + if (lcd_osd_info->fg0.x + lcd_osd_info->fg0.w > jz4755_lcd_info->panel.w) + lcd_osd_info->fg0.x = jz4755_lcd_info->panel.w - lcd_osd_info->fg0.w; + if (lcd_osd_info->fg0.y + lcd_osd_info->fg0.h > jz4755_lcd_info->panel.h) + lcd_osd_info->fg0.y = jz4755_lcd_info->panel.h - lcd_osd_info->fg0.h; + + if (lcd_osd_info->fg0.x >= jz4755_lcd_info->panel.w) + lcd_osd_info->fg0.x = jz4755_lcd_info->panel.w - 1; + if (lcd_osd_info->fg0.y >= jz4755_lcd_info->panel.h) + lcd_osd_info->fg0.y = jz4755_lcd_info->panel.h - 1; + + /* in order to place at odd filed*/ +// if(lcd_osd_info->fg1.y%2 != 0) + // lcd_osd_info->fg1.y = lcd_osd_info->fg1.y + 1; + + pos = lcd_osd_info->fg0.y << 16 | lcd_osd_info->fg0.x; + if (REG_LCD_XYP0 == pos){ + printk("FG0: same position\n"); + return 0; + } + + REG_LCD_XYP0 = pos; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + while(!(REG_LCD_OSDS & LCD_OSDS_READY)); + j = count; + msleep(40); + while((REG_LCD_OSDCTRL & LCD_OSDCTRL_CHANGES) && j--); + if(j == 0) { + printk("Error FG0 Position: Wait change fail.\n"); + return -EFAULT; + } + REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_CHANGES; + return 0; +} +/* Change Window size of Foreground 0 */ +static int jz4755fb0_foreground_resize(struct jz4755lcd_osd_t *lcd_osd_info) +{ + struct lcd_cfb_info *cfb = jz4755fb_info; + int size, fg0_line_size, fg0_frm_size; +// int desc_len = sizeof(struct jz4755_lcd_dma_desc); + + if ( lcd_osd_info->fg0.w > jz4755_lcd_info->panel.w) + lcd_osd_info->fg0.w = jz4755_lcd_info->panel.w - 1; + if ( lcd_osd_info->fg0.h > jz4755_lcd_info->panel.h) + lcd_osd_info->fg0.h = jz4755_lcd_info->panel.h - 1; + + size = lcd_osd_info->fg0.h << 16 | lcd_osd_info->fg0.w; + + if (REG_LCD_SIZE0 == size) { + printk("FG0: same size\n"); + return 0; + } + + fg0_line_size = lcd_osd_info->fg0.w * lcd_osd_info->fg0.bpp / 8; + fg0_line_size = ((fg0_line_size + 3) >> 2) << 2; /* word aligned */ + fg0_frm_size = fg0_line_size * lcd_osd_info->fg0.h; + + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; +#if 0 // For 4755 + if (current_dma0_id == 0) { + printk("Change to dma0_desc0_change\n"); +// REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma0_desc0_change->cmd = dma0_desc1_change->cmd = (fg0_frm_size/4)/2; + dma0_desc0_change->offsize = dma0_desc1_change->offsize + = fg0_line_size/4; + dma0_desc0_change->page_width = dma0_desc1_change->page_width + = fg0_line_size/4; + dma0_desc1_change->databuf = virt_to_phys((void *)(lcd_frame0 + fg0_line_size)); + dma0_desc0_change->desc_size = dma0_desc1->desc_size = size; + dma_cache_wback_inv((unsigned int)(dma0_desc0_change), desc_len); + dma_cache_wback_inv((unsigned int)(dma0_desc1_change), desc_len); + } + else { + dma0_desc0_change->cmd = fg0_frm_size/4; + dma0_desc0_change->offsize = 0; + dma0_desc0_change->page_width = 0; + dma0_desc0_change->desc_size = size; + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + dma_cache_wback_inv((unsigned int)(dma0_desc0_change),desc_len); + } + REG_LCD_SIZE0 = size; + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + dma_cache_wback_inv((unsigned int)(dma0_desc1_change), desc_len); + } + else { + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + dma_cache_wback_inv((unsigned int)(dma0_desc0_change), desc_len); + } + current_dma0_id = 1;//dma0_desc0_change; + } + else { + printk("Change to dma0_desc0\n"); + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + 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)); + dma0_desc0->desc_size = dma0_desc1->desc_size = size; + } + else { + dma0_desc0->cmd = fg0_frm_size/4; + dma0_desc0->offsize =0; + dma0_desc0->page_width = 0; + dma0_desc0->desc_size = size; + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma_cache_wback_inv((unsigned int)(dma0_desc0), desc_len); + } + REG_LCD_SIZE0 = size; + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma0_desc1_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma_cache_wback_inv((unsigned int)(dma0_desc1_change), desc_len); + } + else { + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma_cache_wback_inv((unsigned int)(dma0_desc0_change), desc_len); + } + current_dma0_id = 0;//dma0_desc0; + } + +#else + /* set change bit */ + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + REG_LCD_OSDS |= LCD_OSDS_READY; + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* output to TV */ + if(jz4755_lcd_info->osd.fg0.h % 2 == 0){ + dma1_desc0->cmd = LCD_CMD_EOFINT | (fg0_frm_size/4)/2; + dma1_desc1->cmd = LCD_CMD_EOFINT | (fg0_frm_size/4)/2; + } + else{ + dma1_desc0->cmd = LCD_CMD_EOFINT | (fg0_frm_size/4 + fg0_line_size/4)/2; + dma1_desc1->cmd = LCD_CMD_EOFINT | (fg0_frm_size/4 - fg0_line_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)); + } + else { + dma0_desc0->cmd = dma0_desc1->cmd = LCD_CMD_EOFINT | 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 = size; + REG_LCD_SIZE0 = size; + REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_CHANGES; + dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4755_lcd_dma_desc)); +#endif + jz4755fb_set_var(&cfb->fb0.var, 0, &cfb->fb0); + return 0; +} + + +/* Change Position of Foreground 1 */ +static int jz4755fb1_foreground_move(struct jz4755lcd_osd_t *lcd_osd_info) +{ + int pos; + int j, count = 100000; +#if 0 + /* Foreground 0 */ + if (lcd_osd_info->fg1.x + lcd_osd_info->fg1.w > jz4755_lcd_info->panel.w) + lcd_osd_info->fg1.x = jz4755_lcd_info->panel.w - lcd_osd_info->fg1.w; + if (lcd_osd_info->fg1.y + lcd_osd_info->fg1.h > jz4755_lcd_info->panel.h) + lcd_osd_info->fg1.y = jz4755_lcd_info->panel.h - lcd_osd_info->fg1.h; +#endif + if (lcd_osd_info->fg1.x >= jz4755_lcd_info->panel.w) + lcd_osd_info->fg1.x = jz4755_lcd_info->panel.w - 1; + if (lcd_osd_info->fg1.y >= jz4755_lcd_info->panel.h) + lcd_osd_info->fg1.y = jz4755_lcd_info->panel.h - 1; + + /* in order to place at odd filed*/ +// if(lcd_osd_info->fg1.y%2 != 0) + // lcd_osd_info->fg1.y = lcd_osd_info->fg1.y + 1; + + pos = lcd_osd_info->fg1.y << 16 | lcd_osd_info->fg1.x; + printk("----------lcd_osd_info->fg1.x=%d lcd_osd_info->fg1.y=%d---------\n",lcd_osd_info->fg1.x,lcd_osd_info->fg1.y); + printk("---------------Emily Error FG1 Position REG_LCD_XYP1=0x%x-----------\n", REG_LCD_XYP1); + if (REG_LCD_XYP1 == pos){ + printk("FG1: same position\n"); + return 0; + } + + REG_LCD_XYP1 = pos; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + while(!(REG_LCD_OSDS & LCD_OSDS_READY)); + j = count; + msleep(40); + while((REG_LCD_OSDCTRL & LCD_OSDCTRL_CHANGES) && j--); + if(j == 0) { + printk("Error FG1 Position: Wait change fail.\n"); + return -EFAULT; + } + printk("---------------Emily Error FG1 Position REG_LCD_XYP1=0x%x-----------\n", REG_LCD_XYP1); + REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_CHANGES; + return 0; +} + +/* Change window size of Foreground 1 */ +static int jz4755fb1_foreground_resize(struct jz4755lcd_osd_t *lcd_osd_info) +{ + struct lcd_cfb_info *cfb = jz4755fb_info; + int size, fg1_line_size, fg1_frm_size; +// int desc_len = sizeof(struct jz4755_lcd_dma_desc); + + /* Foreground 1 */ + if (lcd_osd_info->fg1.w > jz4755_lcd_info->panel.w) + lcd_osd_info->fg1.w = jz4755_lcd_info->panel.w - 1; + if (lcd_osd_info->fg1.h > jz4755_lcd_info->panel.h) + lcd_osd_info->fg1.h = jz4755_lcd_info->panel.h - 1; + + size = lcd_osd_info->fg1.h << 16|lcd_osd_info->fg1.w; + if (REG_LCD_SIZE1 == size) { + printk("FG1: same size\n"); + return 0;// -EFAULT; + } + + fg1_line_size = lcd_osd_info->fg1.w * lcd_osd_info->fg1.bpp / 8; + //fg1_line_size = ((fg1_line_size + 3) >> 2) << 2; /* word aligned */ + fg1_frm_size = fg1_line_size * lcd_osd_info->fg1.h; + +#if 0 + if (current_dma1_id == 0) { + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma1_desc0_change->cmd = dma1_desc1_change->cmd = (fg1_frm_size/4)/2; + dma1_desc0_change->offsize = dma1_desc1_change->offsize + = fg1_line_size/4; + dma1_desc0_change->page_width = dma1_desc1_change->page_width + = fg1_line_size/4; + dma1_desc1_change->databuf = virt_to_phys((void *)(lcd_frame + fg1_line_size)); + dma1_desc0_change->desc_size = dma1_desc1->desc_size = size; + dma_cache_wback_inv((unsigned int)(dma1_desc0_change), desc_len); + dma_cache_wback_inv((unsigned int)(dma1_desc1_change), desc_len); + } + else { + dma1_desc0_change->cmd = fg1_frm_size/4; + dma1_desc0_change->offsize = 0; + dma1_desc0_change->page_width = 0; + dma1_desc0_change->desc_size = size; + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + dma_cache_wback_inv((unsigned int)(dma1_desc0_change),desc_len); + } + + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + dma_cache_wback_inv((unsigned int)(dma1_desc1_change), desc_len); + } + else { + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + dma_cache_wback_inv((unsigned int)(dma1_desc0_change), desc_len); + } + REG_LCD_SIZE1 = size; + current_dma1_id = 1;//dma1_desc0_change; + + } + else { + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + 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_frame + fg1_line_size)); + dma1_desc0->desc_size = dma1_desc1->desc_size = size; + } + else { + dma1_desc0->cmd = fg1_frm_size/4; + dma1_desc0->offsize =0; + dma1_desc0->page_width = 0; + dma1_desc0->desc_size = size; + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma_cache_wback_inv((unsigned int)(dma1_desc0), desc_len); + } + if (jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma1_desc1_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma_cache_wback_inv((unsigned int)(dma1_desc1_change), desc_len); + } + else { + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma_cache_wback_inv((unsigned int)(dma1_desc0_change), desc_len); + } + REG_LCD_SIZE1 = size; + current_dma1_id = 0;//dma1_desc0_change; + } + + +#else + /* set change bit */ + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + REG_LCD_OSDS |= LCD_OSDS_READY; + if ( jz4755_lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* output to TV */ + if(jz4755_lcd_info->osd.fg1.h % 2 == 0){ + dma1_desc0->cmd = LCD_CMD_EOFINT | (fg1_frm_size/4)/2; + dma1_desc1->cmd = LCD_CMD_EOFINT | (fg1_frm_size/4)/2; + } + else{ + dma1_desc0->cmd = LCD_CMD_EOFINT | (fg1_frm_size/4 + fg1_line_size/4)/2; + dma1_desc1->cmd = LCD_CMD_EOFINT | (fg1_frm_size/4 - fg1_line_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_frame + fg1_line_size)); + } + else { + dma1_desc0->cmd = dma1_desc1->cmd = LCD_CMD_EOFINT | fg1_frm_size/4; + dma1_desc0->offsize = dma1_desc1->offsize = 0; + dma1_desc0->page_width = dma1_desc1->page_width = 0;//fg1_line_size; + } + + dma1_desc0->desc_size = dma1_desc1->desc_size = size; + REG_LCD_SIZE1 = size; + REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_CHANGES; + REG_LCD_OSDS &= ~LCD_OSDS_READY; + dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4755_lcd_dma_desc)); +#endif + jz4755fb_set_var(&cfb->fb1.var, 1, &cfb->fb1); + + return 0; +} + + + +/* + * Set lcd pixel clock + */ +static void jz4755fb_change_clock( struct jz4755lcd_info * lcd_info ) +{ + 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 */ + pclk = 27000000; + __cpm_select_pixclk_tve(); + } + else { /* LCDC output to LCD panel */ + __cpm_select_pixclk_lcd(); + } + 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); + + __cpm_enable_pll_change(); + + 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 ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { + __cpm_start_lcd(); + __cpm_start_tve(); + } + else + __cpm_start_lcd(); + udelay(1000); + +} + + +/* + * jz4755fb_set_mode(), set osd configure, resize foreground + * + */ +static void jz4755fb_set_mode(struct jz4755lcd_osd_t * lcd_osd_info) +{ + jz4755fb_set_osd_mode(lcd_osd_info); + jz4755fb1_foreground_resize(lcd_osd_info); + jz4755fb0_foreground_resize(lcd_osd_info); +} + +/* + * jz4755fb_deep_set_mode, + * + */ +static void jz4755fb_deep_set_mode( struct jz4755lcd_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. + */ + struct lcd_cfb_info *cfb = jz4755fb_info; + + __lcd_clr_ena(); /* Quick Disable */ + lcd_info->osd.fg_change = FG_CHANGE_ALL; /* change FG0, FG1 size, postion??? */ + jz4755fb_set_osd_mode(&lcd_info->osd); + jz4755fb_set_panel_mode(lcd_info); + jz4755fb_descriptor_init(lcd_info); + jz4755fb_change_clock(lcd_info); + + jz4755fb_set_var(&cfb->fb0.var, 0, &cfb->fb0); + jz4755fb_set_var(&cfb->fb1.var, 1, &cfb->fb1); + __lcd_set_ena(); /* enable lcdc */ +} + + +static irqreturn_t jz4755fb_interrupt_handler(int irq, void *dev_id) +{ + unsigned long irq_flags; + unsigned int state;//, osdstate; + struct lcd_cfb_info *cfb = jz4755fb_info; + static int irqcnt = 0; + + spin_lock_irqsave(cfb->update_lock, irq_flags); +// dprintk("Lcd irq, state=0x%08x, osdstate=0x%08x\n", state, osdstate); + state = REG_LCD_STATE; +// osdstate = REG_LCD_OSDS; + if (state & LCD_STATE_EOF) {/* End of frame */ + REG_LCD_STATE = state & ~LCD_STATE_EOF; +// dprintk("lcd dma eof interrupt\n"); + } +#if 1 + 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; + } + +#endif + if (state & LCD_STATE_OFU) { + 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__); + } + cfb->frame_done = cfb->frame_requested; + spin_unlock_irqrestore(cfb->update_lock, irq_flags); + wake_up(&cfb->frame_wq); + + return IRQ_HANDLED; +} + + +#ifdef CONFIG_HAS_EARLYSUSPEND + +static void jz4755fb_earlier_suspend(struct early_suspend *h) +{ + lcd_display_off(); + __cpm_stop_lcd(); +} + +static void jz4755fb_earlier_resume(struct early_suspend *h) +{ + __cpm_start_lcd(); + lcd_display_on(); +} + +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +/* The following routine is only for test */ +static void jz4755_lcd_gpio_init(void) +{ + /* gpio init __gpio_as_lcd */ + if (jz4755_lcd_info->panel.cfg & LCD_CFG_MODE_TFT_16BIT) + __gpio_as_lcd_16bit(); + else if (jz4755_lcd_info->panel.cfg & LCD_CFG_MODE_TFT_24BIT) + __gpio_as_lcd_24bit(); + else + __gpio_as_lcd_18bit(); + + /* Configure SLCD module for setting smart lcd control registers */ +#if defined(CONFIG_FB_JZ4755_SLCD) + __lcd_as_smart_lcd(); + __slcd_disable_dma(); + __init_slcd_bus(); /* Note: modify this depend on your lcd */ + +#endif + __lcd_display_pin_init(); +} + +static void jz4755_lcd_init_cfg(void) +{ + + jz4755_lcd_info->osd.osd_cfg |= LCD_OSDC_F0EN; /* only open fg0 */ +// jz4755_lcd_info->osd.osd_cfg |= LCD_OSDC_F1EN; /* only open fg1 */ + + /* In special mode, we only need init special pin, + * as general lcd pin has init in uboot */ +#if defined(CONFIG_SOC_JZ4755) + switch (jz4755_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: + break; + } +#endif + /* Foreground 0 support bpp = 1, 2, 4, 8, 15, 16, 18, 24 */ + switch ( jz4755_lcd_info->osd.fg0.bpp ) { + case 17 ... 32: + jz4755_lcd_info->osd.fg1.bpp = 32; + break; + default: + break; + } + + /* Foreground 1 support bpp = 15, 16, 18, 24 */ + switch ( jz4755_lcd_info->osd.fg1.bpp ) { + case 15: + case 16: + break; + case 17 ... 32: + jz4755_lcd_info->osd.fg1.bpp = 32; + break; + default: + printk("jz4755fb fg1 not support bpp(%d), force to 32bpp\n", + jz4755_lcd_info->osd.fg1.bpp); + jz4755_lcd_info->osd.fg1.bpp = 32; + } +} + +#ifdef CONFIG_LEDS_CLASS +static void lcd_set_backlight_level(struct led_classdev *led_cdev, enum led_brightness value) +{ + __lcd_set_backlight_level((int)value); +} + +static struct led_classdev lcd_backlight_led = { + .name = "lcd-backlight", + .brightness_set = lcd_set_backlight_level, +}; +#endif + +static int __init jz4755fb_probe(struct platform_device *pdev) +{ + struct lcd_cfb_info *cfb; + int err = 0; + + jz_panel[0].w = jz4755_lcd_panel.panel.w; + jz_panel[0].h = jz4755_lcd_panel.panel.h; + jz_panel[0].index = 0; + + jz_panel[1].w = jz4755_info_tve.panel.w-16; + jz_panel[1].h = jz4755_info_tve.panel.h-20; + jz_panel[1].index = 1; + + if (!pdev) + return -EINVAL; + + __lcd_close_backlight(); + jz4755_lcd_gpio_init(); /* gpio init */ + jz4755_lcd_init_cfg(); /* first config of lcd */ + + __lcd_clr_dis(); + __lcd_clr_ena(); + + /* init clock */ + __lcd_slcd_special_on(); + + cfb = jz4755fb_alloc_fb_info(); + if (!cfb) + goto failed; + + err = jz4755fb_map_smem(cfb); + if (err) + goto failed; + + spin_lock_init(&cfb->update_lock); + init_waitqueue_head(&cfb->frame_wq); + cfb->frame_requested = cfb->frame_done = 0; + +#ifdef CONFIG_HAS_EARLYSUSPEND + cfb->earlier_suspend.suspend = jz4755fb_earlier_suspend; + cfb->earlier_suspend.resume = jz4755fb_earlier_resume; + cfb->earlier_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; + register_early_suspend(&cfb->earlier_suspend); +#endif + + jz4755fb_deep_set_mode( jz4755_lcd_info ); + + /* registers frame buffer devices */ + /* register fg0 */ + err = register_framebuffer(&cfb->fb0); + if (err < 0) { + dprintk("jz4755fb_init(): register framebuffer err.\n"); + goto failed; + } + printk("fb%d: %s frame buffer device, using %dK of video memory\n", + cfb->fb0.node, cfb->fb0.fix.id, cfb->fb0.fix.smem_len>>10); + + /* register fg1 */ + err = register_framebuffer(&cfb->fb1); + if (err < 0) { + dprintk("jz4755fb_init(): register framebuffer err.\n"); + goto failed; + } + printk("fb%d: %s frame buffer device, using %dK of video memory\n", + cfb->fb1.node, cfb->fb1.fix.id, cfb->fb1.fix.smem_len>>10); +#ifdef CONFIG_JZSOC_BOOT_LOGO + load_565_image(INIT_IMAGE_FILE); +#endif + if (request_irq(IRQ_LCD, jz4755fb_interrupt_handler, IRQF_DISABLED, + "lcd", 0)) { + err = -EBUSY; + goto failed; + } + + +#ifdef CONFIG_LEDS_CLASS + err = led_classdev_register(&pdev->dev, &lcd_backlight_led); + if (err < 0) + goto failed; +#endif + + lcd_display_on(); + print_lcdc_registers(); + + + return 0; + +failed: + print_dbg(); + jz_del_wired_entry(); + jz4755fb_unmap_smem(cfb); + jz4755fb_free_fb_info(cfb); + + return err; +} + +static int jz4755fb_remove(struct platform_device *pdev) +{ + struct lcd_cfb_info *cfb = platform_get_drvdata(pdev); + + jz_del_wired_entry(); + jz4755fb_unmap_smem(cfb); + jz4755fb_free_fb_info(cfb); + return 0; +} + +static struct platform_driver jz_lcd_driver = { + .probe = jz4755fb_probe, + .remove = jz4755fb_remove, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init jz4755fb_init(void) +{ + return platform_driver_register(&jz_lcd_driver); +} + +static void __exit jz4755fb_cleanup(void) +{ + platform_driver_unregister(&jz_lcd_driver); +} + +module_init(jz4755fb_init); +module_exit(jz4755fb_cleanup); + diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jz4755_android_lcd.h b/target/linux/xburst/files-2.6.27/drivers/video/jz4755_android_lcd.h new file mode 100644 index 000000000..f24d16e3e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz4755_android_lcd.h @@ -0,0 +1,268 @@ + +/* + * linux/drivers/video/jz4755_android_lcd.h -- Ingenic Jz4755 On-Chip LCD frame buffer device + * + * Copyright (C) 2005-2009, 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 __JZ4755_LCD_H__ +#define __JZ4755_LCD_H__ + +/* Please define next in lcd panel header file + * __lcd_special_pin_init() + * __lcd_special_on() + * __lcd_special_off() + */ + +#if defined(CONFIG_JZ4755_ANDROID_LCD_AUO_A043FL01V2) +#include "jz_auo_a043fl01v2.h" +#endif + +#if defined(CONFIG_JZ4755_ANDROID_LCD_TOPPOLY_TD043MGEB1) +#include "jz_toppoly_td043mgeb1.h" +#endif + +//#include + + +#define NR_PALETTE 256 +#define PALETTE_SIZE (NR_PALETTE*2) + + +/* use new descriptor(8 words) */ +struct jz4755_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 jz4755lcd_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 jz4755lcd_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 jz4755lcd_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 jz4755lcd_fg_t fg0; /* foreground 0 */ + struct jz4755lcd_fg_t fg1; /* foreground 1 */ +}; + +struct jz4755lcd_info { + struct jz4755lcd_panel_t panel; + struct jz4755lcd_osd_t osd; +}; + + +/***********************Emily****************************/ + +#define JZ_ANDROID_PANELNUM 2 +struct jz_android_din_t{ + unsigned int w; + unsigned int h; + unsigned int index; +}; + +struct android_display_info_t { + unsigned int flag; + unsigned int fg0_number; /**/ + unsigned int fg0_index; + unsigned int fg0_alpha; /* */ + unsigned int fg0_colorkey;/**/ + unsigned int fg0_enable;/**/ + unsigned int fg0_x; /*fg0 start position x*/ + unsigned int fg0_y; /*fg0 start position y*/ + unsigned int fg0_w; /*the weight of fg0*/ + unsigned int fg0_h; /*the height of fg0*/ + unsigned int fg1_x; /*fg1 start position x*/ + unsigned int fg1_y; /*fg1 start position y*/ + unsigned int fg1_w; /*the weight of fg1*/ + unsigned int fg1_h; /*the height of fg1*/ + unsigned int fg1_enable; /*start or stop fg1*/ + unsigned int fg1_short_cut;/*IPU direct*/ +}; + +#define FBIO_ANDROID_CTL 0xad10 + +#define ANDROID_GET_DISPLAY_NUM 0x00000001 +#define ANDROID_GET_DISPLAY_INFO 0x00000002 +#define ANDROID_SET_DISPLAY_INDEX 0x00000004 +#define ANDROID_SET_FG0_ALPHA 0x00000008 +#define ANDROID_SET_FG0_COLORKEY 0x00000010 +#define ANDROID_SET_FG0_ENABLE 0x00000020 +#define ANDROID_SET_FG1_POS 0x00000040 +#define ANDROID_SET_FG1_SIZE 0x00000080 +#define ANDROID_SET_FG1_ENABLE 0x00000100 +#define ANDROID_SET_FG1_IPU_DIRECT 0x00000200 +#define ANDROID_GET_PANEL_SIZE 0x00000400 + +#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ + "nop; nop; nop; nop; nop; nop;\n\t" \ + ".set reorder\n\t") +extern void local_flush_tlb_all(void); + +/******************************Emily**************************************/ + +/* 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 */ +#define FBIODISON_FG 0x46a8 /* FG display on */ +#define FBIODISOFF_FG 0x46a9 /* FG display on */ +#define FBIO_SET_LCD_TO_TVE 0x46b0 /* set lcd to tve mode */ +#define FBIO_SET_FRM_TO_LCD 0x46b1 /* set framebuffer to lcd */ +#define FBIO_SET_IPU_TO_LCD 0x46b2 /* set ipu to lcd directly */ +#define FBIO_CHANGE_SIZE 0x46b3 /* change FG size */ +#define FBIO_CHANGE_POSITION 0x46b4 /* change FG starts position */ +#define FBIO_SET_BG_COLOR 0x46b5 /* set background color */ +#define FBIO_SET_IPU_RESTART_VAL 0x46b6 /* set ipu restart value */ +#define FBIO_SET_IPU_RESTART_ON 0x46b7 /* set ipu restart on */ +#define FBIO_SET_IPU_RESTART_OFF 0x46b8 /* set ipu restart off */ +#define FBIO_ALPHA_ON 0x46b9 /* enable alpha */ +#define FBIO_ALPHA_OFF 0x46c0 /* disable alpha */ +#define FBIO_SET_ALPHA_VAL 0x46c1 /* set alpha value */ + +/* + * Platform specific definition + */ +#if defined(CONFIG_SOC_JZ4755) || defined(CONFIG_SOC_JZ4755D) + +#if defined(CONFIG_JZ4755_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_JZ4755D_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(); \ +} while (0) + +#define __lcd_display_off() \ +do { \ + __lcd_special_off(); \ +} while (0) +#endif /* APUS */ +#endif /* CONFIG_SOC_JZ4755 */ + + +/***************************************************************************** + * LCD display pin dummy macros + *****************************************************************************/ +#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 + +#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 /* __JZ4755_LCD_H__ */ + diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jz4755_android_tve.h b/target/linux/xburst/files-2.6.27/drivers/video/jz4755_android_tve.h new file mode 100644 index 000000000..af9c11b25 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz4755_android_tve.h @@ -0,0 +1,57 @@ +#ifndef __JZ4755_TVE_H__ +#define __JZ4755_TVE_H__ + + +#define PANEL_MODE_TVE_NTSC 2 +#define PANEL_MODE_TVE_PAL 1 +#define PANEL_MODE_LCD_PANEL 0 + +#define PANEL_OUT_FMT_YCBCR 2 +#define PANEL_OUT_FMT_SVIDEO 1 +#define PANEL_OUT_FMT_CVBS 0 + +/* 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 jz4755tve_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; +}; + +struct jz4755tve_mode { + unsigned int mode; /* PAL or NTSC mode, lcd mode*/ + unsigned int out_fmt; /* CVBS, S-video, YCbCr(Jz4755 didn't support)*/ +}; + +extern struct jz4755tve_info *jz4755_tve_info; + +extern void jz4755tve_enable_tve(void); +extern void jz4755tve_disable_tve(void); + +extern void jz4755tve_set_tve_mode( struct jz4755tve_info *tve ); +extern void jz4755tve_init( int tve_mode ); + +extern void jz4755tve_outfmt_init(unsigned int outfmt); + +#endif /* __JZ4755_TVE_H__ */ + diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jz4760_lcd.c b/target/linux/xburst/files-2.6.27/drivers/video/jz4760_lcd.c new file mode 100644 index 000000000..026f8d560 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz4760_lcd.c @@ -0,0 +1,2993 @@ +/* + * linux/drivers/video/jz4760_lcd.c -- Ingenic Jz4760 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "console/fbcon.h" + +#include "jz4760_lcd.h" + +//#include "jz4760_tve.h" + +#define DRIVER_NAME "jz-lcd" + +#ifdef CONFIG_JZ4760_SLCD_KGM701A3_TFT_SPFD5420A +#include "jz_kgm_spfd5420a.h" +#endif + +MODULE_DESCRIPTION("Jz4760 LCD Controller driver"); +MODULE_AUTHOR("Wolfgang Wang , Lemon Liu "); +MODULE_LICENSE("GPL"); + + +//#define LCD_DEBUG +#undef LCD_DEBUG + +#ifdef LCD_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) + +#define JZ_LCD_ID "jz-lcd" +#define ANDROID_NUMBER_OF_BUFFERS 2 + +struct lcd_cfb_info { + struct fb_info fb0; /* foreground 0 */ + struct fb_info fb; /* foreground 1 */ + 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 +}; + +static struct lcd_cfb_info *jz4760fb_info; +static int current_dma0_id, current_dma1_id; +static struct jz4760_lcd_dma_desc *dma_desc_base; +static struct jz4760_lcd_dma_desc *dma0_desc_palette, *dma0_desc0, *dma0_desc1, *dma1_desc0, *dma1_desc1; +static struct jz4760_lcd_dma_desc *dma0_desc0_change, *dma1_desc0_change, *dma0_desc1_change, *dma1_desc1_change; + +#define DMA_DESC_NUM 9 + +static unsigned char *lcd_palette; +static unsigned char *lcd_frame0; +static unsigned char *lcd_frame; + +/* APP */ +static void jz4760fb_set_mode(struct jz4760lcd_osd_t * lcd_osd_info ); +static void jz4760fb_deep_set_mode( struct jz4760lcd_info * lcd_info ); +static void print_lcdc_registers(void); +#ifdef CONFIG_FB_JZ4760_TVE +static void jz4760lcd_info_switch_to_TVE(int mode); +static void jz4760lcd_info_switch_to_lcd(void); +#endif +#if defined(CONFIG_JZ4760_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) +static int jz4760fb0_foreground_resize(struct jz4760lcd_osd_t *lcd_osd_info); +static int jz4760fb0_foreground_move(struct jz4760lcd_osd_t *lcd_osd_info); +#endif + +#if defined(CONFIG_JZ4760_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) +static int jz4760fb_foreground_resize(struct jz4760lcd_osd_t *lcd_osd_info); +static int jz4760fb_foreground_move(struct jz4760lcd_osd_t *lcd_osd_info); +#endif + +struct jz4760lcd_info jz4760_lcd_panel = { +#if defined(CONFIG_JZ4760_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 */ + .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, 480, 272}, /* bpp, x, y, w, h */ + }, +#elif defined(CONFIG_JZ4760_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 | LCD_OSDC_ALPHAEN,// | /* Use OSD mode */ + .osd_ctrl = 0, /* disable ipu, */ + .rgb_ctrl = 0, + .bgcolor = 0x000000, /* set background color Black */ + .colorkey0 = 0x80000000, /* disable colorkey */ +// .colorkey0 = 0, /* disable colorkey */ + .colorkey1 = 0, /* disable colorkey */ + .alpha = 0xff, /* alpha value */ +// .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, 480, 272}, /* bpp, x, y, w, h */ + }, +#elif defined(CONFIG_JZ4760_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 */ + .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_JZ4760_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_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 */ + .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_JZ4760_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 */ + .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_JZ4760_SLCD_KGM701A3_TFT_SPFD5420A) + .panel = { + .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 */ + .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 */ + .fg1 = {32, 0, 0, 400, 240}, /* bpp, x, y, w, h */ + }, +#elif defined(CONFIG_JZ4760_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 +}; + +#ifdef CONFIG_FB_JZ4760_TVE +struct jz4760lcd_info jz4760_info_tve = { + .panel = { + .w = TVE_WIDTH_PAL, TVE_HEIGHT_PAL, TVE_FREQ_PAL, 0, 0, 0, 0, 0, 0, + }, + .osd = { + .rgb_ctrl = LCD_RGBC_YCC, /* enable RGB => YUV */ + .fg0 = {32,}, /* */ + .fg1 = {32,}, + }, +}; +#endif + +struct jz4760lcd_info *jz4760_lcd_info = &jz4760_lcd_panel; /* default output to lcd panel */ + + + +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 void display_v_color_bar(void *frame, int w, int h, int bpp) { + int i, j, wpl, bpl, data = 0; + int *ptr; + printk("frame_v = 0x%08x\n", (unsigned int)frame); + if(w == 0 || h == 0) + return; + ptr = (int *)frame; + wpl = w*bpp/32; + bpl = w*bpp/8; + + 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: + #ifndef CONFIG_FB_JZ4760_LCD_USE_COMPRESS_24BPP + #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 + #else + #if 1 + ptrc = (unsigned char *)lcd_frame1; + for (j = 0;j < h; j++) + for (i = 0;i < bpl; i+=3) { + if (i < bpl/8*1 ) { + *ptrc++ = 0xff; + *ptrc++ = 0x0; + *ptrc++ = 0x0; + } + else if (i < bpl/8*2) { + *ptrc++ = 0x00; + *ptrc++ = 0xff; + *ptrc++ = 0x00; + } + else if (i < bpl/8*3) { + *ptrc++ = 0x00; + *ptrc++ = 0x00; + *ptrc++ = 0xff; + } + else if (i < bpl/8*4) { + *ptrc++ = 0xff; + *ptrc++ = 0x00; + *ptrc++ = 0x00; + } + else if (i < bpl/8*5) { + *ptrc++ = 0x00; + *ptrc++ = 0xff; + *ptrc++ = 0x00; + } + else if (i < bpl/8*6) { + *ptrc++ = 0x00; + *ptrc++ = 0x00; + *ptrc++ = 0xff; + } + else if (i < bpl/8*7) { + *ptrc++ = 0xff; + *ptrc++ = 0x00; + *ptrc++ = 0x00; + } + else if (i < bpl) { + *ptrc++ = 0x00; + *ptrc++ = 0xff; + *ptrc++ = 0x00; + } + } + #endif + #endif + break; + } + } + dma_cache_wback_inv((unsigned int)(frame), w*h*bpp/8); + } +static void display_h_color_bar(void *frame, int w, int h, int bpp) { + int i, data = 0; + int *ptr; + int wpl; //word_per_line + printk("frame_h = 0x%08x\n", (unsigned int)frame); + if(w == 0 || h == 0) + return; + ptr = (int *)frame; + 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; + } + + } + dma_cache_wback_inv((unsigned int)(frame), w*h*bpp/8); + } +/************************************ + * Jz475X Framebuffer ops + ************************************/ +#if defined(CONFIG_JZ4760_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) +static int jz4760fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + struct fb_info *fb = info; + if (regno >= NR_PALETTE) + return 1; + if (fb->var.bits_per_pixel <= 16) { + red >>= 8; + green >>= 8; + blue >>= 8; + + red &= 0xff; + green &= 0xff; + blue &= 0xff; + } + + switch (fb->var.bits_per_pixel) { + case 15: + if (regno < 16) + ((u32 *)fb->pseudo_palette)[regno] = + ((red >> 3) << 10) | + ((green >> 3) << 5) | + (blue >> 3); + break; + case 16: + if (regno < 16) { + ((u32 *)fb->pseudo_palette)[regno] = + ((red >> 3) << 11) | + ((green >> 2) << 5) | + (blue >> 3); + } + break; + case 17 ... 32: + if (regno < 16) + ((u32 *)fb->pseudo_palette)[regno] = + (red << 16) | + (green << 8) | + (blue << 0); + +/* if (regno < 16) { + unsigned val; + val = chan_to_field(red, &fb->var.red); + val |= chan_to_field(green, &fb->var.green); + val |= chan_to_field(blue, &fb->var.blue); + ((u32 *)fb->pseudo_palette)[regno] = val; + } +*/ + + break; + } + return 0; +} +static int jz4760fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + void __user *argp = (void __user *)arg; + struct jz4760lcd_fg_t fg1; +#ifdef CONFIG_FB_JZ4760_TVE + struct jz4760tve_mode jz4760_tve_mode; +#endif + + switch (cmd) { + case FBIOSETBACKLIGHT: + __lcd_set_backlight_level(arg); /* We support 8 levels here. */ + break; + case FBIODISPON: + REG_LCD_STATE = 0; /* clear lcdc status */ + __lcd_slcd_special_on(); + REG_LCD_DA1 = virt_to_phys(dma1_desc0); + __lcd_clr_dis(); + __lcd_set_ena(); /* enable lcdc */ + __lcd_display_on(); + break; + case FBIODISPOFF: + __lcd_display_off(); + if ( jz4760_lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD || + jz4760_lcd_info->panel.cfg & LCD_CFG_TVEN ) /* */ + __lcd_clr_ena(); /* Smart lcd and TVE mode only support quick disable */ + else + __lcd_set_dis(); /* regular disable */ + break; + case FBIOPRINT_REG: + print_lcdc_registers(); + break; + case FBIO_GET_MODE: + print_dbg("fbio get mode\n"); + if (copy_to_user(argp, jz4760_lcd_info, sizeof(struct jz4760lcd_info))) + return -EFAULT; + break; + case FBIO_SET_MODE: + print_dbg("fbio set mode\n"); + if (copy_from_user(jz4760_lcd_info, argp, sizeof(struct jz4760lcd_info))) + return -EFAULT; + /* set mode */ + jz4760fb_set_mode(&jz4760_lcd_info->osd); + break; + case FBIO_DEEP_SET_MODE: + print_dbg("fbio deep set mode\n"); + if (copy_from_user(jz4760_lcd_info, argp, sizeof(struct jz4760lcd_info))) + return -EFAULT; + jz4760fb_deep_set_mode(jz4760_lcd_info); + break; +#ifdef CONFIG_FB_JZ4760_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 */ + jz4760lcd_info_switch_to_TVE(arg); + jz4760tve_init(arg); /* tve controller init */ + jz4760tve_enable_tve(); + /* turn off lcd backlight */ + __lcd_display_off(); + break; + case PANEL_MODE_LCD_PANEL: /* switch to LCD mode */ + default : + /* turn off TVE, turn off DACn... */ + jz4760tve_disable_tve(); + jz4760_lcd_info = &jz4760_lcd_panel; + /* turn on lcd backlight */ + __lcd_display_on(); + break; + } + jz4760fb_deep_set_mode(jz4760_lcd_info); + break; + case FBIO_GET_TVE_MODE: + print_dbg("fbio get TVE mode\n"); + if (copy_to_user(argp, jz4760_tve_info, sizeof(struct jz4760tve_info))) + return -EFAULT; + break; + case FBIO_SET_TVE_MODE: + print_dbg("fbio set TVE mode\n"); + if (copy_from_user(jz4760_tve_info, argp, sizeof(struct jz4760tve_info))) + return -EFAULT; + /* set tve mode */ + jz4760tve_set_tve_mode(jz4760_tve_info); + break; +#endif +#if 1 + case FBIODISON_FG: //pass + /*lcdc_enable_fg1();*/ + print_dbg("lcdc_disable_fg1()\n"); + jz4760_lcd_info->osd.osd_cfg |= LCD_OSDC_F1EN; + __lcd_enable_f1(); + break; + case FBIODISOFF_FG://pass + /*lcdc_disable_fg1();*/ + jz4760_lcd_info->osd.osd_cfg &= ~LCD_OSDC_F1EN; + __lcd_disable_f1(); + break; +#ifdef CONFIG_FB_JZ4760_TVE + case FBIO_SET_LCD_TO_TVE: + /*tve PAL NTSC, LCD, */ + //jz4760_tve_info + /* 1. display off 2. enable ipu_restart 3. use ipu as input 4. after run_ipu, display on lcd*/ + if (copy_from_user(&jz4760_tve_mode, argp, sizeof(struct jz4760tve_mode))) + return -EFAULT; + if (jz4760_tve_mode.mode == PANEL_MODE_LCD_PANEL) { + jz4760tve_disable_tve(); + jz4760lcd_info_switch_to_lcd(); + __lcd_display_on(); + } + else { + jz4760lcd_info_switch_to_TVE(jz4760_tve_mode.mode); + jz4760tve_outfmt_init(jz4760_tve_mode.out_fmt); + jz4760tve_init(jz4760_tve_mode.mode); + jz4760tve_enable_tve(); + __lcd_display_off(); + } + jz4760fb_deep_set_mode(jz4760_lcd_info); + break; +#endif + case FBIO_SET_IPU_TO_LCD: + /* 1. display off 2. enable ipu_restart 3. use ipu as input 4. after run_ipu, display on lcd*/ + __lcd_set_dis(); + __lcd_fg1_use_ipu(); + REG_LCD_BGC = jz4760_lcd_info->osd.ipu_restart; + jz4760fb_deep_set_mode(jz4760_lcd_info); + break; + case FBIO_SET_FRM_TO_LCD: + __lcd_fg1_use_dma_chan1(); + jz4760fb_deep_set_mode(jz4760_lcd_info); + break; + case FBIO_CHANGE_SIZE: + /*fg1_change_size();*/ + if(!(REG_LCD_OSDC & LCD_OSDC_F1EN)) + return -EFAULT; + if (copy_from_user(&fg1, argp, sizeof(struct jz4760lcd_fg_t))) + return -EFAULT; + jz4760_lcd_info->osd.fg1.w = fg1.w; + jz4760_lcd_info->osd.fg1.h = fg1.h; + jz4760fb_foreground_resize(&jz4760_lcd_info->osd); + break; + case FBIO_CHANGE_POSITION: + if (copy_from_user(&fg1, argp, sizeof(struct jz4760lcd_fg_t))) + return -EFAULT; + jz4760_lcd_info->osd.fg1.x = fg1.x; + jz4760_lcd_info->osd.fg1.y = fg1.y; + jz4760fb_foreground_move(&jz4760_lcd_info->osd); + break; + case FBIO_SET_BG_COLOR://pass + jz4760_lcd_info->osd.bgcolor = arg; + /*lcdc_set_bgcolor(arg);*/ + REG_LCD_BGC = jz4760_lcd_info->osd.bgcolor; + break; + case FBIO_SET_IPU_RESTART_VAL: + /*lcdc_set_ipu_restart_val(arg);*/ + jz4760_lcd_info->osd.ipu_restart &= ~LCD_IPUR_IPURMASK; + jz4760_lcd_info->osd.ipu_restart |= (arg & LCD_IPUR_IPURMASK); + __lcd_set_ipu_restart_triger(arg); + break; + case FBIO_SET_IPU_RESTART_ON: + /*lcdc_enable_ipu_restart();*/ + __lcd_enable_ipu_restart(); + break; + case FBIO_SET_IPU_RESTART_OFF: + /*lcdc_disable_ipu_restart();*/ + __lcd_disable_ipu_restart(); + 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 jz4760fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + + struct fb_info *fb = 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 = fb->fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + 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; +} + +#endif /*end of Foreground 1 ops*/ + +#if defined(CONFIG_JZ4760_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) +static int jz4760fb0_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; + + if (regno >= NR_PALETTE) + return 1; + + cfb->palette[regno].red = red ; + cfb->palette[regno].green = green; + cfb->palette[regno].blue = blue; + if (cfb->fb0.var.bits_per_pixel <= 16) { + red >>= 8; + green >>= 8; + blue >>= 8; + + red &= 0xff; + green &= 0xff; + blue &= 0xff; + } + switch (cfb->fb0.var.bits_per_pixel) { + case 1: + case 2: + case 4: + case 8: + if (((jz4760_lcd_info->panel.cfg & LCD_CFG_MODE_MASK) == LCD_CFG_MODE_SINGLE_MSTN ) || + ((jz4760_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->fb0.pseudo_palette)[regno] = + ((red >> 3) << 10) | + ((green >> 3) << 5) | + (blue >> 3); + break; + case 16: + if (regno < 16) { + ((u32 *)cfb->fb0.pseudo_palette)[regno] = + ((red >> 3) << 11) | + ((green >> 2) << 5) | + (blue >> 3); + } + break; + case 17 ... 32: + if (regno < 16) + ((u32 *)cfb->fb0.pseudo_palette)[regno] = + (red << 16) | + (green << 8) | + (blue << 0); + +/* if (regno < 16) { + unsigned val; + val = chan_to_field(red, &cfb->fb0.var.red); + val |= chan_to_field(green, &cfb->fb0.var.green); + val |= chan_to_field(blue, &cfb->fb0.var.blue); + ((u32 *)cfb->fb.pseudo_palette)[regno] = val; + } +*/ + + break; + } + return 0; +} + + + +static int jz4760fb0_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + void __user *argp = (void __user *)arg; + struct jz4760lcd_fg_t fg0; + + switch (cmd) { + case FBIOSETBACKLIGHT: + __lcd_set_backlight_level(arg); /* We support 8 levels here. */ + break; + case FBIODISPON: + REG_LCD_STATE = 0; /* clear lcdc status */ + __lcd_slcd_special_on(); + __lcd_clr_dis(); + __lcd_set_ena(); /* enable lcdc */ + __lcd_display_on(); + break; + case FBIODISPOFF: + __lcd_display_off(); + if ( jz4760_lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD || + jz4760_lcd_info->panel.cfg & LCD_CFG_TVEN ) /* */ + __lcd_clr_ena(); /* Smart lcd and TVE mode only support quick disable */ + else + __lcd_set_dis(); /* regular disable */ + break; + case FBIOPRINT_REG: + print_lcdc_registers(); + break; + case FBIO_GET_MODE: + print_dbg("fbio get mode\n"); + if (copy_to_user(argp, jz4760_lcd_info, sizeof(struct jz4760lcd_info))) +// if (copy_to_user(argp, &jz4760_lcd_info->osd, sizeof(struct jz4760lcd_osd_t))) + return -EFAULT; + break; + case FBIO_SET_MODE: + print_dbg("fbio set mode\n"); + if (copy_from_user(jz4760_lcd_info, argp, sizeof(struct jz4760lcd_info))) +// if (copy_to_user(argp, &jz4760_lcd_info->osd, sizeof(struct jz4760lcd_osd_t))) + return -EFAULT; + /* set mode */ + jz4760fb_set_mode(&jz4760_lcd_info->osd); +// jz4760fb_set_mode(jz4760_lcd_info); + break; + case FBIO_DEEP_SET_MODE: + print_dbg("fbio deep set mode\n"); + if (copy_from_user(jz4760_lcd_info, argp, sizeof(struct jz4760lcd_info))) + return -EFAULT; + jz4760fb_deep_set_mode(jz4760_lcd_info); + break; +#ifdef CONFIG_FB_JZ4760_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 */ + jz4760lcd_info_switch_to_TVE(arg); + jz4760tve_init(arg); /* tve controller init */ + jz4760tve_enable_tve(); + /* turn off lcd backlight */ + __lcd_display_off(); + break; + case PANEL_MODE_LCD_PANEL: /* switch to LCD mode */ + default : + /* turn off TVE, turn off DACn... */ + jz4760tve_disable_tve(); + jz4760_lcd_info = &jz4760_lcd_panel; + /* turn on lcd backlight */ + __lcd_display_on(); + break; + } + jz4760fb_deep_set_mode(jz4760_lcd_info); + break; + case FBIO_GET_TVE_MODE: + print_dbg("fbio get TVE mode\n"); + if (copy_to_user(argp, jz4760_tve_info, sizeof(struct jz4760tve_info))) + return -EFAULT; + break; + case FBIO_SET_TVE_MODE: + print_dbg("fbio set TVE mode\n"); + if (copy_from_user(jz4760_tve_info, argp, sizeof(struct jz4760tve_info))) + return -EFAULT; + /* set tve mode */ + jz4760tve_set_tve_mode(jz4760_tve_info); + break; +#endif +#if 1 + case FBIODISON_FG: //pass + /*lcdc_enable_fg0();*/ + jz4760_lcd_info->osd.osd_cfg |= LCD_OSDC_F0EN; + __lcd_enable_f0(); + break; + case FBIODISOFF_FG://pass + /*lcdc_disable_fg0();*/ + print_dbg("lcdc_disable_fg0()\n"); + jz4760_lcd_info->osd.osd_cfg &= ~LCD_OSDC_F0EN; + __lcd_disable_f0(); + break; + case FBIO_CHANGE_SIZE: + /*fg0_change_size();*/ + if(!(REG_LCD_OSDC & LCD_OSDC_F0EN)) + return -EFAULT; + if (copy_from_user(&fg0, argp, sizeof(struct jz4760lcd_fg_t))) + return -EFAULT; + jz4760_lcd_info->osd.fg0.w = fg0.w; + jz4760_lcd_info->osd.fg0.h = fg0.h; + jz4760fb0_foreground_resize(&jz4760_lcd_info->osd); + break; + case FBIO_CHANGE_POSITION: + if (copy_from_user(&fg0, argp, sizeof(struct jz4760lcd_fg_t))) + return -EFAULT; + jz4760_lcd_info->osd.fg0.x = fg0.x; + jz4760_lcd_info->osd.fg0.y = fg0.y; + jz4760fb0_foreground_move(&jz4760_lcd_info->osd); + break; + case FBIO_SET_BG_COLOR://pass + jz4760_lcd_info->osd.bgcolor = arg; + /*lcdc_set_bgcolor(arg);*/ + REG_LCD_BGC = jz4760_lcd_info->osd.bgcolor; + break; + case FBIO_ALPHA_ON://pass + /*lcdc_enable_alpha();*/ + jz4760_lcd_info->osd.osd_cfg |= LCD_OSDC_ALPHAEN; + __lcd_enable_alpha(); + break; + case FBIO_ALPHA_OFF://pass + /*lcdc_disable_alpha();*/ + jz4760_lcd_info->osd.osd_cfg &= ~LCD_OSDC_ALPHAEN; + __lcd_disable_alpha(); + break; + case FBIO_SET_ALPHA_VAL://pass + jz4760_lcd_info->osd.alpha = arg; + /*lcdc_set_alpha(arg);*/ + REG_LCD_ALPHA = jz4760_lcd_info->osd.alpha; + break; +#endif + default: + printk("FG0:%s, unknown command(0x%x)", __FILE__, cmd); + break; + } + + return ret; +} + + +static int jz4760fb0_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->fb0.fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb0.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; +} +#endif /* end of Foreground 0 ops*/ + +/* checks var and eventually tweaks it to something supported, + * DO NOT MODIFY PAR */ +static int jz4760fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + + if((var->rotate & 1) != (info->var.rotate & 1)) { + if((var->xres != info->var.yres) || + (var->yres != info->var.xres) || + (var->xres_virtual != info->var.yres) || + (var->yres_virtual > + info->var.xres * ANDROID_NUMBER_OF_BUFFERS) || + (var->yres_virtual < info->var.xres )) { + return -EINVAL; + } + } + else { + if((var->xres != info->var.xres) || + (var->yres != info->var.yres) || + (var->xres_virtual != info->var.xres) || + (var->yres_virtual > + info->var.yres * ANDROID_NUMBER_OF_BUFFERS) || + (var->yres_virtual < info->var.yres )) { + return -EINVAL; + } + } + if((var->xoffset != info->var.xoffset) || + (var->bits_per_pixel != info->var.bits_per_pixel)) {// || +// (var->grayscale != info->var.grayscale)) { + return -EINVAL; + } + return 0; +} + + +/* + * set the video mode according to info->var + */ +static int jz4760fb_set_par(struct fb_info *info) +{ + dprintk("jz4760fb_set_par, not implemented\n"); + return 0; +} + + +/* + * (Un)Blank the display. + * Fix me: should we use VESA value? + */ +static int jz4760fb_blank(int blank_mode, struct fb_info *info) +{ + printk("jz4760 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: + /* Turn off panel */ +#if 0 + __lcd_display_off(); + __lcd_set_dis(); +#endif + break; + default: + break; + + } + return 0; +} + +/* + * pan display + */ +static int jz4760fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct fb_info *fb = info; + int dy; + if (!var || !fb) { + return -EINVAL; + } + + if (var->xoffset - fb->var.xoffset) { + /* No support for X panning for now! */ + return -EINVAL; + } + /* TODO: Wait for current frame to finished */ + dy = var->yoffset;// - fb->var.yoffset; +#if defined(CONFIG_JZ4760_LCD_USE_FG1_ONLY) + if (dy) { + dma1_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame + (fb->fix.line_length * dy)); + dma_cache_wback((unsigned int)(dma1_desc0), sizeof(struct jz4760_lcd_dma_desc)); + + } + else { + dma1_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame); + dma_cache_wback((unsigned int)(dma1_desc0), sizeof(struct jz4760_lcd_dma_desc)); + } +#else + if (dy) { + dma0_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame0 + (fb->fix.line_length * dy)); + dma_cache_wback((unsigned int)(dma0_desc0), sizeof(struct jz4760_lcd_dma_desc)); + + } + else { + dma0_desc0->databuf = (unsigned int)virt_to_phys((void *)lcd_frame0); + dma_cache_wback((unsigned int)(dma0_desc0), sizeof(struct jz4760_lcd_dma_desc)); + } +#endif + return 0; +} + + +/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ +#if defined(CONFIG_JZ4760_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) +static struct fb_ops jz4760fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = jz4760fb_setcolreg, + .fb_check_var = jz4760fb_check_var, + .fb_set_par = jz4760fb_set_par, + .fb_blank = jz4760fb_blank, + .fb_pan_display = jz4760fb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = jz4760fb_mmap, + .fb_ioctl = jz4760fb_ioctl, +}; +#endif +#if defined(CONFIG_JZ4760_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) +/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ +static struct fb_ops jz4760fb0_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = jz4760fb0_setcolreg, + .fb_check_var = jz4760fb_check_var, + .fb_set_par = jz4760fb_set_par, + .fb_blank = jz4760fb_blank, + .fb_pan_display = jz4760fb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = jz4760fb0_mmap, + .fb_ioctl = jz4760fb0_ioctl, +}; +#endif + +static int jz4760fb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + + struct fb_info *fb = info; + struct jz4760lcd_info *lcd_info = jz4760_lcd_info; + int chgvar = 0; + + if (con == 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; + } + else { + var->height = lcd_info->osd.fg1.h; + var->width = lcd_info->osd.fg1.w; + var->bits_per_pixel = lcd_info->osd.fg1.bpp; + } + + var->vmode = FB_VMODE_NONINTERLACED; +// var->vmode = FB_VMODE_DOUBLE + var->activate = fb->var.activate; + var->xres = var->width; + var->yres = var->height; + var->xres_virtual = var->width; + var->yres_virtual = var->height * ANDROID_NUMBER_OF_BUFFERS; + var->xoffset = 0; + var->yoffset = 0; + var->pixclock = KHZ2PICOS(jz_clocks.pixclk/1000); + + var->left_margin = lcd_info->panel.elw; + var->right_margin = lcd_info->panel.blw; + var->upper_margin = lcd_info->panel.efw; + var->lower_margin = lcd_info->panel.bfw; + var->hsync_len = lcd_info->panel.hsw; + var->vsync_len = lcd_info->panel.vsw; + var->sync = 0; + var->activate = FB_ACTIVATE_NOW; + + + /* + * 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 = fb->var.xoffset; + var->yoffset = fb->var.yoffset; + } + + if (var->activate & FB_ACTIVATE_TEST) + return 0; + + if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) + return -EINVAL; + + if (fb->var.xres != var->xres) + chgvar = 1; + if (fb->var.yres != var->yres) + chgvar = 1; + if (fb->var.xres_virtual != var->xres_virtual) + chgvar = 1; + if (fb->var.yres_virtual != var->yres_virtual) + chgvar = 1; + if (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 */ + fb->fix.visual = FB_VISUAL_MONO01; + 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; + + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_DIRECTCOLOR; + 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; + + fb->fix.visual = FB_VISUAL_TRUECOLOR; + 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; + + fb->fix.visual = FB_VISUAL_TRUECOLOR; + 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", + fb->fix.id, var->bits_per_pixel); + break; + } + + fb->var = *var; + 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(&fb->cmap, fb); + return 0; +} + +static struct lcd_cfb_info * jz4760fb_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; + + jz4760fb_info = cfb; + + memset(cfb, 0, sizeof(struct lcd_cfb_info) ); + + cfb->currcon = -1; + +#if defined(CONFIG_JZ4760_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + /* Foreground 1 -- fb */ + strcpy(cfb->fb.fix.id, "jzlcd-fg1"); + cfb->fb.flags = FBINFO_FLAG_DEFAULT; + 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 = &jz4760fb_ops; + cfb->fb.flags = FBINFO_FLAG_DEFAULT; + + cfb->fb.pseudo_palette = (void *)(cfb + 1); + + switch (jz4760_lcd_info->osd.fg1.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; + } +#endif + +#if defined(CONFIG_JZ4760_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + /* Foreground 0 -- fb0 */ + strcpy(cfb->fb0.fix.id, "jzlcd-fg0"); + cfb->fb0.fix.type = FB_TYPE_PACKED_PIXELS; + cfb->fb0.fix.type_aux = 0; + cfb->fb0.fix.xpanstep = 1; + cfb->fb0.fix.ypanstep = 1; + cfb->fb0.fix.ywrapstep = 0; + cfb->fb0.fix.accel = FB_ACCEL_NONE; + + cfb->fb0.var.nonstd = 0; + cfb->fb0.var.activate = FB_ACTIVATE_NOW; + cfb->fb0.var.height = -1; + cfb->fb0.var.width = -1; + cfb->fb0.var.accel_flags = FB_ACCELF_TEXT; + + cfb->fb0.fbops = &jz4760fb0_ops; + cfb->fb0.flags = FBINFO_FLAG_DEFAULT; + + cfb->fb0.pseudo_palette = (void *)(cfb + 1); + + switch (jz4760_lcd_info->osd.fg0.bpp) { + case 1: + fb_alloc_cmap(&cfb->fb0.cmap, 4, 0); + break; + case 2: + fb_alloc_cmap(&cfb->fb0.cmap, 8, 0); + break; + case 4: + fb_alloc_cmap(&cfb->fb0.cmap, 32, 0); + break; + case 8: + + default: + fb_alloc_cmap(&cfb->fb0.cmap, 256, 0); + break; + } +#endif + dprintk("fb_alloc_cmap, fb.cmap.len:%d, fb0.cmap.len:%d....\n", cfb->fb.cmap.len, cfb->fb0.cmap.len); + return cfb; +} + +/* + * Map screen memory + */ +static int jz4760fb_map_smem(struct lcd_cfb_info *cfb) +{ + unsigned long page; + unsigned int page_shift, needroom = 0, needroom1=0, bpp, w, h; + unsigned char *fb_palette, *fb_frame; + /* caculate the mem size of Foreground 1 */ +#if defined(CONFIG_JZ4760_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + bpp = jz4760_lcd_info->osd.fg1.bpp; + if (bpp == 18 || bpp == 24) + bpp = 32; + if (bpp == 15) + bpp = 16; +#ifndef CONFIG_FB_JZ4760_TVE + w = jz4760_lcd_info->osd.fg1.w; + h = jz4760_lcd_info->osd.fg1.h; +#else /* CONFIG_FB_JZ4760_TVE */ + w = (jz4760_lcd_info->osd.fg1.w > TVE_WIDTH_PAL) ? jz4760_lcd_info->osd.fg1.w : TVE_WIDTH_PAL; + h = (jz4760_lcd_info->osd.fg1.h > TVE_HEIGHT_PAL) ? jz4760_lcd_info->osd.fg1.h : TVE_HEIGHT_PAL; +#endif + needroom1 = needroom = ((w * bpp + 7) >> 3) * h * ANDROID_NUMBER_OF_BUFFERS; + +#endif /* end of alloc Foreground 1 mem */ + + + /* caculate the mem size of Foreground 1 */ +#if defined(CONFIG_JZ4760_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + bpp = jz4760_lcd_info->osd.fg0.bpp; + if (bpp == 18 || bpp == 24) + bpp = 32; + if (bpp == 15) + bpp = 16; +#ifndef CONFIG_FB_JZ4760_TVE + w = jz4760_lcd_info->osd.fg0.w; + h = jz4760_lcd_info->osd.fg0.h; +#else + w = (jz4760_lcd_info->osd.fg0.w > TVE_WIDTH_PAL) ? jz4760_lcd_info->osd.fg0.w : TVE_WIDTH_PAL; + h = (jz4760_lcd_info->osd.fg0.h > TVE_HEIGHT_PAL) ? jz4760_lcd_info->osd.fg0.h : TVE_HEIGHT_PAL; +#endif +// needroom += ((w * bpp + 7) >> 3) * h; + needroom += ((w * bpp + 7) >> 3) * h * ANDROID_NUMBER_OF_BUFFERS; +#endif /* end of alloc Foreground 1 mem */ + + + /* Alloc memory */ + for (page_shift = 0; page_shift < 12; page_shift++) + if ((PAGE_SIZE << page_shift) >= needroom) + break; + fb_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); + fb_frame = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); + if ((!fb_palette) || (!fb_frame)) + return -ENOMEM; + memset((void *)fb_palette, 0, PAGE_SIZE); + memset((void *)fb_frame, 0, PAGE_SIZE << page_shift); + + lcd_palette = fb_palette; + dma_desc_base = (struct jz4760_lcd_dma_desc *)((void*)lcd_palette + ((PALETTE_SIZE+3)/4)*4); +/* +#if defined(CONFIG_FB_JZ4760_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 +*/ + + /* + * 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)); +#if 1 + for (page = (unsigned long)fb_frame; + page < PAGE_ALIGN((unsigned long)fb_frame + (PAGE_SIZE<fb.fix.smem_start = virt_to_phys((void *)lcd_frame); + cfb->fb.fix.smem_len = needroom - needroom1; /* page_shift/2 ??? */ + cfb->fb.screen_base = + (unsigned char *)(((unsigned int)lcd_frame&0x1fffffff) | 0xa0000000); + if (!cfb->fb.screen_base) { + printk("jz4760fb, %s: unable to map screen memory\n", cfb->fb.fix.id); + return -ENOMEM; + } +#endif + +#if defined(CONFIG_JZ4760_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + lcd_frame0 = fb_frame; + cfb->fb0.fix.smem_start = virt_to_phys((void *)lcd_frame0); + cfb->fb0.fix.smem_len = needroom1; /* page_shift/2 ??? */ + cfb->fb0.screen_base = + (unsigned char *)(((unsigned int)lcd_frame0&0x1fffffff) | 0xa0000000); + if (!cfb->fb0.screen_base) { + printk("jz4760fb0, %s: unable to map screen memory\n", cfb->fb0.fix.id); + return -ENOMEM; + } +#endif + + return 0; +} + +static void jz4760fb_free_fb_info(struct lcd_cfb_info *cfb) +{ + if (cfb) { + fb_alloc_cmap(&cfb->fb.cmap, 0, 0); + kfree(cfb); + } +} + +static void jz4760fb_unmap_smem(struct lcd_cfb_info *cfb) +{ + struct page * map = NULL; + unsigned char *tmp; + unsigned int page_shift, needroom, bpp, w, h; + bpp = jz4760_lcd_info->osd.fg0.bpp; + if ( bpp == 18 || bpp == 24) + bpp = 32; + if ( bpp == 15 ) + bpp = 16; + w = jz4760_lcd_info->osd.fg0.w; + h = jz4760_lcd_info->osd.fg0.h; + needroom = ((w * bpp + 7) >> 3) * h; +#if defined(JZ4760_LCD_USE_2LAYER_FG) + bpp = jz4760_lcd_info->osd.fg1.bpp; + if ( bpp == 18 || bpp == 24) + bpp = 32; + if ( bpp == 15 ) + bpp = 16; + w = jz4760_lcd_info->osd.fg1.w; + h = jz4760_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); + } +} + +/************************************ + * Jz475X Chipset OPS + ************************************/ + +/* + * 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 print_lcdc_registers(void) /* debug */ +{ +#ifdef 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++); + } + } + } +#endif +} + +#ifdef CONFIG_FB_JZ4760_TVE +static void jz4760lcd_info_switch_to_TVE(int mode) +{ + struct jz4760lcd_info *info; + struct jz4760lcd_osd_t *osd_lcd; + struct jz4760lcd_panel_t *panel_lcd; + int x, y, w, h; + + info = &jz4760_info_tve; + + /* Set to tve mode */ + info->panel.cfg = jz4760_lcd_panel.panel.cfg; + info->panel.cfg |= LCD_CFG_TVEN | LCD_CFG_MODE_INTER_CCIR656; /* Interlace CCIR656 mode */ + info->panel.ctrl = jz4760_lcd_panel.panel.ctrl; + info->osd.rgb_ctrl = LCD_RGBC_YCC; /* enable RGB => YUV */ + + /* Copy current to keep the old style */ + osd_lcd = &jz4760_lcd_panel.osd; + panel_lcd = &jz4760_lcd_panel.panel; + + 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; + + /* set Foreground 0 */ + w = osd_lcd->fg0.w / panel_lcd->w * TVE_WIDTH_PAL; + h = osd_lcd->fg0.h / panel_lcd->h * TVE_HEIGHT_PAL; + x = osd_lcd->fg0.x / panel_lcd->w * TVE_WIDTH_PAL; + y = osd_lcd->fg0.y / panel_lcd->h * TVE_HEIGHT_PAL; + 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; + + /* set Foreground 1 */ + w = osd_lcd->fg1.w / panel_lcd->w * TVE_WIDTH_PAL; + h = osd_lcd->fg1.h / panel_lcd->h * TVE_HEIGHT_PAL; + x = osd_lcd->fg1.x / panel_lcd->w * TVE_WIDTH_PAL; + y = osd_lcd->fg1.y / panel_lcd->h * TVE_HEIGHT_PAL; + 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 / panel_lcd->w * TVE_WIDTH_PAL; + h = osd_lcd->fg0.h / panel_lcd->h * TVE_HEIGHT_NTSC; + x = osd_lcd->fg0.x / panel_lcd->w * TVE_WIDTH_NTSC; + y = osd_lcd->fg0.y / panel_lcd->h * TVE_HEIGHT_NTSC; + 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 / panel_lcd->w * TVE_WIDTH_PAL; + h = osd_lcd->fg1.h / panel_lcd->h * TVE_HEIGHT_NTSC; + x = osd_lcd->fg1.x / panel_lcd->w * TVE_WIDTH_NTSC; + y = osd_lcd->fg1.y / panel_lcd->h * TVE_HEIGHT_NTSC; + 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__); + } + jz4760_lcd_info = &jz4760_info_tve; +} + +/* + * switch to lcd mode from TVE mode + */ + +static void jz4760lcd_info_switch_to_lcd(void) +{ + struct jz4760lcd_info *info; + struct jz4760lcd_osd_t *osd_lcd; + struct jz4760lcd_panel_t *panel_lcd; + int x, y, w, h; + + info = &jz4760_lcd_panel; + + /* set to tve mode */ + info->panel.cfg = jz4760_info_tve.panel.cfg; + info->panel.cfg &= ~(LCD_CFG_TVEN | LCD_CFG_MODE_INTER_CCIR656); /* Interlace CCIR656 mode */ + info->panel.ctrl = jz4760_info_tve.panel.ctrl; + info->osd.rgb_ctrl &= ~LCD_RGBC_YCC; /* enable YUV => RGB*/ + + /* */ + osd_lcd = &jz4760_info_tve.osd; + panel_lcd = &jz4760_info_tve.panel; + + /* set Foreground 0 */ + w = osd_lcd->fg0.w / panel_lcd->w * info->panel.w; + h = osd_lcd->fg0.h / panel_lcd->h * info->panel.h; + x = osd_lcd->fg0.x / panel_lcd->w * info->panel.w; + y = osd_lcd->fg0.y / panel_lcd->h * info->panel.h; + info->osd.fg0.x = x; + info->osd.fg0.y = y; + info->osd.fg0.w = w; + info->osd.fg0.h = h; + + /* set Foreground 1 */ + w = osd_lcd->fg1.w / panel_lcd->w * info->panel.w; + h = osd_lcd->fg1.h / panel_lcd->h * info->panel.h; + x = osd_lcd->fg1.x / panel_lcd->w * info->panel.w; + y = osd_lcd->fg1.y / panel_lcd->h * info->panel.h; + info->osd.fg1.x = x; + info->osd.fg1.y = y; + info->osd.fg1.w = w; + info->osd.fg1.h = h; + + jz4760_lcd_info = &jz4760_lcd_panel; +} +#endif +/* initial dma descriptors */ +static void jz4760fb_descriptor_init( struct jz4760lcd_info * lcd_info ) +{ + unsigned int pal_size; + int fg0_line_size, fg0_frm_size, fg1_line_size, fg1_frm_size; + int size0, size1; + + 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; + + /* + * 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 --> ... + * DMA Chan1: + * TO LCD Panel: + * dma1_desc0 <<==>> dma1_desc0 + * TO TV Encoder: + * dma1_desc0 <<==>> dma1_desc1 + */ + + dma0_desc_palette = dma_desc_base + 0; +#if 1//defined(CONFIG_JZ4760_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + dma0_desc0 = dma_desc_base + 1; + dma0_desc1 = dma_desc_base + 2; + dma0_desc0_change = dma_desc_base + 3; + dma0_desc1_change = dma_desc_base + 4; + + /* Foreground 0, caculate size */ + if ( lcd_info->osd.fg0.x >= lcd_info->panel.w ) + lcd_info->osd.fg0.x = lcd_info->panel.w - 1; + if ( lcd_info->osd.fg0.y >= lcd_info->panel.h ) + lcd_info->osd.fg0.y = lcd_info->panel.h - 1; + 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; + + size0 = lcd_info->osd.fg0.h << 16 | lcd_info->osd.fg0.w; + 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; + + /* Palette Descriptor */ + 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 */ + + /* DMA0 Descriptor */ + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ + /* Next */ + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc1); + 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 + dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc1_change); + dma0_desc1_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + + /* frame phys addr */ + dma0_desc0->databuf = dma0_desc0_change->databuf = virt_to_phys((void *)lcd_frame0); + dma0_desc1->databuf = virt_to_phys((void *)(lcd_frame0 + fg0_line_size)); + + /* frame id */ + dma0_desc0->frame_id = (unsigned int)0x0da00000; /* DMA0'0 */ + dma0_desc1->frame_id = (unsigned int)0x0da00001; /* DMA0'1 */ + dma0_desc0_change->frame_id = (unsigned int)0x0da000c0; /* DMA0'2 */ + dma0_desc1_change->frame_id = (unsigned int)0x0da000c1; + + /* others */ + 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_desc0->desc_size = dma0_desc1->desc_size = size0; + + } + else { /* Normal TFT LCD */ + /* next */ + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + + /* frame phys addr */ + dma0_desc0->databuf = dma0_desc0_change->databuf = virt_to_phys((void *)lcd_frame0); + + /* frame id */ + dma0_desc0->frame_id = (unsigned int)0x0000da00; /* DMA0'0 */ + dma0_desc0_change->frame_id = (unsigned int)0x0da000c0; /* DMA0'2 */ + + /* others */ + dma0_desc0->cmd = fg0_frm_size/4; + dma0_desc0->offsize =0; + dma0_desc0->page_width = 0; + dma0_desc0->desc_size = size0; + } + + 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_desc0); //tft + REG_LCD_SIZE0 = size0; + current_dma0_id = 0;//dma0_desc0; + + +#endif + +#if 1//defined(CONFIG_JZ4760_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + dma1_desc0 = dma_desc_base + 5; + dma1_desc1 = dma_desc_base + 6; + dma1_desc0_change = dma_desc_base + 7; + dma1_desc1_change = dma_desc_base + 8; + + /* Foreground 1, caculate size */ + if ( lcd_info->osd.fg1.x >= lcd_info->panel.w ) + lcd_info->osd.fg1.x = lcd_info->panel.w - 1; + if ( lcd_info->osd.fg1.y >= lcd_info->panel.h ) + lcd_info->osd.fg1.y = lcd_info->panel.h - 1; + 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; + + + size1 = lcd_info->osd.fg1.h << 16 | lcd_info->osd.fg1.w; + fg1_line_size = lcd_info->osd.fg1.w*lcd_info->osd.fg1.bpp/8; + fg1_line_size = ((fg1_line_size+3)>>2)<<2; /* word aligned */ + fg1_frm_size = fg1_line_size * lcd_info->osd.fg1.h; + + /* DMA1 Descriptor */ + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) {/* TVE mode */ + /* Next */ + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc1); + dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc1_change); + dma1_desc1_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + + /* frame phys addr */ + dma1_desc0->databuf = dma1_desc0_change->databuf = virt_to_phys((void *)lcd_frame); + dma1_desc1->databuf = virt_to_phys((void *)(lcd_frame + fg1_line_size)); + + /* frame id */ + dma1_desc0->frame_id = (unsigned int)0x0da10000; /* DMA1'0 */ + dma1_desc1->frame_id = (unsigned int)0x0da10001; /* DMA1'1 */ + dma1_desc0_change->frame_id = (unsigned int)0x0da100c0; /* DMA1'C0 */ + dma1_desc1_change->frame_id = (unsigned int)0x0da100c1; /* DMA1'C1 */ + + /* other*/ + 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_desc0->desc_size = dma1_desc1->desc_size = size1; + + } + else { /* Normal TFT LCD */ + /* Next */ + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + + /* frame phys addr */ + dma1_desc0->databuf = dma1_desc0_change->databuf = virt_to_phys((void *)lcd_frame); + + /* frame id */ + dma1_desc0->frame_id = (unsigned int)0x0da10000; /* DMA1'0 */ + dma1_desc0_change->frame_id = (unsigned int)0x0da100c0; /* DMA1'C0 */ + + /* other */ + dma1_desc0->cmd = fg1_frm_size/4; + dma1_desc0->offsize = 0; + dma1_desc0->page_width = 0; + dma1_desc0->desc_size = size1; + } + + REG_LCD_DA1 = virt_to_phys(dma1_desc0); /* set Dma-chan1's Descripter Addrress */ + REG_LCD_SIZE1 = size1; + current_dma1_id = 0;//dma1_desc0; +#endif + dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4760_lcd_dma_desc)); + +} + +static void jz4760fb_set_panel_mode(struct jz4760lcd_info * lcd_info) +{ + struct jz4760lcd_panel_t *panel = &lcd_info->panel; + + /* 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 jz4760fb_set_osd_mode( struct jz4760lcd_info * lcd_info ) +static void jz4760fb_set_osd_mode(struct jz4760lcd_osd_t *lcd_osd_info) +{ + lcd_osd_info->osd_ctrl &= ~(LCD_OSDCTRL_OSDBPP_MASK); + if ( lcd_osd_info->fg1.bpp == 15 ) + lcd_osd_info->osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB555; + else if ( lcd_osd_info->fg1.bpp == 16 ) + lcd_osd_info->osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB565; + else { + lcd_osd_info->fg1.bpp = 32; + lcd_osd_info->osd_ctrl |= LCD_OSDCTRL_OSDBPP_18_24; + } + + REG_LCD_OSDC = lcd_osd_info->osd_cfg; /* F0, F1, alpha, */ + + REG_LCD_OSDCTRL = lcd_osd_info->osd_ctrl; /* IPUEN, bpp */ + REG_LCD_RGBC = lcd_osd_info->rgb_ctrl; + REG_LCD_BGC = lcd_osd_info->bgcolor; + REG_LCD_KEY0 = lcd_osd_info->colorkey0; + REG_LCD_KEY1 = lcd_osd_info->colorkey1; + REG_LCD_ALPHA = lcd_osd_info->alpha; + REG_LCD_IPUR = lcd_osd_info->ipu_restart; +} + +#if defined(CONFIG_JZ4760_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + +/* Change Position of Foreground 0 */ +static int jz4760fb0_foreground_move(struct jz4760lcd_osd_t *lcd_osd_info) +{ + int pos; + int j, count; + /* + * 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 fg0 position: + * fg0.x + fg0.w <= panel.w; + * fg0.y + fg0.h <= panel.h; + * + * When output is LCD panel, fg.y 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 should be even number always. + * + */ + + /* Foreground 0 */ + if (lcd_osd_info->fg0.x + lcd_osd_info->fg0.w > jz4760_lcd_info->panel.w) + lcd_osd_info->fg0.x = jz4760_lcd_info->panel.w - lcd_osd_info->fg0.w; + if (lcd_osd_info->fg0.y + lcd_osd_info->fg0.h > jz4760_lcd_info->panel.h) + lcd_osd_info->fg0.y = jz4760_lcd_info->panel.h - lcd_osd_info->fg0.h; + + if (lcd_osd_info->fg0.x >= jz4760_lcd_info->panel.w) + lcd_osd_info->fg0.x = jz4760_lcd_info->panel.w - 1; + if (lcd_osd_info->fg0.y >= jz4760_lcd_info->panel.h) + lcd_osd_info->fg0.y = jz4760_lcd_info->panel.h - 1; + + pos = lcd_osd_info->fg0.y << 16 | lcd_osd_info->fg0.x; + if (REG_LCD_XYP0 == pos){ + printk("FG0: same position\n"); + return 0; + } + +#if 0//defined(CONFIG_SOC_JZ4760) + /****jz4760****/ +// REG_LCD_OSDC &= ~LCD_OSDC_F0EN; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + REG_LCD_XYP0 = pos; +// REG_LCD_OSDC |= LCD_OSDC_F0EN; + /*********************************************/ +#endif + REG_LCD_XYP0 = pos; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + while(!(REG_LCD_OSDS & LCD_OSDS_READY)); + j = count; + msleep(40); + while((REG_LCD_OSDCTRL & LCD_OSDCTRL_CHANGES) && j--); + if(j == 0) { + printk("Error FG0 Position: Wait change fail.\n"); + return -EFAULT; + } + + return 0; +} +/* Change Window size of Foreground 0 */ +static int jz4760fb0_foreground_resize(struct jz4760lcd_osd_t *lcd_osd_info) +{ + struct lcd_cfb_info *cfb = jz4760fb_info; + int size, fg0_line_size, fg0_frm_size; +// int desc_len = sizeof(struct jz4760_lcd_dma_desc); + /* + * 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_osd_info->fg0.x + lcd_osd_info->fg0.w > jz4760_lcd_info->panel.w) + lcd_osd_info->fg0.w = jz4760_lcd_info->panel.w - lcd_osd_info->fg0.x; + if (lcd_osd_info->fg0.y + lcd_osd_info->fg0.h > jz4760_lcd_info->panel.h) + lcd_osd_info->fg0.h = jz4760_lcd_info->panel.h - lcd_osd_info->fg0.y; + + size = lcd_osd_info->fg0.h << 16 | lcd_osd_info->fg0.w; + + if (REG_LCD_SIZE0 == size) { + printk("FG0: same size\n"); + return 0; + } + + fg0_line_size = lcd_osd_info->fg0.w * lcd_osd_info->fg0.bpp / 8; + fg0_line_size = ((fg0_line_size + 3) >> 2) << 2; /* word aligned */ + fg0_frm_size = fg0_line_size * lcd_osd_info->fg0.h; + + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; +#if 0 // For 4760d + if (current_dma0_id == 0) { + printk("Change to dma0_desc0_change\n"); +// REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + if (jz4760_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma0_desc0_change->cmd = dma0_desc1_change->cmd = (fg0_frm_size/4)/2; + dma0_desc0_change->offsize = dma0_desc1_change->offsize + = fg0_line_size/4; + dma0_desc0_change->page_width = dma0_desc1_change->page_width + = fg0_line_size/4; + dma0_desc1_change->databuf = virt_to_phys((void *)(lcd_frame0 + fg0_line_size)); + dma0_desc0_change->desc_size = dma0_desc1->desc_size = size; + dma_cache_wback_inv((unsigned int)(dma0_desc0_change), desc_len); + dma_cache_wback_inv((unsigned int)(dma0_desc1_change), desc_len); + } + else { + dma0_desc0_change->cmd = fg0_frm_size/4; + dma0_desc0_change->offsize = 0; + dma0_desc0_change->page_width = 0; + dma0_desc0_change->desc_size = size; + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + dma_cache_wback_inv((unsigned int)(dma0_desc0_change),desc_len); + } + REG_LCD_SIZE0 = size; + if (jz4760_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + dma_cache_wback_inv((unsigned int)(dma0_desc1_change), desc_len); + } + else { + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0_change); + dma_cache_wback_inv((unsigned int)(dma0_desc0_change), desc_len); + } + current_dma0_id = 1;//dma0_desc0_change; + } + else { + printk("Change to dma0_desc0\n"); + if (jz4760_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + 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)); + dma0_desc0->desc_size = dma0_desc1->desc_size = size; + } + else { + dma0_desc0->cmd = fg0_frm_size/4; + dma0_desc0->offsize =0; + dma0_desc0->page_width = 0; + dma0_desc0->desc_size = size; + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma_cache_wback_inv((unsigned int)(dma0_desc0), desc_len); + } + REG_LCD_SIZE0 = size; + if (jz4760_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma0_desc1_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma_cache_wback_inv((unsigned int)(dma0_desc1_change), desc_len); + } + else { + dma0_desc0_change->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma_cache_wback_inv((unsigned int)(dma0_desc0_change), desc_len); + } + current_dma0_id = 0;//dma0_desc0; + } + +#else + /* set change bit */ + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + + if (jz4760_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)); + } + 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 = size; +// = lcd_osd_info->fg0.h << 16 | lcd_osd_info->fg0.w; + REG_LCD_SIZE0 = size; +// REG_LCD_SIZE0 = (lcd_osd_info->fg0.h << 16) | lcd_osd_info->fg0.w; + + dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4760_lcd_dma_desc)); +#endif + jz4760fb_set_var(&cfb->fb0.var, 0, &cfb->fb0); + return 0; +} +#endif +#if defined(CONFIG_JZ4760_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + +/* Change Position of Foreground 1 */ +static int jz4760fb_foreground_move(struct jz4760lcd_osd_t *lcd_osd_info) +{ + int pos; + int j, count = 100000; + /* + * 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 fg1 position: + * fg1.x + fg1.w <= panel.w; + * fg1.y + fg1.h <= panel.h; + * + * When output is LCD panel, fg.y 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 should be even number always. + * + */ + + /* Foreground 0 */ + if (lcd_osd_info->fg1.x + lcd_osd_info->fg1.w > jz4760_lcd_info->panel.w) + lcd_osd_info->fg1.x = jz4760_lcd_info->panel.w - lcd_osd_info->fg1.w; + if (lcd_osd_info->fg1.y + lcd_osd_info->fg1.h > jz4760_lcd_info->panel.h) + lcd_osd_info->fg1.y = jz4760_lcd_info->panel.h - lcd_osd_info->fg1.h; + + if (lcd_osd_info->fg1.x >= jz4760_lcd_info->panel.w) + lcd_osd_info->fg1.x = jz4760_lcd_info->panel.w - 1; + if (lcd_osd_info->fg1.y >= jz4760_lcd_info->panel.h) + lcd_osd_info->fg1.y = jz4760_lcd_info->panel.h - 1; + + pos = lcd_osd_info->fg1.y << 16 | lcd_osd_info->fg1.x; + if (REG_LCD_XYP1 == pos){ + printk("FG1: same position\n"); + return 0; + } + +#if 0//defined(CONFIG_SOC_JZ4760) + /****jz4760****/ +// REG_LCD_OSDC &= ~LCD_OSDC_F0EN; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + REG_LCD_XYP1 = pos; +// REG_LCD_OSDC |= LCD_OSDC_F0EN; +#endif + /*********************************************/ + REG_LCD_XYP1 = pos; + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + while(!(REG_LCD_OSDS & LCD_OSDS_READY)); + j = count; + msleep(40); + while((REG_LCD_OSDCTRL & LCD_OSDCTRL_CHANGES) && j--); + if(j == 0) { + printk("Error FG1 Position: Wait change fail.\n"); + return -EFAULT; + + } + return 0; +} + +/* Change window size of Foreground 1 */ +static int jz4760fb_foreground_resize(struct jz4760lcd_osd_t *lcd_osd_info) +{ + struct lcd_cfb_info *cfb = jz4760fb_info; + int size, fg1_line_size, fg1_frm_size; +// int desc_len = sizeof(struct jz4760_lcd_dma_desc); + /* + * 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_osd_info->fg1.x + lcd_osd_info->fg1.w > jz4760_lcd_info->panel.w) + lcd_osd_info->fg1.w = jz4760_lcd_info->panel.w - lcd_osd_info->fg1.x; + if (lcd_osd_info->fg1.y + lcd_osd_info->fg1.h > jz4760_lcd_info->panel.h) + lcd_osd_info->fg1.h = jz4760_lcd_info->panel.h - lcd_osd_info->fg1.y; +// size = lcd_info->osd.fg1.h << 16|lcd_info->osd.fg1.w; + size = lcd_osd_info->fg1.h << 16|lcd_osd_info->fg1.w; + if (REG_LCD_SIZE1 == size) { + printk("FG1: same size\n"); + return 0;// -EFAULT; + } + +// fg1_line_size = lcd_osd_info->fg1.w * ((lcd_osd_info->fg1.bpp + 7) / 8); + fg1_line_size = lcd_osd_info->fg1.w * lcd_osd_info->fg1.bpp / 8; + fg1_line_size = ((fg1_line_size + 3) >> 2) << 2; /* word aligned */ + fg1_frm_size = fg1_line_size * lcd_osd_info->fg1.h; + +#if 0 + if (current_dma1_id == 0) { + if (jz4760_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma1_desc0_change->cmd = dma1_desc1_change->cmd = (fg1_frm_size/4)/2; + dma1_desc0_change->offsize = dma1_desc1_change->offsize + = fg1_line_size/4; + dma1_desc0_change->page_width = dma1_desc1_change->page_width + = fg1_line_size/4; + dma1_desc1_change->databuf = virt_to_phys((void *)(lcd_frame + fg1_line_size)); + dma1_desc0_change->desc_size = dma1_desc1->desc_size = size; + dma_cache_wback_inv((unsigned int)(dma1_desc0_change), desc_len); + dma_cache_wback_inv((unsigned int)(dma1_desc1_change), desc_len); + } + else { + dma1_desc0_change->cmd = fg1_frm_size/4; + dma1_desc0_change->offsize = 0; + dma1_desc0_change->page_width = 0; + dma1_desc0_change->desc_size = size; + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + dma_cache_wback_inv((unsigned int)(dma1_desc0_change),desc_len); + } + + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + if (jz4760_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + dma_cache_wback_inv((unsigned int)(dma1_desc1_change), desc_len); + } + else { + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0_change); + dma_cache_wback_inv((unsigned int)(dma1_desc0_change), desc_len); + } + REG_LCD_SIZE1 = size; + current_dma1_id = 1;//dma1_desc0_change; + + } + else { + if (jz4760_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + 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_frame + fg1_line_size)); + dma1_desc0->desc_size = dma1_desc1->desc_size = size; + } + else { + dma1_desc0->cmd = fg1_frm_size/4; + dma1_desc0->offsize =0; + dma1_desc0->page_width = 0; + dma1_desc0->desc_size = size; + dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma_cache_wback_inv((unsigned int)(dma1_desc0), desc_len); + } + if (jz4760_lcd_info->panel.cfg & LCD_CFG_TVEN ) { + dma1_desc1_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma_cache_wback_inv((unsigned int)(dma1_desc1_change), desc_len); + } + else { + dma1_desc0_change->next_desc = (unsigned int)virt_to_phys(dma1_desc0); + dma_cache_wback_inv((unsigned int)(dma1_desc0_change), desc_len); + } + REG_LCD_SIZE1 = size; + current_dma1_id = 0;//dma1_desc0_change; + } + + +#else + /* set change bit */ + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + if ( jz4760_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_frame + fg1_line_size)); + } + 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 = size; + REG_LCD_SIZE1 = size; + + dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4760_lcd_dma_desc)); +#endif + jz4760fb_set_var(&cfb->fb.var, 1, &cfb->fb); + return 0; +} +#endif + + +/* + * Set lcd pixel clock + */ +static void jz4760fb_change_clock( struct jz4760lcd_info * lcd_info ) +{ +#if defined(CONFIG_FPGA) /* FPGA test, pixdiv */ + 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 */ + pclk = 27000000; + __cpm_select_pixclk_tve(); + } + else { /* LCDC output to LCD panel */ + __cpm_select_pixclk_lcd(); + } + 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); + __cpm_enable_pll_change(); + + 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); + __cpm_start_lcd(); + udelay(1000); + + /* + * set lcd device clock and lcd pixel clock. + * what about TVE mode??? + * + */ +#endif + +} + + +/* + * jz4760fb_set_mode(), set osd configure, resize foreground + * + */ +static void jz4760fb_set_mode(struct jz4760lcd_osd_t * lcd_osd_info) +//static void jz4760fb_set_mode(struct jz4760lcd_info * lcd_info) +{ +// struct jz4760lcd_osd_t * lcd_osd_info = jz4760_lcd_info->osd; +// struct lcd_cfb_info *cfb = jz4760fb_info; + + jz4760fb_set_osd_mode(lcd_osd_info); +#if defined(CONFIG_JZ4760_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + jz4760fb_foreground_resize(lcd_osd_info); +#endif +#if defined(CONFIG_JZ4760_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + jz4760fb0_foreground_resize(lcd_osd_info); +#endif +} + +/* + * jz4760fb_deep_set_mode, + * + */ +static void jz4760fb_deep_set_mode( struct jz4760lcd_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. + */ + struct lcd_cfb_info *cfb = jz4760fb_info; + + __lcd_clr_ena(); /* Quick Disable */ + lcd_info->osd.fg_change = FG_CHANGE_ALL; /* change FG0, FG1 size, postion??? */ + jz4760fb_set_osd_mode(&lcd_info->osd); + jz4760fb_set_panel_mode(lcd_info); + jz4760fb_descriptor_init(lcd_info); + jz4760fb_change_clock(lcd_info); +#if defined(CONFIG_JZ4760_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + jz4760fb_set_var(&cfb->fb0.var, 0, &cfb->fb0); +#endif +#if defined(CONFIG_JZ4760_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + jz4760fb_set_var(&cfb->fb.var, 1, &cfb->fb); +#endif + __lcd_set_ena(); /* enable lcdc */ +} + + +static irqreturn_t jz4760fb_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 jz4760fb_suspend(struct platform_device *pdev, pm_message_t state) +{ + __lcd_clr_ena(); /* Quick Disable */ + __lcd_display_off(); + __cpm_stop_lcd(); + + return 0; +} + +/* + * Resume the LCDC. + */ +static int jz4760fb_resume(struct platform_device *pdev) +{ + __cpm_start_lcd(); + REG_LCD_DA1 = virt_to_phys(dma1_desc0); + __lcd_set_ena(); + __lcd_display_on(); + + return 0; +} +#else +static int jz4760fb_suspend(struct device *dev, pm_message_t state) {return 0;} +static int jz4760fb_resume(struct device *dev) {return 0;} +#endif /* CONFIG_PM */ + +/* The following routine is only for test */ + +static void jz4760_lcd_gpio_init(void) +{ + /* gpio init __gpio_as_lcd */ + if (jz4760_lcd_info->panel.cfg & LCD_CFG_MODE_TFT_16BIT) + __gpio_as_lcd_16bit(); + else if (jz4760_lcd_info->panel.cfg & LCD_CFG_MODE_TFT_24BIT) + __gpio_as_lcd_24bit(); + else + __gpio_as_lcd_18bit(); + + /* Configure SLCD module for setting smart lcd control registers */ +#if defined(CONFIG_FB_JZ4760_SLCD) + __lcd_as_smart_lcd(); + __slcd_disable_dma(); + __init_slcd_bus(); /* Note: modify this depend on you lcd */ + +#endif + __lcd_display_pin_init(); +} + +static void jz4760_lcd_init_cfg(void) +{ + +#if defined(CONFIG_JZ4760_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + jz4760_lcd_info->osd.osd_cfg |= LCD_OSDC_F0EN; /* only open fg0 */ +#endif +// jz4760_lcd_info->osd.osd_cfg |= LCD_OSDC_F1EN; /* only open fg1 */ + + /* In special mode, we only need init special pin, + * as general lcd pin has init in uboot */ +#if defined(CONFIG_SOC_JZ4760) + switch (jz4760_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: + break; + } +#endif + /* Foreground 0 support bpp = 1, 2, 4, 8, 15, 16, 18, 24 */ + switch ( jz4760_lcd_info->osd.fg0.bpp ) { + case 17 ... 32: + jz4760_lcd_info->osd.fg1.bpp = 32; + break; + default: + break; + } + + /* Foreground 1 support bpp = 15, 16, 18, 24 */ + switch ( jz4760_lcd_info->osd.fg1.bpp ) { + case 15: + case 16: + break; + case 17 ... 32: + jz4760_lcd_info->osd.fg1.bpp = 32; + break; + default: + printk("jz4760fb fg1 not support bpp(%d), force to 32bpp\n", + jz4760_lcd_info->osd.fg1.bpp); + jz4760_lcd_info->osd.fg1.bpp = 32; + } +} + +#ifdef CONFIG_LEDS_CLASS +static void lcd_set_backlight_level(struct led_classdev *led_cdev, enum led_brightness value) { + __lcd_set_backlight_level((int)value); +} + +static struct led_classdev lcd_backlight_led = { + .name = "lcd-backlight", + .brightness_set = lcd_set_backlight_level, +}; +#endif + +static int __init jz4760fb_probe(struct platform_device *pdev) +{ + struct lcd_cfb_info *cfb; + int err = 0; + __lcd_close_backlight(); + if (!pdev) + return -EINVAL; + jz4760_lcd_gpio_init(); /* gpio init */ + jz4760_lcd_init_cfg(); /* first config of lcd */ + + __lcd_clr_dis(); + __lcd_clr_ena(); + + /* init clock */ + __lcd_slcd_special_on(); + + cfb = jz4760fb_alloc_fb_info(); + if (!cfb) + goto failed; + + err = jz4760fb_map_smem(cfb); + if (err) + goto failed; + + jz4760fb_deep_set_mode( jz4760_lcd_info ); + + /* registers frame buffer devices */ + +#if defined(CONFIG_JZ4760_LCD_USE_FG0_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + /* register fg0 */ + err = register_framebuffer(&cfb->fb0); + if (err < 0) { + dprintk("jz4760fb_init(): register framebuffer err.\n"); + goto failed; + } + printk("fb%d: %s frame buffer device, using %dK of video memory\n", + cfb->fb0.node, cfb->fb0.fix.id, cfb->fb0.fix.smem_len>>10); + +#endif + +#if defined(CONFIG_JZ4760_LCD_USE_FG1_ONLY) || defined(CONFIG_JZ4760_LCD_USE_2LAYER_FG) + /* register fg1 */ + err = register_framebuffer(&cfb->fb); + if (err < 0) { + dprintk("jz4760fb_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); +#endif + + if (request_irq(IRQ_LCD, jz4760fb_interrupt_handler, IRQF_DISABLED, + "lcd", 0)) { + err = -EBUSY; + goto failed; + } +// display_h_color_bar((void *)lcd_frame, jz4760_lcd_info->osd.fg1.w, jz4760_lcd_info->osd.fg1.h, jz4760_lcd_info->osd.fg1.bpp); + +#ifdef CONFIG_LEDS_CLASS + err = led_classdev_register(&pdev->dev, &lcd_backlight_led); + if (err < 0) + goto failed; +#endif + + __lcd_set_ena(); /* enalbe LCD Controller */ + __lcd_display_on(); + print_lcdc_registers(); + pm_set_vt_switch(0); /*disable VT switch during suspend/resume*/ + return 0; + +failed: + print_dbg(); + jz4760fb_unmap_smem(cfb); + jz4760fb_free_fb_info(cfb); + + return err; +} + +static int jz4760fb_remove(struct platform_device *pdev) +{ + struct lcd_cfb_info *cfb = platform_get_drvdata(pdev); + + jz4760fb_unmap_smem(cfb); + jz4760fb_free_fb_info(cfb); + return 0; +} + + + +static struct platform_driver jz_lcd_driver = { + .probe = jz4760fb_probe, + .remove = jz4760fb_remove, +#ifdef CONFIG_PM + .suspend = jz4760fb_suspend, + .resume = jz4760fb_resume, +#endif + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init jz4760fb_init(void) +{ + return platform_driver_register(&jz_lcd_driver); +} + +static void __exit jz4760fb_cleanup(void) +{ + platform_driver_unregister(&jz_lcd_driver); +} + +module_init(jz4760fb_init); +module_exit(jz4760fb_cleanup); diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jz4760_lcd.h b/target/linux/xburst/files-2.6.27/drivers/video/jz4760_lcd.h new file mode 100644 index 000000000..9b89d4025 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz4760_lcd.h @@ -0,0 +1,331 @@ +/* + * linux/drivers/video/jz4760_lcd.h -- Ingenic Jz4760 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 __JZ4760_LCD_H__ +#define __JZ4760_LCD_H__ + +//#include + + +#define NR_PALETTE 256 +#define PALETTE_SIZE (NR_PALETTE*2) + +/* use new descriptor(8 words) */ +struct jz4760_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 jz4760lcd_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 jz4760lcd_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 jz4760lcd_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 jz4760lcd_fg_t fg0; /* foreground 0 */ + struct jz4760lcd_fg_t fg1; /* foreground 1 */ +}; + +struct jz4760lcd_info { + struct jz4760lcd_panel_t panel; + struct jz4760lcd_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 */ +#define FBIODISON_FG 0x46a8 /* FG display on */ +#define FBIODISOFF_FG 0x46a9 /* FG display on */ +#define FBIO_SET_LCD_TO_TVE 0x46b0 /* set lcd to tve mode */ +#define FBIO_SET_FRM_TO_LCD 0x46b1 /* set framebuffer to lcd */ +#define FBIO_SET_IPU_TO_LCD 0x46b2 /* set ipu to lcd directly */ +#define FBIO_CHANGE_SIZE 0x46b3 /* change FG size */ +#define FBIO_CHANGE_POSITION 0x46b4 /* change FG starts position */ +#define FBIO_SET_BG_COLOR 0x46b5 /* set background color */ +#define FBIO_SET_IPU_RESTART_VAL 0x46b6 /* set ipu restart value */ +#define FBIO_SET_IPU_RESTART_ON 0x46b7 /* set ipu restart on */ +#define FBIO_SET_IPU_RESTART_OFF 0x46b8 /* set ipu restart off */ +#define FBIO_ALPHA_ON 0x46b9 /* enable alpha */ +#define FBIO_ALPHA_OFF 0x46c0 /* disable alpha */ +#define FBIO_SET_ALPHA_VAL 0x46c1 /* set alpha value */ + +/* + * LCD panel specific definition + */ +/* AUO */ +#if defined(CONFIG_JZ4760_LCD_AUO_A043FL01V2) +#if defined(CONFIG_JZ4760_F4760) /* Jz4760 FPGA board */ + #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*/ +#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 */ + +#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_SOC_JZ4760) || defined(CONFIG_SOC_JZ4760D) + +#if defined(CONFIG_JZ4760_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(); \ + mdelay(200); \ + __lcd_set_backlight_level(80); \ +} while (0) + +#define __lcd_display_off() \ +do { \ + __lcd_close_backlight(); \ + __lcd_special_off(); \ +} while (0) + +#elif defined(CONFIG_JZ4760D_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(); \ + __lcd_set_backlight_level(80); \ +} while (0) + +#define __lcd_display_off() \ +do { \ + __lcd_close_backlight(); \ + __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 */ +#endif /* CONFIG_SOC_JZ4760 */ + + +/***************************************************************************** + * 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 /* __JZ4760_LCD_H__ */ diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jz_auo_a043fl01v2.h b/target/linux/xburst/files-2.6.27/drivers/video/jz_auo_a043fl01v2.h new file mode 100644 index 000000000..00a572899 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz_auo_a043fl01v2.h @@ -0,0 +1,129 @@ +/* + * linux/drivers/video/jz_auo_a043fl01v2.h -- Ingenic LCD driver + */ + +#ifndef __JZ_AUO_A043FL01V2_H__ +#define __JZ_AUO_A043FL01V2_H__ + +#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_DISP_N (32*4+25) /*LCD_DISP_N use for lcd reset*/ +#elif defined(CONFIG_JZ4750_FUWA) /* 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_DISP_N (32*5+2) /*LCD_DISP_N use for lcd reset*/ +#elif defined(CONFIG_JZ4750D_CETUS) /* board cetus */ + #define SPEN (32*5+13) /*LCD_CS*/ + #define SPCK (32*5+10) /*LCD_SCL*/ + #define SPDA (32*5+11) /*LCD_SDA*/ + #define LCD_DISP_N (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_DISP_N); \ + __gpio_clear_pin(LCD_DISP_N); \ + } while (0) +#define __lcd_special_on() \ + do { \ + udelay(50);\ + __gpio_clear_pin(LCD_DISP_N); \ + udelay(100); \ + __gpio_set_pin(LCD_DISP_N); \ +} while (0) + + #define __lcd_special_off() \ + do { \ + __gpio_clear_pin(LCD_DISP_N); \ + } while (0) + +#endif /* __JZ_AUO_A043FL01V2_H__ */ + diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jz_kgm_spfd5420a.h b/target/linux/xburst/files-2.6.27/drivers/video/jz_kgm_spfd5420a.h new file mode 100644 index 000000000..bf674b0f1 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz_kgm_spfd5420a.h @@ -0,0 +1,382 @@ +/* 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 + +#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 */ +#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/target/linux/xburst/files-2.6.27/drivers/video/jz_toppoly_td043mgeb1.h b/target/linux/xburst/files-2.6.27/drivers/video/jz_toppoly_td043mgeb1.h new file mode 100644 index 000000000..44fc61691 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jz_toppoly_td043mgeb1.h @@ -0,0 +1,157 @@ +#ifndef __JZ_TOPPOLY_TD043MGEB1_H__ +#define __JZ_TOPPOLY_TD043MGEB1_H__ + +#include + +#if defined(CONFIG_JZ4750_LCD_TOPPOLY_TD043MGEB1) || defined(CONFIG_JZ4750_ANDROID_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/jz_toppoly_td043mgeb1.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<<10)|(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 << 2) | (1 << 1)); \ + 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); \ + } while (0) + +#define __lcd_special_on() \ + do { \ + __gpio_set_pin(LCD_STBY); \ + udelay(1000); \ + __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, 0x2F); \ + __spi_write_reg(0x0F, 0x2f); \ + __spi_write_reg(0x10, 0x2F); \ + __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, 0x08); \ + } while (0) + +#define __lcd_special_off() \ + do { \ + __gpio_clear_pin(LCD_STBY); \ + } while (0) + +#endif /* LCD_TOPPOLY_TD043MGEB1 */ + +#endif /* __JZ_TOPPOLY_TD043MGEB1_H__ */ diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jzlcd.c b/target/linux/xburst/files-2.6.27/drivers/video/jzlcd.c new file mode 100755 index 000000000..6df943965 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/jzlcd.c @@ -0,0 +1,1538 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "console/fbcon.h" + +#include "jzlcd.h" + +#define DRIVER_NAME "jz-lcd" + +#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;ivar.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;ivar.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(struct platform_device *pdev, pm_message_t state) +{ + __lcd_clr_ena(); /* Quick Disable */ + __lcd_display_off(); + __cpm_stop_lcd(); + + return 0; +} + +/* + * Resume the LCDC. + */ +#ifdef CONFIG_SOC_JZ4730 +static int jzfb_resume(struct platform_device *pdev, pm_message_t state) +{ + __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(struct platform_device *pdev, pm_message_t state) +{ + __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 */ +#else /* CONFIG_PM */ +#define jzfb_suspend NULL +#define jzfb_resume NULL +#endif /* CONFIG_PM */ + +static int __init jzfb_probe(struct platform_device *pdev) +{ + 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); + + __lcd_display_on(); + + return 0; + +failed: + jzfb_unmap_smem(cfb); + jzfb_free_fb_info(cfb); + + return err; +} + +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; +} + +static struct platform_driver jz_lcd_driver = { + .probe = jzfb_probe, + .remove = jzfb_remove, +#ifdef CONFIG_PM + .suspend = jzfb_suspend, + .resume = jzfb_resume, +#endif + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init jzfb_init(void) +{ + return platform_driver_register(&jz_lcd_driver); +} + +static void __exit jzfb_cleanup(void) +{ +#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) + kthread_stop(jzlcd_info->rotate_daemon_thread); +#endif + platform_driver_unregister(&jz_lcd_driver); +} + +module_init(jzfb_init); +module_exit(jzfb_cleanup); + +MODULE_DESCRIPTION("JzSOC LCD Controller driver"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/drivers/video/jzlcd.h b/target/linux/xburst/files-2.6.27/drivers/video/jzlcd.h new file mode 100755 index 000000000..3676b9bc6 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +#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/target/linux/xburst/files-2.6.27/drivers/video/logo.c b/target/linux/xburst/files-2.6.27/drivers/video/logo.c new file mode 100644 index 000000000..3f2b4b1e2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/drivers/video/logo.c @@ -0,0 +1,194 @@ +/* drivers/video/logo.c + * + * Show Logo in RLE 565 or RGB 565 format + * + * Copyright (C) 2008 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#define fb_width(fb) ((fb)->var.xres) +#define fb_height(fb) ((fb)->var.yres) +#define fb_size(fb) ((fb)->var.xres * (fb)->var.yres * 2) + +void jzfb_get_panel_size(unsigned int *w, unsigned *h); + +#ifdef CONFIG_FB_565RLE_LOGO +static void memset16(void *_ptr, unsigned short val, unsigned count) +{ + unsigned short *ptr = _ptr; + count >>= 1; + while (count--) + *ptr++ = val; +} +/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */ +int display_fb_rle565(unsigned short *buf, unsigned count) { + struct fb_info *info; + unsigned max; + int vm_width, vm_height, stride, ppl; + unsigned short *bits, *ptr; + info = registered_fb[0]; + if (!info) { + printk(KERN_WARNING "%s: Can not access framebuffer\n", + __func__); + return -ENODEV; + } + + jzfb_get_panel_size(&vm_width, &vm_height); + + max = vm_width * vm_height; + stride = fb_width(info) - vm_width; + ppl = fb_width(info); /*pixel per line*/ + ptr = (unsigned short *)buf; + bits = (unsigned short *)(info->screen_base); + if (vm_width < ppl) { + while (count > 3) { + unsigned n = ptr[0]; + unsigned h; + unsigned l; + unsigned o; + h = n < max%vm_width ? n : max%vm_width; + l = (n-h) / vm_width; + o = (n-h) % vm_width; + if (n > max) + break; + /* data before total line */ + if (h) { + memset16(bits, ptr[1], h<<1); + bits += h; + max -= h; + if (max%vm_width == 0) + bits += stride; + } + /* total lines */ + while(l--){ + memset16(bits, ptr[1], vm_width<<1); + max -= vm_width; + bits += ppl; + } + if (o) { + /* data after total line */ + memset16(bits, ptr[1], o<<1); + bits += o; + max -= o; + if (max%vm_width == 0) + bits += stride; + } + ptr += 2; + count -= 4; + } + } + else { + while (count > 3) { + unsigned n = ptr[0]; + if (n > max) + break; + memset16(bits, ptr[1], n << 1); + bits += n; + max -= n; + ptr += 2; + count -= 4; + } + } + return 0; +} +#endif + +/* 565RGB image format: rgb565 */ +#ifdef CONFIG_FB_565RGB_LOGO +int display_fb_rgb565(unsigned short *buf, unsigned count) { + struct fb_info *info; + unsigned max; + int vm_width, vm_height, stride, ppl; + unsigned short *bits, *ptr; + info = registered_fb[0]; + if (!info) { + printk(KERN_WARNING "%s: Can not access framebuffer\n", + __func__); + return -ENODEV; + } + + jzfb_get_panel_size(&vm_width, &vm_height); + + max = vm_width * vm_height; + stride = fb_width(info) - vm_width; + ppl = fb_width(info); /*pixel per line*/ + ptr = (unsigned short *)buf; + bits = (unsigned short *)(info->screen_base); + if (vm_width < ppl) { + while (vm_height--) { + memcpy((void *)bits, (void *)ptr, vm_width<<1); + bits += ppl; + ptr += vm_width; + } + } + else { + memcpy((void *)bits, (void *)ptr, max<<1); + } + return 0; +} +#endif + +int load_565_image(char *filename) +{ + int fd, err = 0; + unsigned count; + unsigned short *data; + + fd = sys_open(filename, O_RDONLY, 0); + if (fd < 0) { + printk(KERN_WARNING "%s: Can not open %s\n", + __func__, filename); + return -ENOENT; + } + count = (unsigned)sys_lseek(fd, (off_t)0, 2); + if (count == 0) { + sys_close(fd); + err = -EIO; + goto err_logo_close_file; + } + sys_lseek(fd, (off_t)0, 0); + data = kmalloc(count, GFP_KERNEL); + if (!data) { + printk(KERN_WARNING "%s: Can not alloc data\n", __func__); + err = -ENOMEM; + goto err_logo_close_file; + } + if ((unsigned)sys_read(fd, (char *)data, count) != count) { + err = -EIO; + goto err_logo_free_data; + } +#ifdef CONFIG_FB_565RLE_LOGO + /* 565RLE image format: [count(2 bytes), rle(2 bytes)] */ + display_fb_rle565(data, count); +#endif +#ifdef CONFIG_FB_565RGB_LOGO + /* 565RGB image format: rgb565 */ + display_fb_rgb565(data, count); +#endif + + +err_logo_free_data: + kfree(data); +err_logo_close_file: + sys_close(fd); + return err; +} +EXPORT_SYMBOL(load_565_image); diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/jzsoc.h b/target/linux/xburst/files-2.6.27/include/asm-mips/jzsoc.h new file mode 100644 index 000000000..057fb5867 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/jzsoc.h @@ -0,0 +1,52 @@ +/* + * linux/include/asm-mips/jzsoc.h + * + * Ingenic's JZXXXX SoC common include. + * + * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 +#endif + +#ifdef CONFIG_SOC_JZ4740 +#include +#endif + +#ifdef CONFIG_SOC_JZ4750 +#include +#endif + +#ifdef CONFIG_SOC_JZ4750D +#include +#endif + +#ifdef CONFIG_SOC_JZ4760 +#include +#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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/board-pmp.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/board-pmp.h new file mode 100644 index 000000000..44475d2a8 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/clock.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/clock.h new file mode 100644 index 000000000..16971d0ba --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/dma.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/dma.h new file mode 100644 index 000000000..511152e39 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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 +#include /* need byte IO */ +#include /* And spinlocks */ +#include +#include + +#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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/jz4730.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/jz4730.h new file mode 100644 index 000000000..5688f01b9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/jz4730.h @@ -0,0 +1,40 @@ +/* + * linux/include/asm-mips/mach-jz4730/jz4730.h + * + * JZ4730 common definition. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 +#include +#include +#include + +/*------------------------------------------------------------------ + * Platform definitions + */ +#ifdef CONFIG_JZ4730_PMP +#include +#endif + +/* Add other platform definition here ... */ + + +/*------------------------------------------------------------------ + * Follows are related to platform definitions + */ + +#include +#include + +#endif /* __ASM_JZ4730_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/misc.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/misc.h new file mode 100644 index 000000000..ea01474fb --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/ops.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/ops.h new file mode 100644 index 000000000..625419ee3 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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> 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/regs.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/regs.h new file mode 100644 index 000000000..86bde9178 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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) /* Motorolas 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/serial.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/serial.h new file mode 100644 index 000000000..4a0afc3fe --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/war.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4730/war.h new file mode 100644 index 000000000..3a5bc17e2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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 + */ +#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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-dipper.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-dipper.h new file mode 100644 index 000000000..ae84f24d5 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-leo.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-leo.h new file mode 100644 index 000000000..4b883e288 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-lyra.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-lyra.h new file mode 100644 index 000000000..29e0ce00f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-pavo.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-pavo.h new file mode 100644 index 000000000..f33831b89 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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 */ + + +/*====================================================================== + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-virgo.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/board-virgo.h new file mode 100644 index 000000000..acd7bb717 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/clock.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/clock.h new file mode 100644 index 000000000..11ffe8894 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/dma.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/dma.h new file mode 100644 index 000000000..b82b984ea --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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 +#include /* need byte IO */ +#include /* And spinlocks */ +#include +#include + +/* + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/jz4740.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/jz4740.h new file mode 100644 index 000000000..437caf454 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/jz4740.h @@ -0,0 +1,56 @@ +/* + * linux/include/asm-mips/mach-jz4740/jz4740.h + * + * JZ4740 common definition. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 +#include +#include +#include + +/*------------------------------------------------------------------ + * Platform definitions + */ +#ifdef CONFIG_JZ4740_PAVO +#include +#endif + +#ifdef CONFIG_JZ4740_LEO +#include +#endif + +#ifdef CONFIG_JZ4740_LYRA +#include +#endif + +#ifdef CONFIG_JZ4725_DIPPER +#include +#endif + +#ifdef CONFIG_JZ4720_VIRGO +#include +#endif + +/* Add other platform definition here ... */ + + +/*------------------------------------------------------------------ + * Follows are related to platform definitions + */ + +#include +#include + +#endif /* __ASM_JZ4740_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/misc.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/misc.h new file mode 100644 index 000000000..8f14a5ace --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/ops.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/ops.h new file mode 100644 index 000000000..6ff050a63 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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_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_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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/regs.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/regs.h new file mode 100644 index 000000000..07528bc41 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/regs.h @@ -0,0 +1,2392 @@ +/* + * linux/include/asm-mips/mach-jz4740/regs.h + * + * Ingenic's JZ4740 common include. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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_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_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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/serial.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/serial.h new file mode 100644 index 000000000..c4819b982 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/war.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4740/war.h new file mode 100644 index 000000000..3a5bc17e2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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 + */ +#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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/board-apus.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/board-apus.h new file mode 100644 index 000000000..d8274f9b2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/board-apus.h @@ -0,0 +1,124 @@ +/* + * linux/include/asm-mips/mach-jz4750/board-apus.h + * + * JZ4750-based APUS board ver 1.x definition. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 +#define GPIO_NET_INT (32*2+6) /* GPC6 */ +#define GPIO_AMPEN_N (32*2+7) + +/*==================================================================== + * 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 + +/*====================================================================== + * Analog input for VBAT is the battery voltage divided by CFG_PBAT_DIV. + */ +#define CFG_PBAT_DIV 4 + +/*====================================================================== + * 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) + +/*====================================================================== + * LCD backlight + */ +#define LCD_PWM_CHN 4 /* pwm channel */ +#define LCD_PWM_FULL 256 +/* 100 level: 0,1,...,100 */ +#define __lcd_set_backlight_level(n) \ +do { \ + __gpio_as_pwm(4); \ + __tcu_disable_pwm_output(LCD_PWM_CHN); \ + __tcu_stop_counter(LCD_PWM_CHN); \ + __tcu_init_pwm_output_high(LCD_PWM_CHN); \ + __tcu_set_pwm_output_shutdown_abrupt(LCD_PWM_CHN); \ + __tcu_select_clk_div1(LCD_PWM_CHN); \ + __tcu_mask_full_match_irq(LCD_PWM_CHN); \ + __tcu_mask_half_match_irq(LCD_PWM_CHN); \ + __tcu_set_count(LCD_PWM_CHN,0); \ + __tcu_set_full_data(LCD_PWM_CHN,__cpm_get_extalclk()/30000); \ + __tcu_set_half_data(LCD_PWM_CHN,__cpm_get_extalclk()/30000*n/(LCD_PWM_FULL-1)); \ + __tcu_enable_pwm_output(LCD_PWM_CHN); \ + __tcu_select_extalclk(LCD_PWM_CHN); \ + __tcu_start_counter(LCD_PWM_CHN); \ +} while (0) + +#define __lcd_close_backlight() \ +do { \ + __gpio_as_output(GPIO_LCD_PWM); \ + __gpio_clear_pin(GPIO_LCD_PWM); \ +} while (0) + +/* + * 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 */ + +#endif /* __ASM_JZ4750_APUS_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/board-fuwa.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/board-fuwa.h new file mode 100644 index 000000000..816a482f9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/board-fuwa.h @@ -0,0 +1,71 @@ +/* + * linux/include/asm-mips/mach-jz4750/board-fuwa.h + * + * JZ4750-based FUWA board ver 1.x definition. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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__ + +/*====================================================================== + * 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 121 /* GPD25, LCD_REV */ +#define GPIO_LED_EN 124 /* GPD28 */ +#define GPIO_NET_INT (32*4+20) /* GPE20 */ + +#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_JZ4750_FUWA_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/clock.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/clock.h new file mode 100644 index 000000000..5747e458c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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 /* 3.6864 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/dma.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/dma.h new file mode 100644 index 000000000..fc1f2c8e9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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 +#include /* need byte IO */ +#include /* And spinlocks */ +#include +#include + +/* + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/jz4750.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/jz4750.h new file mode 100644 index 000000000..9517780cd --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/jz4750.h @@ -0,0 +1,44 @@ +/* + * linux/include/asm-mips/mach-jz4750/jz4750.h + * + * JZ4750 common definition. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 +#include +#include +#include + +/*------------------------------------------------------------------ + * Platform definitions + */ +#ifdef CONFIG_JZ4750_FUWA +#include +#endif + +#ifdef CONFIG_JZ4750_APUS +#include +#endif + +/* Add other platform definition here ... */ + + +/*------------------------------------------------------------------ + * Follows are related to platform definitions + */ + +#include +#include + +#endif /* __ASM_JZ4750_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/misc.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/misc.h new file mode 100644 index 000000000..f6c75c9cf --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/ops.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/ops.h new file mode 100644 index 000000000..d28657c55 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/ops.h @@ -0,0 +1,3569 @@ +/* + * 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_PXSELS(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_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_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_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_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)<=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)< 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_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_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< + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/war.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750/war.h new file mode 100644 index 000000000..3a5bc17e2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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 + */ +#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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/board-cetus.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/board-cetus.h new file mode 100644 index 000000000..accf97a32 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/board-cetus.h @@ -0,0 +1,112 @@ +/* + * linux/include/asm-mips/mach-jz4750d/board-cetus.h + * + * JZ4750D-based CETUS board ver 1.x definition. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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_DISP_OFF_N (32*4+18) /* SDATO */ +#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) /* CHARG_DET_N, CIM_VSYNC */ +#define GPIO_LCD_VCC_EN_N (32*4+19) /* SDATI */ +#define GPIO_LCD_PWM (32*4+22) /* GPE22 PWM2 */ + +#define GPIO_UDC_HOTPLUG GPIO_USB_DETE +#define GPIO_AMPEN_N (32*4+5) + +/*==================================================================== + * 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 + +/*====================================================================== + * 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) + +/*====================================================================== + * LCD backlight + */ +#define LCD_PWM_CHN 2 /* pwm channel */ +#define LCD_PWM_FULL 256 +/* 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) + +/* + * 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 */ + +#endif /* __ASM_JZ4750d_CETUS_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/board-draco.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/board-draco.h new file mode 100644 index 000000000..9a000f899 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/board-draco.h @@ -0,0 +1,131 @@ +/* + * linux/include/asm-mips/mach-jz4750d/board-draco.h + * + * JZ4750D-based DRACO board ver 1.x definition. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 + +/*====================================================================== + * Analog input for VBAT is the battery voltage divided by CFG_PBAT_DIV. + */ +#define CFG_PBAT_DIV 1 + +/*====================================================================== + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/board-fuwa1.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/board-fuwa1.h new file mode 100644 index 000000000..5193188fd --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/board-fuwa1.h @@ -0,0 +1,131 @@ +/* + * linux/include/asm-mips/mach-jz4750d/board-fuwa1.h + * + * JZ4750D-based FUWA1 board ver 1.x definition. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 + +/*====================================================================== + * Analog input for VBAT is the battery voltage divided by CFG_PBAT_DIV. + */ +#define CFG_PBAT_DIV 1 + +/*====================================================================== + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/clock.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/clock.h new file mode 100644 index 000000000..4cb92c336 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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 +} + +/* 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_JZ4750D_CLOCK_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/dma.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/dma.h new file mode 100644 index 000000000..3cca84449 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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 +#include /* need byte IO */ +#include /* And spinlocks */ +#include +#include + +/* + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/jz4750d.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/jz4750d.h new file mode 100644 index 000000000..ac592264e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/jz4750d.h @@ -0,0 +1,43 @@ +/* + * linux/include/asm-mips/mach-jz4750d/jz4750d.h + * + * JZ4750 common definition. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 +#include +#include +#include + +/*------------------------------------------------------------------ + * Platform definitions + */ +#ifdef CONFIG_JZ4750D_FUWA1 +#include +#endif + +#ifdef CONFIG_JZ4750D_CETUS +#include +#endif +/* Add other platform definition here ... */ + + +/*------------------------------------------------------------------ + * Follows are related to platform definitions + */ + +#include +#include + +#endif /* __ASM_JZ4750_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/misc.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/misc.h new file mode 100644 index 000000000..cd0b13c8f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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: + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/ops.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/ops.h new file mode 100644 index 000000000..dca9c6d5e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/ops.h @@ -0,0 +1,3430 @@ +/* + * 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() ( 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_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_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_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)<=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)< 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< + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/war.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4750d/war.h new file mode 100755 index 000000000..3a5bc17e2 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/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 + */ +#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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/board-f4760.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/board-f4760.h new file mode 100644 index 000000000..3ec0cee71 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/board-f4760.h @@ -0,0 +1,94 @@ +/* + * linux/include/asm-mips/mach-jz4760/board-f4760.h + * + * JZ4760-based F4760 board ver 1.x definition. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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_JZ4760_F4760_H__ +#define __ASM_JZ4760_F4760_H__ + +#define CONFIG_FPGA /* fuwa is an FPGA board */ + +/*====================================================================== + * Frequencies of on-board oscillators + */ +#define JZ_EXTAL 24000000 /* Main extal freq: 12 MHz */ +#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ +#define CFG_DIV 1 /* For FPGA */ + + +/*====================================================================== + * 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*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 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_JZ4760_F4760_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/clock.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/clock.h new file mode 100644 index 000000000..41512ac4f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/clock.h @@ -0,0 +1,231 @@ +/* + * linux/include/asm-mips/mach-jz4760/clock.h + * + * JZ4760 clocks definition. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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_JZ4760_CLOCK_H__ +#define __ASM_JZ4760_CLOCK_H__ + +#ifndef JZ_EXTAL +#define JZ_EXTAL 12000000 /* 3.6864 MHz */ +#endif +#ifndef JZ_EXTAL2 +#define JZ_EXTAL2 32768 /* 32.768 KHz */ +#endif + +/* + * JZ4760 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*2/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*2/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_h0clk(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_extalclk0()/2; +#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_JZ4760_CLOCK_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/dma.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/dma.h new file mode 100644 index 000000000..d39aa6ea8 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/dma.h @@ -0,0 +1,306 @@ +/* + * linux/include/asm-mips/mach-jz4760/dma.h + * + * JZ4760 DMA definition. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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_JZ4760_DMA_H__ +#define __ASM_JZ4760_DMA_H__ + +#include +#include /* need byte IO */ +#include /* And spinlocks */ +#include +#include + +/* + * Descriptor structure for JZ4760 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_JZ4760_DMA_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/jz4760.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/jz4760.h new file mode 100644 index 000000000..898ac4610 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/jz4760.h @@ -0,0 +1,40 @@ +/* + * linux/include/asm-mips/mach-jz4760/jz4760.h + * + * JZ4760 common definition. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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_JZ4760_H__ +#define __ASM_JZ4760_H__ + +#include +#include +#include +#include + +/*------------------------------------------------------------------ + * Platform definitions + */ +#ifdef CONFIG_JZ4760_F4760 +#include +#endif + +/* Add other platform definition here ... */ + + +/*------------------------------------------------------------------ + * Follows are related to platform definitions + */ + +#include +#include + +#endif /* __ASM_JZ4760_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/misc.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/misc.h new file mode 100644 index 000000000..79f362fbc --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/misc.h @@ -0,0 +1,44 @@ +/* + * linux/include/asm-mips/mach-jz4760/misc.h + * + * Ingenic's JZ4760 common include. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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_JZ4760_MISC_H__ +#define __ASM_JZ4760_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_JZ4760_MISC_H__ */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/ops.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/ops.h new file mode 100644 index 000000000..4b7d10ecf --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/ops.h @@ -0,0 +1,3445 @@ +/* + * linux/include/asm-mips/mach-jz4760/ops.h + * + * JZ4760 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 __JZ4760_OPS_H__ +#define __JZ4760_OPS_H__ + +/* + * Definition of Module Operations + */ + +/*************************************************************************** + * EMC + ***************************************************************************/ +#define is_share_mode() (1) +/*************************************************************************** + * GPIO + ***************************************************************************/ + +//------------------------------------------------------ +// GPIO Pins Description +// +// PORT 0: +// +// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE +// 0 SD0 - - +// 1 SD1 - - +// 2 SD2 - - +// 3 SD3 - - +// 4 SD4 - - +// 5 SD5 - - +// 6 SD6 - - +// 7 SD7 - - +// 8 SD8 - - +// 9 SD9 - - +// 10 SD10 - - +// 11 SD11 - - +// 12 SD12 - - +// 13 SD13 - - +// 14 SD14 - - +// 15 SD15 - - +// 16 RD_ - - +// 17 WE_ - - +// 18 FRE_ MSC0_CLK SSI0_CLK +// 19 FWE_ MSC0_CMD SSI0_CE0_ +// 20 MSC0_D0 SSI0_DR - 1 +// 21 CS1_ MSC0_D1 SSI0_DT +// 22 CS2_ MSC0_D2 - +// 23 CS3_ - - +// 24 CS4_ - - +// 25 CS5_ - - +// 26 CS6_ - - +// 27 WAIT_ - - +// 28 DREQ0 - - +// 29 DACK0 OWI - +// 30 - - - 6 +// 31 - - - 7 + +//Note1. PA20: GPIO group A bit 20. If NAND flash is used, this pin must be used as NAND FRB. (NAND flash ready/busy) +//Note6. PA30: GPIO group A bit 30 can only be used as input and interrupt, no pull-up and pull-down. +//Note7. PA31: GPIO group A bit 31. No corresponding pin exists for this GPIO. It is only used to select the function between UART and JTAG, which share the same set of pins, by using register PASEL [31] +// When PASEL [31]=0, select JTAG function. +// When PASEL [31]=1, select UART function + +//------------------------------------------------------ +// PORT 1: +// +// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE +// 0 SA0 - - +// 1 SA1 - - +// 2 SA2 - - CL +// 3 SA3 - - AL +// 4 SA4 - - +// 5 SA5 - - +// 6 CIM_PCLK TSCLK - +// 7 CIM_HSYN TSFRM - +// 8 CIM_VSYN TSSTR - +// 9 CIM_MCLK TSFAIL - +// 10 CIM_D0 TSDI0 - +// 11 CIM_D1 TSDI1 - +// 12 CIM_D2 TSDI2 - +// 13 CIM_D3 TSDI3 - +// 14 CIM_D4 TSDI4 - +// 15 CIM_D5 TSDI5 - +// 16 CIM_D6 TSDI6 - +// 17 CIM_D7 TSDI7 - +// 18 - - - +// 19 - - - +// 20 MSC2_D0 SSI2_DR TSDI0 +// 21 MSC2_D1 SSI2_DT TSDI1 +// 22 TSDI2 - - +// 23 TSDI3 - - +// 24 TSDI4 - - +// 25 TSDI5 - - +// 26 TSDI6 - - +// 27 TSDI7 - - +// 28 MSC2_CLK SSI2_CLK TSCLK +// 29 MSC2_CMD SSI2_CE0_ TSSTR +// 30 MSC2_D2 SSI2_GPC TSFAIL +// 31 MSC2_D3 SSI2_CE1_ TSFRM + +//------------------------------------------------------ +// PORT 2: +// PIN/BIT N FUNC0 FUNC1 FUNC2 FUNC3 NOTE +// 0 LCD_B0 (O) LCD_REV (O) - - +// 1 LCD_B1 (O) LCD_PS (O) - - +// 2 LCD_B2 (O) - - - +// 3 LCD_B3 (O) - - - +// 4 LCD_B4 (O) - - - +// 5 LCD_B5 (O) - - - +// 6 LCD_B6 (O) - - - +// 7 LCD_B7 (O) - - - +// 8 LCD_PCLK (O) - - - +// 9 LCD_DE (O) - - - +// 10 LCD_G0 (O) LCD_SPL (O) - - +// 11 LCD_G1 (O) - - - +// 12 LCD_G2 (O) - - - +// 13 LCD_G3 (O) - - - +// 14 LCD_G4 (O) - - - +// 15 LCD_G5 (O) - - - +// 16 LCD_G6 (O) - - - +// 17 LCD_G7 (O) - - - +// 18 LCD_HSYN (IO) - - - +// 19 LCD_VSYN (IO) - - - +// 20 LCD_R0 (O) LCD_CLS (O) - - +// 21 LCD_R1 (O) - - - +// 22 LCD_R2 (O) - - - +// 23 LCD_R3 (O) - - - +// 24 LCD_R4 (O) - - - +// 25 LCD_R5 (O) - - - +// 26 LCD_R6 (O) - - - +// 27 LCD_R7 (O) - - - +// 28 UART2_RxD (I) - - - +// 29 UART2_CTS_ (I) - - - +// 30 UART2_TxD (O) - - - +// 31 UART2_RTS_ (O) - - - + +//------------------------------------------------------ +// PORT 3: +// +// PIN/BIT N FUNC0 FUNC1 FUNC2 FUNC3 NOTE +// 0 MII_TXD0 - - - +// 1 MII_TXD1 - - - +// 2 MII_TXD2 - - - +// 3 MII_TXD3 - - - +// 4 MII_TXEN - - - +// 5 MII_TXCLK(RMII_CLK) - - - +// 6 MII_COL - - - +// 7 MII_RXER - - - +// 8 MII_RXDV - - - +// 9 MII_RXCLK - - - +// 10 MII_RXD0 - - - +// 11 MII_RXD1 - - - +// 12 MII_RXD2 - - - +// 13 MII_RXD3 - - - +// 14 MII_CRS - - - +// 15 MII_MDC - - - +// 16 MII_MDIO - - - +// 17 BOOT_SEL0 - - - Note2,5 +// 18 BOOT_SEL1 - - - Note3,5 +// 19 BOOT_SEL2 - - - Note4,5 +// 20 MSC1_D0 SSI1_DR - - +// 21 MSC1_D1 SSI1_DT - - +// 22 MSC1_D2 SSI1_GPC - - +// 23 MSC1_D3 SSI1_CE1_ - - +// 24 MSC1_CLK SSI1_CLK - - +// 25 MSC1_CMD SSI1_CE0_ - - +// 26 UART1_RxD - - - +// 27 UART1_CTS_ - - - +// 28 UART1_TxD - - - +// 29 UART1_RTS_ - - - +// 30 I2C0_SDA - - - +// 31 I2C0_SCK - - - +// +// Note2. PD17: GPIO group D bit 17 is used as BOOT_SEL0 input during boot. +// Note3. PD18: GPIO group D bit 18 is used as BOOT_SEL1 input during boot. +// Note4. PD19: GPIO group D bit 19 is used as BOOT_SEL2 input during boot. +// Note5. BOOT_SEL2, BOOT_SEL1, BOOT_SEL0 are used to select boot source and function during the processor boot. +// +//------------------------------------------------------ +// PORT 4: +// +// PIN/BIT N FUNC0 FUNC1 FUNC2 FUNC3 NOTE +// 0 PWM0 - - - +// 1 PWM1 - - - +// 2 PWM2 SYNC - - +// 3 PWM3 UART3_RxD BCLK - +// 4 PWM4 - - - +// 5 PWM5 UART3_TxD SCLK_RSTN - +// 6 SDATI - - - +// 7 SDATO - - - +// 8 UART3_CTS_ - - - +// 9 UART3_RTS_ - - - +// 10 - - - - +// 11 SDATO1 - - - +// 12 SDATO2 - - - +// 13 SDATO3 - - - +// 14 SSI0_DR SSI1_DR SSI2_DR - +// 15 SSI0_CLK SI1_CLK SSI2_CLK - +// 16 SSI0_CE0_ SI1_CE0_ SSI2_CE0_ - +// 17 SSI0_DT SSI1_DT SSI2_DT - +// 18 SSI0_CE1_ SSI1_CE1_ SSI2_CE1_ - +// 19 SSI0_GPC SSI1_GPC SSI2_GPC - +// 20 MSC0_D0 MSC1_D0 MSC2_D0 - +// 21 MSC0_D1 MSC1_D1 MSC2_D1 - +// 22 MSC0_D2 MSC1_D2 MSC2_D2 - +// 23 MSC0_D3 MSC1_D3 MSC2_D3 - +// 24 MSC0_CLK MSC1_CLK MSC2_CLK - +// 25 MSC0_CMD MSC1_CMD MSC2_CMD - +// 26 MSC0_D4 MSC0_D4 MSC0_D4 PS2_MCLK +// 27 MSC0_D5 MSC0_D5 MSC0_D5 PS2_MDATA +// 28 MSC0_D6 MSC0_D6 MSC0_D6 PS2_KCLK +// 29 MSC0_D7 MSC0_D7 MSC0_D7 PS2_KDATA +// 30 I2C1_SDA SCC_DATA - - +// 31 I2C1_SCK SCC_CLK - - +// +//------------------------------------------------------ +// PORT 5: +// +// PIN/BIT N FUNC0 FUNC1 FUNC2 FUNC3 NOTE +// 0 UART0_RxD GPS_CLK - - +// 1 UART0_CTS_ GPS_MAG - - +// 2 UART0_TxD GPS_SIG - - +// 3 UART0_RTS_ - - - +// +////////////////////////////////////////////////////////// + +/*---------------------------------------------------------------- + * 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) + +#define __gpio_as_func3(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_PXSELS(p) = (1 << o); \ +} while (0) + + +/* + * MII_TXD0- D3 MII_TXEN MII_TXCLK MII_COL + * MII_RXER MII_RXDV MII_RXCLK MII_RXD0 - D3 + * MII_CRS MII_MDC MII_MDIO + */ + +#define __gpio_as_eth() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x0001ffff; \ + REG_GPIO_PXTRGC(3) = 0x0001ffff; \ + REG_GPIO_PXSELC(3) = 0x0001ffff; \ + REG_GPIO_PXPES(3) = 0x0001ffff; \ +} while (0) + +/* + * UART0_TxD, UART0_RxD + */ +#define __gpio_as_uart0() \ +do { \ + REG_GPIO_PXFUNS(5) = 0x00000005; \ + REG_GPIO_PXTRGC(5) = 0x00000005; \ + REG_GPIO_PXSELC(5) = 0x00000005; \ + REG_GPIO_PXPES(5) = 0x00000005; \ +} while (0) + +/* + * UART0_TxD, UART0_RxD, UART0_CTS, UART0_RTS + */ +#define __gpio_as_uart0_ctsrts() \ +do { \ + REG_GPIO_PXFUNS(5) = 0x0000000f; \ + REG_GPIO_PXTRGC(5) = 0x0000000f; \ + REG_GPIO_PXSELC(5) = 0x0000000f; \ + REG_GPIO_PXPES(5) = 0x0000000f; \ +} while (0) + +/* + * UART1_TxD, UART1_RxD + */ +#define __gpio_as_uart1() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x14000000; \ + REG_GPIO_PXTRGC(3) = 0x14000000; \ + REG_GPIO_PXSELC(3) = 0x14000000; \ + REG_GPIO_PXPES(3) = 0x14000000; \ +} while (0) + +/* + * UART1_TxD, UART1_RxD, UART1_CTS, UART1_RTS + */ +#define __gpio_as_uart1_ctsrts() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x3c000000; \ + REG_GPIO_PXTRGC(3) = 0x3c000000; \ + REG_GPIO_PXSELC(3) = 0x3c000000; \ + REG_GPIO_PXPES(3) = 0x3c000000; \ +} while (0) + + +/* + * UART2_TxD, UART2_RxD + */ +#define __gpio_as_uart2() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x50000000; \ + REG_GPIO_PXTRGC(2) = 0x50000000; \ + REG_GPIO_PXSELC(2) = 0x50000000; \ + REG_GPIO_PXPES(2) = 0x50000000; \ +} while (0) + +/* + * UART2_TxD, UART2_RxD, UART2_CTS, UART2_RTS + */ +#define __gpio_as_uart2_ctsrts() \ +do { \ + REG_GPIO_PXFUNS(2) = 0xf0000000; \ + REG_GPIO_PXTRGC(2) = 0xf0000000; \ + REG_GPIO_PXSELC(2) = 0xf0000000; \ + REG_GPIO_PXPES(2) = 0xf0000000; \ +} while (0) + + +/* + * SD0 ~ SD7, CS1#, CLE, ALE, FRE#, FWE#, FRB# + * @n: chip select number(1 ~ 6) + */ +#define __gpio_as_nand_8bit(n) \ +do { \ + \ + REG_GPIO_PXFUNS(0) = 0x002c00ff; /* SD0 ~ SD7, CS1#, FRE#, FWE# */ \ + REG_GPIO_PXSELC(0) = 0x002c00ff; \ + REG_GPIO_PXPES(0) = 0x002c00ff; \ + REG_GPIO_PXFUNS(1) = 0x0000000c; /* CLE(SA2), ALE(SA3) */ \ + REG_GPIO_PXSELC(1) = 0x0000000c; \ + REG_GPIO_PXPES(1) = 0x0000000c; \ + \ + REG_GPIO_PXFUNS(0) = 0x00200000 << ((n)-1); /* CSn */ \ + REG_GPIO_PXSELC(0) = 0x00200000 << ((n)-1); \ + REG_GPIO_PXPES(0) = 0x00200000 << ((n)-1); \ + \ + REG_GPIO_PXFUNC(0) = 0x00100000; /* FRB#(input) */ \ + REG_GPIO_PXSELC(0) = 0x00100000; \ + REG_GPIO_PXDIRC(0) = 0x00100000; \ + REG_GPIO_PXPES(0) = 0x00100000; \ +} 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) + +/* + * LCD_D0~LCD_D7, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE + */ +#define __gpio_as_lcd_8bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x000c03ff; \ + REG_GPIO_PXTRGC(2) = 0x000c03ff; \ + REG_GPIO_PXSELC(2) = 0x000c03ff; \ + REG_GPIO_PXPES(2) = 0x000c03ff; \ +} while (0) + +/* + * LCD_R3~LCD_R7, LCD_G2~LCD_G7, LCD_B3~LCD_B7, + * LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE + */ +#define __gpio_as_lcd_16bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x0f8ff3f8; \ + REG_GPIO_PXTRGC(2) = 0x0f8ff3f8; \ + REG_GPIO_PXSELC(2) = 0x0f8ff3f8; \ + REG_GPIO_PXPES(2) = 0x0f8ff3f8; \ +} 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(2) = 0x0fcff3fc; \ + REG_GPIO_PXTRGC(2) = 0x0fcff3fc; \ + REG_GPIO_PXSELC(2) = 0x0fcff3fc; \ + REG_GPIO_PXPES(2) = 0x0fcff3fc; \ +} 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(2) = 0x0fffffff; \ + REG_GPIO_PXTRGC(2) = 0x0fffffff; \ + REG_GPIO_PXSELC(2) = 0x0fffffff; \ + REG_GPIO_PXPES(2) = 0x0fffffff; \ +} while (0) + +/* + * LCD_CLS, LCD_SPL, LCD_PS, LCD_REV + */ +#define __gpio_as_lcd_special() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x0fffffff; \ + REG_GPIO_PXTRGC(2) = 0x0fffffff; \ + REG_GPIO_PXSELC(2) = 0x0feffbfc; \ + REG_GPIO_PXSELS(2) = 0x00100403; \ + REG_GPIO_PXPES(2) = 0x0fffffff; \ +} while (0) + +/* + * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC + */ +#define __gpio_as_cim() \ +do { \ + REG_GPIO_PXFUNS(1) = 0x0003ffc0; \ + REG_GPIO_PXTRGC(1) = 0x0003ffc0; \ + REG_GPIO_PXSELC(1) = 0x0003ffc0; \ + REG_GPIO_PXPES(1) = 0x0003ffc0; \ +} 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_PXSELC(1) = 0xfc000000; \ + REG_GPIO_PXPES(1) = 0xfc000000; \ +} while (0) + +/* Port B + * MSC2_CMD, MSC2_CLK, MSC2_D0 ~ MSC2_D3 + */ +#define __gpio_as_msc2_4bit_1() \ +do { \ + REG_GPIO_PXFUNS(1) = 0xf0300000; \ + REG_GPIO_PXTRGC(1) = 0xf0300000; \ + REG_GPIO_PXSELC(1) = 0xf0300000; \ + REG_GPIO_PXPES(1) = 0xf0300000; \ +} 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 */ + +/* + * TSCLK, TSSTR, TSFRM, TSFAIL, TSDI0~7 + */ +#define __gpio_as_tssi_1() \ +do { \ + REG_GPIO_PXFUNS(1) = 0x0003ffc0; \ + REG_GPIO_PXTRGC(1) = 0x0003ffc0; \ + REG_GPIO_PXSELS(1) = 0x0003ffc0; \ + REG_GPIO_PXPES(1) = 0x0003ffc0; \ +} while (0) + +/* + * TSCLK, TSSTR, TSFRM, TSFAIL, TSDI0~7 + */ +#define __gpio_as_tssi_2() \ +do { \ + REG_GPIO_PXFUNS(1) = 0xfff00000; \ + REG_GPIO_PXTRGC(1) = 0x0fc00000; \ + REG_GPIO_PXTRGS(1) = 0xf0300000; \ + REG_GPIO_PXSELC(1) = 0xfff00000; \ + REG_GPIO_PXPES(1) = 0xfff00000; \ +} while (0) + +/* + * SSI_CE0, SSI_CE1, SSI_GPC, SSI_CLK, SSI_DT, SSI_DR + */ +#define __gpio_as_ssi() \ +do { \ + REG_GPIO_PXFUNS(0) = 0x002c0000; /* SSI0_CE0, SSI0_CLK, SSI0_DT */ \ + REG_GPIO_PXTRGS(0) = 0x002c0000; \ + REG_GPIO_PXSELC(0) = 0x002c0000; \ + REG_GPIO_PXPES(0) = 0x002c0000; \ + \ + REG_GPIO_PXFUNS(0) = 0x00100000; /* SSI0_DR */ \ + REG_GPIO_PXTRGC(0) = 0x00100000; \ + REG_GPIO_PXSELS(0) = 0x00100000; \ + REG_GPIO_PXPES(0) = 0x00100000; \ +} 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) + +/* Port B + * SSI2_CE0, SSI2_CE2, SSI2_GPC, SSI2_CLK, SSI2_DT, SSI12_DR + */ +#define __gpio_as_ssi2_1() \ +do { \ + REG_GPIO_PXFUNS(5) = 0xf0300000; \ + REG_GPIO_PXTRGC(5) = 0xf0300000; \ + REG_GPIO_PXSELS(5) = 0xf0300000; \ + REG_GPIO_PXPES(5) = 0xf0300000; \ +} 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() + + +//------------------------------------------- +// 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_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_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_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)<=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)< 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 (I2C0_BASE + 0x000) +#define I2C_CR (I2C0_BASE + 0x004) +#define I2C_SR (I2C0_BASE + 0x008) +#define I2C_GR (I2C0_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) (SSI0_BASE + 0x000 + (n)*0x2000) +#define SSI_CR0(n) (SSI0_BASE + 0x004 + (n)*0x2000) +#define SSI_CR1(n) (SSI0_BASE + 0x008 + (n)*0x2000) +#define SSI_SR(n) (SSI0_BASE + 0x00C + (n)*0x2000) +#define SSI_ITR(n) (SSI0_BASE + 0x010 + (n)*0x2000) +#define SSI_ICR(n) (SSI0_BASE + 0x014 + (n)*0x2000) +#define SSI_GR(n) (SSI0_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) (MSC0_BASE + (n)*0x1000 + 0x000) +#define MSC_STAT(n) (MSC0_BASE + (n)*0x1000 + 0x004) +#define MSC_CLKRT(n) (MSC0_BASE + (n)*0x1000 + 0x008) +#define MSC_CMDAT(n) (MSC0_BASE + (n)*0x1000 + 0x00C) +#define MSC_RESTO(n) (MSC0_BASE + (n)*0x1000 + 0x010) +#define MSC_RDTO(n) (MSC0_BASE + (n)*0x1000 + 0x014) +#define MSC_BLKLEN(n) (MSC0_BASE + (n)*0x1000 + 0x018) +#define MSC_NOB(n) (MSC0_BASE + (n)*0x1000 + 0x01C) +#define MSC_SNOB(n) (MSC0_BASE + (n)*0x1000 + 0x020) +#define MSC_IMASK(n) (MSC0_BASE + (n)*0x1000 + 0x024) +#define MSC_IREG(n) (MSC0_BASE + (n)*0x1000 + 0x028) +#define MSC_CMD(n) (MSC0_BASE + (n)*0x1000 + 0x02C) +#define MSC_ARG(n) (MSC0_BASE + (n)*0x1000 + 0x030) +#define MSC_RES(n) (MSC0_BASE + (n)*0x1000 + 0x034) +#define MSC_RXFIFO(n) (MSC0_BASE + (n)*0x1000 + 0x038) +#define MSC_TXFIFO(n) (MSC0_BASE + (n)*0x1000 + 0x03C) +#define MSC_LPM(n) (MSC0_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) + +/************************************************************************* + * DDRC (DDR Controller) + *************************************************************************/ +#define DDRC_ST (DDRC_BASE + 0x0) /* DDR Status Register */ +#define DDRC_CFG (DDRC_BASE + 0x4) /* DDR Configure Register */ +#define DDRC_CTRL (DDRC_BASE + 0x8) /* DDR Control Register */ +#define DDRC_LMR (DDRC_BASE + 0xc) /* DDR Load-Mode-Register */ +#define DDRC_TIMING1 (DDRC_BASE + 0x10) /* DDR Timing Config Register 1 */ +#define DDRC_TIMING2 (DDRC_BASE + 0x14) /* DDR Timing Config Register 2 */ +#define DDRC_REFCNT (DDRC_BASE + 0x18) /* DDR Auto-Refresh Counter */ +#define DDRC_DQS (DDRC_BASE + 0x1c) /* DDR DQS Delay Control Register */ +#define DDRC_DQS_ADJ (DDRC_BASE + 0x20) /* DDR DQS Delay Adjust Register */ +#define DDRC_MMAP0 (DDRC_BASE + 0x24) /* DDR Memory Map Config Register */ +#define DDRC_MMAP1 (DDRC_BASE + 0x28) /* DDR Memory Map Config Register */ + +/* DDRC Register */ +#define REG_DDRC_ST REG32(DDRC_ST) +#define REG_DDRC_CFG REG32(DDRC_CFG) +#define REG_DDRC_CTRL REG32(DDRC_CTRL) +#define REG_DDRC_LMR REG32(DDRC_LMR) +#define REG_DDRC_TIMING1 REG32(DDRC_TIMING1) +#define REG_DDRC_TIMING2 REG32(DDRC_TIMING2) +#define REG_DDRC_REFCNT REG32(DDRC_REFCNT) +#define REG_DDRC_DQS REG32(DDRC_DQS) +#define REG_DDRC_DQS_ADJ REG32(DDRC_DQS_ADJ) +#define REG_DDRC_MMAP0 REG32(DDRC_MMAP0) +#define REG_DDRC_MMAP1 REG32(DDRC_MMAP1) + +/* DDRC Status Register */ +#define DDRC_ST_ENDIAN (1 << 7) /* 0 Little data endian + 1 Big data endian */ +#define DDRC_ST_DPDN (1 << 5) /* 0 DDR memory is NOT in deep-power-down state + 1 DDR memory is in deep-power-down state */ +#define DDRC_ST_PDN (1 << 4) /* 0 DDR memory is NOT in power-down state + 1 DDR memory is in power-down state */ +#define DDRC_ST_AREF (1 << 3) /* 0 DDR memory is NOT in auto-refresh state + 1 DDR memory is in auto-refresh state */ +#define DDRC_ST_SREF (1 << 2) /* 0 DDR memory is NOT in self-refresh state + 1 DDR memory is in self-refresh state */ +#define DDRC_ST_CKE1 (1 << 1) /* 0 CKE1 Pin is low + 1 CKE1 Pin is high */ +#define DDRC_ST_CKE0 (1 << 0) /* 0 CKE0 Pin is low + 1 CKE0 Pin is high */ + +/* DDRC Configure Register */ +#define DDRC_CFG_MSEL_BIT 16 /* Mask delay select */ +#define DDRC_CFG_MSEL_MASK (0x3 << DDRC_CFG_MSEL_BIT) + #define DDRC_CFG_MSEL_0 (0 << DDRC_CFG_MSEL_BIT) /* 00 No delay */ + #define DDRC_CFG_MSEL_1 (1 << DDRC_CFG_MSEL_BIT) /* 01 delay 1 tCK */ + #define DDRC_CFG_MSEL_2 (2 << DDRC_CFG_MSEL_BIT) /* 10 delay 2 tCK */ + #define DDRC_CFG_MSEL_3 (3 << DDRC_CFG_MSEL_BIT) /* 11 delay 3 tCK */ + +#define DDRC_CFG_HL (1 << 15) /* 0: no extra delay 1: one extra half tCK delay */ + +#define DDRC_CFG_ROW1_BIT 27 /* Row Address width. */ +#define DDRC_CFG_COL1_BIT 25 /* Row Address width. */ +#define DDRC_CFG_BA1_BIT (1 << 24) +#define DDRC_CFG_IMBA_BIT (1 << 23) +#define DDRC_CFG_BTRUN (1 << 21) + +#define DDRC_CFG_TYPE_BIT 12 +#define DDRC_CFG_TYPE_MASK (0x7 << DDRC_CFG_TYPE_BIT) +#define DDRC_CFG_TYPE_DDR1 (2 << DDRC_CFG_TYPE_BIT) +#define DDRC_CFG_TYPE_MDDR (3 << DDRC_CFG_TYPE_BIT) +#define DDRC_CFG_TYPE_DDR2 (4 << DDRC_CFG_TYPE_BIT) + +#define DDRC_CFG_ROW_BIT 10 /* Row Address width. */ +#define DDRC_CFG_ROW_MASK (0x3 << DDRC_CFG_ROW_BIT) + #define DDRC_CFG_ROW_13 (0 << DDRC_CFG_ROW_BIT) /* 13-bit row address is used */ + #define DDRC_CFG_ROW_14 (1 << DDRC_CFG_ROW_BIT) /* 14-bit row address is used */ + +#define DDRC_CFG_COL_BIT 8 /* Column Address width. + Specify the Column address width of external DDR. */ +#define DDRC_CFG_COL_MASK (0x3 << DDRC_CFG_COL_BIT) + #define DDRC_CFG_COL_9 (0 << DDRC_CFG_COL_BIT) /* 9-bit Column address is used */ + #define DDRC_CFG_COL_10 (1 << DDRC_CFG_COL_BIT) /* 10-bit Column address is used */ + +#define DDRC_CFG_CS1EN (1 << 7) /* 0 DDR Pin CS1 un-used + 1 There're DDR memory connected to CS1 */ +#define DDRC_CFG_CS0EN (1 << 6) /* 0 DDR Pin CS0 un-used + 1 There're DDR memory connected to CS0 */ + +#define DDRC_CFG_TSEL_BIT 18 /* Read delay select */ +#define DDRC_CFG_TSEL_MASK (0x3 << DDRC_CFG_TSEL_BIT) +#define DDRC_CFG_TSEL_0 (0 << DDRC_CFG_TSEL_BIT) /* No delay */ +#define DDRC_CFG_TSEL_1 (1 << DDRC_CFG_TSEL_BIT) /* delay 1 tCK */ +#define DDRC_CFG_TSEL_2 (2 << DDRC_CFG_TSEL_BIT) /* delay 2 tCK */ +#define DDRC_CFG_TSEL_3 (3 << DDRC_CFG_TSEL_BIT) /* delay 3 tCK */ + +#define DDRC_CFG_CL_BIT 2 /* CAS Latency */ +#define DDRC_CFG_CL_MASK (0xf << DDRC_CFG_CL_BIT) +#define DDRC_CFG_CL_3 (0 << DDRC_CFG_CL_BIT) /* CL = 3 tCK */ +#define DDRC_CFG_CL_4 (1 << DDRC_CFG_CL_BIT) /* CL = 4 tCK */ +#define DDRC_CFG_CL_5 (2 << DDRC_CFG_CL_BIT) /* CL = 5 tCK */ +#define DDRC_CFG_CL_6 (3 << DDRC_CFG_CL_BIT) /* CL = 6 tCK */ + +#define DDRC_CFG_BA (1 << 1) /* 0 4 bank device, Pin ba[1:0] valid, ba[2] un-used + 1 8 bank device, Pin ba[2:0] valid*/ +#define DDRC_CFG_DW (1 << 0) /*0 External memory data width is 16-bit + 1 External memory data width is 32-bit */ + +/* DDRC Control Register */ +#define DDRC_CTRL_ACTPD (1 << 15) /* 0 Precharge all banks before entering power-down + 1 Do not precharge banks before entering power-down */ +#define DDRC_CTRL_PDT_BIT 12 /* Power-Down Timer */ +#define DDRC_CTRL_PDT_MASK (0x7 << DDRC_CTRL_PDT_BIT) + #define DDRC_CTRL_PDT_DIS (0 << DDRC_CTRL_PDT_BIT) /* power-down disabled */ + #define DDRC_CTRL_PDT_8 (1 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 8 tCK idle */ + #define DDRC_CTRL_PDT_16 (2 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 16 tCK idle */ + #define DDRC_CTRL_PDT_32 (3 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 32 tCK idle */ + #define DDRC_CTRL_PDT_64 (4 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 64 tCK idle */ + #define DDRC_CTRL_PDT_128 (5 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 128 tCK idle */ + +#define DDRC_CTRL_PRET_BIT 8 /* Precharge Timer */ +#define DDRC_CTRL_PRET_MASK (0x7 << DDRC_CTRL_PRET_BIT) /* */ + #define DDRC_CTRL_PRET_DIS (0 << DDRC_CTRL_PRET_BIT) /* PRET function Disabled */ + #define DDRC_CTRL_PRET_8 (1 << DDRC_CTRL_PRET_BIT) /* Precharge active bank after 8 tCK idle */ + #define DDRC_CTRL_PRET_16 (2 << DDRC_CTRL_PRET_BIT) /* Precharge active bank after 16 tCK idle */ + #define DDRC_CTRL_PRET_32 (3 << DDRC_CTRL_PRET_BIT) /* Precharge active bank after 32 tCK idle */ + #define DDRC_CTRL_PRET_64 (4 << DDRC_CTRL_PRET_BIT) /* Precharge active bank after 64 tCK idle */ + #define DDRC_CTRL_PRET_128 (5 << DDRC_CTRL_PRET_BIT) /* Precharge active bank after 128 tCK idle */ + +#define DDRC_CTRL_SR (1 << 5) /* 1 Drive external DDR device entering self-refresh mode + 0 Drive external DDR device exiting self-refresh mode */ +#define DDRC_CTRL_UNALIGN (1 << 4) /* 0 Disable unaligned transfer on AXI BUS + 1 Enable unaligned transfer on AXI BUS */ +#define DDRC_CTRL_ALH (1 << 3) /* Advanced Latency Hiding: + 0 Disable ALH + 1 Enable ALH */ +#define DDRC_CTRL_RDC (1 << 2) /* 0 dclk clock frequency is lower than 60MHz + 1 dclk clock frequency is higher than 60MHz */ +#define DDRC_CTRL_CKE (1 << 1) /* 0 Not set CKE Pin High + 1 Set CKE Pin HIGH */ +#define DDRC_CTRL_RESET (1 << 0) /* 0 End resetting ddrc_controller + 1 Resetting ddrc_controller */ + +/* DDRC Load-Mode-Register */ +#define DDRC_LMR_DDR_ADDR_BIT 16 /* When performing a DDR command, DDRC_ADDR[13:0] + corresponding to external DDR address Pin A[13:0] */ +#define DDRC_LMR_DDR_ADDR_MASK (0xff << DDRC_LMR_DDR_ADDR_BIT) + +#define DDRC_LMR_BA_BIT 8 /* When performing a DDR command, BA[2:0] + corresponding to external DDR address Pin BA[2:0]. */ +#define DDRC_LMR_BA_MASK (0x7 << DDRC_LMR_BA_BIT) + /* For DDR2 */ + #define DDRC_LMR_BA_MRS (0 << DDRC_LMR_BA_BIT) /* Mode Register set */ + #define DDRC_LMR_BA_EMRS1 (1 << DDRC_LMR_BA_BIT) /* Extended Mode Register1 set */ + #define DDRC_LMR_BA_EMRS2 (2 << DDRC_LMR_BA_BIT) /* Extended Mode Register2 set */ + #define DDRC_LMR_BA_EMRS3 (3 << DDRC_LMR_BA_BIT) /* Extended Mode Register3 set */ + /* For mobile DDR */ + #define DDRC_LMR_BA_M_MRS (0 << DDRC_LMR_BA_BIT) /* Mode Register set */ + #define DDRC_LMR_BA_M_EMRS (2 << DDRC_LMR_BA_BIT) /* Extended Mode Register set */ + #define DDRC_LMR_BA_M_SR (1 << DDRC_LMR_BA_BIT) /* Status Register set */ + +#define DDRC_LMR_CMD_BIT 4 +#define DDRC_LMR_CMD_MASK (0x3 << DDRC_LMR_CMD_BIT) + #define DDRC_LMR_CMD_PREC (0 << DDRC_LMR_CMD_BIT)/* Precharge one bank/All banks */ + #define DDRC_LMR_CMD_AUREF (1 << DDRC_LMR_CMD_BIT)/* Auto-Refresh */ + #define DDRC_LMR_CMD_LMR (2 << DDRC_LMR_CMD_BIT)/* Load Mode Register */ + +#define DDRC_LMR_START (1 << 0) /* 0 No command is performed + 1 On the posedge of START, perform a command + defined by CMD field */ + +/* DDRC Mode Register Set */ +#define DDR_MRS_PD_BIT (1 << 10) /* Active power down exit time */ +#define DDR_MRS_PD_MASK (1 << DDR_MRS_PD_BIT) + #define DDR_MRS_PD_FAST_EXIT (0 << 10) + #define DDR_MRS_PD_SLOW_EXIT (1 << 10) +#define DDR_MRS_WR_BIT (1 << 9) /* Write Recovery for autoprecharge */ +#define DDR_MRS_WR_MASK (7 << DDR_MRS_WR_BIT) +#define DDR_MRS_DLL_RST (1 << 8) /* DLL Reset */ +#define DDR_MRS_TM_BIT 7 /* Operating Mode */ +#define DDR_MRS_TM_MASK (1 << DDR_MRS_OM_BIT) + #define DDR_MRS_TM_NORMAL (0 << DDR_MRS_OM_BIT) + #define DDR_MRS_TM_TEST (1 << DDR_MRS_OM_BIT) +#define DDR_MRS_CAS_BIT 4 /* CAS Latency */ +#define DDR_MRS_CAS_MASK (7 << DDR_MRS_CAS_BIT) +#define DDR_MRS_BT_BIT 3 /* Burst Type */ +#define DDR_MRS_BT_MASK (1 << DDR_MRS_BT_BIT) + #define DDR_MRS_BT_SEQ (0 << DDR_MRS_BT_BIT) /* Sequential */ + #define DDR_MRS_BT_INT (1 << DDR_MRS_BT_BIT) /* Interleave */ +#define DDR_MRS_BL_BIT 0 /* Burst Length */ +#define DDR_MRS_BL_MASK (7 << DDR_MRS_BL_BIT) + #define DDR_MRS_BL_4 (2 << DDR_MRS_BL_BIT) + #define DDR_MRS_BL_8 (3 << DDR_MRS_BL_BIT) + +/* DDRC Extended Mode Register1 Set */ +#define DDR_EMRS1_QOFF (1<<12) /* 0 Output buffer enabled + 1 Output buffer disabled */ +#define DDR_EMRS1_RDQS_EN (1<<11) /* 0 Disable + 1 Enable */ +#define DDR_EMRS1_DQS_DIS (1<<10) /* 0 Enable + 1 Disable */ +#define DDR_EMRS1_OCD_BIT 7 /* Additive Latency 0 -> 6 */ +#define DDR_EMRS1_OCD_MASK (0x7 << DDR_EMRS1_OCD_BIT) + #define DDR_EMRS1_OCD_EXIT (0 << DDR_EMRS1_OCD_BIT) + #define DDR_EMRS1_OCD_D0 (1 << DDR_EMRS1_OCD_BIT) + #define DDR_EMRS1_OCD_D1 (2 << DDR_EMRS1_OCD_BIT) + #define DDR_EMRS1_OCD_ADJ (4 << DDR_EMRS1_OCD_BIT) + #define DDR_EMRS1_OCD_DFLT (7 << DDR_EMRS1_OCD_BIT) +#define DDR_EMRS1_AL_BIT 3 /* Additive Latency 0 -> 6 */ +#define DDR_EMRS1_AL_MASK (7 << DDR_EMRS1_AL_BIT) +#define DDR_EMRS1_RTT_BIT 2 /* */ +#define DDR_EMRS1_RTT_MASK (0x11 << DDR_EMRS1_DIC_BIT) /* Bit 6, Bit 2 */ +#define DDR_EMRS1_DIC_BIT 1 /* Output Driver Impedence Control */ +#define DDR_EMRS1_DIC_MASK (1 << DDR_EMRS1_DIC_BIT) /* 100% */ + #define DDR_EMRS1_DIC_NORMAL (0 << DDR_EMRS1_DIC_BIT) /* 60% */ + #define DDR_EMRS1_DIC_HALF (1 << DDR_EMRS1_DIC_BIT) +#define DDR_EMRS1_DLL_BIT 0 /* DLL Enable */ +#define DDR_EMRS1_DLL_MASK (1 << DDR_EMRS1_DLL_BIT) + #define DDR_EMRS1_DLL_EN (0 << DDR_EMRS1_DLL_BIT) + #define DDR_EMRS1_DLL_DIS (1 << DDR_EMRS1_DLL_BIT) + +/* Mobile SDRAM Extended Mode Register */ +#define DDR_EMRS_DS_BIT 5 /* Driver strength */ +#define DDR_EMRS_DS_MASK (7 << DDR_EMRS_DS_BIT) + #define DDR_EMRS_DS_FULL (0 << DDR_EMRS_DS_BIT) /*Full*/ + #define DDR_EMRS_DS_HALF (1 << DDR_EMRS_DS_BIT) /*1/2 Strength*/ + #define DDR_EMRS_DS_QUTR (2 << DDR_EMRS_DS_BIT) /*1/4 Strength*/ + #define DDR_EMRS_DS_OCTANT (3 << DDR_EMRS_DS_BIT) /*1/8 Strength*/ + #define DDR_EMRS_DS_QUTR3 (4 << DDR_EMRS_DS_BIT) /*3/4 Strength*/ + +#define DDR_EMRS_PRSR_BIT 0 /* Partial Array Self Refresh */ +#define DDR_EMRS_PRSR_MASK (7 << DDR_EMRS_PRSR_BIT) + #define DDR_EMRS_PRSR_ALL (0 << DDR_EMRS_PRSR_BIT) /*All Banks*/ + #define DDR_EMRS_PRSR_HALF_TL (1 << DDR_EMRS_PRSR_BIT) /*Half of Total Bank*/ + #define DDR_EMRS_PRSR_QUTR_TL (2 << DDR_EMRS_PRSR_BIT) /*Quarter of Total Bank*/ + #define DDR_EMRS_PRSR_HALF_B0 (5 << DDR_EMRS_PRSR_BIT) /*Half of Bank0*/ + #define DDR_EMRS_PRSR_QUTR_B0 (6 << DDR_EMRS_PRSR_BIT) /*Quarter of Bank0*/ + + +/* DDRC Timing Config Register 1 */ +#define DDRC_TIMING1_TRAS_BIT 28 /* ACTIVE to PRECHARGE command period (2 * tRAS + 1) */ +#define DDRC_TIMING1_TRAS_MASK (0xf << DDRC_TIMING1_TRAS_BIT) + + +#define DDRC_TIMING1_TRTP_BIT 24 /* READ to PRECHARGE command period. */ +#define DDRC_TIMING1_TRTP_MASK (0x3 << DDRC_TIMING1_TRTP_BIT) + +#define DDRC_TIMING1_TRP_BIT 20 /* PRECHARGE command period. */ +#define DDRC_TIMING1_TRP_MASK (0x7 << DDRC_TIMING1_TRP_BIT) + +#define DDRC_TIMING1_TRCD_BIT 16 /* ACTIVE to READ or WRITE command period. */ +#define DDRC_TIMING1_TRCD_MASK (0x7 << DDRC_TIMING1_TRCD_BIT) + +#define DDRC_TIMING1_TRC_BIT 12 /* ACTIVE to ACTIVE command period. */ +#define DDRC_TIMING1_TRC_MASK (0xf << DDRC_TIMING1_TRC_BIT) + +#define DDRC_TIMING1_TRRD_BIT 8 /* ACTIVE bank A to ACTIVE bank B command period. */ +#define DDRC_TIMING1_TRRD_MASK (0x3 << DDRC_TIMING1_TRRD_BIT) +#define DDRC_TIMING1_TRRD_DISABLE (0 << DDRC_TIMING1_TRRD_BIT) +#define DDRC_TIMING1_TRRD_2 (1 << DDRC_TIMING1_TRRD_BIT) +#define DDRC_TIMING1_TRRD_3 (2 << DDRC_TIMING1_TRRD_BIT) +#define DDRC_TIMING1_TRRD_4 (3 << DDRC_TIMING1_TRRD_BIT) + +#define DDRC_TIMING1_TWR_BIT 4 /* WRITE Recovery Time defined by register MR of DDR2 memory */ +#define DDRC_TIMING1_TWR_MASK (0x7 << DDRC_TIMING1_TWR_BIT) + #define DDRC_TIMING1_TWR_1 (0 << DDRC_TIMING1_TWR_BIT) + #define DDRC_TIMING1_TWR_2 (1 << DDRC_TIMING1_TWR_BIT) + #define DDRC_TIMING1_TWR_3 (2 << DDRC_TIMING1_TWR_BIT) + #define DDRC_TIMING1_TWR_4 (3 << DDRC_TIMING1_TWR_BIT) + #define DDRC_TIMING1_TWR_5 (4 << DDRC_TIMING1_TWR_BIT) + #define DDRC_TIMING1_TWR_6 (5 << DDRC_TIMING1_TWR_BIT) + +#define DDRC_TIMING1_TWTR_BIT 0 /* WRITE to READ command delay. */ +#define DDRC_TIMING1_TWTR_MASK (0x3 << DDRC_TIMING1_TWTR_BIT) + #define DDRC_TIMING1_TWTR_1 (0 << DDRC_TIMING1_TWTR_BIT) + #define DDRC_TIMING1_TWTR_2 (1 << DDRC_TIMING1_TWTR_BIT) + #define DDRC_TIMING1_TWTR_3 (2 << DDRC_TIMING1_TWTR_BIT) + #define DDRC_TIMING1_TWTR_4 (3 << DDRC_TIMING1_TWTR_BIT) + +/* DDRC Timing Config Register 2 */ +#define DDRC_TIMING2_TRFC_BIT 12 /* AUTO-REFRESH command period. */ +#define DDRC_TIMING2_TRFC_MASK (0xf << DDRC_TIMING2_TRFC_BIT) +#define DDRC_TIMING2_TMINSR_BIT 8 /* Minimum Self-Refresh / Deep-Power-Down time */ +#define DDRC_TIMING2_TMINSR_MASK (0xf << DDRC_TIMING2_TMINSR_BIT) +#define DDRC_TIMING2_TXP_BIT 4 /* EXIT-POWER-DOWN to next valid command period. */ +#define DDRC_TIMING2_TXP_MASK (0x7 << DDRC_TIMING2_TXP_BIT) +#define DDRC_TIMING2_TMRD_BIT 0 /* Load-Mode-Register to next valid command period. */ +#define DDRC_TIMING2_TMRD_MASK (0x3 << DDRC_TIMING2_TMRD_BIT) + +/* DDRC Auto-Refresh Counter */ +#define DDRC_REFCNT_CON_BIT 16 /* Constant value used to compare with CNT value. */ +#define DDRC_REFCNT_CON_MASK (0xff << DDRC_REFCNT_CON_BIT) +#define DDRC_REFCNT_CNT_BIT 8 /* 8-bit counter */ +#define DDRC_REFCNT_CNT_MASK (0xff << DDRC_REFCNT_CNT_BIT) +#define DDRC_REFCNT_CLKDIV_BIT 1 /* Clock Divider for auto-refresh counter. */ +#define DDRC_REFCNT_CLKDIV_MASK (0x7 << DDRC_REFCNT_CLKDIV_BIT) +#define DDRC_REFCNT_REF_EN (1 << 0) /* Enable Refresh Counter */ + +/* DDRC DQS Delay Control Register */ +#define DDRC_DQS_ERROR (1 << 29) /* ahb_clk Delay Detect ERROR, read-only. */ +#define DDRC_DQS_READY (1 << 28) /* ahb_clk Delay Detect READY, read-only. */ +#define DDRC_DQS_AUTO (1 << 23) /* Hardware auto-detect & set delay line */ +#define DDRC_DQS_DET (1 << 24) /* Start delay detecting. */ +#define DDRC_DQS_CLKD_BIT 16 /* CLKD is reference value for setting WDQS and RDQS.*/ +#define DDRC_DQS_CLKD_MASK (0x7f << DDRC_DQS_CLKD_BIT) +#define DDRC_DQS_WDQS_BIT 8 /* Set delay element number to write DQS delay-line. */ +#define DDRC_DQS_WDQS_MASK (0x3f << DDRC_DQS_WDQS_BIT) +#define DDRC_DQS_RDQS_BIT 0 /* Set delay element number to read DQS delay-line. */ +#define DDRC_DQS_RDQS_MASK (0x3f << DDRC_DQS_RDQS_BIT) + +/* DDRC DQS Delay Adjust Register */ +#define DDRC_DQS_ADJWDQS_BIT 8 /* The adjust value for WRITE DQS delay */ +#define DDRC_DQS_ADJWDQS_MASK (0x1f << DDRC_DQS_ADJWDQS_BIT) +#define DDRC_DQS_ADJRDQS_BIT 0 /* The adjust value for READ DQS delay */ +#define DDRC_DQS_ADJRDQS_MASK (0x1f << DDRC_DQS_ADJRDQS_BIT) + +/* DDRC Memory Map Config Register */ +#define DDRC_MMAP_BASE_BIT 8 /* base address */ +#define DDRC_MMAP_BASE_MASK (0xff << DDRC_MMAP_BASE_BIT) +#define DDRC_MMAP_MASK_BIT 0 /* address mask */ +#define DDRC_MMAP_MASK_MASK (0xff << DDRC_MMAP_MASK_BIT) + +#define DDRC_MMAP0_BASE (0x20 << DDRC_MMAP_BASE_BIT) +#define DDRC_MMAP1_BASE_64M (0x24 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ +#define DDRC_MMAP1_BASE_128M (0x28 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ +#define DDRC_MMAP1_BASE_256M (0x30 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ + +#define DDRC_MMAP_MASK_64_64 (0xfc << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ +#define DDRC_MMAP_MASK_128_128 (0xf8 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ +#define DDRC_MMAP_MASK_256_256 (0xf0 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ + +/************************************************************************* + * 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< + * + * 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/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/war.h b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/war.h new file mode 100755 index 000000000..f88379fdd --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/mach-jz4760/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 + */ +#ifndef __ASM_MIPS_MACH_JZ4760_WAR_H +#define __ASM_MIPS_MACH_JZ4760_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_JZ4760_WAR_H */ diff --git a/target/linux/xburst/files-2.6.27/include/asm-mips/sizes.h b/target/linux/xburst/files-2.6.27/include/asm-mips/sizes.h new file mode 100644 index 000000000..503843db1 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/include/asm-mips/sizes.h @@ -0,0 +1,56 @@ +/* + * 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 + */ +/* DO NOT EDIT!! - this file automatically generated + * from .s file by awk -f s2h.awk + */ +/* Size definitions + * Copyright (C) ARM Limited 1998. All rights reserved. + */ + +#ifndef __sizes_h +#define __sizes_h 1 + +/* handy sizes */ +#define SZ_16 0x00000010 +#define SZ_256 0x00000100 +#define SZ_512 0x00000200 + +#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 + +/* END */ diff --git a/target/linux/xburst/files-2.6.27/sound/oss/ac97_codec.c b/target/linux/xburst/files-2.6.27/sound/oss/ac97_codec.c new file mode 100755 index 000000000..b63839e8f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/oss/ac97_codec.c @@ -0,0 +1,1206 @@ +/* + * ac97_codec.c: Generic AC97 mixer/modem module + * + * Derived from ac97 mixer in maestro and trident driver. + * + * Copyright 2000 Silicon Integrated System 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. + * + ************************************************************************** + * + * The Intel Audio Codec '97 specification is available at the Intel + * audio homepage: http://developer.intel.com/ial/scalableplatforms/audio/ + * + * The specification itself is currently available at: + * ftp://download.intel.com/ial/scalableplatforms/ac97r22.pdf + * + ************************************************************************** + * + * History + * May 02, 2003 Liam Girdwood + * Removed non existant WM9700 + * Added support for WM9705, WM9708, WM9709, WM9710, WM9711 + * WM9712 and WM9717 + * Mar 28, 2002 Randolph Bentson + * corrections to support WM9707 in ViewPad 1000 + * v0.4 Mar 15 2000 Ollie Lho + * dual codecs support verified with 4 channels output + * v0.3 Feb 22 2000 Ollie Lho + * bug fix for record mask setting + * v0.2 Feb 10 2000 Ollie Lho + * add ac97_read_proc for /proc/driver/{vendor}/ac97 + * v0.1 Jan 14 2000 Ollie Lho + * Isolated from trident.c to support multiple ac97 codec + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CODEC_ID_BUFSZ 14 + +static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel); +static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, + unsigned int left, unsigned int right); +static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val ); +static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask); +static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg); + +static int ac97_init_mixer(struct ac97_codec *codec); + +static int wolfson_init03(struct ac97_codec * codec); +static int wolfson_init04(struct ac97_codec * codec); +static int wolfson_init05(struct ac97_codec * codec); +static int wolfson_init11(struct ac97_codec * codec); +static int wolfson_init13(struct ac97_codec * codec); +static int tritech_init(struct ac97_codec * codec); +static int tritech_maestro_init(struct ac97_codec * codec); +static int sigmatel_9708_init(struct ac97_codec *codec); +static int sigmatel_9721_init(struct ac97_codec *codec); +static int sigmatel_9744_init(struct ac97_codec *codec); +static int ad1886_init(struct ac97_codec *codec); +static int eapd_control(struct ac97_codec *codec, int); +static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode); +static int cmedia_init(struct ac97_codec * codec); +static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode); +static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode); + + +/* + * AC97 operations. + * + * If you are adding a codec then you should be able to use + * eapd_ops - any codec that supports EAPD amp control (most) + * null_ops - any ancient codec that supports nothing + * + * The three functions are + * init - used for non AC97 standard initialisation + * amplifier - used to do amplifier control (1=on 0=off) + * digital - switch to digital modes (0 = analog) + * + * Not all codecs support all features, not all drivers use all the + * operations yet + */ + +static struct ac97_ops null_ops = { NULL, NULL, NULL }; +static struct ac97_ops default_ops = { NULL, eapd_control, NULL }; +static struct ac97_ops default_digital_ops = { NULL, eapd_control, generic_digital_control}; +static struct ac97_ops wolfson_ops03 = { wolfson_init03, NULL, NULL }; +static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL }; +static struct ac97_ops wolfson_ops05 = { wolfson_init05, NULL, NULL }; +static struct ac97_ops wolfson_ops11 = { wolfson_init11, NULL, NULL }; +static struct ac97_ops wolfson_ops13 = { wolfson_init13, NULL, NULL }; +static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL }; +static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL }; +static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL }; +static struct ac97_ops sigmatel_9721_ops = { sigmatel_9721_init, NULL, NULL }; +static struct ac97_ops sigmatel_9744_ops = { sigmatel_9744_init, NULL, NULL }; +static struct ac97_ops crystal_digital_ops = { NULL, eapd_control, crystal_digital_control }; +static struct ac97_ops ad1886_ops = { ad1886_init, eapd_control, NULL }; +static struct ac97_ops cmedia_ops = { NULL, eapd_control, NULL}; +static struct ac97_ops cmedia_digital_ops = { cmedia_init, eapd_control, cmedia_digital_control}; + +/* sorted by vendor/device id */ +static const struct { + u32 id; + char *name; + struct ac97_ops *ops; + int flags; +} ac97_codec_ids[] = { + {0x41445303, "Analog Devices AD1819", &null_ops}, + {0x41445340, "Analog Devices AD1881", &null_ops}, + {0x41445348, "Analog Devices AD1881A", &null_ops}, + {0x41445360, "Analog Devices AD1885", &default_ops}, + {0x41445361, "Analog Devices AD1886", &ad1886_ops}, + {0x41445370, "Analog Devices AD1981", &null_ops}, + {0x41445372, "Analog Devices AD1981A", &null_ops}, + {0x41445374, "Analog Devices AD1981B", &null_ops}, + {0x41445460, "Analog Devices AD1885", &default_ops}, + {0x41445461, "Analog Devices AD1886", &ad1886_ops}, + {0x414B4D00, "Asahi Kasei AK4540", &null_ops}, + {0x414B4D01, "Asahi Kasei AK4542", &null_ops}, + {0x414B4D02, "Asahi Kasei AK4543", &null_ops}, + {0x414C4326, "ALC100P", &null_ops}, + {0x414C4710, "ALC200/200P", &null_ops}, + {0x414C4720, "ALC650", &default_digital_ops}, + {0x434D4941, "CMedia", &cmedia_ops, AC97_NO_PCM_VOLUME }, + {0x434D4942, "CMedia", &cmedia_ops, AC97_NO_PCM_VOLUME }, + {0x434D4961, "CMedia", &cmedia_digital_ops, AC97_NO_PCM_VOLUME }, + {0x43525900, "Cirrus Logic CS4297", &default_ops}, + {0x43525903, "Cirrus Logic CS4297", &default_ops}, + {0x43525913, "Cirrus Logic CS4297A rev A", &default_ops}, + {0x43525914, "Cirrus Logic CS4297A rev B", &default_ops}, + {0x43525923, "Cirrus Logic CS4298", &null_ops}, + {0x4352592B, "Cirrus Logic CS4294", &null_ops}, + {0x4352592D, "Cirrus Logic CS4294", &null_ops}, + {0x43525931, "Cirrus Logic CS4299 rev A", &crystal_digital_ops}, + {0x43525933, "Cirrus Logic CS4299 rev C", &crystal_digital_ops}, + {0x43525934, "Cirrus Logic CS4299 rev D", &crystal_digital_ops}, + {0x43585430, "CXT48", &default_ops, AC97_DELUDED_MODEM }, + {0x43585442, "CXT66", &default_ops, AC97_DELUDED_MODEM }, + {0x44543031, "Diamond Technology DT0893", &default_ops}, + {0x45838308, "ESS Allegro ES1988", &null_ops}, + {0x49434511, "ICE1232", &null_ops}, /* I hope --jk */ + {0x4e534331, "National Semiconductor LM4549", &null_ops}, + {0x53494c22, "Silicon Laboratory Si3036", &null_ops}, + {0x53494c23, "Silicon Laboratory Si3038", &null_ops}, + {0x545200FF, "TriTech TR?????", &tritech_m_ops}, + {0x54524102, "TriTech TR28022", &null_ops}, + {0x54524103, "TriTech TR28023", &null_ops}, + {0x54524106, "TriTech TR28026", &null_ops}, + {0x54524108, "TriTech TR28028", &tritech_ops}, + {0x54524123, "TriTech TR A5", &null_ops}, + {0x574D4C03, "Wolfson WM9703/07/08/17", &wolfson_ops03}, + {0x574D4C04, "Wolfson WM9704M/WM9704Q", &wolfson_ops04}, + {0x574D4C05, "Wolfson WM9705/WM9710", &wolfson_ops05}, + {0x574D4C09, "Wolfson WM9709", &null_ops}, + {0x574D4C12, "Wolfson WM9711/9712", &wolfson_ops11}, + {0x574D4C13, "Wolfson WM9713", &wolfson_ops13, AC97_DEFAULT_POWER_OFF}, + {0x83847600, "SigmaTel STAC????", &null_ops}, + {0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops}, + {0x83847605, "SigmaTel STAC9704", &null_ops}, + {0x83847608, "SigmaTel STAC9708", &sigmatel_9708_ops}, + {0x83847609, "SigmaTel STAC9721/23", &sigmatel_9721_ops}, + {0x83847644, "SigmaTel STAC9744/45", &sigmatel_9744_ops}, + {0x83847652, "SigmaTel STAC9752/53", &default_ops}, + {0x83847656, "SigmaTel STAC9756/57", &sigmatel_9744_ops}, + {0x83847666, "SigmaTel STAC9750T", &sigmatel_9744_ops}, + {0x83847684, "SigmaTel STAC9783/84?", &null_ops}, + {0x57454301, "Winbond 83971D", &null_ops}, +}; + +/* this table has default mixer values for all OSS mixers. */ +static struct mixer_defaults { + int mixer; + unsigned int value; +} mixer_defaults[SOUND_MIXER_NRDEVICES] = { + /* all values 0 -> 100 in bytes */ + {SOUND_MIXER_VOLUME, 0x4343}, + {SOUND_MIXER_BASS, 0x4343}, + {SOUND_MIXER_TREBLE, 0x4343}, + {SOUND_MIXER_PCM, 0x4343}, + {SOUND_MIXER_SPEAKER, 0x4343}, + {SOUND_MIXER_LINE, 0x4343}, + {SOUND_MIXER_MIC, 0x0000}, + {SOUND_MIXER_CD, 0x4343}, + {SOUND_MIXER_ALTPCM, 0x4343}, + {SOUND_MIXER_IGAIN, 0x4343}, + {SOUND_MIXER_LINE1, 0x4343}, + {SOUND_MIXER_PHONEIN, 0x4343}, + {SOUND_MIXER_PHONEOUT, 0x4343}, + {SOUND_MIXER_VIDEO, 0x4343}, + {-1,0} +}; + +/* table to scale scale from OSS mixer value to AC97 mixer register value */ +static struct ac97_mixer_hw { + unsigned char offset; + int scale; +} ac97_hw[SOUND_MIXER_NRDEVICES]= { + [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,64}, + [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 16}, + [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 16}, + [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 32}, + [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 16}, + [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 32}, + [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 32}, + [SOUND_MIXER_CD] = {AC97_CD_VOL, 32}, + [SOUND_MIXER_ALTPCM] = {AC97_HEADPHONE_VOL, 64}, + [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 16}, + [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 32}, + [SOUND_MIXER_PHONEIN] = {AC97_PHONE_VOL, 32}, + [SOUND_MIXER_PHONEOUT] = {AC97_MASTER_VOL_MONO, 64}, + [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 32}, +}; + +/* the following tables allow us to go from OSS <-> ac97 quickly. */ +enum ac97_recsettings { + AC97_REC_MIC=0, + AC97_REC_CD, + AC97_REC_VIDEO, + AC97_REC_AUX, + AC97_REC_LINE, + AC97_REC_STEREO, /* combination of all enabled outputs.. */ + AC97_REC_MONO, /*.. or the mono equivalent */ + AC97_REC_PHONE +}; + +static const unsigned int ac97_rm2oss[] = { + [AC97_REC_MIC] = SOUND_MIXER_MIC, + [AC97_REC_CD] = SOUND_MIXER_CD, + [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, + [AC97_REC_AUX] = SOUND_MIXER_LINE1, + [AC97_REC_LINE] = SOUND_MIXER_LINE, + [AC97_REC_STEREO]= SOUND_MIXER_IGAIN, + [AC97_REC_PHONE] = SOUND_MIXER_PHONEIN +}; + +/* indexed by bit position */ +static const unsigned int ac97_oss_rm[] = { + [SOUND_MIXER_MIC] = AC97_REC_MIC, + [SOUND_MIXER_CD] = AC97_REC_CD, + [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO, + [SOUND_MIXER_LINE1] = AC97_REC_AUX, + [SOUND_MIXER_LINE] = AC97_REC_LINE, + [SOUND_MIXER_IGAIN] = AC97_REC_STEREO, + [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE +}; + +static LIST_HEAD(codecs); +static LIST_HEAD(codec_drivers); +static DEFINE_MUTEX(codec_mutex); + +/* reads the given OSS mixer from the ac97 the caller must have insured that the ac97 knows + about that given mixer, and should be holding a spinlock for the card */ +static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel) +{ + u16 val; + int ret = 0; + int scale; + struct ac97_mixer_hw *mh = &ac97_hw[oss_channel]; + + val = codec->codec_read(codec , mh->offset); + + if (val & AC97_MUTE) { + ret = 0; + } else if (AC97_STEREO_MASK & (1 << oss_channel)) { + /* nice stereo mixers .. */ + int left,right; + + left = (val >> 8) & 0x7f; + right = val & 0x7f; + + if (oss_channel == SOUND_MIXER_IGAIN) { + right = (right * 100) / mh->scale; + left = (left * 100) / mh->scale; + } else { + /* these may have 5 or 6 bit resolution */ + if(oss_channel == SOUND_MIXER_VOLUME || oss_channel == SOUND_MIXER_ALTPCM) + scale = (1 << codec->bit_resolution); + else + scale = mh->scale; + + right = 100 - ((right * 100) / scale); + left = 100 - ((left * 100) / scale); + } + ret = left | (right << 8); + } else if (oss_channel == SOUND_MIXER_SPEAKER) { + ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale); + } else if (oss_channel == SOUND_MIXER_PHONEIN) { + ret = 100 - (((val & 0x1f) * 100) / mh->scale); + } else if (oss_channel == SOUND_MIXER_PHONEOUT) { + scale = (1 << codec->bit_resolution); + ret = 100 - (((val & 0x1f) * 100) / scale); + } else if (oss_channel == SOUND_MIXER_MIC) { + ret = 100 - (((val & 0x1f) * 100) / mh->scale); + /* the low bit is optional in the tone sliders and masking + it lets us avoid the 0xf 'bypass'.. */ + } else if (oss_channel == SOUND_MIXER_BASS) { + ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale); + } else if (oss_channel == SOUND_MIXER_TREBLE) { + ret = 100 - (((val & 0xe) * 100) / mh->scale); + } + +#ifdef DEBUG + printk("ac97_codec: read OSS mixer %2d (%s ac97 register 0x%02x), " + "0x%04x -> 0x%04x\n", + oss_channel, codec->id ? "Secondary" : "Primary", + mh->offset, val, ret); +#endif + + return ret; +} + +/* write the OSS encoded volume to the given OSS encoded mixer, again caller's job to + make sure all is well in arg land, call with spinlock held */ +static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, + unsigned int left, unsigned int right) +{ + u16 val = 0; + int scale; + struct ac97_mixer_hw *mh = &ac97_hw[oss_channel]; + +#ifdef DEBUG + printk("ac97_codec: wrote OSS mixer %2d (%s ac97 register 0x%02x), " + "left vol:%2d, right vol:%2d:", + oss_channel, codec->id ? "Secondary" : "Primary", + mh->offset, left, right); +#endif + + if (AC97_STEREO_MASK & (1 << oss_channel)) { + /* stereo mixers */ + if (left == 0 && right == 0) { + val = AC97_MUTE; + } else { + if (oss_channel == SOUND_MIXER_IGAIN) { + right = (right * mh->scale) / 100; + left = (left * mh->scale) / 100; + if (right >= mh->scale) + right = mh->scale-1; + if (left >= mh->scale) + left = mh->scale-1; + } else { + /* these may have 5 or 6 bit resolution */ + if (oss_channel == SOUND_MIXER_VOLUME || + oss_channel == SOUND_MIXER_ALTPCM) + scale = (1 << codec->bit_resolution); + else + scale = mh->scale; + + right = ((100 - right) * scale) / 100; + left = ((100 - left) * scale) / 100; + if (right >= scale) + right = scale-1; + if (left >= scale) + left = scale-1; + } + val = (left << 8) | right; + } + } else if (oss_channel == SOUND_MIXER_BASS) { + val = codec->codec_read(codec , mh->offset) & ~0x0f00; + left = ((100 - left) * mh->scale) / 100; + if (left >= mh->scale) + left = mh->scale-1; + val |= (left << 8) & 0x0e00; + } else if (oss_channel == SOUND_MIXER_TREBLE) { + val = codec->codec_read(codec , mh->offset) & ~0x000f; + left = ((100 - left) * mh->scale) / 100; + if (left >= mh->scale) + left = mh->scale-1; + val |= left & 0x000e; + } else if(left == 0) { + val = AC97_MUTE; + } else if (oss_channel == SOUND_MIXER_SPEAKER) { + left = ((100 - left) * mh->scale) / 100; + if (left >= mh->scale) + left = mh->scale-1; + val = left << 1; + } else if (oss_channel == SOUND_MIXER_PHONEIN) { + left = ((100 - left) * mh->scale) / 100; + if (left >= mh->scale) + left = mh->scale-1; + val = left; + } else if (oss_channel == SOUND_MIXER_PHONEOUT) { + scale = (1 << codec->bit_resolution); + left = ((100 - left) * scale) / 100; + if (left >= mh->scale) + left = mh->scale-1; + val = left; + } else if (oss_channel == SOUND_MIXER_MIC) { + val = codec->codec_read(codec , mh->offset) & ~0x801f; + left = ((100 - left) * mh->scale) / 100; + if (left >= mh->scale) + left = mh->scale-1; + val |= left; + /* the low bit is optional in the tone sliders and masking + it lets us avoid the 0xf 'bypass'.. */ + } +#ifdef DEBUG + printk(" 0x%04x", val); +#endif + + codec->codec_write(codec, mh->offset, val); + +#ifdef DEBUG + val = codec->codec_read(codec, mh->offset); + printk(" -> 0x%04x\n", val); +#endif +} + +/* a thin wrapper for write_mixer */ +static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val ) +{ + unsigned int left,right; + + /* cleanse input a little */ + right = ((val >> 8) & 0xff) ; + left = (val & 0xff) ; + + if (right > 100) right = 100; + if (left > 100) left = 100; + + codec->mixer_state[oss_mixer] = (right << 8) | left; + codec->write_mixer(codec, oss_mixer, left, right); +} + +/* read or write the recmask, the ac97 can really have left and right recording + inputs independantly set, but OSS doesn't seem to want us to express that to + the user. the caller guarantees that we have a supported bit set, and they + must be holding the card's spinlock */ +static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask) +{ + unsigned int val; + + if (rw) { + /* read it from the card */ + val = codec->codec_read(codec, AC97_RECORD_SELECT); +#ifdef DEBUG + printk("ac97_codec: ac97 recmask to set to 0x%04x\n", val); +#endif + return (1 << ac97_rm2oss[val & 0x07]); + } + + /* else, write the first set in the mask as the + output */ + /* clear out current set value first (AC97 supports only 1 input!) */ + val = (1 << ac97_rm2oss[codec->codec_read(codec, AC97_RECORD_SELECT) & 0x07]); + if (mask != val) + mask &= ~val; + + val = ffs(mask); + val = ac97_oss_rm[val-1]; + val |= val << 8; /* set both channels */ + +#ifdef DEBUG + printk("ac97_codec: setting ac97 recmask to 0x%04x\n", val); +#endif + + codec->codec_write(codec, AC97_RECORD_SELECT, val); + + return 0; +}; + +static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg) +{ + int i, val = 0; + + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + memset(&info, 0, sizeof(info)); + strlcpy(info.id, codec->name, sizeof(info.id)); + strlcpy(info.name, codec->name, sizeof(info.name)); + info.modify_counter = codec->modcnt; + if (copy_to_user((void __user *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + memset(&info, 0, sizeof(info)); + strlcpy(info.id, codec->name, sizeof(info.id)); + strlcpy(info.name, codec->name, sizeof(info.name)); + if (copy_to_user((void __user *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) + return -EINVAL; + + if (cmd == OSS_GETVERSION) + return put_user(SOUND_VERSION, (int __user *)arg); + + if (_SIOC_DIR(cmd) == _SIOC_READ) { + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* give them the current record source */ + if (!codec->recmask_io) { + val = 0; + } else { + val = codec->recmask_io(codec, 1, 0); + } + break; + + case SOUND_MIXER_DEVMASK: /* give them the supported mixers */ + val = codec->supported_mixers; + break; + + case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ + val = codec->record_sources; + break; + + case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ + val = codec->stereo_mixers; + break; + + case SOUND_MIXER_CAPS: + val = SOUND_CAP_EXCL_INPUT; + break; + + default: /* read a specific mixer */ + i = _IOC_NR(cmd); + + if (!supported_mixer(codec, i)) + return -EINVAL; + + /* do we ever want to touch the hardware? */ + /* val = codec->read_mixer(codec, i); */ + val = codec->mixer_state[i]; + break; + } + return put_user(val, (int __user *)arg); + } + + if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) { + codec->modcnt++; + if (get_user(val, (int __user *)arg)) + return -EFAULT; + + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + if (!codec->recmask_io) return -EINVAL; + if (!val) return 0; + if (!(val &= codec->record_sources)) return -EINVAL; + + codec->recmask_io(codec, 0, val); + + return 0; + default: /* write a specific mixer */ + i = _IOC_NR(cmd); + + if (!supported_mixer(codec, i)) + return -EINVAL; + + ac97_set_mixer(codec, i, val); + + return 0; + } + } + return -EINVAL; +} + +/** + * codec_id - Turn id1/id2 into a PnP string + * @id1: Vendor ID1 + * @id2: Vendor ID2 + * @buf: CODEC_ID_BUFSZ byte buffer + * + * Fills buf with a zero terminated PnP ident string for the id1/id2 + * pair. For convenience the return is the passed in buffer pointer. + */ + +static char *codec_id(u16 id1, u16 id2, char *buf) +{ + if(id1&0x8080) { + snprintf(buf, CODEC_ID_BUFSZ, "0x%04x:0x%04x", id1, id2); + } else { + buf[0] = (id1 >> 8); + buf[1] = (id1 & 0xFF); + buf[2] = (id2 >> 8); + snprintf(buf+3, CODEC_ID_BUFSZ - 3, "%d", id2&0xFF); + } + return buf; +} + +/** + * ac97_check_modem - Check if the Codec is a modem + * @codec: codec to check + * + * Return true if the device is an AC97 1.0 or AC97 2.0 modem + */ + +static int ac97_check_modem(struct ac97_codec *codec) +{ + /* Check for an AC97 1.0 soft modem (ID1) */ + if(codec->codec_read(codec, AC97_RESET) & 2) + return 1; + /* Check for an AC97 2.x soft modem */ + codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L); + if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1) + return 1; + return 0; +} + + +/** + * ac97_alloc_codec - Allocate an AC97 codec + * + * Returns a new AC97 codec structure. AC97 codecs may become + * refcounted soon so this interface is needed. Returns with + * one reference taken. + */ + +struct ac97_codec *ac97_alloc_codec(void) +{ + struct ac97_codec *codec = kzalloc(sizeof(struct ac97_codec), GFP_KERNEL); + if(!codec) + return NULL; + + spin_lock_init(&codec->lock); + INIT_LIST_HEAD(&codec->list); + return codec; +} + +EXPORT_SYMBOL(ac97_alloc_codec); + +/** + * ac97_release_codec - Release an AC97 codec + * @codec: codec to release + * + * Release an allocated AC97 codec. This will be refcounted in + * time but for the moment is trivial. Calls the unregister + * handler if the codec is now defunct. + */ + +void ac97_release_codec(struct ac97_codec *codec) +{ + /* Remove from the list first, we don't want to be + "rediscovered" */ + mutex_lock(&codec_mutex); + list_del(&codec->list); + mutex_unlock(&codec_mutex); + /* + * The driver needs to deal with internal + * locking to avoid accidents here. + */ + if(codec->driver) + codec->driver->remove(codec, codec->driver); + kfree(codec); +} + +EXPORT_SYMBOL(ac97_release_codec); + +/** + * ac97_probe_codec - Initialize and setup AC97-compatible codec + * @codec: (in/out) Kernel info for a single AC97 codec + * + * Reset the AC97 codec, then initialize the mixer and + * the rest of the @codec structure. + * + * The codec_read and codec_write fields of @codec are + * required to be setup and working when this function + * is called. All other fields are set by this function. + * + * codec_wait field of @codec can optionally be provided + * when calling this function. If codec_wait is not %NULL, + * this function will call codec_wait any time it is + * necessary to wait for the audio chip to reach the + * codec-ready state. If codec_wait is %NULL, then + * the default behavior is to call schedule_timeout. + * Currently codec_wait is used to wait for AC97 codec + * reset to complete. + * + * Some codecs will power down when a register reset is + * performed. We now check for such codecs. + * + * Returns 1 (true) on success, or 0 (false) on failure. + */ + +int ac97_probe_codec(struct ac97_codec *codec) +{ + u16 id1, id2; + u16 audio; + int i; + char cidbuf[CODEC_ID_BUFSZ]; + u16 f; + struct list_head *l; + struct ac97_driver *d; + + /* wait for codec-ready state */ + if (codec->codec_wait) + codec->codec_wait(codec); + else + udelay(10); + + /* will the codec power down if register reset ? */ + id1 = codec->codec_read(codec, AC97_VENDOR_ID1); + id2 = codec->codec_read(codec, AC97_VENDOR_ID2); + codec->name = NULL; + codec->codec_ops = &null_ops; + for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) { + if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) { + codec->type = ac97_codec_ids[i].id; + codec->name = ac97_codec_ids[i].name; + codec->codec_ops = ac97_codec_ids[i].ops; + codec->flags = ac97_codec_ids[i].flags; + break; + } + } + + codec->model = (id1 << 16) | id2; + if ((codec->flags & AC97_DEFAULT_POWER_OFF) == 0) { + /* reset codec and wait for the ready bit before we continue */ + codec->codec_write(codec, AC97_RESET, 0L); + if (codec->codec_wait) + codec->codec_wait(codec); + else + udelay(10); + } + + /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should + * be read zero. + * + * FIXME: is the following comment outdated? -jgarzik + * Probing of AC97 in this way is not reliable, it is not even SAFE !! + */ + if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) { + printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n", + (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") + : (codec->id&1 ? "Secondary": "Primary")); + return 0; + } + + /* probe for Modem Codec */ + codec->modem = ac97_check_modem(codec); + + /* enable SPDIF */ + f = codec->codec_read(codec, AC97_EXTENDED_STATUS); + if((codec->codec_ops == &null_ops) && (f & 4)) + codec->codec_ops = &default_digital_ops; + + /* A device which thinks its a modem but isnt */ + if(codec->flags & AC97_DELUDED_MODEM) + codec->modem = 0; + + if (codec->name == NULL) + codec->name = "Unknown"; + printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s (%s)\n", + codec->modem ? "Modem" : (audio ? "Audio" : ""), + codec_id(id1, id2, cidbuf), codec->name); + + if(!ac97_init_mixer(codec)) + return 0; + + /* + * Attach last so the caller can override the mixer + * callbacks. + */ + + mutex_lock(&codec_mutex); + list_add(&codec->list, &codecs); + + list_for_each(l, &codec_drivers) { + d = list_entry(l, struct ac97_driver, list); + if ((codec->model ^ d->codec_id) & d->codec_mask) + continue; + if(d->probe(codec, d) == 0) + { + codec->driver = d; + break; + } + } + + mutex_unlock(&codec_mutex); + return 1; +} + +static int ac97_init_mixer(struct ac97_codec *codec) +{ + u16 cap; + int i; + + cap = codec->codec_read(codec, AC97_RESET); + + /* mixer masks */ + codec->supported_mixers = AC97_SUPPORTED_MASK; + codec->stereo_mixers = AC97_STEREO_MASK; + codec->record_sources = AC97_RECORD_MASK; + if (!(cap & 0x04)) + codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE); + if (!(cap & 0x10)) + codec->supported_mixers &= ~SOUND_MASK_ALTPCM; + + + /* detect bit resolution */ + codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0x2020); + if(codec->codec_read(codec, AC97_MASTER_VOL_STEREO) == 0x2020) + codec->bit_resolution = 6; + else + codec->bit_resolution = 5; + + /* generic OSS to AC97 wrapper */ + codec->read_mixer = ac97_read_mixer; + codec->write_mixer = ac97_write_mixer; + codec->recmask_io = ac97_recmask_io; + codec->mixer_ioctl = ac97_mixer_ioctl; + + /* initialize mixer channel volumes */ + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + struct mixer_defaults *md = &mixer_defaults[i]; + if (md->mixer == -1) + break; + if (!supported_mixer(codec, md->mixer)) + continue; + ac97_set_mixer(codec, md->mixer, md->value); + } + + /* codec specific initialization for 4-6 channel output or secondary codec stuff */ + if (codec->codec_ops->init != NULL) { + codec->codec_ops->init(codec); + } + + /* + * Volume is MUTE only on this device. We have to initialise + * it but its useless beyond that. + */ + if(codec->flags & AC97_NO_PCM_VOLUME) + { + codec->supported_mixers &= ~SOUND_MASK_PCM; + printk(KERN_WARNING "AC97 codec does not have proper volume support.\n"); + } + return 1; +} + +#define AC97_SIGMATEL_ANALOG 0x6c /* Analog Special */ +#define AC97_SIGMATEL_DAC2INVERT 0x6e +#define AC97_SIGMATEL_BIAS1 0x70 +#define AC97_SIGMATEL_BIAS2 0x72 +#define AC97_SIGMATEL_MULTICHN 0x74 /* Multi-Channel programming */ +#define AC97_SIGMATEL_CIC1 0x76 +#define AC97_SIGMATEL_CIC2 0x78 + + +static int sigmatel_9708_init(struct ac97_codec * codec) +{ + u16 codec72, codec6c; + + codec72 = codec->codec_read(codec, AC97_SIGMATEL_BIAS2) & 0x8000; + codec6c = codec->codec_read(codec, AC97_SIGMATEL_ANALOG); + + if ((codec72==0) && (codec6c==0)) { + codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1000); + codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0007); + } else if ((codec72==0x8000) && (codec6c==0)) { + codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x1001); + codec->codec_write(codec, AC97_SIGMATEL_DAC2INVERT, 0x0008); + } else if ((codec72==0x8000) && (codec6c==0x0080)) { + /* nothing */ + } + codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000); + return 0; +} + + +static int sigmatel_9721_init(struct ac97_codec * codec) +{ + /* Only set up secondary codec */ + if (codec->id == 0) + return 0; + + codec->codec_write(codec, AC97_SURROUND_MASTER, 0L); + + /* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link + sloc 3,4 = 0x01, slot 7,8 = 0x00, */ + codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x00); + + /* we don't have the crystal when we are on an AMR card, so use + BIT_CLK as our clock source. Write the magic word ABBA and read + back to enable register 0x78 */ + codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); + codec->codec_read(codec, AC97_SIGMATEL_CIC1); + + /* sync all the clocks*/ + codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x3802); + + return 0; +} + + +static int sigmatel_9744_init(struct ac97_codec * codec) +{ + // patch for SigmaTel + codec->codec_write(codec, AC97_SIGMATEL_CIC1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_CIC2, 0x0000); // is this correct? --jk + codec->codec_write(codec, AC97_SIGMATEL_BIAS1, 0xabba); + codec->codec_write(codec, AC97_SIGMATEL_BIAS2, 0x0002); + codec->codec_write(codec, AC97_SIGMATEL_MULTICHN, 0x0000); + return 0; +} + +static int cmedia_init(struct ac97_codec *codec) +{ + /* Initialise the CMedia 9739 */ + /* + We could set various options here + Register 0x20 bit 0x100 sets mic as center bass + Also do multi_channel_ctrl &=~0x3000 |=0x1000 + + For now we set up the GPIO and PC beep + */ + + u16 v; + + /* MIC */ + codec->codec_write(codec, 0x64, 0x3000); + v = codec->codec_read(codec, 0x64); + v &= ~0x8000; + codec->codec_write(codec, 0x64, v); + codec->codec_write(codec, 0x70, 0x0100); + codec->codec_write(codec, 0x72, 0x0020); + return 0; +} + +#define AC97_WM97XX_FMIXER_VOL 0x72 +#define AC97_WM97XX_RMIXER_VOL 0x74 +#define AC97_WM97XX_TEST 0x5a +#define AC97_WM9704_RPCM_VOL 0x70 +#define AC97_WM9711_OUT3VOL 0x16 + +static int wolfson_init03(struct ac97_codec * codec) +{ + /* this is known to work for the ViewSonic ViewPad 1000 */ + codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808); + codec->codec_write(codec, AC97_GENERAL_PURPOSE, 0x8000); + return 0; +} + +static int wolfson_init04(struct ac97_codec * codec) +{ + codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808); + codec->codec_write(codec, AC97_WM97XX_RMIXER_VOL, 0x0808); + + // patch for DVD noise + codec->codec_write(codec, AC97_WM97XX_TEST, 0x0200); + + // init vol as PCM vol + codec->codec_write(codec, AC97_WM9704_RPCM_VOL, + codec->codec_read(codec, AC97_PCMOUT_VOL)); + + /* set rear surround volume */ + codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000); + return 0; +} + +/* WM9705, WM9710 */ +static int wolfson_init05(struct ac97_codec * codec) +{ + /* set front mixer volume */ + codec->codec_write(codec, AC97_WM97XX_FMIXER_VOL, 0x0808); + return 0; +} + +/* WM9711, WM9712 */ +static int wolfson_init11(struct ac97_codec * codec) +{ + /* stop pop's during suspend/resume */ + codec->codec_write(codec, AC97_WM97XX_TEST, + codec->codec_read(codec, AC97_WM97XX_TEST) & 0xffbf); + + /* set out3 volume */ + codec->codec_write(codec, AC97_WM9711_OUT3VOL, 0x0808); + return 0; +} + +/* WM9713 */ +static int wolfson_init13(struct ac97_codec * codec) +{ + codec->codec_write(codec, AC97_RECORD_GAIN, 0x00a0); + codec->codec_write(codec, AC97_POWER_CONTROL, 0x0000); + codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0xDA00); + codec->codec_write(codec, AC97_EXTEND_MODEM_STAT, 0x3810); + codec->codec_write(codec, AC97_PHONE_VOL, 0x0808); + codec->codec_write(codec, AC97_PCBEEP_VOL, 0x0808); + + return 0; +} + +static int tritech_init(struct ac97_codec * codec) +{ + codec->codec_write(codec, 0x26, 0x0300); + codec->codec_write(codec, 0x26, 0x0000); + codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0000); + codec->codec_write(codec, AC97_RESERVED_3A, 0x0000); + return 0; +} + + +/* copied from drivers/sound/maestro.c */ +static int tritech_maestro_init(struct ac97_codec * codec) +{ + /* no idea what this does */ + codec->codec_write(codec, 0x2A, 0x0001); + codec->codec_write(codec, 0x2C, 0x0000); + codec->codec_write(codec, 0x2C, 0XFFFF); + return 0; +} + + + +/* + * Presario700 workaround + * for Jack Sense/SPDIF Register mis-setting causing + * no audible output + * by Santiago Nullo 04/05/2002 + */ + +#define AC97_AD1886_JACK_SENSE 0x72 + +static int ad1886_init(struct ac97_codec * codec) +{ + /* from AD1886 Specs */ + codec->codec_write(codec, AC97_AD1886_JACK_SENSE, 0x0010); + return 0; +} + + + + +/* + * This is basically standard AC97. It should work as a default for + * almost all modern codecs. Note that some cards wire EAPD *backwards* + * That side of it is up to the card driver not us to cope with. + * + */ + +static int eapd_control(struct ac97_codec * codec, int on) +{ + if(on) + codec->codec_write(codec, AC97_POWER_CONTROL, + codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000); + else + codec->codec_write(codec, AC97_POWER_CONTROL, + codec->codec_read(codec, AC97_POWER_CONTROL)&~0x8000); + return 0; +} + +static int generic_digital_control(struct ac97_codec *codec, int slots, int rate, int mode) +{ + u16 reg; + + reg = codec->codec_read(codec, AC97_SPDIF_CONTROL); + + switch(rate) + { + /* Off by default */ + default: + case 0: + reg = codec->codec_read(codec, AC97_EXTENDED_STATUS); + codec->codec_write(codec, AC97_EXTENDED_STATUS, (reg & ~AC97_EA_SPDIF)); + if(rate == 0) + return 0; + return -EINVAL; + case 1: + reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K; + break; + case 2: + reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K; + break; + case 3: + reg = (reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K; + break; + } + + reg &= ~AC97_SC_CC_MASK; + reg |= (mode & AUDIO_CCMASK) << 6; + + if(mode & AUDIO_DIGITAL) + reg |= 2; + if(mode & AUDIO_PRO) + reg |= 1; + if(mode & AUDIO_DRS) + reg |= 0x4000; + + codec->codec_write(codec, AC97_SPDIF_CONTROL, reg); + + reg = codec->codec_read(codec, AC97_EXTENDED_STATUS); + reg &= (AC97_EA_SLOT_MASK); + reg |= AC97_EA_VRA | AC97_EA_SPDIF | slots; + codec->codec_write(codec, AC97_EXTENDED_STATUS, reg); + + reg = codec->codec_read(codec, AC97_EXTENDED_STATUS); + if(!(reg & 0x0400)) + { + codec->codec_write(codec, AC97_EXTENDED_STATUS, reg & ~ AC97_EA_SPDIF); + return -EINVAL; + } + return 0; +} + +/* + * Crystal digital audio control (CS4299) + */ + +static int crystal_digital_control(struct ac97_codec *codec, int slots, int rate, int mode) +{ + u16 cv; + + if(mode & AUDIO_DIGITAL) + return -EINVAL; + + switch(rate) + { + case 0: cv = 0x0; break; /* SPEN off */ + case 48000: cv = 0x8004; break; /* 48KHz digital */ + case 44100: cv = 0x8104; break; /* 44.1KHz digital */ + case 32768: /* 32Khz */ + default: + return -EINVAL; + } + codec->codec_write(codec, 0x68, cv); + return 0; +} + +/* + * CMedia digital audio control + * Needs more work. + */ + +static int cmedia_digital_control(struct ac97_codec *codec, int slots, int rate, int mode) +{ + u16 cv; + + if(mode & AUDIO_DIGITAL) + return -EINVAL; + + switch(rate) + { + case 0: cv = 0x0001; break; /* SPEN off */ + case 48000: cv = 0x0009; break; /* 48KHz digital */ + default: + return -EINVAL; + } + codec->codec_write(codec, 0x2A, 0x05c4); + codec->codec_write(codec, 0x6C, cv); + + /* Switch on mix to surround */ + cv = codec->codec_read(codec, 0x64); + cv &= ~0x0200; + if(mode) + cv |= 0x0200; + codec->codec_write(codec, 0x64, cv); + return 0; +} + + +/* copied from drivers/sound/maestro.c */ +#if 0 /* there has been 1 person on the planet with a pt101 that we + know of. If they care, they can put this back in :) */ +static int pt101_init(struct ac97_codec * codec) +{ + printk(KERN_INFO "ac97_codec: PT101 Codec detected, initializing but _not_ installing mixer device.\n"); + /* who knows.. */ + codec->codec_write(codec, 0x2A, 0x0001); + codec->codec_write(codec, 0x2C, 0x0000); + codec->codec_write(codec, 0x2C, 0xFFFF); + codec->codec_write(codec, 0x10, 0x9F1F); + codec->codec_write(codec, 0x12, 0x0808); + codec->codec_write(codec, 0x14, 0x9F1F); + codec->codec_write(codec, 0x16, 0x9F1F); + codec->codec_write(codec, 0x18, 0x0404); + codec->codec_write(codec, 0x1A, 0x0000); + codec->codec_write(codec, 0x1C, 0x0000); + codec->codec_write(codec, 0x02, 0x0404); + codec->codec_write(codec, 0x04, 0x0808); + codec->codec_write(codec, 0x0C, 0x801F); + codec->codec_write(codec, 0x0E, 0x801F); + return 0; +} +#endif + + +EXPORT_SYMBOL(ac97_probe_codec); + +MODULE_LICENSE("GPL"); + diff --git a/target/linux/xburst/files-2.6.27/sound/oss/ak4642en.c b/target/linux/xburst/files-2.6.27/sound/oss/ak4642en.c new file mode 100755 index 000000000..092f7f0dc --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/oss/ak4642en.c @@ -0,0 +1,712 @@ +/* + * linux/sound/oss/ak4642en.c + * + * AKM ak4642en codec chip driver to I2S interface + * + * Copyright (c) 2005-2007 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/sound/oss/jz_ac97.c b/target/linux/xburst/files-2.6.27/sound/oss/jz_ac97.c new file mode 100755 index 000000000..698a003f1 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#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 0) { + count -= 2; + jz_audio_count += 2; + cnt += 2 * jz_audio_k; + d1 = *(s++) - 0x80; + d2 = *(s++) - 0x80; + for (i=0;i= jz_audio_q * 2) { + cnt += 2 * jz_audio_k; + last_jz_audio_count = jz_audio_count; + for (i=0;i= 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/target/linux/xburst/files-2.6.27/sound/oss/jz_i2s.c b/target/linux/xburst/files-2.6.27/sound/oss/jz_i2s.c new file mode 100755 index 000000000..dcd3e939c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/oss/jz_i2s.c @@ -0,0 +1,2908 @@ +/* + * 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 +#include +#include +//#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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(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 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("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(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); + +#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_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) +#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 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 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 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 + } + +#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; + 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); + spin_lock(&controller->ioctllock); + 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); + spin_unlock(&controller->ioctllock); + /* 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); + spin_lock(&controller->ioctllock); + cinfo.bytes = controller->total_bytes; + cinfo.blocks = controller->blocks; + cinfo.ptr = controller->nextIn; + controller->blocks = 0; + //spin_unlock_irqrestore(&controller->ioctllock, flags); + spin_unlock(&controller->ioctllock); + + 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); + spin_lock(&controller->ioctllock); + cinfo.bytes = controller->total_bytes; + cinfo.blocks = controller->blocks; + cinfo.ptr = controller->nextOut; + controller->blocks = 0; + //spin_unlock_irqrestore(&controller->ioctllock, flags); + spin_unlock(&controller->ioctllock); + + 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); + spin_lock(&controller->ioctllock); + 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); + spin_unlock(&controller->ioctllock); + + 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 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); + spin_lock(&controller->lock); + 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); + spin_unlock(&controller->lock); + + 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); + + 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); + 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); + } + 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; + 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); + 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) { + 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); + 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); + 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/target/linux/xburst/files-2.6.27/sound/oss/jz_pcm_tlv320aic1106_dma.c b/target/linux/xburst/files-2.6.27/sound/oss/jz_pcm_tlv320aic1106_dma.c new file mode 100644 index 000000000..1a1f4cfad --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/oss/jz_pcm_tlv320aic1106_dma.c @@ -0,0 +1,1839 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 int 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 int 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/target/linux/xburst/files-2.6.27/sound/oss/jzcodec.c b/target/linux/xburst/files-2.6.27/sound/oss/jzcodec.c new file mode 100755 index 000000000..0af65804b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/oss/jzcodec.c @@ -0,0 +1,443 @@ +/* + * linux/drivers/sound/jzcodec.c + * + * JzSOC internal audio driver. + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/sound/oss/jzdlv.c b/target/linux/xburst/files-2.6.27/sound/oss/jzdlv.c new file mode 100755 index 000000000..8f8f2ba1f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/oss/jzdlv.c @@ -0,0 +1,644 @@ +/* + * linux/drivers/sound/jzcodec.c + * + * JzSOC internal audio driver. + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 0 /* mask warning */ +/* set Playback LINE input audio direct only */ +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 */ +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/target/linux/xburst/files-2.6.27/sound/oss/jzdlv.h b/target/linux/xburst/files-2.6.27/sound/oss/jzdlv.h new file mode 100755 index 000000000..d36156378 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/sound/soc/codecs/jzcodec.c b/target/linux/xburst/files-2.6.27/sound/soc/codecs/jzcodec.c new file mode 100755 index 000000000..a8cba3835 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/soc/codecs/jzcodec.c @@ -0,0 +1,725 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_priv { + unsigned int sysclk; +}; + +/* + * 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 char *intercon[][3] = { + /* 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"}, + + /* terminator */ + {NULL, NULL, NULL}, +}; + +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]); + } +#if 1 + /* set up audio path interconnects */ + for(i = 0; intercon[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, intercon[i][0], + intercon[i][1], intercon[i][2]); + } +#endif + 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_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + u16 reg_val = jzcodec_read_reg_cache(codec, ICODEC_2_LOW); + +#if 0 + /* bit size. codec side */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + } +#endif + /* 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) +{ + 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->codec; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + //case SNDRV_PCM_TRIGGER_RESUME: + //case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + + 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_STOP: + //case SNDRV_PCM_TRIGGER_SUSPEND: + //case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + + 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_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; */ + + return 0; +} + +static void jzcodec_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->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_priv *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; +} +#if 1 +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; +} +#endif + +#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) + +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 = { + .trigger = jzcodec_pcm_trigger, + .prepare = jzcodec_pcm_prepare, + .hw_params = jzcodec_hw_params, + .shutdown = jzcodec_shutdown, + }, + .dai_ops = { + .digital_mute = jzcodec_mute, + .set_sysclk = jzcodec_set_dai_sysclk, + .set_fmt = jzcodec_set_dai_fmt, + } +}; +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) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->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); + return 0; +} + +static int jzcodec_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->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); + return 0; +} +#else +#define jzcodec_suspend NULL +#define jzcodec_resume NULL +#endif +/* + * initialise the JZCODEC driver + * register the mixer and dsp interfaces with the kernel + */ +static int jzcodec_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + int reg, ret = 0; + u16 reg_val; + + 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; + } + } + + 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); + /* 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"); + goto pcm_err; + } + + /* 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_register_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); +pcm_err: + kfree(codec->reg_cache); + return ret; +} + +static struct snd_soc_device *jzcodec_socdev; + +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; +} + +static int jzcodec_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct jzcodec_priv *jzcodec; + int ret = 0; + + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + jzcodec = kzalloc(sizeof(struct jzcodec_priv), GFP_KERNEL); + if (jzcodec == NULL) { + kfree(codec); + return -ENOMEM; + } + + codec->private_data = jzcodec; + socdev->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + jzcodec_socdev = socdev; + + /* Add other interfaces here ,no I2C connection */ + codec->hw_write = (hw_write_t)write_codec_reg; + ret = jzcodec_init(jzcodec_socdev); + + if (ret < 0) { + codec = jzcodec_socdev->codec; + err("failed to initialise jzcodec\n"); + kfree(codec); + } + + return ret; +} + +/* 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->codec; + + if (codec->control_data) + jzcodec_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_jzcodec = { + .probe = jzcodec_probe, + .remove = jzcodec_remove, + .suspend = jzcodec_suspend, + .resume = jzcodec_resume, +}; + +EXPORT_SYMBOL_GPL(soc_codec_dev_jzcodec); + +MODULE_DESCRIPTION("ASoC JZCODEC driver"); +MODULE_AUTHOR("Richard"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/sound/soc/codecs/jzcodec.h b/target/linux/xburst/files-2.6.27/sound/soc/codecs/jzcodec.h new file mode 100755 index 000000000..785613278 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/sound/soc/codecs/jzdlv.c b/target/linux/xburst/files-2.6.27/sound/soc/codecs/jzdlv.c new file mode 100755 index 000000000..d849f148c --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/soc/codecs/jzdlv.c @@ -0,0 +1,981 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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) + +struct snd_soc_codec_device soc_codec_dev_jzdlv; + +/* codec private data */ +struct jzdlv_priv { + unsigned int sysclk; +}; + +/* + * 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; +} + +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; +} + +/* + * 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; +} + +static const char *jzdlv_input_select[] = {"Line In", "Mic"}; +static const char *jzdlv_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; + +static const struct soc_enum jzdlv_enum[] = { + SOC_ENUM_SINGLE(0x04, 2, 2, jzdlv_input_select), + SOC_ENUM_SINGLE(0x05, 1, 4, jzdlv_deemph), +}; + +/* 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, 15, 0), +}; + +/* add non dapm controls */ +static int jzdlv_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(jzdlv_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&jzdlv_snd_controls[i], codec, NULL)); + if (err < 0) + return err; + } + + return 0; +} + +/* Output Mixer */ +static const struct snd_kcontrol_new jzdlv_output_mixer_controls[] = { +SOC_DAPM_SINGLE("Line Bypass Switch", 0x04, 3, 1, 0), +SOC_DAPM_SINGLE("Mic Sidetone Switch", 0x04, 5, 1, 0), +SOC_DAPM_SINGLE("HiFi Playback Switch", 0x04, 4, 1, 0), +}; + +/* Input mux */ +static const struct snd_kcontrol_new jzdlv_input_mux_controls = +SOC_DAPM_ENUM("Input Select", jzdlv_enum[0]); + +static const struct snd_soc_dapm_widget jzdlv_dapm_widgets[] = { +SND_SOC_DAPM_MIXER("Output Mixer", 0x06, 4, 1, + &jzdlv_output_mixer_controls[0], + ARRAY_SIZE(jzdlv_output_mixer_controls)), +//SND_SOC_DAPM_DAC("DAC", "HiFi Playback", 0x06, 3, 1), +SND_SOC_DAPM_OUTPUT("LOUT"), +SND_SOC_DAPM_OUTPUT("LHPOUT"), +SND_SOC_DAPM_OUTPUT("ROUT"), +SND_SOC_DAPM_OUTPUT("RHPOUT"), +//SND_SOC_DAPM_ADC("ADC", "HiFi Capture", 0x06, 2, 1), +SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &jzdlv_input_mux_controls), +SND_SOC_DAPM_PGA("Line Input", 0x06, 0, 1, NULL, 0), +SND_SOC_DAPM_MICBIAS("Mic Bias", 0x06, 1, 1), +SND_SOC_DAPM_INPUT("MICIN"), +SND_SOC_DAPM_INPUT("RLINEIN"), +SND_SOC_DAPM_INPUT("LLINEIN"), +}; + + +static const struct snd_soc_dapm_route intercon[] = { + /* 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)); + + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + 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_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->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) +{ + int ret = 0; + //struct snd_soc_pcm_runtime *rtd = substream->private_data; + //struct snd_soc_device *socdev = rtd->socdev; + //struct snd_soc_codec *codec = socdev->codec; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + //case SNDRV_PCM_TRIGGER_RESUME: + //case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + init_codec(); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + REG_AIC_I2SCR = 0x10; + mdelay(1); + set_audio_data_replay(); + mdelay(5); + write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0 + __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_STOP: + //case SNDRV_PCM_TRIGGER_SUSPEND: + //case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + + 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_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; */ + + return 0; +} + +static void jzdlv_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->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_priv *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 | SNDRV_PCM_RATE_12000 |\ + SNDRV_PCM_RATE_24000) + +#define JZDLV_FORMATS (SNDRV_PCM_FORMAT_S8 | SNDRV_PCM_FMTBIT_S16_LE) + +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 = { + .trigger = jzdlv_pcm_trigger, + .prepare = jzdlv_pcm_prepare, + .hw_params = jzdlv_hw_params, + .shutdown = jzdlv_shutdown, + }, + .dai_ops = { + .digital_mute = jzdlv_mute, + .set_sysclk = jzdlv_set_dai_sysclk, + .set_fmt = jzdlv_set_dai_fmt, + } +}; +EXPORT_SYMBOL_GPL(jzdlv_dai); + +#ifdef CONFIG_PM +static int jzdlv_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->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 jzdlv_resume(struct platform_device *pdev) +{ +#if 0 + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->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 jzdlv_suspend NULL +#define jzdlv_resume NULL +#endif +/* + * initialise the JZDLV driver + * register the mixer and dsp interfaces with the kernel + */ +static int jzdlv_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + int ret = 0, retval; + + /*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); + + __cpm_start_idct(); + __cpm_start_db(); + __cpm_start_me(); + __cpm_start_mc(); + __cpm_start_ipu(); + + 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) + return -ENOMEM; + + jzdlv_reset(codec); + /* 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 pcm_err; + } + + /* power on device */ + jzdlv_dapm_event(codec, SNDRV_CTL_POWER_D3hot); + jzdlv_add_controls(codec); + jzdlv_add_widgets(codec); + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "jzcodec: failed to register card\n"); + goto card_err; + } + + mdelay(10); + REG_AIC_I2SCR = 0x10; + mdelay(20); + /* power on DLV */ + write_codec_file(9, 0xff); + write_codec_file(8, 0x3f); + 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; + } + + printk_codec_files(); + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(codec->reg_cache); + return ret; +} + +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_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct jzdlv_priv *jzdlv; + int ret = 0; + + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + jzdlv = kzalloc(sizeof(struct jzdlv_priv), GFP_KERNEL); + if (jzdlv == NULL) { + kfree(codec); + return -ENOMEM; + } + + codec->private_data = jzdlv; + socdev->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + jzdlv_socdev = socdev; + + /* 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; + ret = jzdlv_init(jzdlv_socdev); + + if (ret < 0) { + codec = jzdlv_socdev->codec; + err("failed to initialise jzdlv\n"); + kfree(codec); + } + + return ret; +} + +/* 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 = socdev->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_GPL(soc_codec_dev_jzdlv); + +MODULE_DESCRIPTION("ASoC JZDLV driver"); +MODULE_AUTHOR("Richard"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/sound/soc/codecs/jzdlv.h b/target/linux/xburst/files-2.6.27/sound/soc/codecs/jzdlv.h new file mode 100755 index 000000000..13a294c2e --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/soc/codecs/jzdlv.h @@ -0,0 +1,50 @@ +/* + * 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/target/linux/xburst/files-2.6.27/sound/soc/jz4740/Kconfig b/target/linux/xburst/files-2.6.27/sound/soc/jz4740/Kconfig new file mode 100755 index 000000000..0bfbffeee --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/sound/soc/jz4740/Makefile b/target/linux/xburst/files-2.6.27/sound/soc/jz4740/Makefile new file mode 100755 index 000000000..4c79b138b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-ac97.c b/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-ac97.c new file mode 100755 index 000000000..84da470e9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-ac97.h b/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-ac97.h new file mode 100755 index 000000000..e80e2a0ad --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-i2s.c b/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-i2s.c new file mode 100755 index 000000000..27f6b62ef --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-i2s.c @@ -0,0 +1,297 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_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_pcm_runtime *rtd = substream->private_data; + //struct snd_soc_cpu_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; + rtd->dai->cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_out; + if (channels == 1) + __aic_enable_mono2stereo(); + else + __aic_disable_mono2stereo(); + } else + rtd->dai->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) +{ + 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) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + } else { + } + + return; +} + +static int jz4740_i2s_probe(struct platform_device *pdev) +{ + __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 platform_device *dev, + struct snd_soc_dai *dai) +{ + if (!dai->active) + return 0; + + return 0; +} + +static int jz4740_i2s_resume(struct platform_device *pdev, + 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_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) + +struct snd_soc_dai jz4740_i2s_dai = { + .name = "jz4740-i2s", + .id = 0, + .type = SND_SOC_DAI_I2S, + .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 = { + .startup = jz4740_i2s_startup, + .shutdown = jz4740_i2s_shutdown, + .trigger = jz4740_i2s_trigger, + .hw_params = jz4740_i2s_hw_params,}, + .dai_ops = { + .set_fmt = jz4740_i2s_set_dai_fmt, + .set_sysclk = jz4740_i2s_set_dai_sysclk, + }, +}; + +EXPORT_SYMBOL_GPL(jz4740_i2s_dai); + +/* Module information */ +MODULE_AUTHOR("Richard, cjfeng@ingenic.cn, www.ingenic.cn"); +MODULE_DESCRIPTION("jz4740 I2S SoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-i2s.h b/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-i2s.h new file mode 100755 index 000000000..7c38f8d9f --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-pcm.c b/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-pcm.c new file mode 100755 index 000000000..6787f6c95 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-pcm.c @@ -0,0 +1,689 @@ +/* + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#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 + +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_U16_LE | + SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S8, + .rates = SNDRV_PCM_RATE_8000_48000/*0x3fe*/, + .rate_min = 8000, + .rate_min = 48000, + .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, +}; + +/* 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; + printk("%s:%s:%d\n",__FILE__,__FUNCTION__,__LINE__); + 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; + } + /* 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 = 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, + 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; + 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 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_32BIT_MASK; + +int jz4740_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 = &jz4740_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = DMA_32BIT_MASK; + + 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); + +MODULE_AUTHOR("Richard"); +MODULE_DESCRIPTION("Ingenic Jz4740 PCM DMA module"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-pcm.h b/target/linux/xburst/files-2.6.27/sound/soc/jz4740/jz4740-pcm.h new file mode 100755 index 000000000..68ea842d1 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +#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/target/linux/xburst/files-2.6.27/sound/soc/jz4740/pavo.c b/target/linux/xburst/files-2.6.27/sound/soc/jz4740/pavo.c new file mode 100755 index 000000000..a364cfa45 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/soc/jz4740/pavo.c @@ -0,0 +1,364 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + +#if 0 + /* set the enpoints to their new connetion states */ + snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk); + snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic); + snd_soc_dapm_set_endpoint(codec, "Line Jack", line); + snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp); + snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs); + + /* signal a DAPM event */ + snd_soc_dapm_sync_endpoints(codec); +#endif +} + +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->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->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->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->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->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 char *audio_map[][3] = { + + /* 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; + +#if 0 + snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); + snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); +#endif + /* 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]); + } +#if 0 + /* Set up pavo specific audio path audio_map */ + for(i = 0; audio_map[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + } + + snd_soc_dapm_sync_endpoints(codec); +#endif + 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_machine snd_soc_machine_pavo = { + .name = "Pavo", + .dai_link = &pavo_dai, + .num_links = 1, +}; + +/* pavo audio subsystem */ +static struct snd_soc_device pavo_snd_devdata = { + .machine = &snd_soc_machine_pavo, + .platform = &jz4740_soc_platform, + .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/target/linux/xburst/files-2.6.27/sound/soc/jz4750/Kconfig b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/Kconfig new file mode 100755 index 000000000..23e270b94 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 || JZ4750D_CETUS) && 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/target/linux/xburst/files-2.6.27/sound/soc/jz4750/Makefile b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/Makefile new file mode 100755 index 000000000..ba5cbfaa7 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/sound/soc/jz4750/apus.c b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/apus.c new file mode 100755 index 000000000..a9862d5bc --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/apus.c @@ -0,0 +1,405 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../codecs/jzdlv.h" +#include "jz4750-pcm.h" +#include "jz4750-i2s.h" + +//static struct snd_soc_machine apus; + +#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; + snd_soc_dapm_disable_pin(codec, "Mic Jack"); + snd_soc_dapm_disable_pin(codec, "Line Jack"); + snd_soc_dapm_enable_pin(codec, "Headphone Jack"); + snd_soc_dapm_disable_pin(codec, "Headset Jack"); + break; + case APUS_MIC: + mic = 1; + snd_soc_dapm_enable_pin(codec, "Mic Jack"); + snd_soc_dapm_disable_pin(codec, "Line Jack"); + snd_soc_dapm_disable_pin(codec, "Headphone Jack"); + snd_soc_dapm_disable_pin(codec, "Headset Jack"); + break; + case APUS_LINE: + line = 1; + snd_soc_dapm_disable_pin(codec, "Mic Jack"); + snd_soc_dapm_enable_pin(codec, "Line Jack"); + snd_soc_dapm_disable_pin(codec, "Headphone Jack"); + snd_soc_dapm_disable_pin(codec, "Headset Jack"); + break; + case APUS_HEADSET: + hs = 1; + mic = 1; + snd_soc_dapm_enable_pin(codec, "Mic Jack"); + snd_soc_dapm_disable_pin(codec, "Line Jack"); + snd_soc_dapm_disable_pin(codec, "Headphone Jack"); + snd_soc_dapm_enable_pin(codec, "Headset Jack"); + break; + } + + if (apus_spk_func == APUS_SPK_ON) + spk = 1; + + if (apus_spk_func == APUS_SPK_ON) + snd_soc_dapm_enable_pin(codec, "Ext Spk"); + else + snd_soc_dapm_disable_pin(codec, "Ext Spk"); + + /* 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->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 int 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 0; +} + +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->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);*/ + ret = snd_soc_dai_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->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);*/ + ret = snd_soc_dai_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->dai_ops.set_sysclk(codec_dai, JZDLV_SYSCLK, 111, + SND_SOC_CLOCK_IN);*/ + ret = snd_soc_dai_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->dai_ops.set_sysclk(cpu_dai, JZ4750_I2S_SYSCLK, 0, + SND_SOC_CLOCK_IN);*/ + ret = snd_soc_dai_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; +} + +static int jzdlv_get_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + //int reg = kcontrol->private_value & 0xFF; + //int shift = (kcontrol->private_value >> 8) & 0x0F; + //int mask = (kcontrol->private_value >> 16) & 0xFF; + + //ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; + return 0; +} + +static int jzdlv_set_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + //int reg = kcontrol->private_value & 0xFF; + //int shift = (kcontrol->private_value >> 8) & 0x0F; + //int mask = (kcontrol->private_value >> 16) & 0xFF; + + /*if (((lm4857_regs[reg] >> shift) & mask) == + ucontrol->value.integer.value[0]) + return 0; + + lm4857_regs[reg] &= ~(mask << shift); + lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift; + lm4857_write_regs();*/ + return 1; +} + +/* 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 DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); +//static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); + +static const struct snd_kcontrol_new jzdlv_apus_controls[] = { +/* SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", 1, 0, 31, 0, + jzdlv_get_reg, jzdlv_set_reg, stereo_tlv),*/ + SOC_SINGLE_EXT_TLV("PCM", 1, 0, 31, 0, + jzdlv_get_reg, jzdlv_set_reg, stereo_tlv), + SOC_SINGLE_EXT_TLV("Capture", 2, 0, 31, 0, + jzdlv_get_reg, jzdlv_set_reg, stereo_tlv), +/* SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0, + lm4857_get_reg, lm4857_set_reg, mono_tlv),*/ + + 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 i, err; + + snd_soc_dapm_disable_pin(codec, "LLINEIN"); + snd_soc_dapm_disable_pin(codec, "RLINEIN"); + + /* Add apus specific controls */ + for (i = 0; i < ARRAY_SIZE(jzdlv_apus_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&jzdlv_apus_controls[i],codec, NULL)); + if (err < 0) + return err; + } + + /* Add apus specific widgets */ + snd_soc_dapm_new_controls(codec, jzdlv_dapm_widgets, + ARRAY_SIZE(jzdlv_dapm_widgets)); + + /* Set up apus specific audio path audio_map */ + 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_machine snd_soc_machine_apus = { + .name = "Apus", + .dai_link = &apus_dai, + .num_links = 1, +}; + +/* apus audio subsystem */ +static struct snd_soc_device apus_snd_devdata = { + .machine = &snd_soc_machine_apus, + .platform = &jz4750_soc_platform, + .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/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-ac97.c b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-ac97.c new file mode 100755 index 000000000..84da470e9 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-ac97.h b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-ac97.h new file mode 100755 index 000000000..cd116e9f3 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-i2s.c b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-i2s.c new file mode 100755 index 000000000..a1a49936a --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-i2s.c @@ -0,0 +1,311 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_pcm_runtime *rtd = substream->private_data; + struct snd_soc_cpu_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_pcm_runtime *rtd = substream->private_data; + //struct snd_soc_cpu_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; + rtd->dai->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) +{ + 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) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + } else { + } + + return; +} + +static int jz4750_i2s_probe(struct platform_device *pdev) +{ + __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 platform_device *dev, + struct snd_soc_dai *dai) +{ + if (!dai->active) + return 0; + + return 0; +} + +static int jz4750_i2s_resume(struct platform_device *pdev, + 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) + +struct snd_soc_dai jz4750_i2s_dai = { + .name = "jz4750-i2s", + .id = 0, + .type = SND_SOC_DAI_I2S, + .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 = { + .startup = jz4750_i2s_startup, + .shutdown = jz4750_i2s_shutdown, + .trigger = jz4750_i2s_trigger, + .hw_params = jz4750_i2s_hw_params,}, + .dai_ops = { + .set_fmt = jz4750_i2s_set_dai_fmt, + .set_sysclk = jz4750_i2s_set_dai_sysclk, + }, +}; + +EXPORT_SYMBOL_GPL(jz4750_i2s_dai); + +/* Module information */ +MODULE_AUTHOR("Richard, cjfeng@ingenic.cn, www.ingenic.cn"); +MODULE_DESCRIPTION("jz4750 I2S SoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-i2s.h b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-i2s.h new file mode 100755 index 000000000..f4f97dc55 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-pcm.c b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-pcm.c new file mode 100755 index 000000000..4f7bad2d8 --- /dev/null +++ b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#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_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_32BIT_MASK; + +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_32BIT_MASK; + + 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); + +MODULE_AUTHOR("Richard"); +MODULE_DESCRIPTION("Ingenic Jz4750 PCM DMA module"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-pcm.h b/target/linux/xburst/files-2.6.27/sound/soc/jz4750/jz4750-pcm.h new file mode 100755 index 000000000..d7d4f722b --- /dev/null +++ b/target/linux/xburst/files-2.6.27/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 + +#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 diff --git a/target/linux/xburst/patches-2.6.27/001-ingenic-patchset.patch b/target/linux/xburst/patches-2.6.27/001-ingenic-patchset.patch new file mode 100644 index 000000000..981861659 --- /dev/null +++ b/target/linux/xburst/patches-2.6.27/001-ingenic-patchset.patch @@ -0,0 +1,6033 @@ +diff -ru linux-2.6/arch/mips/boot/Makefile /plain/src/qi/linux-2.6.27.git.svn/arch/mips/boot/Makefile +--- linux-2.6/arch/mips/boot/Makefile 2009-08-18 00:01:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/arch/mips/boot/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -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 @@ + + 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 @@ + $(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 -ru linux-2.6/arch/mips/Kconfig /plain/src/qi/linux-2.6.27.git.svn/arch/mips/Kconfig +--- linux-2.6/arch/mips/Kconfig 2009-08-18 00:01:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/arch/mips/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -19,6 +19,90 @@ + 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 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 JZ4760_F4760 ++ bool "Ingenic JZ4760 FPGA board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4760 ++ select JZ_FPGA ++ + config MACH_ALCHEMY + bool "Alchemy processor based machines" + +@@ -610,6 +694,52 @@ + + 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_JZ4760 ++ 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 GENERIC_LOCKBREAK + bool + default y +@@ -1740,6 +1870,14 @@ + + source "kernel/time/Kconfig" + ++# the value of (max order + 1) ++config FORCE_MAX_ZONEORDER ++ prompt "MAX_ZONEORDER" ++ int ++ default "12" ++ help ++ The max memory that can be allocated = 4KB * 2^(CONFIG_FORCE_MAX_ZONEORDER - 1) ++ + # + # Timer Interrupt Frequency Configuration + # +@@ -2013,6 +2151,23 @@ + + endmenu + ++menu "CPU Frequency scaling" ++ ++config CPU_FREQ_JZ ++ tristate "CPUfreq driver for JZ CPUs" ++ depends on JZSOC ++ default n ++ help ++ This enables the CPUfreq driver for JZ CPUs. ++ ++ If in doubt, say N. ++ ++if (CPU_FREQ_JZ) ++source "drivers/cpufreq/Kconfig" ++endif ++ ++endmenu ++ + menu "Power management options" + + config ARCH_SUSPEND_POSSIBLE +diff -ru linux-2.6/arch/mips/kernel/cpu-probe.c /plain/src/qi/linux-2.6.27.git.svn/arch/mips/kernel/cpu-probe.c +--- linux-2.6/arch/mips/kernel/cpu-probe.c 2009-08-17 23:58:00.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/arch/mips/kernel/cpu-probe.c 2009-08-12 10:39:09.000000000 +0200 +@@ -153,6 +153,7 @@ + case CPU_25KF: + case CPU_PR4450: + case CPU_BCM3302: ++ case CPU_JZRISC: + cpu_wait = r4k_wait; + break; + +@@ -813,6 +814,22 @@ + } + } + ++static inline void cpu_probe_ingenic(struct cpuinfo_mips *c) ++{ ++ 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; ++ break; ++ default: ++ panic("Unknown Ingenic Processor ID!"); ++ break; ++ } ++} ++ + const char *__cpu_name[NR_CPUS]; + + /* +@@ -894,6 +911,7 @@ + case CPU_BCM4710: name = "Broadcom BCM4710"; break; + case CPU_PR4450: name = "Philips PR4450"; break; + case CPU_LOONGSON2: name = "ICT Loongson-2"; break; ++ case CPU_JZRISC: name = "Ingenic JZRISC"; break; + default: + BUG(); + } +@@ -933,6 +951,9 @@ + case PRID_COMP_NXP: + cpu_probe_nxp(c); + break; ++ case PRID_COMP_INGENIC: ++ cpu_probe_ingenic(c); ++ break; + default: + c->cputype = CPU_UNKNOWN; + } +diff -ru linux-2.6/arch/mips/kernel/proc.c /plain/src/qi/linux-2.6.27.git.svn/arch/mips/kernel/proc.c +--- linux-2.6/arch/mips/kernel/proc.c 2009-08-17 23:58:00.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/arch/mips/kernel/proc.c 2009-08-12 10:39:09.000000000 +0200 +@@ -17,6 +17,10 @@ + + unsigned int vced_count, vcei_count; + ++#ifdef CONFIG_JZSOC ++extern const char *get_board_type(void); ++#endif ++ + static int show_cpuinfo(struct seq_file *m, void *v) + { + unsigned long n = (unsigned long) v - 1; +@@ -35,6 +39,10 @@ + if (n == 0) + seq_printf(m, "system type\t\t: %s\n", get_system_type()); + ++#ifdef CONFIG_JZSOC ++ /* Android requires 'Hardware' to setup the init.%hardware%.rc */ ++ seq_printf(m, "Hardware\t\t: %s\n", get_board_type()); ++#endif + seq_printf(m, "processor\t\t: %ld\n", n); + sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", + cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : ""); +diff -ru linux-2.6/arch/mips/kernel/signal.c /plain/src/qi/linux-2.6.27.git.svn/arch/mips/kernel/signal.c +--- linux-2.6/arch/mips/kernel/signal.c 2009-08-17 23:58:00.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/arch/mips/kernel/signal.c 2009-08-12 10:39:09.000000000 +0200 +@@ -351,6 +351,7 @@ + if (!access_ok(VERIFY_READ, act, sizeof(*act))) + return -EFAULT; + err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler); ++ err |= __get_user(new_ka.sa.sa_restorer, &act->sa_restorer); + err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + err |= __get_user(mask, &act->sa_mask.sig[0]); + if (err) +@@ -366,6 +367,7 @@ + return -EFAULT; + err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); ++ err |= __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer); + err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); + err |= __put_user(0, &oact->sa_mask.sig[1]); + err |= __put_user(0, &oact->sa_mask.sig[2]); +@@ -565,6 +567,10 @@ + regs->regs[31] = (unsigned long) frame->rs_code; + regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; + ++ /* Add for bionic. I'm not sure whether it works. */ ++ if (ka->sa.sa_flags & SA_RESTORER) ++ regs->regs[31] = (unsigned long)ka->sa.sa_restorer; ++ + DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", + current->comm, current->pid, + frame, regs->cp0_epc, regs->regs[31]); +diff -ru linux-2.6/arch/mips/kernel/unaligned.c /plain/src/qi/linux-2.6.27.git.svn/arch/mips/kernel/unaligned.c +--- linux-2.6/arch/mips/kernel/unaligned.c 2009-08-17 23:58:00.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/arch/mips/kernel/unaligned.c 2009-08-12 10:39:09.000000000 +0200 +@@ -497,6 +497,11 @@ + send_sig(SIGILL, current, 1); + } + ++#if defined(CONFIG_JZ_TCSM) ++#undef user_mode ++#define user_mode(regs) ((((regs)->cp0_status & KU_MASK) == KU_USER) || (regs->cp0_badvaddr < 0x80000000)) ++#endif ++ + asmlinkage void do_ade(struct pt_regs *regs) + { + extern int do_dsemulret(struct pt_regs *); +@@ -534,8 +539,9 @@ + * This is all so but ugly ... + */ + seg = get_fs(); +- if (!user_mode(regs)) ++ if (!user_mode(regs)) { + set_fs(KERNEL_DS); ++ } + emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc); + set_fs(seg); + +diff -ru linux-2.6/arch/mips/Makefile /plain/src/qi/linux-2.6.27.git.svn/arch/mips/Makefile +--- linux-2.6/arch/mips/Makefile 2009-08-17 23:58:00.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/arch/mips/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -167,6 +167,46 @@ + # + + # ++# Commond Ingenic JZ4730 series ++# ++core-$(CONFIG_SOC_JZ4730) += arch/mips/jz4730/ ++cflags-$(CONFIG_SOC_JZ4730) += -Iinclude/asm-mips/mach-jz4730 ++load-$(CONFIG_SOC_JZ4730) += 0xffffffff80010000 ++ ++# ++# Commond Ingenic JZ4740 series ++# ++ ++core-$(CONFIG_SOC_JZ4740) += arch/mips/jz4740/ ++cflags-$(CONFIG_SOC_JZ4740) += -Iinclude/asm-mips/mach-jz4740 ++load-$(CONFIG_SOC_JZ4740) += 0xffffffff80010000 ++ ++# ++# Commond Ingenic JZ4750 series ++# ++ ++core-$(CONFIG_SOC_JZ4750) += arch/mips/jz4750/ ++cflags-$(CONFIG_SOC_JZ4750) += -Iinclude/asm-mips/mach-jz4750 ++load-$(CONFIG_SOC_JZ4750) += 0xffffffff80010000 ++ ++ ++# ++# Commond Ingenic JZ4750D series ++# ++ ++core-$(CONFIG_SOC_JZ4750D) += arch/mips/jz4750d/ ++cflags-$(CONFIG_SOC_JZ4750D) += -Iinclude/asm-mips/mach-jz4750d ++load-$(CONFIG_SOC_JZ4750D) += 0xffffffff80010000 ++ ++# ++# Commond Ingenic JZ4760 series ++# ++ ++core-$(CONFIG_SOC_JZ4760) += arch/mips/jz4760/ ++cflags-$(CONFIG_SOC_JZ4760) += -Iinclude/asm-mips/mach-jz4760 ++load-$(CONFIG_SOC_JZ4760) += 0xffffffff80010000 ++ ++# + # Acer PICA 61, Mips Magnum 4000 and Olivetti M700. + # + core-$(CONFIG_MACH_JAZZ) += arch/mips/jazz/ +@@ -673,6 +713,12 @@ + + all: $(all-y) + ++uImage: $(vmlinux-32) ++ +@$(call makeboot,$@) ++ ++zImage: $(vmlinux-32) ++ +@$(call makeboot,$@) ++ + vmlinux.bin: $(vmlinux-32) + +@$(call makeboot,$@) + +@@ -697,6 +743,7 @@ + + archclean: + @$(MAKE) $(clean)=arch/mips/boot ++ @$(MAKE) $(clean)=arch/mips/boot/compressed + @$(MAKE) $(clean)=arch/mips/lasat + + define archhelp +@@ -703,6 +746,9 @@ + 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 -ru linux-2.6/arch/mips/mm/cache.c /plain/src/qi/linux-2.6.27.git.svn/arch/mips/mm/cache.c +--- linux-2.6/arch/mips/mm/cache.c 2009-08-17 23:58:00.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/arch/mips/mm/cache.c 2009-08-12 10:39:09.000000000 +0200 +@@ -51,6 +51,8 @@ + 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 -ru linux-2.6/arch/mips/mm/c-r4k.c /plain/src/qi/linux-2.6.27.git.svn/arch/mips/mm/c-r4k.c +--- linux-2.6/arch/mips/mm/c-r4k.c 2009-08-17 23:58:00.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/arch/mips/mm/c-r4k.c 2009-08-12 10:39:09.000000000 +0200 +@@ -895,6 +895,36 @@ + 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 -ru linux-2.6/arch/mips/mm/fault.c /plain/src/qi/linux-2.6.27.git.svn/arch/mips/mm/fault.c +--- linux-2.6/arch/mips/mm/fault.c 2009-08-17 23:58:00.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/arch/mips/mm/fault.c 2009-08-12 10:39:09.000000000 +0200 +@@ -31,6 +31,9 @@ + * and the problem, and then passes it off to one of the appropriate + * routines. + */ ++extern void show_registers(struct pt_regs *); ++extern void show_backtrace(struct task_struct *, const struct pt_regs *); ++ + asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, + unsigned long address) + { +@@ -131,14 +134,17 @@ + if (user_mode(regs)) { + tsk->thread.cp0_badvaddr = address; + tsk->thread.error_code = write; +-#if 0 +- printk("do_page_fault() #2: sending SIGSEGV to %s for " +- "invalid %s\n%0*lx (epc == %0*lx, ra == %0*lx)\n", ++#if 1 ++ printk("do_page_fault() #2: pid = %d sending SIGSEGV to %s for " ++ "invalid %s\n%0*lx (epc == %0*lx, ra == %0*lx)\n ", ++ tsk->pid, + tsk->comm, + write ? "write access to" : "read access from", + field, address, + field, (unsigned long) regs->cp0_epc, + field, (unsigned long) regs->regs[31]); ++ ++ show_registers(regs); + #endif + info.si_signo = SIGSEGV; + info.si_errno = 0; +diff -ru linux-2.6/arch/mips/mm/tlbex.c /plain/src/qi/linux-2.6.27.git.svn/arch/mips/mm/tlbex.c +--- linux-2.6/arch/mips/mm/tlbex.c 2009-08-17 23:58:00.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/arch/mips/mm/tlbex.c 2009-08-12 10:39:09.000000000 +0200 +@@ -379,6 +379,11 @@ + 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 -ru linux-2.6/drivers/i2c/busses/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/i2c/busses/Kconfig +--- linux-2.6/drivers/i2c/busses/Kconfig 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/i2c/busses/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -7,6 +7,14 @@ + comment "PC SMBus host controller drivers" + depends on PCI + ++config I2C_JZ47XX ++ tristate "JZ47XX I2C Interface support" ++ depends on JZSOC ++ help ++ If you have devices in the Ingenic JZ4730/JZ4740 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 -ru linux-2.6/drivers/i2c/busses/Makefile /plain/src/qi/linux-2.6.27.git.svn/drivers/i2c/busses/Makefile +--- linux-2.6/drivers/i2c/busses/Makefile 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/i2c/busses/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -3,6 +3,7 @@ + # + + # 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 -ru linux-2.6/drivers/i2c/i2c-dev.c /plain/src/qi/linux-2.6.27.git.svn/drivers/i2c/i2c-dev.c +--- linux-2.6/drivers/i2c/i2c-dev.c 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/i2c/i2c-dev.c 2009-08-12 10:39:09.000000000 +0200 +@@ -37,6 +37,8 @@ + #include + #include + ++extern unsigned short sub_addr; ++extern int addr_val; + static struct i2c_driver i2cdev_driver; + + /* +@@ -424,6 +426,14 @@ + case I2C_TIMEOUT: + client->adapter->timeout = arg; + break; ++ case I2C_SET_SUB_ADDRESS: ++ addr_val = 1; ++ sub_addr = arg; ++ break; ++ case I2C_SET_CLOCK: ++ i2c_jz_setclk(arg); ++ break; ++ + default: + /* NOTE: returning a fault code here could cause trouble + * in buggy userspace code. Some old kernel bugs returned +diff -ru linux-2.6/drivers/input/keyboard/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/input/keyboard/Kconfig +--- linux-2.6/drivers/input/keyboard/Kconfig 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/input/keyboard/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -280,6 +280,39 @@ + To compile this driver as a module, choose M here: the + module will be called aaed2000_kbd. + ++config KEYBOARD_JZ_GPIO ++ tristate "JZ keypad driver based on GPIO Buttons" ++ depends on JZSOC ++ 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 jz_gpio_keypad. ++ ++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 KEYBOARD_JZ_5x5 ++ 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_5x5. ++ + config KEYBOARD_GPIO + tristate "GPIO Buttons" + depends on GENERIC_GPIO +diff -ru linux-2.6/drivers/input/keyboard/Makefile /plain/src/qi/linux-2.6.27.git.svn/drivers/input/keyboard/Makefile +--- linux-2.6/drivers/input/keyboard/Makefile 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/input/keyboard/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -20,6 +20,9 @@ + obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o + obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o + obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o ++obj-$(CONFIG_KEYBOARD_JZ_GPIO) += jz_gpio_keypad.o ++obj-$(CONFIG_KEYBOARD_JZ_5x5) += jz_keypad_5x5.o ++obj-$(CONFIG_KEYBOARD_JZ) += jz_keypad.o + obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o + obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o + obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o +diff -ru linux-2.6/drivers/input/touchscreen/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/input/touchscreen/Kconfig +--- linux-2.6/drivers/input/touchscreen/Kconfig 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/input/touchscreen/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -115,6 +115,24 @@ + To compile this driver as a module, choose M here: the + module will be called inexio. + ++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_MK712 + tristate "ICS MicroClock MK712 touchscreen" + help +@@ -181,6 +199,12 @@ + To compile this driver as a module, choose M here: the + module will be called migor_ts. + ++config TOUCHSCREEN_SYNAPTICS_I2C_RMI ++ tristate "Synaptics i2c touchscreen" ++ depends on I2C ++ help ++ This enables support for Synaptics RMI over I2C based touchscreens. ++ + config TOUCHSCREEN_TOUCHRIGHT + tristate "Touchright serial touchscreen" + select SERIO +diff -ru linux-2.6/drivers/input/touchscreen/Makefile /plain/src/qi/linux-2.6.27.git.svn/drivers/input/touchscreen/Makefile +--- linux-2.6/drivers/input/touchscreen/Makefile 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/input/touchscreen/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -14,6 +14,7 @@ + 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 +@@ -22,6 +23,7 @@ + obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o + obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o + obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o ++obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI) += synaptics_i2c_rmi.o + obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o + obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o + obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o +diff -ru linux-2.6/drivers/misc/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/misc/Kconfig +--- linux-2.6/drivers/misc/Kconfig 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/misc/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -13,6 +13,40 @@ + + if MISC_DEVICES + ++config JZ_TCSM ++ bool "JZ TCSM for multimedia" ++ default y ++ ++config JZ_CIM ++ bool "JZ CIM for Camera driver" ++ default y ++ ++choice ++ depends on JZ_CIM ++ prompt "Camera Sensor" ++ default OV3640 ++ ++config OV3640 ++ bool "OmniVision OV3640 sensor support (3.1 MegaPixel)" ++config OV2640 ++ bool "OmniVision OV2640 sensor support (2.0 MegaPixel)" ++config OV9650 ++ bool "OmniVision OV9650 sensor support (1.3 MegaPixel)" ++endchoice ++ ++config ANDROID_PMEM ++ bool "Android pmem allocator" ++ default y ++ ++config TIMED_OUTPUT ++ bool "Timed output class driver" ++ default y ++ ++config TIMED_GPIO ++ bool "Android timed gpio driver" ++ depends on GENERIC_GPIO && TIMED_OUTPUT ++ default y ++ + config ATMEL_PWM + tristate "Atmel AT32/AT91 PWM support" + depends on AVR32 || ARCH_AT91 +@@ -55,6 +89,10 @@ + TC can be used for other purposes, such as PWM generation and + interval timing. + ++config BINDER_IPC ++ tristate "Binder IPC Driver" ++ default y ++ + config IBM_ASM + tristate "Device driver for IBM RSA service processor" + depends on X86 && PCI && INPUT && EXPERIMENTAL +@@ -424,6 +462,13 @@ + driver (SCSI/ATA) which supports enclosures + or a SCSI enclosure device (SES) to use these services. + ++config KERNEL_DEBUGGER_CORE ++ bool "Kernel Debugger Core" ++ default n ++ ---help--- ++ Generic kernel debugging command processor used by low level ++ (interrupt context) platform-specific debuggers. ++ + config SGI_XP + tristate "Support communication between SGI SSIs" + depends on NET +@@ -475,4 +520,75 @@ + This option enables addition debugging code for the SGI GRU driver. If + you are unsure, say N. + ++config LOW_MEMORY_KILLER ++ tristate "Low Memory Killer" ++ ---help--- ++ Register processes to be killed when memory is low ++ ++config LOGGER ++ bool "High-speed in-kernel logging driver" ++ default y ++ ++config UID_STAT ++ bool "UID based statistics tracking exported to /proc/uid_stat" ++ default n ++ ++config ANDROID_RAM_CONSOLE ++ bool "RAM buffer console" ++ default n ++ ++config ANDROID_RAM_CONSOLE_ENABLE_VERBOSE ++ bool "Enable verbose console messages" ++ default y ++ depends on ANDROID_RAM_CONSOLE ++ ++menuconfig ANDROID_RAM_CONSOLE_ERROR_CORRECTION ++ bool "Enable error correction" ++ default n ++ depends on ANDROID_RAM_CONSOLE ++ depends on !ANDROID_RAM_CONSOLE_EARLY_INIT ++ select REED_SOLOMON ++ select REED_SOLOMON_ENC8 ++ select REED_SOLOMON_DEC8 ++ ++if ANDROID_RAM_CONSOLE_ERROR_CORRECTION ++ ++config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE ++ int "Data data size" ++ default 128 ++ help ++ Must be a power of 2. ++ ++config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE ++ int "ECC size" ++ default 16 ++ ++config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE ++ int "Symbol size" ++ default 8 ++config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL ++ hex "Polynomial" ++ default 0x19 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 4) ++ default 0x29 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 5) ++ default 0x61 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 6) ++ default 0x89 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 7) ++ default 0x11d if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 8) ++ ++endif #ANDROID_RAM_CONSOLE_ERROR_CORRECTION ++ ++config ANDROID_RAM_CONSOLE_EARLY_INIT ++ bool "Start ram console early" ++ default n ++ depends on ANDROID_RAM_CONSOLE ++ ++config ANDROID_RAM_CONSOLE_EARLY_ADDR ++ hex "RAM console virtual address" ++ default 0 ++ depends on ANDROID_RAM_CONSOLE_EARLY_INIT ++ ++config ANDROID_RAM_CONSOLE_EARLY_SIZE ++ hex "RAM console buffer size" ++ default 0 ++ depends on ANDROID_RAM_CONSOLE_EARLY_INIT ++ + endif # MISC_DEVICES +diff -ru linux-2.6/drivers/misc/Makefile /plain/src/qi/linux-2.6.27.git.svn/drivers/misc/Makefile +--- linux-2.6/drivers/misc/Makefile 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/misc/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -10,9 +10,13 @@ + obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o + obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o + obj-$(CONFIG_ACER_WMI) += acer-wmi.o ++obj-$(CONFIG_ANDROID_PMEM) += pmem.o ++obj-$(CONFIG_TIMED_OUTPUT) += timed_output.o ++obj-$(CONFIG_TIMED_GPIO) += timed_gpio.o + obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o + obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o + obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o ++obj-$(CONFIG_BINDER_IPC) += binder.o + obj-$(CONFIG_HP_WMI) += hp-wmi.o + obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o + obj-$(CONFIG_LKDTM) += lkdtm.o +@@ -26,7 +30,14 @@ + obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o + obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o + obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o ++obj-$(CONFIG_KERNEL_DEBUGGER_CORE) += kernel_debugger.o + obj-$(CONFIG_KGDB_TESTS) += kgdbts.o + obj-$(CONFIG_SGI_XP) += sgi-xp/ + obj-$(CONFIG_SGI_GRU) += sgi-gru/ + obj-$(CONFIG_HP_ILO) += hpilo.o ++obj-$(CONFIG_LOGGER) += logger.o ++obj-$(CONFIG_UID_STAT) += uid_stat.o ++obj-$(CONFIG_LOW_MEMORY_KILLER) += lowmemorykiller.o ++obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o ++obj-$(CONFIG_JZ_TCSM) += jz_tcsm.o ++obj-$(CONFIG_JZ_CIM) += jz_sensor.o jz_cim.o +diff -ru linux-2.6/drivers/mmc/card/block.c /plain/src/qi/linux-2.6.27.git.svn/drivers/mmc/card/block.c +--- linux-2.6/drivers/mmc/card/block.c 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mmc/card/block.c 2009-08-12 10:39:09.000000000 +0200 +@@ -228,7 +228,11 @@ + brq.mrq.cmd = &brq.cmd; + brq.mrq.data = &brq.data; + ++#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0 ++ brq.cmd.arg = req->sector + 8192; ++#else + brq.cmd.arg = req->sector; ++#endif + if (!mmc_card_blockaddr(card)) + brq.cmd.arg <<= 9; + brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; +@@ -594,6 +598,9 @@ + + if (md) { + mmc_blk_set_blksize(md, card); ++#ifdef CONFIG_MMC_BLOCK_PARANOID_RESUME ++ md->queue.check_status = 1; ++#endif + mmc_queue_resume(&md->queue); + } + return 0; +diff -ru linux-2.6/drivers/mmc/core/mmc.c /plain/src/qi/linux-2.6.27.git.svn/drivers/mmc/core/mmc.c +--- linux-2.6/drivers/mmc/core/mmc.c 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mmc/core/mmc.c 2009-08-12 10:39:09.000000000 +0200 +@@ -140,8 +140,12 @@ + + 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 -= 8192; ++#else ++ csd->capacity = (1 + m) << (e + 2); ++#endif + csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); + csd->read_partial = UNSTUFF_BITS(resp, 79, 1); + csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); +diff -ru linux-2.6/drivers/mmc/core/sd.c /plain/src/qi/linux-2.6.27.git.svn/drivers/mmc/core/sd.c +--- linux-2.6/drivers/mmc/core/sd.c 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mmc/core/sd.c 2009-08-12 10:39:09.000000000 +0200 +@@ -109,8 +109,12 @@ + + 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 -= 8192; ++#else ++ csd->capacity = (1 + m) << (e + 2); ++#endif + csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); + csd->read_partial = UNSTUFF_BITS(resp, 79, 1); + csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); +@@ -137,7 +141,12 @@ + 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 -= 8192; ++#else + csd->capacity = (1 + m) << 10; ++#endif + + csd->read_blkbits = 9; + csd->read_partial = 0; +@@ -336,7 +345,9 @@ + int err; + u32 cid[4]; + unsigned int max_dtr; +- ++#ifdef CONFIG_MMC_PARANOID_SD_INIT ++ int retries; ++#endif + BUG_ON(!host); + WARN_ON(!host->claimed); + +@@ -448,11 +459,29 @@ + err = mmc_decode_scr(card); + if (err < 0) + goto free_card; +- + /* + * Fetch switch information from card. + */ ++#ifdef CONFIG_MMC_PARANOID_SD_INIT ++ for (retries = 1; retries <= 3; retries++) { ++ err = mmc_read_switch(card); ++ if (!err) { ++ if (retries > 1) { ++ printk(KERN_WARNING ++ "%s: recovered\n", ++ mmc_hostname(host)); ++ } ++ break; ++ } else { ++ printk(KERN_WARNING ++ "%s: read switch failed (attempt %d)\n", ++ mmc_hostname(host), retries); ++ } ++ } ++#else + err = mmc_read_switch(card); ++#endif ++ + if (err) + goto free_card; + } +@@ -535,18 +564,37 @@ + */ + static void mmc_sd_detect(struct mmc_host *host) + { +- int err; ++ int err = 0; ++#ifdef CONFIG_MMC_PARANOID_SD_INIT ++ int retries = 5; ++#endif + + BUG_ON(!host); + BUG_ON(!host->card); +- ++ + mmc_claim_host(host); + + /* + * Just check if our card has been removed. + */ ++#ifdef CONFIG_MMC_PARANOID_SD_INIT ++ while(retries) { ++ err = mmc_send_status(host->card, NULL); ++ printk("%s(%s): err = %d\n", __func__, mmc_hostname(host), err); ++ if (err) { ++ retries--; ++ udelay(5); ++ continue; ++ } ++ break; ++ } ++ if (!retries) { ++ printk(KERN_ERR "%s(%s): Unable to re-detect card (%d)\n", ++ __func__, mmc_hostname(host), err); ++ } ++#else + err = mmc_send_status(host->card, NULL); +- ++#endif + mmc_release_host(host); + + if (err) { +@@ -584,12 +632,31 @@ + static void mmc_sd_resume(struct mmc_host *host) + { + int err; ++#ifdef CONFIG_MMC_PARANOID_SD_INIT ++ int retries; ++#endif + + BUG_ON(!host); + BUG_ON(!host->card); + + mmc_claim_host(host); ++#ifdef CONFIG_MMC_PARANOID_SD_INIT ++ retries = 5; ++ while (retries) { ++ err = mmc_sd_init_card(host, host->ocr, host->card); ++ ++ if (err) { ++ printk(KERN_ERR "%s: Re-init card rc = %d (retries = %d)\n", ++ mmc_hostname(host), err, retries); ++ mdelay(5); ++ retries--; ++ continue; ++ } ++ break; ++ } ++#else + err = mmc_sd_init_card(host, host->ocr, host->card); ++#endif + mmc_release_host(host); + + if (err) { +@@ -622,6 +689,9 @@ + int mmc_attach_sd(struct mmc_host *host, u32 ocr) + { + int err; ++#ifdef CONFIG_MMC_PARANOID_SD_INIT ++ int retries; ++#endif + + BUG_ON(!host); + WARN_ON(!host->claimed); +@@ -670,9 +740,27 @@ + /* + * Detect and init the card. + */ ++#ifdef CONFIG_MMC_PARANOID_SD_INIT ++ retries = 5; ++ while (retries) { ++ err = mmc_sd_init_card(host, host->ocr, NULL); ++ if (err) { ++ retries--; ++ continue; ++ } ++ break; ++ } ++ ++ if (!retries) { ++ printk(KERN_ERR "%s: mmc_sd_init_card() failure (err = %d)\n", ++ mmc_hostname(host), err); ++ goto err; ++ } ++#else + err = mmc_sd_init_card(host, host->ocr, NULL); + if (err) + goto err; ++#endif + + mmc_release_host(host); + +diff -ru linux-2.6/drivers/mmc/host/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/mmc/host/Kconfig +--- linux-2.6/drivers/mmc/host/Kconfig 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mmc/host/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -4,6 +4,104 @@ + + comment "MMC/SD 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 -ru linux-2.6/drivers/mmc/host/Makefile /plain/src/qi/linux-2.6.27.git.svn/drivers/mmc/host/Makefile +--- linux-2.6/drivers/mmc/host/Makefile 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mmc/host/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -6,6 +6,9 @@ + 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 -ru linux-2.6/drivers/mtd/mtd_blkdevs.c /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/mtd_blkdevs.c +--- linux-2.6/drivers/mtd/mtd_blkdevs.c 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/mtd_blkdevs.c 2009-08-12 10:39:09.000000000 +0200 +@@ -39,8 +39,8 @@ + unsigned long block, nsect; + char *buf; + +- block = req->sector << 9 >> tr->blkshift; +- nsect = req->current_nr_sectors << 9 >> tr->blkshift; ++ block = ((unsigned long long)req->sector) << 9 >> tr->blkshift; ++ nsect = ((unsigned long long)req->current_nr_sectors) << 9 >> tr->blkshift; + + buf = req->buffer; + +@@ -275,7 +275,7 @@ + + /* 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); ++ set_capacity(gd, ((u_int64_t)new->size * tr->blksize) >> 9); + + gd->private_data = new; + new->blkcore_priv = gd; +diff -ru linux-2.6/drivers/mtd/mtdblock.c /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/mtdblock.c +--- linux-2.6/drivers/mtd/mtdblock.c 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/mtdblock.c 2009-08-12 10:39:09.000000000 +0200 +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -359,12 +360,26 @@ + kfree(dev); + } + ++static int mtdblock_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) ++{ ++ struct gendisk *gd = dev->blkcore_priv; ++ memset(geo, 0, sizeof(*geo)); ++ geo->heads = 4; ++ geo->sectors = 16; ++ geo->cylinders = dev->size/(4*16); ++ ++ printk("cylinders: %x \n", geo->cylinders); ++ printk("sects: %x\n", dev->size); ++ 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, +diff -ru linux-2.6/drivers/mtd/mtdchar.c /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/mtdchar.c +--- linux-2.6/drivers/mtd/mtdchar.c 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/mtdchar.c 2009-08-12 10:39:09.000000000 +0200 +@@ -145,8 +145,7 @@ + + DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); + +- /* Only sync if opened RW */ +- if ((file->f_mode & 2) && mtd->sync) ++ if (mtd->sync) + mtd->sync(mtd); + + put_mtd_device(mtd); +@@ -165,7 +164,7 @@ + { + 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; +@@ -259,7 +258,7 @@ + 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; +@@ -592,6 +591,72 @@ + 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; ++ } ++ + case MEMLOCK: + { + struct erase_info_user einfo; +@@ -643,9 +708,9 @@ + + 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; +@@ -656,9 +721,9 @@ + + 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; +@@ -773,6 +838,7 @@ + } + + default: ++ printk("line : %d\n", __LINE__); + ret = -ENOTTY; + } + +diff -ru linux-2.6/drivers/mtd/mtdcore.c /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/mtdcore.c +--- linux-2.6/drivers/mtd/mtdcore.c 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/mtdcore.c 2009-08-12 10:39:09.000000000 +0200 +@@ -297,10 +298,10 @@ + */ + + 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) { +@@ -344,7 +345,7 @@ + if (!this) + return 0; + +- return sprintf(buf, "mtd%d: %8.8x %8.8x \"%s\"\n", i, this->size, ++ return sprintf(buf, "mtd%d: %09llx %8.8x \"%s\"\n", i, this->size, + this->erasesize, this->name); + } + +diff -ru linux-2.6/drivers/mtd/mtdpart.c /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/mtdpart.c +--- linux-2.6/drivers/mtd/mtdpart.c 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/mtdpart.c 2009-08-12 10:39:09.000000000 +0200 +@@ -26,7 +26,7 @@ + struct mtd_part { + struct mtd_info mtd; + struct mtd_info *master; +- u_int32_t offset; ++ u_int64_t offset; + int index; + struct list_head list; + int registered; +@@ -44,8 +44,8 @@ + * 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); + int res; +@@ -65,8 +65,8 @@ + 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) +@@ -77,14 +77,14 @@ + 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); + + part->master->unpoint(part->master, from + part->offset, len); + } + +-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); +@@ -105,8 +105,8 @@ + 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, +@@ -114,14 +114,14 @@ + } + + 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, +@@ -129,14 +129,14 @@ + } + + 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)) +@@ -149,8 +149,8 @@ + 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)) +@@ -163,7 +163,7 @@ + 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); +@@ -178,23 +178,23 @@ + 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)) +@@ -235,7 +235,7 @@ + } + EXPORT_SYMBOL_GPL(mtd_erase_callback); + +-static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len) ++static int part_lock(struct mtd_info *mtd, loff_mtd_t ofs, size_mtd_t len) + { + struct mtd_part *part = PART(mtd); + if ((len + ofs) > mtd->size) +@@ -243,7 +243,7 @@ + return part->master->lock(part->master, ofs + part->offset, len); + } + +-static int part_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) ++static int part_unlock(struct mtd_info *mtd, loff_mtd_t ofs, size_mtd_t len) + { + struct mtd_part *part = PART(mtd); + if ((len + ofs) > mtd->size) +@@ -269,7 +269,7 @@ + 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) +@@ -278,7 +278,7 @@ + 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; +@@ -317,7 +317,7 @@ + + static struct mtd_part *add_one_partition(struct mtd_info *master, + const struct mtd_partition *part, int partno, +- u_int32_t cur_offset) ++ u_int64_t cur_offset) + { + struct mtd_part *slave; + +@@ -345,6 +345,7 @@ + + slave->mtd.read = part_read; + slave->mtd.write = part_write; ++ slave->mtd.priv = master->priv; //add by Nancy + + if (master->panic_write) + slave->mtd.panic_write = part_panic_write; +@@ -395,18 +396,20 @@ + slave->offset = cur_offset; + if (slave->offset == MTDPART_OFS_NXTBLK) { + slave->offset = cur_offset; +- if ((cur_offset % master->erasesize) != 0) { ++ if (((u32)cur_offset % master->erasesize) != 0) { + /* Round up to next erasesize */ +- slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; +- printk(KERN_NOTICE "Moving partition %d: " +- "0x%08x -> 0x%08x\n", partno, +- cur_offset, slave->offset); ++ //slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; ++ slave->offset = ((cur_offset >> (ffs(master->erasesize)-1)) + 1) * master->erasesize; ++ printk(KERN_NOTICE "Moving partition %d: " ++ "0x%09llx -> 0x%09llx\n", partno, ++ cur_offset, slave->offset); + } + } ++ + if (slave->mtd.size == MTDPART_SIZ_FULL) + slave->mtd.size = master->size - slave->offset; + +- printk(KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, ++ printk (KERN_NOTICE "0x%09llx-0x%09llx : \"%s\"\n", slave->offset, + slave->offset + slave->mtd.size, slave->mtd.name); + + /* let's do some sanity checks */ +@@ -420,9 +423,10 @@ + } + if (slave->offset + slave->mtd.size > master->size) { + slave->mtd.size = master->size - slave->offset; +- printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n", ++ printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n", + part->name, master->name, slave->mtd.size); + } ++ + if (master->numeraseregions > 1) { + /* Deal with variable erase size stuff */ + int i, max = master->numeraseregions; +@@ -449,7 +453,7 @@ + } + + if ((slave->mtd.flags & MTD_WRITEABLE) && +- (slave->offset % slave->mtd.erasesize)) { ++ ((u32)slave->offset % slave->mtd.erasesize)) { + /* Doesn't start on a boundary of major erase size */ + /* FIXME: Let it be writable if it is on a boundary of + * _minor_ erase size though */ +@@ -458,7 +462,7 @@ + part->name); + } + if ((slave->mtd.flags & MTD_WRITEABLE) && +- (slave->mtd.size % slave->mtd.erasesize)) { ++ ((u32)slave->mtd.size % slave->mtd.erasesize)) { + slave->mtd.flags &= ~MTD_WRITEABLE; + printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", + part->name); +@@ -466,7 +470,7 @@ + + slave->mtd.ecclayout = master->ecclayout; + if (master->block_isbad) { +- uint32_t offs = 0; ++ uint64_t offs = 0; + + while (offs < slave->mtd.size) { + if (master->block_isbad(master, +@@ -501,7 +505,7 @@ + int nbparts) + { + struct mtd_part *slave; +- u_int32_t cur_offset = 0; ++ u_int64_t cur_offset = 0; + int i, j, ret; + + printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); +diff -ru linux-2.6/drivers/mtd/nand/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/nand/Kconfig +--- linux-2.6/drivers/mtd/nand/Kconfig 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/nand/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -406,4 +406,121 @@ + Enables support for NAND Flash chips wired onto Freescale PowerPC + processor localbus with User-Programmable Machine support. + ++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 ++ 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 ++ bool 'Use DMA mode' ++ help ++ This enables using DMA for reading and writing NAND flash, if not selected, ++ then CPU mode is used. ++ ++config MTD_NAND_DMABUF ++ depends on MTD_NAND_DMA ++ 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 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. ++ + endif # MTD_NAND +diff -ru linux-2.6/drivers/mtd/nand/Makefile /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/nand/Makefile +--- linux-2.6/drivers/mtd/nand/Makefile 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/nand/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -34,5 +34,7 @@ + obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o + obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o + obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.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 -ru linux-2.6/drivers/mtd/nand/nand_base.c /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/nand/nand_base.c +--- linux-2.6/drivers/mtd/nand/nand_base.c 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/nand/nand_base.c 2009-08-12 10:39:09.000000000 +0200 +@@ -52,6 +52,16 @@ + #include + #endif + ++#include ++ ++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 */ ++ ++struct mtd_info *jz_mtd1 = NULL; /* for 1 plane operation */ ++char all_use_planes = 1; /* indicates whether multiple planes operation is used ++ by all partitions if multiple planes is supported by NAND */ ++ + /* Define default oob placement schemes for large and small page devices */ + static struct nand_ecclayout nand_oob_8 = { + .eccbytes = 3, +@@ -72,6 +82,20 @@ + }; + + static struct nand_ecclayout nand_oob_64 = { ++#if defined(CONFIG_MTD_HW_RS_ECC) || defined(CONFIG_MTD_HW_BCH_ECC) ++/* Reed-Solomon ECC or BCH 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}} ++#else ++/* HW&SW Hamming ECC */ + .eccbytes = 24, + .eccpos = { + 40, 41, 42, 43, 44, 45, 46, 47, +@@ -80,12 +104,85 @@ + .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 = { ++ 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 = 54}} ++ ++#elif defined(CONFIG_MTD_HW_BCH_ECC) ++#if !defined(CONFIG_MTD_HW_BCH_8BIT) ++/* 4-bit BCH ECC */ ++ .eccbytes = 56, ++ .eccpos = { ++ 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 = 70}} ++ ++#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, ++ 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 = 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); + + /* +@@ -95,6 +192,35 @@ + 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 + * +@@ -169,6 +295,20 @@ + 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: +@@ -298,13 +438,19 @@ + * + * 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); +@@ -343,7 +489,7 @@ + * 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 }; +@@ -363,6 +509,7 @@ + */ + 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; +@@ -402,7 +549,7 @@ + * 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; +@@ -554,7 +701,10 @@ + + /* 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; + } + +@@ -600,6 +750,8 @@ + 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; + + /* +@@ -675,7 +827,6 @@ + spin_lock(lock); + + /* Hardware controller shared among independend devices */ +- /* Hardware controller shared among independend devices */ + if (!chip->controller->active) + chip->controller->active = chip; + +@@ -878,7 +1029,8 @@ + return 0; + } + +-/** ++#ifndef CONFIG_MTD_HW_RS_ECC ++/* HW&SW Hamming ECC *//** + * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function + * @mtd: mtd info structure + * @chip: nand chip info structure +@@ -922,6 +1074,63 @@ + return 0; + } + ++#else /* CONFIG_MTD_HW_RS_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 +@@ -984,7 +1193,7 @@ + * @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) { + +@@ -996,7 +1205,7 @@ + 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 ? */ +@@ -1006,11 +1215,11 @@ + 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); +@@ -1033,7 +1242,7 @@ + * + * 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; +@@ -1067,10 +1276,18 @@ + if (realpage != chip->pagebuf || oob) { + bufpoi = aligned ? buf : chip->buffers->databuf; + ++ global_page = page; ++#if defined(CONFIG_MTD_HW_RS_ECC) || defined(CONFIG_MTD_NAND_DMA) ++ bufpoi[0] = (uint8_t)page; ++ bufpoi[1] = (uint8_t)(page >> 8); ++ bufpoi[2] = (uint8_t)(page >> 16); ++ bufpoi[3] = (uint8_t)(page >> 24); ++#else + 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)) +@@ -1149,7 +1366,7 @@ + sndcmd = 1; + } + +- ops->retlen = ops->len - (size_t) readlen; ++ ops->retlen = ops->len - (size_mtd_t) readlen; + if (oob) + ops->oobretlen = ops->ooblen - oobreadlen; + +@@ -1172,8 +1389,8 @@ + * + * 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; +@@ -1346,7 +1563,7 @@ + * + * 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; +@@ -1439,7 +1656,7 @@ + * + * 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; +@@ -1602,12 +1819,17 @@ + { + int status; + +- 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 { ++ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); ++ ++ 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 +@@ -1617,7 +1839,15 @@ + + 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) || \ ++ (!defined(CONFIG_SOC_JZ4730) && !defined(CONFIG_SOC_JZ4740) \ ++ && !defined(CONFIG_MTD_NAND_DMA)) ++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++#endif + status = chip->waitfunc(mtd, chip); + /* + * See if operation failed and additional status checks are +@@ -1653,7 +1883,7 @@ + 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) { + +@@ -1665,7 +1895,7 @@ + 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 ? */ +@@ -1675,11 +1905,11 @@ + 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); +@@ -1703,7 +1933,7 @@ + * + * 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; +@@ -1806,8 +2036,8 @@ + * + * 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; +@@ -1841,7 +2071,7 @@ + * + * 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; +@@ -1919,7 +2149,7 @@ + * @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; +@@ -2083,7 +2313,7 @@ + /* + * 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); +@@ -2205,7 +2435,7 @@ + * @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) +@@ -2219,7 +2449,7 @@ + * @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; +@@ -2379,7 +2609,21 @@ + 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 +@@ -2417,7 +2661,7 @@ + + chip->bbt_erase_shift = chip->phys_erase_shift = + ffs(mtd->erasesize) - 1; +- chip->chip_shift = ffs(chip->chipsize) - 1; ++ chip->chip_shift = ffs_ll(chip->chipsize) - 1; + + /* Set the bad block position */ + chip->badblockpos = mtd->writesize > 512 ? +@@ -2449,8 +2693,8 @@ + 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; + } +@@ -2517,7 +2761,7 @@ + */ + 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)) +@@ -2542,6 +2786,16 @@ + case 64: + chip->ecc.layout = &nand_oob_64; + break; ++ case 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 " + "oobsize %d\n", mtd->oobsize); +@@ -2565,7 +2819,11 @@ + case NAND_ECC_HW: + /* Use standard hwecc read page function ? */ + 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_oob) +@@ -2575,11 +2833,7 @@ + + case NAND_ECC_HW_SYNDROME: + if ((!chip->ecc.calculate || !chip->ecc.correct || +- !chip->ecc.hwctl) && +- (!chip->ecc.read_page || +- chip->ecc.read_page == nand_read_page_hwecc || +- !chip->ecc.write_page || +- chip->ecc.write_page == nand_write_page_hwecc)) { ++ !chip->ecc.hwctl)) { + printk(KERN_WARNING "No ECC functions supplied, " + "Hardware ECC not possible\n"); + BUG(); +@@ -2600,7 +2854,7 @@ + "%d byte page size, fallback to SW ECC\n", + chip->ecc.size, mtd->writesize); + chip->ecc.mode = NAND_ECC_SOFT; +- ++ + case NAND_ECC_SOFT: + chip->ecc.calculate = nand_calculate_ecc; + chip->ecc.correct = nand_correct_data; +@@ -2703,8 +2957,58 @@ + 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); ++ } ++ ++ return res; + } + + /* module_text_address() isn't exported, and it's mostly a pointless +diff -ru linux-2.6/drivers/mtd/nand/nand_bbt.c /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/nand/nand_bbt.c +--- linux-2.6/drivers/mtd/nand/nand_bbt.c 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/nand/nand_bbt.c 2009-08-12 10:39:09.000000000 +0200 +@@ -145,15 +145,15 @@ + { + 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) { +@@ -233,8 +233,8 @@ + /* + * 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 @@ + /* + * 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; +@@ -306,7 +306,7 @@ + * 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 @@ + * 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 @@ + 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 @@ + * 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 @@ + numblocks = this->chipsize >> (this->bbt_erase_shift - 1); + startblock = chip * numblocks; + numblocks += startblock; +- from = startblock << (this->bbt_erase_shift - 1); ++ from = (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;) { +@@ -428,8 +428,8 @@ + + if (ret) { + this->bbt[i >> 3] |= 0x03 << (i & 0x6); +- printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", +- i >> 1, (unsigned int)from); ++ printk(KERN_WARNING "Bad eraseblock %d at 0x%09llx\n", ++ i >> 1, (unsigned long long)from); + mtd->ecc_stats.badblocks++; + } + +@@ -495,7 +495,7 @@ + for (block = 0; block < td->maxblocks; block++) { + + int actblock = startblock + dir * block; +- loff_t offs = actblock << this->bbt_erase_shift; ++ loff_mtd_t offs = actblock << this->bbt_erase_shift; + + /* Read first page */ + scan_read_raw(mtd, buf, offs, mtd->writesize); +@@ -565,8 +565,8 @@ + 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 @@ + + 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 @@ + 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); +@@ -1015,7 +1015,7 @@ + * + * 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; +@@ -1191,7 +1191,7 @@ + * @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 -ru linux-2.6/drivers/mtd/nand/nand_ids.c /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/nand/nand_ids.c +--- linux-2.6/drivers/mtd/nand/nand_ids.c 2009-08-17 23:57:37.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/mtd/nand/nand_ids.c 2009-08-12 10:39:09.000000000 +0200 +@@ -109,6 +109,10 @@ + {"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}, ++ {"NAND 4GiB 3,3V 8-bit", 0xD5, 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 -ru linux-2.6/drivers/net/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/net/Kconfig +--- linux-2.6/drivers/net/Kconfig 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/net/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -207,6 +207,33 @@ + 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 JZ4760_ETH ++ tristate "JZ4760 On-Chip Ethernet support" ++ depends on NET_ETHERNET && (SOC_JZ4760 || SOC_JZ4810 || JZ_FPGA) ++ help ++ Say Y for support of JZ4760 On-Chip Ethernet interface. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called jz4760_eth. ++ + config MACB + tristate "Atmel MACB support" + depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91SAM9G20 || ARCH_AT91CAP9 +diff -ru linux-2.6/drivers/net/Makefile /plain/src/qi/linux-2.6.27.git.svn/drivers/net/Makefile +--- linux-2.6/drivers/net/Makefile 2009-08-17 23:58:01.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/net/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -90,6 +90,9 @@ + obj-$(CONFIG_MII) += mii.o + obj-$(CONFIG_PHYLIB) += phy/ + ++obj-$(CONFIG_JZ_ETH) += jz_eth.o ++obj-$(CONFIG_JZCS8900) += jzcs8900a.o ++obj-$(CONFIG_JZ4760_ETH) += jz4760_eth.o + obj-$(CONFIG_SUNDANCE) += sundance.o + obj-$(CONFIG_HAMACHI) += hamachi.o + obj-$(CONFIG_NET) += Space.o loopback.o +diff -ru linux-2.6/drivers/power/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/power/Kconfig +--- linux-2.6/drivers/power/Kconfig 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/power/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -62,4 +62,9 @@ + help + Say Y to enable support for the battery in Palm T|X. + ++config BATTERY_JZ ++ tristate "JZ battery" ++ help ++ Say Y to enable support for the battery in JZ SOC. ++ + endif # POWER_SUPPLY +diff -ru linux-2.6/drivers/power/Makefile /plain/src/qi/linux-2.6.27.git.svn/drivers/power/Makefile +--- linux-2.6/drivers/power/Makefile 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/power/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -22,3 +22,4 @@ + obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o + obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o + obj-$(CONFIG_BATTERY_PALMTX) += palmtx_battery.o ++obj-$(CONFIG_BATTERY_JZ) += jz_battery.o +diff -ru linux-2.6/drivers/power/power_supply_sysfs.c /plain/src/qi/linux-2.6.27.git.svn/drivers/power/power_supply_sysfs.c +--- linux-2.6/drivers/power/power_supply_sysfs.c 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/power/power_supply_sysfs.c 2009-08-12 10:39:09.000000000 +0200 +@@ -107,7 +107,8 @@ + POWER_SUPPLY_ATTR(energy_now), + POWER_SUPPLY_ATTR(energy_avg), + POWER_SUPPLY_ATTR(capacity), +- POWER_SUPPLY_ATTR(temp), ++ POWER_SUPPLY_ATTR(batt_temp), ++ POWER_SUPPLY_ATTR(batt_vol), + POWER_SUPPLY_ATTR(temp_ambient), + POWER_SUPPLY_ATTR(time_to_empty_now), + POWER_SUPPLY_ATTR(time_to_empty_avg), +diff -ru linux-2.6/drivers/rtc/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/rtc/Kconfig +--- linux-2.6/drivers/rtc/Kconfig 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/rtc/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -105,6 +105,16 @@ + driver does not expose RTC_UIE ioctls. Those requests generate + once-per-second update interrupts, used for synchronization. + ++config RTC_INTF_ALARM ++ bool "Android alarm driver" ++ depends on RTC_CLASS ++ default y ++ help ++ Provides non-wakeup and rtc backed wakeup alarms based on rtc or ++ elapsed realtime, and a non-wakeup alarm on the monotonic clock. ++ Also provides an ioctl to set the wall time which must be used ++ for elapsed realtime to work. ++ + config RTC_DRV_TEST + tristate "Test driver/device" + help +@@ -468,6 +478,16 @@ + To compile this driver as a module, choose M here: the + module will be called rtc-sa1100. + ++config RTC_DRV_JZ4750 ++ tristate "JZ4750/JZ4750D" ++ depends on SOC_JZ4750 || SOC_JZ4750D ++ help ++ If you say Y here you will get access to the real time clock ++ built into your JZ4750 or JZ4750D CPU. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called rtc-jz4750. ++ + config RTC_DRV_SH + tristate "SuperH On-Chip RTC" + depends on RTC_CLASS && SUPERH +diff -ru linux-2.6/drivers/rtc/Makefile /plain/src/qi/linux-2.6.27.git.svn/drivers/rtc/Makefile +--- linux-2.6/drivers/rtc/Makefile 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/rtc/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -11,6 +11,7 @@ + obj-$(CONFIG_RTC_CLASS) += rtc-core.o + rtc-core-y := class.o interface.o + ++rtc-core-$(CONFIG_RTC_INTF_ALARM) += alarm.o + rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o + rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o + rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o +@@ -59,3 +60,4 @@ + obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o + obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o + obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o ++obj-$(CONFIG_RTC_DRV_JZ4750) += rtc-jz4750.o +diff -ru linux-2.6/drivers/serial/8250.c /plain/src/qi/linux-2.6.27.git.svn/drivers/serial/8250.c +--- linux-2.6/drivers/serial/8250.c 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/serial/8250.c 2009-08-12 10:39:09.000000000 +0200 +@@ -178,7 +178,7 @@ + [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, + }, +@@ -397,6 +397,10 @@ + break; + + case UPIO_MEM: ++#if defined(CONFIG_JZSOC) ++ if (offset == (UART_FCR << up->port.regshift)) ++ value |= 0x10; /* set FCR.UUE */ ++#endif + writeb(value, up->port.membase + offset); + break; + +@@ -2057,6 +2061,83 @@ + 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; +@@ -2076,6 +2157,7 @@ + + return quot; + } ++#endif + + static void + serial8250_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -2085,6 +2167,9 @@ + 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: +@@ -2117,7 +2202,12 @@ + * 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 +@@ -2195,6 +2285,10 @@ + 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) { +@@ -2229,7 +2323,15 @@ + 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 +diff -ru linux-2.6/drivers/usb/core/hub.c /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/core/hub.c +--- linux-2.6/drivers/usb/core/hub.c 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/core/hub.c 2009-08-12 10:39:09.000000000 +0200 +@@ -1749,6 +1749,25 @@ + { + int i, status; + ++#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 0; ++ } ++#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 0; ++ } ++#endif ++ + /* Block EHCI CF initialization during the port reset. + * Some companion controllers don't like it when they mix. + */ +@@ -2666,11 +2685,35 @@ + le16_to_cpu(hub->descriptor->wHubCharacteristics); + struct usb_device *udev; + int status, i; ++#ifdef CONFIG_JZSOC ++ static char jzhub = 1; /* the hub first to be initialized is jzsoc on-chip hub */ ++#endif + + dev_dbg (hub_dev, + "port %d, status %04x, change %04x, %s\n", + port1, portstatus, portchange, portspeed (portstatus)); + ++#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) && (jzhub)) { ++ jzhub = 0; ++ return; ++ } ++#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) && (jzhub)) { ++ jzhub = 0; ++ return; ++ } ++#endif ++ + if (hub->has_indicators) { + set_port_led(hub, port1, HUB_LED_AUTO); + hub->indicator[port1-1] = INDICATOR_AUTO; +diff -ru linux-2.6/drivers/usb/gadget/composite.c /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/gadget/composite.c +--- linux-2.6/drivers/usb/gadget/composite.c 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/gadget/composite.c 2009-08-12 10:39:09.000000000 +0200 +@@ -492,7 +492,8 @@ + + while (*sp) { + s = *sp++; +- if (s->language != language) ++ ++ if (language && s->language != language) + continue; + value = usb_gadget_get_string(s, id, buf); + if (value > 0) +@@ -612,8 +613,8 @@ + * housekeeping for the gadget function we're implementing. Most of + * the work is in config and function specific setup. + */ +-static int +-composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ++ ++int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) + { + struct usb_composite_dev *cdev = get_gadget_data(gadget); + struct usb_request *req = cdev->req; +@@ -984,7 +985,7 @@ + .speed = USB_SPEED_HIGH, + + .bind = composite_bind, +- .unbind = __exit_p(composite_unbind), ++ .unbind = composite_unbind, + + .setup = composite_setup, + .disconnect = composite_disconnect, +diff -ru linux-2.6/drivers/usb/gadget/file_storage.c /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/gadget/file_storage.c +--- linux-2.6/drivers/usb/gadget/file_storage.c 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/gadget/file_storage.c 2009-08-12 10:39:09.000000000 +0200 +@@ -274,6 +274,18 @@ + + + /*-------------------------------------------------------------------------*/ ++#if defined(CONFIG_UDC_USE_LB_CACHE) ++#define GHOST ++#endif ++ ++#ifdef GHOST ++extern unsigned long udc_read(unsigned int offset, unsigned int len, unsigned char *); ++extern unsigned long udc_write(unsigned int 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) +@@ -345,8 +357,8 @@ + } mod_data = { // Default values + .transport_parm = "BBB", + .protocol_parm = "SCSI", +- .removable = 0, +- .can_stall = 1, ++ .removable = 1, ++ .can_stall = 0, + .vendor = DRIVER_VENDOR_ID, + .product = DRIVER_PRODUCT_ID, + .release = 0xffff, // Use controller chip type +@@ -806,6 +818,7 @@ + #define STRING_SERIAL 3 + #define STRING_CONFIG 4 + #define STRING_INTERFACE 5 ++#define STRING_MS_OS 0xee + + /* There is only one configuration. */ + #define CONFIG_VALUE 1 +@@ -993,6 +1006,7 @@ + {STRING_SERIAL, serial}, + {STRING_CONFIG, "Self-powered"}, + {STRING_INTERFACE, "Mass Storage"}, ++ {STRING_MS_OS, "Microsoft"}, + {} + }; + +@@ -1614,9 +1628,13 @@ + + /* Perform the read */ + file_offset_tmp = file_offset; ++#ifdef GHOST ++ nread = udc_read(file_offset_tmp, amount, bh->buf); ++#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); +@@ -1795,9 +1813,13 @@ + + /* Perform the write */ + file_offset_tmp = file_offset; ++#ifdef GHOST ++ nwritten = udc_write(file_offset_tmp, amount, bh->buf); ++#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); +@@ -1972,9 +1994,13 @@ + + /* Perform the read */ + file_offset_tmp = file_offset; ++#ifdef GHOST ++ nread = udc_read(file_offset_tmp, amount, bh->buf); ++#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); +@@ -2009,7 +2035,7 @@ + { + u8 *buf = (u8 *) bh->buf; + +- static char vendor_id[] = "Linux "; ++ static char vendor_id[] = "Ingenic "; + static char product_id[] = "File-Stor Gadget"; + + if (!fsg->curlun) { // Unsupported LUNs are okay +@@ -2876,6 +2902,15 @@ + 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 +@@ -3425,6 +3460,13 @@ + + /* The main loop */ + while (fsg->state != FSG_STATE_TERMINATED) { ++#ifdef GHOST ++ if ((fsg->atomic_bitflags & SUSPENDED)) ++ { ++ NAND_LB_FLASHCACHE(); ++ NAND_MTD_FLASHCACHE(); ++ } ++#endif + if (exception_in_progress(fsg) || signal_pending(current)) { + handle_exception(fsg); + continue; +@@ -3547,6 +3589,10 @@ + LDBG(curlun, "open backing file: %s\n", filename); + rc = 0; + ++#ifdef GHOST ++ NAND_LB_Init(); ++#endif ++ + out: + filp_close(filp, current->files); + return rc; +diff -ru linux-2.6/drivers/usb/gadget/gadget_chips.h /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/gadget/gadget_chips.h +--- linux-2.6/drivers/usb/gadget/gadget_chips.h 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/gadget/gadget_chips.h 2009-08-12 10:39:09.000000000 +0200 +@@ -15,6 +15,24 @@ + #ifndef __GADGET_CHIPS_H + #define __GADGET_CHIPS_H + ++#ifdef CONFIG_USB_GADGET_JZ4750 ++#define gadget_is_jz4750(g) !strcmp("ingenic_hsusb", (g)->name) /* same driver */ ++#else ++#define gadget_is_jz4750(g) 0 ++#endif ++ ++#ifdef CONFIG_USB_GADGET_JZ4740 ++#define gadget_is_jz4740(g) !strcmp("ingenic_hsusb", (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 +@@ -216,6 +234,13 @@ + return 0x20; + else if (gadget_is_m66592(gadget)) + return 0x21; ++ else if (gadget_is_jz4730(gadget)) ++ return 0x22; ++ else if (gadget_is_jz4740(gadget)) ++ return 0x23; ++ else if (gadget_is_jz4750(gadget)) ++ return 0x24; ++ + return -ENOENT; + } + +diff -ru linux-2.6/drivers/usb/gadget/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/gadget/Kconfig +--- linux-2.6/drivers/usb/gadget/Kconfig 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/gadget/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -94,6 +94,47 @@ + Many controller drivers are platform-specific; these + often need board-specific hooks. + ++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 || SOC_JZ4750D ++ 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_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_AMD5536UDC + boolean "AMD5536 UDC" + depends on PCI +@@ -399,6 +440,18 @@ + + endchoice + ++config USB_JZ_UDC_HOTPLUG ++ boolean "Ingenic USB Device Controller Hotplug Support" ++ depends on USB_GADGET_JZ4750 ++ ++config UDC_USE_LB_CACHE ++ bool "NAND LB Cache Support" ++ depends on (USB_FILE_STORAGE || USB_ANDROID) && (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_GADGET_DUALSPEED + bool + depends on USB_GADGET +@@ -406,7 +459,6 @@ + help + Means that gadget drivers should include extra descriptors + and code to handle dual-speed controllers. +- + # + # USB Gadget Drivers + # +@@ -596,6 +648,16 @@ + For more information, see Documentation/usb/gadget_printer.txt + which includes sample code for accessing the device file. + ++config USB_ANDROID ++ tristate "Android Gadget" ++ select USB_JZ_UDC_HOTPLUG ++ ++ help ++ The Android gadget provides mass storage and adb transport. ++ ++ Say "y" to link the driver statically, or "m" to build a ++ dynamically linked module called "g_android". ++ + config USB_CDC_COMPOSITE + tristate "CDC Composite Device (Ethernet and ACM)" + depends on NET +diff -ru linux-2.6/drivers/usb/gadget/Makefile /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/gadget/Makefile +--- linux-2.6/drivers/usb/gadget/Makefile 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/gadget/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -18,6 +18,11 @@ + obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o + obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o + obj-$(CONFIG_USB_M66592) += m66592-udc.o ++obj-$(CONFIG_USB_JZ4740) += jz4740_udc.o ++obj-$(CONFIG_USB_JZ4730) += jz4730_udc.o ++obj-$(CONFIG_USB_JZ4750) += jz4740_udc.o ++ ++obj-$(CONFIG_USB_JZ_UDC_HOTPLUG)+= udc_hotplug_core.o + + # + # USB gadget drivers +@@ -35,6 +40,7 @@ + epautoconf.o + g_cdc-objs := cdc2.o u_ether.o f_ecm.o \ + u_serial.o f_acm.o $(C_UTILS) ++g_android-objs := android.o f_adb.o f_mass_storage.o $(C_UTILS) + + ifeq ($(CONFIG_USB_ETH_RNDIS),y) + g_ether-objs += f_rndis.o rndis.o +@@ -48,4 +54,5 @@ + obj-$(CONFIG_USB_G_PRINTER) += g_printer.o + obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o + obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o ++obj-$(CONFIG_USB_ANDROID) += g_android.o + +diff -ru linux-2.6/drivers/usb/host/ohci-hcd.c /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/host/ohci-hcd.c +--- linux-2.6/drivers/usb/host/ohci-hcd.c 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/host/ohci-hcd.c 2009-08-12 10:39:09.000000000 +0200 +@@ -995,6 +995,11 @@ + #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 -ru linux-2.6/drivers/usb/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/Kconfig +--- linux-2.6/drivers/usb/Kconfig 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -42,6 +42,7 @@ + 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 -ru linux-2.6/drivers/usb/musb/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/Kconfig +--- linux-2.6/drivers/usb/musb/Kconfig 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -8,7 +8,10 @@ + + # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller + config USB_MUSB_HDRC +- depends on (USB || USB_GADGET) && HAVE_CLK ++ depends on (USB || USB_GADGET) ++ ++#&& HAVE_CLK Disabled by River ++ + depends on !SUPERH + select TWL4030_USB if MACH_OMAP_3430SDP + tristate 'Inventra Highspeed Dual Role Controller (TI, ...)' +@@ -144,12 +147,17 @@ + parameter. + + config USB_INVENTRA_DMA +- bool ++ bool 'Use INVENTRA DMA' + depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY +- default ARCH_OMAP2430 || ARCH_OMAP34XX ++ default ARCH_OMAP2430 || ARCH_OMAP34XX || SOC_JZ4760 + help + Enable DMA transfers using Mentor's engine. + ++config USB_MUSB_HSDMA_IRQ_SHARED ++ bool 'INVENTRA DMA IRQ shared with USB IRQ' ++ depends on USB_MUSB_HDRC && USB_INVENTRA_DMA && !MUSB_PIO_ONLY ++ default SOC_JZ4760 ++ + config USB_TI_CPPI_DMA + bool + depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY +diff -ru linux-2.6/drivers/usb/musb/Makefile /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/Makefile +--- linux-2.6/drivers/usb/musb/Makefile 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -22,6 +22,10 @@ + musb_hdrc-objs += omap2430.o + endif + ++ifeq ($(CONFIG_SOC_JZ4760),y) ++ musb_hdrc-objs += jz4760.o ++endif ++ + ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y) + musb_hdrc-objs += musb_gadget_ep0.o musb_gadget.o + endif +diff -ru linux-2.6/drivers/usb/musb/musb_core.c /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musb_core.c +--- linux-2.6/drivers/usb/musb/musb_core.c 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musb_core.c 2009-08-12 10:39:09.000000000 +0200 +@@ -107,13 +107,10 @@ + + #include "musb_core.h" + +- + #ifdef CONFIG_ARCH_DAVINCI + #include "davinci.h" + #endif + +- +- + unsigned debug; + module_param(debug, uint, S_IRUGO | S_IWUSR); + MODULE_PARM_DESC(debug, "Debug message level. Default = 0"); +@@ -148,6 +145,34 @@ + + /*-------------------------------------------------------------------------*/ + ++static inline void musb_dump_packet(int epnum, const u8 *packet, u16 len) ++{ ++ u16 i; ++ ++#ifdef MUSB_DUMP_EP_NUM ++ if (epnum != MUSB_DUMP_EP_NUM) ++ return; ++#endif ++ ++ printk(KERN_ERR "\nMUSB Packet Dump: Length: %d bytes.\n", len); ++ printk(KERN_ERR "==============================================\n"); ++ ++ for (i = 0; i < len; i++) { ++ printk("0x%02x ", packet[i]); ++ if ((i+ 1) % 10 == 0) ++ printk("\n"); ++ } ++ ++ printk("\n"); ++ printk(KERN_ERR "==============================================\n"); ++} ++ ++#define MUSB_DUMP_TX_PACKET(epnum, packet, len) \ ++// musb_dump_packet(epnum, packet, len) ++ ++#define MUSB_DUMP_RX_PACKET(epnum, packet, len) \ ++// musb_dump_packet(epnum, packet, len) ++ + #ifndef CONFIG_USB_TUSB6010 + /* + * Load an endpoint's FIFO +@@ -187,6 +212,8 @@ + /* byte aligned */ + writesb(fifo, src, len); + } ++ ++ MUSB_DUMP_TX_PACKET(hw_ep->num, src, len); + } + + /* +@@ -225,6 +252,8 @@ + /* byte aligned */ + readsb(fifo, dst, len); + } ++ ++ MUSB_DUMP_RX_PACKET(hw_ep->epnum, dst, len); + } + + #endif /* normal PIO */ +@@ -477,6 +506,20 @@ + + #ifdef CONFIG_USB_MUSB_HDRC_HCD + /* see manual for the order of the tests */ ++ ++#ifdef CONFIG_SOC_JZ4760 ++ /* ++ * Modified by River ++ * Note: There is a strange Session request IRQ asserted in the MUSB IP core of JZ4760 when MUSB is operating in DEVICE mode. ++ * We just ignore it. ++ */ ++ ++ if ((int_usb & MUSB_INTR_SESSREQ) && !(devctl & MUSB_DEVCTL_HM)) { ++ DBG(1, "SESSION_REQUEST (%s)\n", otg_state_string(musb)); ++ ++ handled = IRQ_HANDLED; ++ } ++#else + if (int_usb & MUSB_INTR_SESSREQ) { + DBG(1, "SESSION_REQUEST (%s)\n", otg_state_string(musb)); + +@@ -495,6 +538,7 @@ + + handled = IRQ_HANDLED; + } ++#endif + + if (int_usb & MUSB_INTR_VBUSERROR) { + int ignore = 0; +@@ -766,6 +810,7 @@ + #ifdef CONFIG_USB_MUSB_HDRC_HCD + case OTG_STATE_A_HOST: + case OTG_STATE_A_SUSPEND: ++ usb_hcd_resume_root_hub(musb_to_hcd(musb)); /* River - from Linux-2.6.29-rc6 usb-musb-resume-suspend-root-hub-on-disconnect.patch */ + musb_root_disconnect(musb); + if (musb->a_wait_bcon != 0) + musb_platform_try_idle(musb, jiffies +@@ -896,7 +941,7 @@ + + } else if (is_host_enabled(musb)) { + /* assume ID pin is hard-wired to ground */ +- devctl |= MUSB_DEVCTL_SESSION; ++ devctl |= MUSB_DEVCTL_SESSION; + + } else /* peripheral is enabled */ { + if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) +@@ -959,10 +1004,13 @@ + spin_lock_irqsave(&musb->lock, flags); + musb_platform_disable(musb); + musb_generic_disable(musb); ++ ++#ifdef CONFIG_HAVE_CLK + if (musb->clock) { + clk_put(musb->clock); + musb->clock = NULL; + } ++#endif + spin_unlock_irqrestore(&musb->lock, flags); + + /* FIXME power down */ +@@ -1259,7 +1307,7 @@ + hw_ep = musb->endpoints + epnum; + + /* read from core using indexed model */ +- reg = musb_readb(hw_ep->regs, 0x10 + MUSB_FIFOSIZE); ++ reg = musb_readb(mbase, 0x10 + MUSB_FIFOSIZE); /* Do not use hw_ep->regs before it's initialized. - Fixed by River. */ + if (!reg) { + /* 0's returned when no more endpoints */ + break; +@@ -1402,6 +1450,9 @@ + /* configure ep0 */ + musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE; + musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE; ++ ++ /* Added by River */ ++ musb->endpoints[0].is_shared_fifo = 1; + + /* discover endpoint configuration */ + musb->nr_endpoints = 1; +@@ -1477,8 +1528,48 @@ + + /*-------------------------------------------------------------------------*/ + +-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) ++#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_SOC_JZ4760) /* Added by River */ ++ ++/* Modified by River - For DMA IRQ Sharing */ ++#if defined(CONFIG_USB_MUSB_HSDMA_IRQ_SHARED) ++static irqreturn_t generic_interrupt(int irq, void *__hci) ++{ ++ unsigned long flags; ++ struct musb *musb = __hci; ++ ++ irqreturn_t rv, rv_dma, rv_usb; ++ ++ rv = rv_dma = rv_usb = IRQ_NONE; ++ ++ spin_lock_irqsave(&musb->lock, flags); ++ ++ /* Process DMA IRQ. */ ++ if (dma_controller_fetch_intr(musb->dma_controller)) ++ rv_dma = dma_controller_irq(irq, (void *)musb); ++ ++ musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); ++ musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); ++ musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); ++ ++ if (musb->int_usb || musb->int_tx || musb->int_rx) ++ rv_usb = musb_interrupt(musb); ++ ++ spin_unlock_irqrestore(&musb->lock, flags); ++ ++ /* REVISIT we sometimes get spurious IRQs on g_ep0 ++ * not clear why... ++ */ ++ ++ rv = (rv_dma == IRQ_HANDLED || rv_usb == IRQ_HANDLED) ? IRQ_HANDLED : IRQ_NONE; + ++ if (rv != IRQ_HANDLED) ++ DBG(5, "spurious?\n"); ++ ++ return IRQ_HANDLED; ++} ++ ++#else /* !CONFIG_USB_MUSB_HSDMA_IRQ_SHARED */ ++/* Original IRQ Handler */ + static irqreturn_t generic_interrupt(int irq, void *__hci) + { + unsigned long flags; +@@ -1504,6 +1595,7 @@ + + return IRQ_HANDLED; + } ++#endif /* Defined CONFIG_USB_MUSB_HSDMA_IRQ_SHARED - End added */ + + #else + #define generic_interrupt NULL +@@ -1525,11 +1617,14 @@ + + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + power = musb_readb(musb->mregs, MUSB_POWER); ++ ++ D("DEVCTL: 0x%x, POWER: 0x%x.\n", devctl, power); ++ D("musb->int_usb: 0x%x, musb->int_tx: 0x%x, musb->int_rx: 0x%x.\n", musb->int_usb, musb->int_tx, musb->int_rx); + + DBG(4, "** IRQ %s usb%04x tx%04x rx%04x\n", + (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral", + musb->int_usb, musb->int_tx, musb->int_rx); +- ++ + /* the core can interrupt us for multiple reasons; docs have + * a generic interrupt flowchart to follow + */ +@@ -1652,6 +1747,30 @@ + #ifdef CONFIG_SYSFS + + static ssize_t ++musb_devctl_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct musb *musb = dev_to_musb(dev); ++ unsigned long flags; ++ int ret = -EINVAL; ++ ++ ++ spin_lock_irqsave(&musb->lock, flags); ++ ret = sprintf(buf, "0x%x\n", musb_readb(musb->mregs, MUSB_DEVCTL)); ++ spin_unlock_irqrestore(&musb->lock, flags); ++ ++ return ret; ++} ++ ++static ssize_t ++musb_devctl_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t n) ++{ ++ return n; ++} ++static DEVICE_ATTR(devctl, 0644, musb_devctl_show, musb_devctl_store); ++ ++ ++static ssize_t + musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) + { + struct musb *musb = dev_to_musb(dev); +@@ -1826,6 +1945,7 @@ + */ + + #ifdef CONFIG_SYSFS ++ device_remove_file(musb->controller, &dev_attr_devctl); + device_remove_file(musb->controller, &dev_attr_mode); + device_remove_file(musb->controller, &dev_attr_vbus); + #ifdef CONFIG_USB_MUSB_OTG +@@ -1838,9 +1958,12 @@ + #endif + + if (musb->nIrq >= 0) { +- disable_irq_wake(musb->nIrq); ++ if (musb->b_irq_wake) /* Fixed by River. - Don't call disable_irq_wake() when set_irq_wake() fails. */ ++ disable_irq_wake(musb->nIrq); ++ + free_irq(musb->nIrq, musb); + } ++ + if (is_dma_capable() && musb->dma_controller) { + struct dma_controller *c = musb->dma_controller; + +@@ -1852,10 +1975,12 @@ + musb_platform_exit(musb); + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); + ++#ifdef CONFIG_HAVE_CLK /* Added by River */ + if (musb->clock) { + clk_disable(musb->clock); + clk_put(musb->clock); + } ++#endif + + #ifdef CONFIG_USB_MUSB_OTG + put_device(musb->xceiv.dev); +@@ -1922,9 +2047,13 @@ + spin_lock_init(&musb->lock); + musb->board_mode = plat->mode; + musb->board_set_power = plat->set_power; ++ ++#ifdef CONFIG_HAVE_CLK /* Added by River */ + musb->set_clock = plat->set_clock; ++#endif + musb->min_power = plat->min_power; + ++#ifdef CONFIG_HAVE_CLK /* Added by River */ + /* Clock usage is chip-specific ... functional clock (DaVinci, + * OMAP2430), or PHY ref (some TUSB6010 boards). All this core + * code does is make sure a clock handle is available; platform +@@ -1938,6 +2067,7 @@ + goto fail; + } + } ++#endif + + /* assume vbus is off */ + +@@ -1990,8 +2120,10 @@ + } + musb->nIrq = nIrq; + /* FIXME this handles wakeup irqs wrong */ +- if (enable_irq_wake(nIrq) == 0) ++ if (enable_irq_wake(nIrq) == 0) { /* Fixe by River. */ + device_init_wakeup(dev, 1); ++ musb->b_irq_wake = 1; ++ } + + pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n", + musb_driver_name, +@@ -2057,13 +2189,18 @@ + return 0; + + fail: ++ ++#ifdef CONFIG_HAVE_CLK + if (musb->clock) + clk_put(musb->clock); ++#endif ++ + device_init_wakeup(dev, 0); + musb_free(musb); + return status; + + #ifdef CONFIG_SYSFS ++ status = device_create_file(dev, &dev_attr_devctl); + status = device_create_file(dev, &dev_attr_mode); + status = device_create_file(dev, &dev_attr_vbus); + #ifdef CONFIG_USB_GADGET_MUSB_HDRC +@@ -2144,8 +2281,10 @@ + unsigned long flags; + struct musb *musb = dev_to_musb(&pdev->dev); + ++#ifdef CONFIG_HAVE_CLK + if (!musb->clock) + return 0; ++#endif + + spin_lock_irqsave(&musb->lock, flags); + +@@ -2159,10 +2298,13 @@ + */ + } + ++#ifdef CONFIG_HAVE_CLK + if (musb->set_clock) + musb->set_clock(musb->clock, 0); + else + clk_disable(musb->clock); ++#endif ++ + spin_unlock_irqrestore(&musb->lock, flags); + return 0; + } +@@ -2172,15 +2314,18 @@ + unsigned long flags; + struct musb *musb = dev_to_musb(&pdev->dev); + ++#ifdef CONFIG_HAVE_CLK + if (!musb->clock) + return 0; +- ++#endif + spin_lock_irqsave(&musb->lock, flags); + ++#ifdef CONFIG_HAVE_CLK + if (musb->set_clock) + musb->set_clock(musb->clock, 1); + else + clk_enable(musb->clock); ++#endif + + /* for static cmos like DaVinci, register values were preserved + * unless for some reason the whole soc powered down and we're +diff -ru linux-2.6/drivers/usb/musb/musb_core.h /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musb_core.h +--- linux-2.6/drivers/usb/musb/musb_core.h 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musb_core.h 2009-08-12 10:39:09.000000000 +0200 +@@ -52,7 +52,6 @@ + struct musb_hw_ep; + struct musb_ep; + +- + #include "musb_debug.h" + #include "musb_dma.h" + +@@ -63,7 +62,8 @@ + #include "../core/hcd.h" + #include "musb_host.h" + +- ++#define D(fmt, args...) \ ++// printk(KERN_ERR "%s(): LINE: %d "fmt, __func__, __LINE__, ##args) + + #ifdef CONFIG_USB_MUSB_OTG + +@@ -306,7 +306,10 @@ + struct musb { + /* device lock */ + spinlock_t lock; ++ ++#ifdef CONFIG_HAVE_CLK /* Added by River */ + struct clk *clock; ++#endif + irqreturn_t (*isr)(int, void *); + struct work_struct irq_work; + +@@ -359,7 +362,8 @@ + struct otg_transceiver xceiv; + + int nIrq; +- ++ u8 b_irq_wake; /* Added by River. */ ++ + struct musb_hw_ep endpoints[MUSB_C_NUM_EPS]; + #define control_ep endpoints + +@@ -371,8 +375,9 @@ + u8 board_mode; /* enum musb_mode */ + int (*board_set_power)(int state); + ++#ifdef CONFIG_HAVE_CLK /* Added by River */ + int (*set_clock)(struct clk *clk, int is_active); +- ++#endif + u8 min_power; /* vbus for periph, in mA/2 */ + + bool is_host; +diff -ru linux-2.6/drivers/usb/musb/musb_dma.h /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musb_dma.h +--- linux-2.6/drivers/usb/musb/musb_dma.h 2009-08-17 23:57:37.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musb_dma.h 2009-08-12 10:39:09.000000000 +0200 +@@ -148,6 +148,13 @@ + * Controllers manage dma channels. + */ + struct dma_controller { ++ ++/* Added by River - For DMA IRQ Sharing */ ++#ifdef CONFIG_USB_MUSB_HSDMA_IRQ_SHARED ++ u8 int_hsdma; /* MUSB_HSDMA_INTR */ ++#endif ++/* End added */ ++ + int (*start)(struct dma_controller *); + int (*stop)(struct dma_controller *); + struct dma_channel *(*channel_alloc)(struct dma_controller *, +@@ -163,10 +170,18 @@ + /* called after channel_program(), may indicate a fault */ + extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit); + +- + extern struct dma_controller *__init + dma_controller_create(struct musb *, void __iomem *); + + extern void dma_controller_destroy(struct dma_controller *); + ++/* Added by River - For DMA IRQ Sharing */ ++#ifdef CONFIG_USB_MUSB_HSDMA_IRQ_SHARED ++extern u8 dma_controller_fetch_intr(struct dma_controller *c); ++ ++irqreturn_t dma_controller_irq(int irq, void *private_data); ++ ++#endif /* End added */ ++ + #endif /* __MUSB_DMA_H__ */ ++ +diff -ru linux-2.6/drivers/usb/musb/musb_gadget_ep0.c /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musb_gadget_ep0.c +--- linux-2.6/drivers/usb/musb/musb_gadget_ep0.c 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musb_gadget_ep0.c 2009-08-12 10:39:09.000000000 +0200 +@@ -405,7 +405,8 @@ + csr |= MUSB_RXCSR_P_SENDSTALL + | MUSB_RXCSR_FLUSHFIFO + | MUSB_RXCSR_CLRDATATOG +- | MUSB_TXCSR_P_WZC_BITS; ++// | MUSB_TXCSR_P_WZC_BITS; ++ | MUSB_RXCSR_P_WZC_BITS; /* Corrected by River. */ + musb_writew(regs, MUSB_RXCSR, + csr); + } +diff -ru linux-2.6/drivers/usb/musb/musb_host.c /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musb_host.c +--- linux-2.6/drivers/usb/musb/musb_host.c 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musb_host.c 2009-08-12 10:39:09.000000000 +0200 +@@ -40,10 +40,16 @@ + #include + #include + #include ++#include + + #include "musb_core.h" + #include "musb_host.h" + ++/* Added by River. */ ++/* The MUSBHDRC core RTL V1.8 in JZ4760 has no data toogle control. */ ++#ifndef CONFIG_SOC_JZ4760 ++#define HAVE_DATA_TOGGLE_CONTROL 1 ++#endif + + /* MUSB HOST status 22-mar-2006 + * +@@ -296,9 +302,10 @@ + spin_lock(&musb->lock); + } + ++/* Modified by River. */ ++#ifdef HAVE_DATA_TOGGLE_CONTROL + /* for bulk/interrupt endpoints only */ +-static inline void +-musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb) ++static inline void musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb) + { + struct usb_device *udev = urb->dev; + u16 csr; +@@ -326,6 +333,12 @@ + ? 1 : 0); + } + } ++#else /* !HAVE_DATA_TOGGLE_CONTROL */ ++static inline void musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb) ++{ ++ return; ++} ++#endif + + /* caller owns controller lock, irqs are blocked */ + static struct musb_qh * +@@ -563,7 +576,7 @@ + musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) + { + u16 csr; +- ++ + /* NOTE: we know the "rx" fifo reinit never triggers for ep0. + * That always uses tx_reinit since ep0 repurposes TX register + * offsets; the initial SETUP packet is also a kind of OUT. +@@ -586,8 +599,12 @@ + if (csr & MUSB_RXCSR_RXPKTRDY) + WARNING("rx%d, packet/%d ready?\n", ep->epnum, + musb_readw(ep->regs, MUSB_RXCOUNT)); +- ++/* Modified by River. */ ++#ifdef HAVE_DATA_TOGGLE_CONTROL + musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG); ++#else ++ musb_h_flush_rxfifo(ep, 0); ++#endif + } + + /* target addr and (for multipoint) hub addr/port */ +@@ -688,13 +705,15 @@ + | MUSB_TXCSR_TXPKTRDY + ); + csr |= MUSB_TXCSR_MODE; +- ++/* Modified by River. */ ++#ifdef HAVE_DATA_TOGGLE_CONTROL + if (usb_gettoggle(urb->dev, + qh->epnum, 1)) + csr |= MUSB_TXCSR_H_WR_DATATOGGLE + | MUSB_TXCSR_H_DATATOGGLE; + else + csr |= MUSB_TXCSR_CLRDATATOG; ++#endif + + /* twice in case of double packet buffering */ + musb_writew(epio, MUSB_TXCSR, csr); +@@ -867,13 +886,18 @@ + + if (hw_ep->rx_reinit) { + musb_rx_reinit(musb, qh, hw_ep); +- ++/* Modified by River. */ ++#ifdef HAVE_DATA_TOGGLE_CONTROL + /* init new state: toggle and NYET, maybe DMA later */ +- if (usb_gettoggle(urb->dev, qh->epnum, 0)) ++ if (usb_gettoggle(urb->dev, qh->epnum, 0)) { + csr = MUSB_RXCSR_H_WR_DATATOGGLE + | MUSB_RXCSR_H_DATATOGGLE; +- else ++ }else{ + csr = 0; ++ } ++#else ++ csr = 0; ++#endif + if (qh->type == USB_ENDPOINT_XFER_INT) + csr |= MUSB_RXCSR_DISNYET; + +diff -ru linux-2.6/drivers/usb/musb/musbhsdma.c /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musbhsdma.c +--- linux-2.6/drivers/usb/musb/musbhsdma.c 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musbhsdma.c 2009-08-12 10:39:09.000000000 +0200 +@@ -294,7 +294,11 @@ + return 0; + } + ++#ifdef CONFIG_USB_MUSB_HSDMA_IRQ_SHARED ++irqreturn_t dma_controller_irq(int irq, void *private_data) ++#else + static irqreturn_t dma_controller_irq(int irq, void *private_data) ++#endif /* Defined CONFIG_USB_MUSB_HSDMA_IRQ_SHARED */ + { + struct musb_dma_controller *controller = + (struct musb_dma_controller *)private_data; +@@ -311,7 +315,14 @@ + + spin_lock_irqsave(&musb->lock, flags); + ++ /* Added By River - For DMA IRQ Sharing */ ++#ifdef CONFIG_USB_MUSB_HSDMA_IRQ_SHARED ++ int_hsdma = controller->Controller.int_hsdma; ++#else + int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR); ++#endif ++ /* End added */ ++ + if (!int_hsdma) + goto done; + +@@ -419,15 +430,32 @@ + controller->Controller.channel_release = dma_channel_release; + controller->Controller.channel_program = dma_channel_program; + controller->Controller.channel_abort = dma_channel_abort; +- ++ ++ /* Modified By River - For DMA IRQ Sharing */ ++#ifdef CONFIG_USB_MUSB_HSDMA_IRQ_SHARED ++ irq = 0; /* Skip free_irq() when the controller will be removed. */ ++#else + if (request_irq(irq, dma_controller_irq, IRQF_DISABLED, + musb->controller->bus_id, &controller->Controller)) { + dev_err(dev, "request_irq %d failed!\n", irq); + dma_controller_destroy(&controller->Controller); + return NULL; + } +- ++#endif ++ /* End modified */ + controller->irq = irq; + + return &controller->Controller; + } ++ ++/* Added by river - For DMA IRQ Sharing */ ++#ifdef CONFIG_USB_MUSB_HSDMA_IRQ_SHARED ++u8 dma_controller_fetch_intr(struct dma_controller *c) ++{ ++ struct musb_dma_controller *mc = (struct musb_dma_controller *)c; /* See the defination... */ ++ ++ c->int_hsdma = musb_readb(mc->pCoreBase, MUSB_HSDMA_INTR); ++ ++ return c->int_hsdma; ++} ++#endif +diff -ru linux-2.6/drivers/usb/musb/musb_io.h /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musb_io.h +--- linux-2.6/drivers/usb/musb/musb_io.h 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/usb/musb/musb_io.h 2009-08-12 10:39:09.000000000 +0200 +@@ -37,7 +37,7 @@ + + #include + +-#ifndef CONFIG_ARM ++#if !defined(CONFIG_ARM) && !defined(CONFIG_MIPS) + static inline void readsl(const void __iomem *addr, void *buf, int len) + { insl((unsigned long)addr, buf, len); } + static inline void readsw(const void __iomem *addr, void *buf, int len) +diff -ru linux-2.6/drivers/video/Kconfig /plain/src/qi/linux-2.6.27.git.svn/drivers/video/Kconfig +--- linux-2.6/drivers/video/Kconfig 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/video/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -234,6 +234,454 @@ + comment "Frame buffer hardware drivers" + depends on FB + ++/************************************************************/ ++ ++config JZSOC_BOOT_LOGO ++ tristate "JZSOC boot up LOGO support" ++ depends on FB && JZSOC ++ ---help--- ++ If you select this function, you need put a logo file at ramdisk root directory, ++ whose name should be "/logo.rle" or "/logo.rgb565". ++ ++choice ++ prompt "Boot LOGO File Format Select" ++ depends on JZSOC_BOOT_LOGO ++ ++config FB_565RLE_LOGO ++ bool "Boot logo is 565REL file" ++ ++config FB_565RGB_LOGO ++ bool "Boot logo a 565RGB file" ++ ++endchoice ++ ++ ++config FB_ANDROID_JZ4755SOC ++ tristate "JZ4755SOC ANDROID LCD controller support" ++ depends on FB && JZSOC ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ ---help--- ++ JZSOC ANDROID LCD Controller driver support. ++ ++config IPU_ANDROID_JZ4755 ++ bool "Jz4755 android ipu support" ++ depends on FB_ANDROID_JZ4755SOC && SOC_JZ4750D ++ ---help--- ++ Use JZ4755 Android IPU, if need, please select this. ++config FB_JZ4755_ANDROID_LCD ++ tristate "JZ4755 Android LCD Controller support" ++ depends on FB_ANDROID_JZ4755SOC && SOC_JZ4750D ++ ---help--- ++ JZ4755 Android LCD Controller driver. ++ JZ4755 Android LCD Controller support OSD function(refer jz4755_lcdc_spec.pdf). ++ JZ4755 Android LCD OSD implement 2 framebuffer layers: foreground0 and foreground1. ++# JZ4755 LCD driver support 2 foregrounds default. ++ ++choice ++ prompt "Android LCD Type Select" ++ depends on FB_JZ4755_ANDROID_LCD ++ default FB_JZ4755_ANDROID_TFT_LCD ++ ++config FB_JZ4755_ANDROID_TFT ++ bool "JZ4755 Android LCD Controller TFT LCD support" ++ ++endchoice ++ ++choice ++ depends on FB_JZ4755_ANDROID_LCD && FB_JZ4755_ANDROID_TFT ++ prompt "JZ4755 Android LCD TFT Panels Support" ++ default JZ4755_ANDROID_LCD_AUO_A043FL01V2 ++ ---help--- ++ Please select the lcd panel in you board ++ ++config JZ4755_ANDROID_LCD_AUO_A043FL01V2 ++ bool "AUO A043FL01V2 TFT panel (480x272)(24bits)" ++ ++config JZ4755_ANDROID_LCD_TOPPOLY_TD043MGEB1 ++ bool "TOPPOLY_TD043MGEB1 TFT panel(800x480)(24bit mode)" ++ ++endchoice ++ ++ ++config FB_ANDROID_JZSOC ++ tristate "JZSOC ANDROID LCD controller support" ++ depends on FB && JZSOC ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ ---help--- ++ JZSOC ANDROID LCD Controller driver support. ++ ++config IPU_ANDROID_JZ4750 ++ bool "Jz4750 android ipu support" ++ depends on FB_ANDROID_JZSOC && SOC_JZ4750 ++ ---help--- ++ Use JZ4750 Android IPU, if need, please select this. ++config FB_JZ4750_ANDROID_LCD ++ tristate "JZ4750 Android LCD Controller support" ++ depends on FB_ANDROID_JZSOC && SOC_JZ4750 ++ ---help--- ++ JZ4750 Android LCD Controller driver. ++ JZ4750 Android LCD Controller support OSD function(refer jz4750_lcdc_spec.pdf). ++ JZ4750 Android LCD OSD implement 2 framebuffer layers: foreground0 and foreground1. ++# JZ4750 LCD driver support 2 foregrounds default. ++ ++choice ++ prompt "Android LCD Type Select" ++ depends on FB_JZ4750_ANDROID_LCD ++ default FB_JZ4750_ANDROID_TFT_LCD ++ ++config FB_JZ4750_ANDROID_TFT ++ bool "JZ4750 Android LCD Controller TFT LCD support" ++ ++endchoice ++ ++choice ++ depends on FB_JZ4750_ANDROID_LCD && FB_JZ4750_ANDROID_TFT ++ prompt "JZ4750 Android LCD TFT Panels Support" ++ default JZ4750_ANDROID_LCD_AUO_A043FL01V2 ++ ---help--- ++ Please select the lcd panel in you board ++ ++config JZ4750_ANDROID_LCD_AUO_A043FL01V2 ++ bool "AUO A043FL01V2 TFT panel (480x272)(24bits)" ++ ++config JZ4750_ANDROID_LCD_TOPPOLY_TD043MGEB1 ++ bool "TOPPOLY_TD043MGEB1 TFT panel(800x480)(24bit mode)" ++ ++endchoice ++ ++/************************************************************/ ++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 to . ++ ++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_TVE ++ bool "Jz4750 TV Encode support" ++ depends on FB_JZSOC && (SOC_JZ4750 || SOC_JZ4750D) ++ ---help--- ++ Use JZ4750 TV Encoder controller to display on TV. ++ ++config IPU_JZ4750 ++ bool "Jz4750 ipu support" ++ depends on FB_JZSOC && (SOC_JZ4750 || SOC_JZ4750D) ++ ---help--- ++ Use JZ4750 IPU, if need, please select this. ++ ++config FB_JZ4750_LCD ++ tristate "JZ4750 LCD Controller support" ++ depends on FB_JZSOC && (SOC_JZ4750 || SOC_JZ4750D) ++ ---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. ++ ++choice ++ depends on FB_JZ4750_LCD ++ prompt "JZ4750 LCD OSD Mode select" ++ default JZ4750_LCD_USE_FG1_ONLY ++ ++config JZ4750_LCD_USE_FG0_ONLY ++ bool "Only use foreground 0" ++ ++config JZ4750_LCD_USE_FG1_ONLY ++ bool "Only use foreground 1" ++ ++config JZ4750_LCD_USE_2LAYER_FG ++ bool "Use two-layer foregrounds." ++endchoice ++ ++ ++choice ++ prompt "LCD Type Select" ++ depends on FB_JZ4750_LCD ++ default FB_JZ4750_TFT_LCD ++ ++config FB_JZ4750_TFT ++ bool "JZ4750 LCD Controller TFT LCD support" ++ ++config FB_JZ4750_SLCD ++ bool "JZ4750 LCD Controller Smart LCD support" ++endchoice ++ ++choice ++ depends on FB_JZ4750_LCD && FB_JZ4750_TFT ++ prompt "JZ4750 LCD TFT 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_TRULY_TFTG320240DTSW_18BIT ++ bool "TRULY_TFTG320240DTSW TFT panel (320x240) (Parallel 18bit mode)" ++ ++config JZ4750D_VGA_DISPLAY ++ depends on SOC_JZ4750D ++ bool "Jz4750D VGA Display, Jz4750 don't support" ++endchoice ++ ++choice ++ depends on FB_JZ4750_LCD && FB_JZ4750_SLCD ++ prompt "JZ4750 Smart LCD Panels Support" ++ default JZ4750_SLCD_KGM701A3_TFT_SPFD5420A ++ ---help--- ++ Please select the lcd panel in you board ++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)" ++ ++endchoice ++ ++config FB_JZ4760_LCD ++ tristate "JZ4760 LCD Controller support" ++ depends on FB_JZSOC && SOC_JZ4760 ++ ---help--- ++ JZ4760 LCD Controller driver. ++ JZ4760 LCD Controller support OSD function(refer jz4760_lcdc_spec.pdf). ++ JZ4760 LCD OSD implement 2 framebuffer layers: foreground0 and foreground1. ++# JZ4760 LCD driver support only foreground0 default. ++ ++choice ++ depends on FB_JZ4760_LCD ++ prompt "JZ4760 LCD OSD Mode select" ++ default JZ4760_LCD_USE_FG1_ONLY ++ ++config JZ4760_LCD_USE_FG0_ONLY ++ bool "Only use foreground 0" ++ ++config JZ4760_LCD_USE_FG1_ONLY ++ bool "Only use foreground 1" ++ ++config JZ4760_LCD_USE_2LAYER_FG ++ bool "Use two-layer foregrounds." ++endchoice ++ ++ ++choice ++ prompt "LCD Type Select" ++ depends on FB_JZ4760_LCD ++ default FB_JZ4760_TFT_LCD ++ ++config FB_JZ4760_TFT ++ bool "JZ4760 LCD Controller TFT LCD support" ++ ++config FB_JZ4760_SLCD ++ bool "JZ4760 LCD Controller Smart LCD support" ++endchoice ++ ++choice ++ depends on FB_JZ4760_LCD && FB_JZ4760_TFT ++ prompt "JZ4760 LCD TFT Panels Support" ++ default JZ4760_LCD_SAMSUNG_LTP400WQF02 ++ ---help--- ++ Please select the lcd panel in you board ++ ++config JZ4760_LCD_SAMSUNG_LTP400WQF01 ++ bool "SAMSUNG LTP400WQF01 TFT panel (480x272)(16bits)" ++ ++config JZ4760_LCD_SAMSUNG_LTP400WQF02 ++ bool "SAMSUNG LTP400WQF02 TFT panel (480x272)(18bits)" ++ ++config JZ4760_LCD_AUO_A043FL01V2 ++ bool "AUO A043FL01V2 TFT panel (480x272)(24bits)" ++ ++config JZ4760_LCD_FOXCONN_PT035TN01 ++ bool "FOXCONN PT035TN01 TFT panel (320x240,3.5in)(18bit-parallel mode)" ++ ++config JZ4760_LCD_INNOLUX_PT035TN01_SERIAL ++ bool "INNOLUX PT035TN01 TFT panel (320x240,3.5in)(8bit-serial mode)" ++ ++config JZ4760_LCD_TOPPOLY_TD025THEA7_RGB_DELTA ++ bool "TOPPOLY_TD025THEA7 TFT panel(320x240)(serial RGB delta mode)" ++ ++config JZ4760_LCD_TRULY_TFTG320240DTSW_18BIT ++ bool "TRULY_TFTG320240DTSW TFT panel (320x240) (Parallel 18bit mode)" ++ ++config JZ4760_VGA_DISPLAY ++ bool "Jz4760 VGA Display, Jz4760 don't support" ++endchoice ++ ++choice ++ depends on FB_JZ4760_LCD && FB_JZ4760_SLCD ++ prompt "JZ4760 Smart LCD Panels Support" ++ default JZ4760_SLCD_KGM701A3_TFT_SPFD5420A ++ ---help--- ++ Please select the lcd panel in you board ++config JZ4760_LCD_TRULY_TFT_GG1P0319LTSW_W ++ bool "TRULY_TFT_GG1P0319LTSW_W (240x320) (Smart LCD 16bit)" ++ ++config JZ4760_SLCD_KGM701A3_TFT_SPFD5420A ++ bool "KGM701A3_TFT_SPFD5420A (400x240) (Smart LCD 18bit)" ++ ++endchoice ++ ++ + config FB_CIRRUS + tristate "Cirrus Logic support" + depends on FB && (ZORRO || PCI) +diff -ru linux-2.6/drivers/video/Makefile /plain/src/qi/linux-2.6.27.git.svn/drivers/video/Makefile +--- linux-2.6/drivers/video/Makefile 2009-08-17 23:58:02.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/drivers/video/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -28,6 +28,17 @@ + obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o + + # Hardware specific drivers go first ++obj-$(CONFIG_JZSOC_BOOT_LOGO) += logo.o ++obj-$(CONFIG_FB_JZLCD_4730_4740) += jzlcd.o ++obj-$(CONFIG_FB_JZ4740_SLCD) += jz4740_slcd.o ++obj-$(CONFIG_FB_JZ4750_TFT) += jz4750_lcd.o ++obj-$(CONFIG_FB_JZ4750_SLCD) += jz4750_slcd.o ++obj-$(CONFIG_FB_JZ4760_TFT) += jz4760_lcd.o ++obj-$(CONFIG_FB_JZ4760_SLCD) += jz4760_slcd.o ++obj-$(CONFIG_FB_JZ4750_TVE) += jz4750_tve.o ++obj-$(CONFIG_FB_JZ4750_ANDROID_TFT) += jz4750_android_lcd.o ++obj-$(CONFIG_FB_JZ4755_ANDROID_TFT) += jz4755_android_lcd.o ++ + obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o + obj-$(CONFIG_FB_AM200EPD) += am200epd.o + obj-$(CONFIG_FB_ARC) += arcfb.o +diff -ru linux-2.6/include/asm-mips/bootinfo.h /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/bootinfo.h +--- linux-2.6/include/asm-mips/bootinfo.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/bootinfo.h 2009-08-12 10:39:09.000000000 +0200 +@@ -57,6 +57,15 @@ + #define MACH_MIKROTIK_RB532 0 /* Mikrotik RouterBoard 532 */ + #define MACH_MIKROTIK_RB532A 1 /* Mikrotik RouterBoard 532A */ + ++/* ++ * Valid machtype for group INGENIC ++ */ ++#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_JZ4760 4 /* JZ4760 SOC */ ++ + #define CL_SIZE COMMAND_LINE_SIZE + + extern char *system_type; +diff -ru linux-2.6/include/asm-mips/cpu.h /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/cpu.h +--- linux-2.6/include/asm-mips/cpu.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/cpu.h 2009-08-12 10:39:09.000000000 +0200 +@@ -33,8 +33,11 @@ + #define PRID_COMP_TOSHIBA 0x070000 + #define PRID_COMP_LSI 0x080000 + #define PRID_COMP_LEXRA 0x0b0000 +- +- ++#if defined(CONFIG_JZ_FPGA) && defined(CONFIG_SOC_JZ4760) ++#define PRID_COMP_INGENIC 0xd80000 ++#else ++#define PRID_COMP_INGENIC 0xd00000 ++#endif + /* + * Assigned values for the product ID register. In order to detect a + * certain CPU type exactly eventually additional registers may need to +@@ -114,6 +117,12 @@ + #define PRID_IMP_BCM3302 0x9000 + + /* ++ * These are the PRID's for when 23:16 == PRID_COMP_INGENIC ++ */ ++ ++#define PRID_IMP_JZRISC 0x0200 ++ ++/* + * Definitions for 7:0 on legacy processors + */ + +@@ -204,6 +213,11 @@ + */ + CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2, + ++ /* ++ * Ingenic class processors ++ */ ++ CPU_JZRISC, CPU_XBURST, ++ + CPU_LAST + }; + +diff -ru linux-2.6/include/asm-mips/mach-generic/irq.h /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/mach-generic/irq.h +--- linux-2.6/include/asm-mips/mach-generic/irq.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/mach-generic/irq.h 2009-08-12 10:39:09.000000000 +0200 +@@ -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 -ru linux-2.6/include/asm-mips/ptrace.h /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/ptrace.h +--- linux-2.6/include/asm-mips/ptrace.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/ptrace.h 2009-08-12 10:39:09.000000000 +0200 +@@ -79,7 +79,12 @@ + /* + * 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 -ru linux-2.6/include/asm-mips/r4kcache.h /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/r4kcache.h +--- linux-2.6/include/asm-mips/r4kcache.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/r4kcache.h 2009-08-12 10:39:09.000000000 +0200 +@@ -17,6 +17,58 @@ + #include + #include + ++#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 @@ + { + __iflush_prologue + cache_op(Index_Invalidate_I, addr); ++ INVALIDATE_BTB(); + __iflush_epilogue + } + +@@ -151,6 +204,7 @@ + { + __dflush_prologue + cache_op(Index_Writeback_Inv_D, addr); ++ SYNC_WB(); + __dflush_epilogue + } + +@@ -163,6 +217,7 @@ + { + __iflush_prologue + cache_op(Hit_Invalidate_I, addr); ++ INVALIDATE_BTB(); + __iflush_epilogue + } + +@@ -170,6 +225,7 @@ + { + __dflush_prologue + cache_op(Hit_Writeback_Inv_D, addr); ++ SYNC_WB(); + __dflush_epilogue + } + +@@ -177,6 +233,7 @@ + { + __dflush_prologue + cache_op(Hit_Invalidate_D, addr); ++ SYNC_WB(); + __dflush_epilogue + } + +@@ -209,6 +266,7 @@ + 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_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,20 +455,132 @@ + __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(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64) + __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, \ +@@ -431,13 +602,73 @@ + __##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 -ru linux-2.6/include/asm-mips/signal.h /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/signal.h +--- linux-2.6/include/asm-mips/signal.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/signal.h 2009-08-12 10:39:09.000000000 +0200 +@@ -11,6 +11,11 @@ + + #include + ++/* Avoid too many header ordering problems. */ ++struct siginfo; ++ ++#ifdef __KERNEL__ ++ + #define _NSIG 128 + #define _NSIG_BPW (sizeof(unsigned long) * 8) + #define _NSIG_WORDS (_NSIG / _NSIG_BPW) +@@ -21,6 +26,14 @@ + + typedef unsigned long old_sigset_t; /* at least 32 bits */ + ++#else ++/* Here we must cater to libcs that poke about in kernel headers. */ ++ ++#define NSIG 32 ++typedef unsigned long sigset_t; ++ ++#endif /* __KERNEL__ */ ++ + #define SIGHUP 1 /* Hangup (POSIX). */ + #define SIGINT 2 /* Interrupt (ANSI). */ + #define SIGQUIT 3 /* Quit (POSIX). */ +@@ -55,6 +68,9 @@ + #define SIGPROF 29 /* Profiling alarm clock (4.2 BSD). */ + #define SIGXCPU 30 /* CPU limit exceeded (4.2 BSD). */ + #define SIGXFSZ 31 /* File size limit exceeded (4.2 BSD). */ ++/* Define these two used by Android's bionic */ ++#define SIGUNUSED SIGSYS ++#define SIGSTKFLT SIGEMT + + /* These should not be considered constants from userland. */ + #define SIGRTMIN 32 +@@ -111,16 +127,38 @@ + + #include + ++#ifdef __KERNEL__ ++ + struct sigaction { + unsigned int sa_flags; + __sighandler_t sa_handler; + sigset_t sa_mask; ++ __sigrestore_t sa_restorer; + }; + + struct k_sigaction { + struct sigaction sa; + }; + ++#else ++/* Here we must cater to libcs that poke about in kernel headers. */ ++ ++struct sigaction { ++ unsigned long sa_flags; ++ union { ++ __sighandler_t _sa_handler; ++ void (*_sa_sigaction)(int, struct siginfo *, void *); ++ } _u; ++ sigset_t sa_mask; ++ unsigned long pad[3]; /* padding for sa_mask */ ++ void (*sa_restorer)(void); ++}; ++ ++#define sa_handler _u._sa_handler ++#define sa_sigaction _u._sa_sigaction ++ ++#endif ++ + /* IRIX compatible stack_t */ + typedef struct sigaltstack { + void __user *ss_sp; +diff -ru linux-2.6/include/asm-mips/suspend.h /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/suspend.h +--- linux-2.6/include/asm-mips/suspend.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/asm-mips/suspend.h 2009-08-12 10:39:09.000000000 +0200 +@@ -1,6 +1,11 @@ + #ifndef __ASM_SUSPEND_H + #define __ASM_SUSPEND_H + +-/* Somewhen... Maybe :-) */ ++/* Jz suspend interfaces */ ++ ++#if defined(CONFIG_PM) && defined(CONFIG_JZSOC) ++extern int jz_pm_init(void); ++static inline int arch_prepare_suspend(void) { return 0; } ++#endif + + #endif /* __ASM_SUSPEND_H */ +diff -ru linux-2.6/include/linux/miscdevice.h /plain/src/qi/linux-2.6.27.git.svn/include/linux/miscdevice.h +--- linux-2.6/include/linux/miscdevice.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/linux/miscdevice.h 2009-08-12 10:39:09.000000000 +0200 +@@ -30,6 +30,8 @@ + #define TUN_MINOR 200 + #define HPET_MINOR 228 + #define KVM_MINOR 232 ++#define TCSM_MINOR 233 /* JZ TCSM for multimedia */ ++#define CIM_MINOR 234 /* JZ CIM for multimedia */ + + struct device; + +diff -ru linux-2.6/include/linux/mmc/host.h /plain/src/qi/linux-2.6.27.git.svn/include/linux/mmc/host.h +--- linux-2.6/include/linux/mmc/host.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/linux/mmc/host.h 2009-08-12 10:39:09.000000000 +0200 +@@ -41,6 +41,7 @@ + + #define MMC_BUS_WIDTH_1 0 + #define MMC_BUS_WIDTH_4 2 ++#define MMC_BUS_WIDTH_8 4 + + unsigned char timing; /* timing specification used */ + +@@ -159,6 +160,15 @@ + + struct dentry *debugfs_root; + ++#ifdef CONFIG_MMC_EMBEDDED_SDIO ++ struct { ++ struct sdio_cis *cis; ++ struct sdio_cccr *cccr; ++ struct sdio_embedded_func *funcs; ++ int num_funcs; ++ } embedded_sdio_data; ++#endif ++ + unsigned long private[0] ____cacheline_aligned; + }; + +@@ -167,6 +177,14 @@ + extern void mmc_remove_host(struct mmc_host *); + extern void mmc_free_host(struct mmc_host *); + ++#ifdef CONFIG_MMC_EMBEDDED_SDIO ++extern void mmc_set_embedded_sdio_data(struct mmc_host *host, ++ struct sdio_cis *cis, ++ struct sdio_cccr *cccr, ++ struct sdio_embedded_func *funcs, ++ int num_funcs); ++#endif ++ + static inline void *mmc_priv(struct mmc_host *host) + { + return (void *)host->private; +diff -ru linux-2.6/include/linux/mtd/mtd.h /plain/src/qi/linux-2.6.27.git.svn/include/linux/mtd/mtd.h +--- linux-2.6/include/linux/mtd/mtd.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/linux/mtd/mtd.h 2009-08-12 10:39:09.000000000 +0200 +@@ -30,9 +30,9 @@ + specific to any particular block. */ + struct erase_info { + struct mtd_info *mtd; +- u_int32_t addr; +- u_int32_t len; +- u_int32_t fail_addr; ++ u_int64_t addr; ++ u_int64_t len; ++ u_int64_t fail_addr; + u_long time; + u_long retries; + u_int dev; +@@ -44,7 +44,7 @@ + }; + + struct mtd_erase_region_info { +- u_int32_t offset; /* At which this region starts, from the beginning of the MTD */ ++ u_int64_t offset; /* At which this region starts, from the beginning of the MTD */ + u_int32_t erasesize; /* For this region */ + u_int32_t numblocks; /* Number of blocks of erasesize in this region */ + unsigned long *lockmap; /* If keeping bitmap of locks */ +@@ -87,10 +87,10 @@ + */ + 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; +@@ -99,7 +99,7 @@ + struct mtd_info { + u_char type; + u_int32_t flags; +- u_int32_t size; // Total size of the MTD ++ u_int64_t size; // Total size of the MTD + + /* "Major" erase size for the device. Naïve users may take this + * to be the only erase size available, or may use the more detailed +@@ -142,15 +142,15 @@ + + /* 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); + + +- 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 +@@ -159,11 +159,11 @@ + 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); + + /* +@@ -171,33 +171,33 @@ + * 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, size_t len); +- int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len); ++ int (*lock) (struct mtd_info *mtd, loff_mtd_t ofs, size_mtd_t len); ++ int (*unlock) (struct mtd_info *mtd, loff_mtd_t ofs, size_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 */ + +@@ -242,10 +242,10 @@ + 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 -ru linux-2.6/include/linux/mtd/nand.h /plain/src/qi/linux-2.6.27.git.svn/include/linux/mtd/nand.h +--- linux-2.6/include/linux/mtd/nand.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/linux/mtd/nand.h 2009-08-12 10:39:09.000000000 +0200 +@@ -37,14 +37,14 @@ + extern void nand_wait_ready(struct mtd_info *mtd); + + /* The maximum number of NAND chips in an array */ +-#define NAND_MAX_CHIPS 8 ++#define NAND_MAX_CHIPS 4 + + /* This constant declares the max. oobsize / page, which + * is supported now. If you add a chip with bigger oobsize/page + * adjust this accordingly. + */ +-#define NAND_MAX_OOBSIZE 64 +-#define NAND_MAX_PAGESIZE 2048 ++#define NAND_MAX_OOBSIZE 256 ++#define NAND_MAX_PAGESIZE 8192 + + /* + * Constants for hardware specific CLE/ALE/NCE function +@@ -54,6 +54,10 @@ + */ + /* Select the chip by setting nCE to low */ + #define NAND_NCE 0x01 ++#define NAND_NCE1 0x08 ++#define NAND_NCE2 0x10 ++#define NAND_NCE3 0x20 ++#define NAND_NCE4 0x40 + /* Select the command latch by setting CLE to high */ + #define NAND_CLE 0x02 + /* Select the address latch by setting ALE to high */ +@@ -377,8 +381,8 @@ + 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); +@@ -398,12 +402,14 @@ + int bbt_erase_shift; + int chip_shift; + int numchips; +- unsigned long chipsize; ++ u64 chipsize; + int pagemask; + int pagebuf; + int subpagesize; + uint8_t cellinfo; + int badblockpos; ++ int realplanenum; /* number of planes the NAND has */ ++ int planenum; /* number of planes operating synchronously */ + + nand_state_t state; + +@@ -455,7 +461,7 @@ + char *name; + int id; + unsigned long pagesize; +- unsigned long chipsize; ++ u64 chipsize; + unsigned long erasesize; + unsigned long options; + }; +@@ -543,13 +549,13 @@ + #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 -ru linux-2.6/include/linux/mtd/partitions.h /plain/src/qi/linux-2.6.27.git.svn/include/linux/mtd/partitions.h +--- linux-2.6/include/linux/mtd/partitions.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/linux/mtd/partitions.h 2009-08-12 10:39:09.000000000 +0200 +@@ -36,8 +36,9 @@ + + struct mtd_partition { + char *name; /* identifier string */ +- u_int32_t size; /* partition size */ +- u_int32_t offset; /* offset within the master MTD space */ ++ u_int64_t size; /* partition size */ ++ u_int64_t offset; /* offset within the master MTD space */ ++ char use_planes; /* flag to specify whether multiple planes of NAND is used in the partition */ + u_int32_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)*/ + struct mtd_info **mtdp; /* pointer to store the MTD object */ +diff -ru linux-2.6/include/linux/power_supply.h /plain/src/qi/linux-2.6.27.git.svn/include/linux/power_supply.h +--- linux-2.6/include/linux/power_supply.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/linux/power_supply.h 2009-08-12 10:39:09.000000000 +0200 +@@ -86,7 +86,8 @@ + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_ENERGY_AVG, + POWER_SUPPLY_PROP_CAPACITY, /* in percents! */ +- POWER_SUPPLY_PROP_TEMP, ++ POWER_SUPPLY_PROP_TEMP, /* for android, but not supported */ ++ POWER_SUPPLY_PROP_VOL, /* for android, but not supported */ + POWER_SUPPLY_PROP_TEMP_AMBIENT, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, +diff -ru linux-2.6/include/linux/suspend.h /plain/src/qi/linux-2.6.27.git.svn/include/linux/suspend.h +--- linux-2.6/include/linux/suspend.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/linux/suspend.h 2009-08-12 10:39:09.000000000 +0200 +@@ -1,9 +1,11 @@ + #ifndef _LINUX_SUSPEND_H + #define _LINUX_SUSPEND_H + +-#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32) || defined(CONFIG_PPC64) ++#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32)\ ++ || defined(CONFIG_PPC64) || defined(CONFIG_MIPS) + #include + #endif ++ + #include + #include + #include +@@ -245,6 +247,9 @@ + void save_processor_state(void); + void restore_processor_state(void); + ++//void save_processor_state(void){} ++//void restore_processor_state(void){} ++ + /* kernel/power/main.c */ + extern int register_pm_notifier(struct notifier_block *nb); + extern int unregister_pm_notifier(struct notifier_block *nb); +diff -ru linux-2.6/include/mtd/mtd-abi.h /plain/src/qi/linux-2.6.27.git.svn/include/mtd/mtd-abi.h +--- linux-2.6/include/mtd/mtd-abi.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/mtd/mtd-abi.h 2009-08-12 10:39:09.000000000 +0200 +@@ -1,13 +1,23 @@ + /* ++ * $Id: mtd-abi.h,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $ ++ * + * Portions of MTD ABI definition which are shared by kernel and user space + */ + + #ifndef __MTD_ABI_H__ + #define __MTD_ABI_H__ + ++#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into ++ separate files was to avoid #ifdef __KERNEL__ */ ++#define __user ++#endif ++ ++typedef unsigned long long size_mtd_t; ++typedef unsigned long long loff_mtd_t; ++ + struct erase_info_user { +- uint32_t start; +- uint32_t length; ++ uint64_t start; ++ uint64_t length; + }; + + struct mtd_oob_buf { +@@ -16,6 +26,14 @@ + unsigned char __user *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 +@@ -50,7 +68,7 @@ + struct mtd_info_user { + uint8_t type; + uint32_t flags; +- uint32_t size; // Total size of the MTD ++ uint64_t size; // Total size of the MTD + uint32_t erasesize; + uint32_t writesize; + uint32_t oobsize; // Amount of OOB data per block (e.g. 16) +@@ -61,7 +79,7 @@ + }; + + struct region_info_user { +- uint32_t offset; /* At which this region starts, ++ uint64_t offset; /* At which this region starts, + * from the beginning of the MTD */ + uint32_t erasesize; /* For this region */ + uint32_t numblocks; /* Number of blocks in this region */ +@@ -84,8 +102,8 @@ + #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_t) +-#define MEMSETBADBLOCK _IOW('M', 12, 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) +@@ -93,6 +111,7 @@ + #define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout) + #define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats) + #define MTDFILEMODE _IO('M', 19) ++#define MEMWRITEPAGE _IOWR('M', 20, struct mtd_page_buf) + #define MTDREFRESH _IO('M', 23) + + /* +@@ -102,7 +121,8 @@ + uint32_t useecc; + uint32_t eccbytes; + uint32_t oobfree[8][2]; +- uint32_t eccpos[32]; ++ uint32_t eccpos[104]; /* more fields(13*8) are required for ++ * 8-bit BCH ECC and 4KB pagesize nand, by Regen */ + }; + + struct nand_oobfree { +@@ -117,7 +137,7 @@ + */ + struct nand_ecclayout { + uint32_t eccbytes; +- uint32_t eccpos[64]; ++ uint32_t eccpos[128]; + uint32_t oobavail; + struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; + }; +diff -ru linux-2.6/include/sound/pcm.h /plain/src/qi/linux-2.6.27.git.svn/include/sound/pcm.h +--- linux-2.6/include/sound/pcm.h 2009-08-17 23:58:03.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/include/sound/pcm.h 2009-08-12 10:39:09.000000000 +0200 +@@ -107,23 +107,23 @@ + #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 */ + +-#define SNDRV_PCM_RATE_8000_44100 (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|\ +- SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|\ +- SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100) ++#define SNDRV_PCM_RATE_8000_44100 (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) + #define SNDRV_PCM_RATE_8000_48000 (SNDRV_PCM_RATE_8000_44100|SNDRV_PCM_RATE_48000) + #define SNDRV_PCM_RATE_8000_96000 (SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_64000|\ + SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000) +diff -ru linux-2.6/sound/core/pcm_lib.c /plain/src/qi/linux-2.6.27.git.svn/sound/core/pcm_lib.c +--- linux-2.6/sound/core/pcm_lib.c 2009-08-17 23:58:04.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/sound/core/pcm_lib.c 2009-08-12 10:39:09.000000000 +0200 +@@ -1875,6 +1875,7 @@ + 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; +@@ -1892,6 +1893,99 @@ + 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; ++ ++ snd_assert(substream != NULL, return -ENXIO); ++ runtime = substream->runtime; ++ snd_assert(runtime != NULL, return -ENXIO); ++ snd_assert(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 */ ++ snd_assert(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 -ru linux-2.6/sound/core/pcm_native.c /plain/src/qi/linux-2.6.27.git.svn/sound/core/pcm_native.c +--- linux-2.6/sound/core/pcm_native.c 2009-08-17 23:58:04.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/sound/core/pcm_native.c 2009-08-12 10:39:09.000000000 +0200 +@@ -1756,12 +1756,13 @@ + 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), +@@ -1772,9 +1773,17 @@ + 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 -ru linux-2.6/sound/oss/Kconfig /plain/src/qi/linux-2.6.27.git.svn/sound/oss/Kconfig +--- linux-2.6/sound/oss/Kconfig 2009-08-17 23:58:04.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/sound/oss/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -5,6 +5,75 @@ + # + # Prompt user for primary drivers. + ++config OSS_OBSOLETE ++ bool "Obsolete OSS drivers" ++ depends on SOUND_PRIME ++ help ++ This option enables support for obsolete OSS drivers that ++ are scheduled for removal in the near future. ++ ++ Please contact Adrian Bunk if you had to ++ say Y here because your hardware is not properly supported ++ by ALSA. ++ ++ If unsure, say N. ++ ++config SOUND_JZ_AC97 ++ bool "Jz On-Chip AC97 driver" ++ depends on OSS_OBSOLETE ++ 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 OSS_OBSOLETE ++ 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 ++ help ++ Answer Y if you have an internal I2S codec on Jz4750 or Jz4750d. ++ ++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 -ru linux-2.6/sound/oss/Makefile /plain/src/qi/linux-2.6.27.git.svn/sound/oss/Makefile +--- linux-2.6/sound/oss/Makefile 2009-08-17 23:58:04.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/sound/oss/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -9,6 +9,12 @@ + + # 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_HAL2) += hal2.o + obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o +diff -ru linux-2.6/sound/oss/os.h /plain/src/qi/linux-2.6.27.git.svn/sound/oss/os.h +--- linux-2.6/sound/oss/os.h 2009-08-17 23:57:37.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/sound/oss/os.h 2009-08-12 10:39:09.000000000 +0200 +@@ -9,7 +9,7 @@ + #ifdef __KERNEL__ + #include + #include +-#include ++//#include + #include + #include + #include +diff -ru linux-2.6/sound/soc/codecs/Kconfig /plain/src/qi/linux-2.6.27.git.svn/sound/soc/codecs/Kconfig +--- linux-2.6/sound/soc/codecs/Kconfig 2009-08-17 23:58:04.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/sound/soc/codecs/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -50,3 +50,15 @@ + config SND_SOC_TLV320AIC3X + tristate + depends on I2C ++ ++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 -ru linux-2.6/sound/soc/codecs/Makefile /plain/src/qi/linux-2.6.27.git.svn/sound/soc/codecs/Makefile +--- linux-2.6/sound/soc/codecs/Makefile 2009-08-17 23:58:04.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/sound/soc/codecs/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -10,6 +10,8 @@ + snd-soc-wm9713-objs := wm9713.o + snd-soc-cs4270-objs := cs4270.o + snd-soc-tlv320aic3x-objs := tlv320aic3x.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_AK4535) += snd-soc-ak4535.o +@@ -23,3 +25,5 @@ + obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o + obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o + obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o ++obj-$(CONFIG_SND_SOC_ICODEC) += snd-soc-jzcodec.o ++obj-$(CONFIG_SND_SOC_DLV) += snd-soc-jzdlv.o +\ No newline at end of file +diff -ru linux-2.6/sound/soc/Kconfig /plain/src/qi/linux-2.6.27.git.svn/sound/soc/Kconfig +--- linux-2.6/sound/soc/Kconfig 2009-08-17 23:58:04.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/sound/soc/Kconfig 2009-08-12 10:39:09.000000000 +0200 +@@ -31,6 +31,8 @@ + source "sound/soc/fsl/Kconfig" + source "sound/soc/davinci/Kconfig" + source "sound/soc/omap/Kconfig" ++source "sound/soc/jz4740/Kconfig" ++source "sound/soc/jz4750/Kconfig" + + # Supported codecs + source "sound/soc/codecs/Kconfig" +diff -ru linux-2.6/sound/soc/Makefile /plain/src/qi/linux-2.6.27.git.svn/sound/soc/Makefile +--- linux-2.6/sound/soc/Makefile 2009-08-17 23:58:04.000000000 +0200 ++++ /plain/src/qi/linux-2.6.27.git.svn/sound/soc/Makefile 2009-08-12 10:39:09.000000000 +0200 +@@ -2,4 +2,4 @@ + + obj-$(CONFIG_SND_SOC) += snd-soc-core.o + obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ +-obj-$(CONFIG_SND_SOC) += omap/ au1x/ ++obj-$(CONFIG_SND_SOC) += omap/ au1x/ jz4740/ jz4750/ diff --git a/target/linux/xburst/patches-2.6.27/010-add-qi_lb60.patch b/target/linux/xburst/patches-2.6.27/010-add-qi_lb60.patch new file mode 100644 index 000000000..928f5007a --- /dev/null +++ b/target/linux/xburst/patches-2.6.27/010-add-qi_lb60.patch @@ -0,0 +1,375 @@ +--- /dev/null ++++ b/arch/mips/jz4740/board-qi_lb60.c +@@ -0,0 +1,110 @@ ++/* ++ * linux/arch/mips/jz4740/board-qi_lb60.c ++ * ++ * QI_LB60 setup routines. ++ * ++ * Copyright (c) 2009 Qi Hardware inc., ++ * Author: Xiangfu Liu ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 3 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++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 pi_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_disable_pull(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); ++} ++ ++void __init jz_board_setup(void) ++{ ++ printk("Qi Hardware JZ4740 QI_LB60 setup\n"); ++ ++ board_cpm_setup(); ++ board_gpio_setup(); ++ ++ jz_timer_callback = pi_timer_callback; ++} +--- a/arch/mips/jz4740/Makefile ++++ b/arch/mips/jz4740/Makefile +@@ -16,6 +16,7 @@ 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 ++obj-$(CONFIG_JZ4740_QI_LB60) += board-qi_lb60.o + + # PM support + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -18,6 +18,14 @@ choice + prompt "System type" + default SGI_IP22 + ++config JZ4740_QI_LB60 ++ bool "Ingenic JZ4740 QI_LB60 board" ++ select DMA_NONCOHERENT ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SOC_JZ4740 ++ + config JZ4730_PMP + bool "Ingenic JZ4730 PMP board" + select DMA_NONCOHERENT +--- a/drivers/mtd/nand/jz4740_nand.c.orig 2009-08-18 11:46:56.000000000 +0200 ++++ b/drivers/mtd/nand/jz4740_nand.c 2009-08-18 11:51:13.000000000 +0200 +@@ -240,6 +240,53 @@ + 20, /* reserved blocks of mtd4 */ + 20}; /* reserved blocks of mtd5 */ + #endif /* CONFIG_JZ4720_VIRGO */ ++ ++#ifdef CONFIG_JZ4740_QI_LB60 ++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: 504 * 0x100000, ++ use_planes: 0 }, ++ { name: "NAND DATA1 partition", ++ offset: 512 * 0x100000, ++ size: 512 * 0x100000, ++ use_planes: 1 }, ++ { name: "NAND DATA2 partition", ++ offset: 1024 * 0x100000, ++ size: 512 * 0x100000, ++ use_planes: 1 }, ++ { name: "NAND VFAT partition", ++ offset: (1024 + 512) * 0x100000, ++ size: 512 * 0x100000, ++ use_planes: 1 }, ++}; ++ ++/* 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 */ ++ 20}; /* reserved blocks of mtd5 */ ++#endif /* CONFIG_JZ4740_QI_LB60 */ ++ + /*------------------------------------------------------------------------- + * Following three functions are exported and used by the mtdblock-jz.c + * NAND FTL driver only. +--- a/drivers/video/jzlcd.c ++++ b/drivers/video/jzlcd.c +@@ -126,15 +126,18 @@ static struct jzfb_info jzfb = { + 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_FOXCONN_PT035TN01) ++ #if defined(CONFIG_JZ4740_PAVO) ++ MODE_TFT_GEN | HSYNC_N | VSYNC_N | MODE_TFT_18BIT | PCLK_N, ++ 320, 240, 18, 80, 1, 1, 10, 50, 10, 13 ++ #elif defined(CONFIG_JZ4740_QI_LB60) ++ MODE_8BIT_SERIAL_TFT | PCLK_N | HSYNC_N | VSYNC_N, ++ 320, 240, 32, 70, 1, 1, 273, 140, 1, 20 ++ #else ++ MODE_TFT_GEN | HSYNC_N | VSYNC_N | PCLK_N, ++ 320, 240, 16, 110, 1, 1, 10, 50, 10, 13 ++ #endif ++#endif /* CONFIG_JZLCD_FOXCONN_PT035TN01 */ + #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 +@@ -1523,7 +1526,7 @@ static int __init jzfb_init(void) + cfb->pm->data = cfb; + #endif + +- __lcd_display_on(); ++ __lcd_display_off(); + + return 0; + +--- a/drivers/video/jzlcd.h ++++ b/drivers/video/jzlcd.h +@@ -363,7 +363,11 @@ do { \ + #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 */ ++ #if defined(CONFIG_JZ4740_QI_LB60) ++ #define MODE 0xc9 ++ #else ++ #define MODE 0xcd /* 24bit parellel RGB */ ++ #endif + #endif + #if defined(CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL) + #define MODE 0xc9 /* 8bit serial RGB */ +@@ -384,6 +388,11 @@ do { \ + #define SPCK (32*1+17) //LCD_CLS + #define SPDA (32*2+12) //LCD_D12 + #define LCD_RET (32*2+23) //LCD_REV, GPC23 ++#elif defined(CONFIG_JZ4740_QI_LB60) ++ #define SPEN (32*2+21) //LCD_SPL ++ #define SPCK (32*2+23) //LCD_CLS ++ #define SPDA (32*2+22) //LCD_D12 ++ #define LCD_RET (32*3+27) + #if 0 /*old driver*/ + #define SPEN (32*1+18) //LCD_SPL + #define SPCK (32*1+17) //LCD_CLS +@@ -655,7 +664,7 @@ do { \ + + /*#if defined(CONFIG_JZ4740_LEO) || defined(CONFIG_JZ4740_PAVO)*/ + #if defined(CONFIG_SOC_JZ4740) +-#if defined(CONFIG_JZ4740_PAVO) || defined(CONFIG_JZ4740_LYRA) ++#if defined(CONFIG_JZ4740_PAVO) || defined(CONFIG_JZ4740_LYRA) || defined(CONFIG_JZ4740_QI_LB60) + #define GPIO_PWM 123 /* GP_D27 */ + #define PWM_CHN 4 /* pwm channel */ + #define PWM_FULL 101 +@@ -725,7 +734,7 @@ do { \ + do { \ + __gpio_set_pin(GPIO_DISP_OFF_N); \ + __lcd_special_on(); \ +- __lcd_set_backlight_level(80); \ ++ __lcd_set_backlight_level(20); \ + } while (0) + + #define __lcd_display_off() \ +--- /dev/null ++++ b/include/asm-mips/mach-jz4740/board-qi_lb60.h +@@ -0,0 +1,79 @@ ++/* ++ * linux/include/asm-mips/mach-jz4740/board-qi_lb60.h ++ * ++ * Copyright (c) 2009 Qi Hardware inc., ++ * Author: Xiangfu Liu ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 3 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_JZ4740_QI_LB60_H__ ++#define __ASM_JZ4740_QI_LB60_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_DC_DETE_N (2 * 32 + 26) ++#define GPIO_CHARG_STAT_N (2 * 32 + 27) ++#define GPIO_LED_EN (2 * 32 + 28) ++#define GPIO_LCD_CS (2 * 32 + 21) ++#define GPIO_DISP_OFF_N (3 * 32 + 21) ++#define GPIO_PWM (3 * 32 + 27) ++ ++#define GPIO_AMP_EN (3 * 32 + 4) ++ ++#define GPIO_SD_CD_N (3 * 32 + 0) ++#define GPIO_SD_VCC_EN_N (3 * 32 + 2) ++#define GPIO_SD_WP (3 * 32 + 16) ++ ++#define GPIO_USB_DETE (3 * 32 + 28) ++#define GPIO_BUZZ_PWM (3 * 32 + 27) ++#define GPIO_UDC_HOTPLUG GPIO_USB_DETE ++ ++#define GPIO_AUDIO_POP (1 * 32 + 29) ++#define GPIO_COB_TEST (1 * 32 + 30) ++ ++#define GPIO_KEYOUT_BASE (2 * 32 + 10) ++#define GPIO_KEYIN_BASE (3 * 32 + 18) ++#define GPIO_KEYIN_8 (3 * 32 + 26) ++ ++/* ++ * 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_QI_LB60_H__ */ +--- a/include/asm-mips/mach-jz4740/jz4740.h ++++ b/include/asm-mips/mach-jz4740/jz4740.h +@@ -43,6 +43,10 @@ + #include + #endif + ++#ifdef CONFIG_JZ4740_QI_LB60 ++#include ++#endif ++ + /* Add other platform definition here ... */ + +