mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-28 17:59:41 +02:00
Add 2.6.31 patches and files.
This commit is contained in:
parent
f58d88c0f1
commit
7d446f792e
422
target/linux/xburst/config-2.6.31
Normal file
422
target/linux/xburst/config-2.6.31
Normal file
@ -0,0 +1,422 @@
|
|||||||
|
CONFIG_32BIT=y
|
||||||
|
# CONFIG_64BIT is not set
|
||||||
|
# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
|
||||||
|
# CONFIG_AR7 is not set
|
||||||
|
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
|
||||||
|
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
|
||||||
|
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||||
|
CONFIG_ARCH_POPULATES_NODE_MAP=y
|
||||||
|
CONFIG_ARCH_REQUIRE_GPIOLIB=y
|
||||||
|
# CONFIG_ARCH_SUPPORTS_MSI is not set
|
||||||
|
CONFIG_ARCH_SUPPORTS_OPROFILE=y
|
||||||
|
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||||
|
# CONFIG_ARPD is not set
|
||||||
|
# CONFIG_BACKTRACE_SELF_TEST is not set
|
||||||
|
CONFIG_BASE_SMALL=0
|
||||||
|
# CONFIG_BCM47XX is not set
|
||||||
|
# CONFIG_BINARY_PRINTF is not set
|
||||||
|
CONFIG_BITREVERSE=y
|
||||||
|
# CONFIG_BLK_DEV_INITRD is not set
|
||||||
|
CONFIG_BLK_DEV_LOOP=y
|
||||||
|
CONFIG_BLK_DEV_RAM=y
|
||||||
|
CONFIG_BLK_DEV_RAM_COUNT=2
|
||||||
|
CONFIG_BLK_DEV_RAM_SIZE=4096
|
||||||
|
CONFIG_BLK_DEV_SD=y
|
||||||
|
# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
|
||||||
|
CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
|
||||||
|
# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
|
||||||
|
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
|
||||||
|
# CONFIG_BOOT_PRINTK_DELAY is not set
|
||||||
|
# CONFIG_BRIDGE is not set
|
||||||
|
# CONFIG_BSD_PROCESS_ACCT is not set
|
||||||
|
# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
|
||||||
|
# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
|
||||||
|
# CONFIG_CFG80211_DEBUGFS is not set
|
||||||
|
# CONFIG_CGROUP_SCHED is not set
|
||||||
|
CONFIG_CMDLINE="mem=32M console=ttyS0,57600n8 rootfstype=ext2 root=/dev/mmcblk0p1 rw rootdelay=2"
|
||||||
|
CONFIG_CONSOLE_TRANSLATIONS=y
|
||||||
|
CONFIG_CONSTRUCTORS=y
|
||||||
|
# CONFIG_CPU_BIG_ENDIAN is not set
|
||||||
|
# CONFIG_CPU_CAVIUM_OCTEON is not set
|
||||||
|
CONFIG_CPU_FREQ=y
|
||||||
|
# CONFIG_CPU_FREQ_DEBUG is not set
|
||||||
|
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
|
||||||
|
# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
|
||||||
|
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
|
||||||
|
# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
|
||||||
|
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
|
||||||
|
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
|
||||||
|
# CONFIG_CPU_FREQ_GOV_ONDEMAND 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_JZ=y
|
||||||
|
CONFIG_CPU_FREQ_STAT=y
|
||||||
|
# CONFIG_CPU_FREQ_STAT_DETAILS is not set
|
||||||
|
CONFIG_CPU_FREQ_TABLE=y
|
||||||
|
CONFIG_CPU_HAS_LLSC=y
|
||||||
|
CONFIG_CPU_HAS_PREFETCH=y
|
||||||
|
CONFIG_CPU_HAS_SYNC=y
|
||||||
|
CONFIG_CPU_LITTLE_ENDIAN=y
|
||||||
|
# CONFIG_CPU_LOONGSON2 is not set
|
||||||
|
CONFIG_CPU_MIPS32=y
|
||||||
|
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_MIPSR1=y
|
||||||
|
# CONFIG_CPU_NEVADA is not set
|
||||||
|
# CONFIG_CPU_R10000 is not set
|
||||||
|
# CONFIG_CPU_R3000 is not set
|
||||||
|
# CONFIG_CPU_R4300 is not set
|
||||||
|
# CONFIG_CPU_R4X00 is not set
|
||||||
|
# CONFIG_CPU_R5000 is not set
|
||||||
|
# CONFIG_CPU_R5432 is not set
|
||||||
|
# CONFIG_CPU_R5500 is not set
|
||||||
|
# CONFIG_CPU_R6000 is not set
|
||||||
|
# CONFIG_CPU_R8000 is not set
|
||||||
|
# CONFIG_CPU_RM7000 is not set
|
||||||
|
# CONFIG_CPU_RM9000 is not set
|
||||||
|
# CONFIG_CPU_SB1 is not set
|
||||||
|
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
|
||||||
|
CONFIG_CPU_SUPPORTS_HIGHMEM=y
|
||||||
|
# CONFIG_CPU_TX39XX is not set
|
||||||
|
# CONFIG_CPU_TX49XX is not set
|
||||||
|
# CONFIG_CPU_VR41XX is not set
|
||||||
|
CONFIG_CRC16=y
|
||||||
|
CONFIG_CRYPTO_AEAD2=y
|
||||||
|
CONFIG_CRYPTO_BLKCIPHER=y
|
||||||
|
CONFIG_CRYPTO_BLKCIPHER2=y
|
||||||
|
CONFIG_CRYPTO_CBC=y
|
||||||
|
CONFIG_CRYPTO_DEFLATE=y
|
||||||
|
CONFIG_CRYPTO_DES=y
|
||||||
|
CONFIG_CRYPTO_HASH=y
|
||||||
|
CONFIG_CRYPTO_HASH2=y
|
||||||
|
CONFIG_CRYPTO_HW=y
|
||||||
|
CONFIG_CRYPTO_LZO=y
|
||||||
|
CONFIG_CRYPTO_MANAGER=y
|
||||||
|
CONFIG_CRYPTO_MANAGER2=y
|
||||||
|
CONFIG_CRYPTO_MD5=y
|
||||||
|
CONFIG_CRYPTO_RNG2=y
|
||||||
|
CONFIG_CRYPTO_WORKQUEUE=y
|
||||||
|
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
|
||||||
|
# CONFIG_DEBUG_DEVRES is not set
|
||||||
|
# CONFIG_DEBUG_DRIVER is not set
|
||||||
|
# CONFIG_DEBUG_GPIO is not set
|
||||||
|
# CONFIG_DEBUG_INFO is not set
|
||||||
|
CONFIG_DEBUG_KERNEL=y
|
||||||
|
# CONFIG_DEBUG_KOBJECT is not set
|
||||||
|
# CONFIG_DEBUG_LIST is not set
|
||||||
|
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
|
||||||
|
# CONFIG_DEBUG_LOCK_ALLOC is not set
|
||||||
|
# CONFIG_DEBUG_MUTEXES is not set
|
||||||
|
# CONFIG_DEBUG_NOTIFIERS is not set
|
||||||
|
# CONFIG_DEBUG_OBJECTS is not set
|
||||||
|
CONFIG_DEBUG_PREEMPT=y
|
||||||
|
# CONFIG_DEBUG_RT_MUTEXES is not set
|
||||||
|
# CONFIG_DEBUG_SG is not set
|
||||||
|
# CONFIG_DEBUG_SHIRQ is not set
|
||||||
|
# CONFIG_DEBUG_SLAB is not set
|
||||||
|
# CONFIG_DEBUG_SPINLOCK is not set
|
||||||
|
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
|
||||||
|
# CONFIG_DEBUG_STACK_USAGE is not set
|
||||||
|
# CONFIG_DEBUG_VM is not set
|
||||||
|
# CONFIG_DEBUG_WRITECOUNT is not set
|
||||||
|
CONFIG_DEFAULT_AS=y
|
||||||
|
# CONFIG_DEFAULT_DEADLINE is not set
|
||||||
|
CONFIG_DEFAULT_IOSCHED="anticipatory"
|
||||||
|
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
|
||||||
|
CONFIG_DEFAULT_TCP_CONG="cubic"
|
||||||
|
CONFIG_DETECT_HUNG_TASK=y
|
||||||
|
CONFIG_DETECT_SOFTLOCKUP=y
|
||||||
|
CONFIG_DMA_NEED_PCI_MAP_STATE=y
|
||||||
|
CONFIG_DMA_NONCOHERENT=y
|
||||||
|
CONFIG_DNOTIFY=y
|
||||||
|
CONFIG_DUMMY_CONSOLE=y
|
||||||
|
CONFIG_EARLY_PRINTK=y
|
||||||
|
CONFIG_ELF_CORE=y
|
||||||
|
CONFIG_ENABLE_MUST_CHECK=y
|
||||||
|
CONFIG_EXT2_FS=y
|
||||||
|
# CONFIG_EXT2_FS_POSIX_ACL is not set
|
||||||
|
# CONFIG_EXT2_FS_SECURITY is not set
|
||||||
|
CONFIG_EXT2_FS_XATTR=y
|
||||||
|
CONFIG_FAT_FS=y
|
||||||
|
# CONFIG_FAULT_INJECTION is not set
|
||||||
|
CONFIG_FB=y
|
||||||
|
# CONFIG_FB_BACKLIGHT is not set
|
||||||
|
# CONFIG_FB_BOOT_VESA_SUPPORT is not set
|
||||||
|
# CONFIG_FB_BROADSHEET is not set
|
||||||
|
CONFIG_FB_CFB_COPYAREA=y
|
||||||
|
CONFIG_FB_CFB_FILLRECT=y
|
||||||
|
CONFIG_FB_CFB_IMAGEBLIT=y
|
||||||
|
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
|
||||||
|
# CONFIG_FB_DDC is not set
|
||||||
|
# CONFIG_FB_FOREIGN_ENDIAN is not set
|
||||||
|
# CONFIG_FB_JZ4740_SLCD is not set
|
||||||
|
CONFIG_FB_JZLCD_4730_4740=y
|
||||||
|
CONFIG_FB_JZSOC=y
|
||||||
|
# CONFIG_FB_MACMODES is not set
|
||||||
|
# CONFIG_FB_MB862XX is not set
|
||||||
|
# CONFIG_FB_METRONOME is not set
|
||||||
|
# CONFIG_FB_MODE_HELPERS is not set
|
||||||
|
# CONFIG_FB_S1D13XXX is not set
|
||||||
|
# CONFIG_FB_SVGALIB is not set
|
||||||
|
# CONFIG_FB_SYS_COPYAREA is not set
|
||||||
|
# CONFIG_FB_SYS_FILLRECT is not set
|
||||||
|
# CONFIG_FB_SYS_FOPS is not set
|
||||||
|
# CONFIG_FB_SYS_IMAGEBLIT is not set
|
||||||
|
# CONFIG_FB_TILEBLITTING is not set
|
||||||
|
# CONFIG_FB_VIRTUAL is not set
|
||||||
|
# CONFIG_FIRMWARE_EDID is not set
|
||||||
|
CONFIG_FONTS=y
|
||||||
|
# CONFIG_FONT_10x18 is not set
|
||||||
|
# CONFIG_FONT_6x11 is not set
|
||||||
|
# CONFIG_FONT_7x14 is not set
|
||||||
|
CONFIG_FONT_8x16=y
|
||||||
|
CONFIG_FONT_8x8=y
|
||||||
|
# CONFIG_FONT_ACORN_8x8 is not set
|
||||||
|
# CONFIG_FONT_MINI_4x6 is not set
|
||||||
|
# CONFIG_FONT_PEARL_8x8 is not set
|
||||||
|
# CONFIG_FONT_SUN12x22 is not set
|
||||||
|
# CONFIG_FONT_SUN8x16 is not set
|
||||||
|
CONFIG_FORCE_MAX_ZONEORDER=12
|
||||||
|
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||||
|
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
|
||||||
|
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
|
||||||
|
CONFIG_FSNOTIFY=y
|
||||||
|
CONFIG_FS_MBCACHE=y
|
||||||
|
CONFIG_FS_POSIX_ACL=y
|
||||||
|
# CONFIG_FW_LOADER is not set
|
||||||
|
# CONFIG_GCOV_KERNEL is not set
|
||||||
|
CONFIG_GENERIC_CLOCKEVENTS=y
|
||||||
|
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
|
||||||
|
CONFIG_GENERIC_CMOS_UPDATE=y
|
||||||
|
CONFIG_GENERIC_FIND_LAST_BIT=y
|
||||||
|
CONFIG_GENERIC_FIND_NEXT_BIT=y
|
||||||
|
CONFIG_GENERIC_GPIO=y
|
||||||
|
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
|
||||||
|
CONFIG_GPIOLIB=y
|
||||||
|
CONFIG_GPIO_SYSFS=y
|
||||||
|
CONFIG_GROUP_SCHED=y
|
||||||
|
# CONFIG_HAMRADIO is not set
|
||||||
|
CONFIG_HARDWARE_WATCHPOINTS=y
|
||||||
|
CONFIG_HAS_DMA=y
|
||||||
|
CONFIG_HAS_IOMEM=y
|
||||||
|
CONFIG_HAS_IOPORT=y
|
||||||
|
CONFIG_HAVE_ARCH_KGDB=y
|
||||||
|
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
|
||||||
|
CONFIG_HAVE_IDE=y
|
||||||
|
CONFIG_HAVE_MLOCK=y
|
||||||
|
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
|
||||||
|
CONFIG_HAVE_OPROFILE=y
|
||||||
|
CONFIG_HID=y
|
||||||
|
CONFIG_HID_SUPPORT=y
|
||||||
|
# CONFIG_HIGH_RES_TIMERS is not set
|
||||||
|
CONFIG_HW_CONSOLE=y
|
||||||
|
# CONFIG_HW_RANDOM is not set
|
||||||
|
# CONFIG_I2C is not set
|
||||||
|
# CONFIG_IEEE802154 is not set
|
||||||
|
CONFIG_INET_DIAG=m
|
||||||
|
CONFIG_INET_TCP_DIAG=m
|
||||||
|
CONFIG_INOTIFY=y
|
||||||
|
CONFIG_INOTIFY_USER=y
|
||||||
|
CONFIG_INPUT=y
|
||||||
|
CONFIG_INPUT_EVDEV=y
|
||||||
|
CONFIG_INPUT_KEYBOARD=y
|
||||||
|
# CONFIG_INPUT_MISC is not set
|
||||||
|
CONFIG_IOSCHED_AS=y
|
||||||
|
CONFIG_IOSCHED_CFQ=y
|
||||||
|
# CONFIG_IP_ADVANCED_ROUTER is not set
|
||||||
|
# CONFIG_IP_MULTICAST is not set
|
||||||
|
CONFIG_IP_PNP=y
|
||||||
|
CONFIG_IP_PNP_BOOTP=y
|
||||||
|
CONFIG_IP_PNP_DHCP=y
|
||||||
|
# CONFIG_IP_PNP_RARP is not set
|
||||||
|
# CONFIG_ISDN is not set
|
||||||
|
CONFIG_JFFS2_FS_DEBUG=1
|
||||||
|
CONFIG_JZ4740_QI_LB60=y
|
||||||
|
# CONFIG_JZLCD_AUO_A030FL01_V1 is not set
|
||||||
|
# CONFIG_JZLCD_CSTN_320x240 is not set
|
||||||
|
# CONFIG_JZLCD_CSTN_800x600 is not set
|
||||||
|
CONFIG_JZLCD_FOXCONN_PT035TN01=y
|
||||||
|
# CONFIG_JZLCD_HYNIX_HT10X21 is not set
|
||||||
|
# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set
|
||||||
|
# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set
|
||||||
|
# CONFIG_JZLCD_MSTN_240x128 is not set
|
||||||
|
# CONFIG_JZLCD_MSTN_320x240 is not set
|
||||||
|
# CONFIG_JZLCD_MSTN_480x320 is not set
|
||||||
|
# CONFIG_JZLCD_SAMSUNG_LTP400WQF01 is not set
|
||||||
|
# CONFIG_JZLCD_SAMSUNG_LTP400WQF02 is not set
|
||||||
|
# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set
|
||||||
|
# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set
|
||||||
|
# CONFIG_JZLCD_SHARP_LQ035Q7 is not set
|
||||||
|
# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set
|
||||||
|
# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set
|
||||||
|
# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set
|
||||||
|
# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set
|
||||||
|
CONFIG_JZRISC=y
|
||||||
|
CONFIG_JZSOC=y
|
||||||
|
CONFIG_KALLSYMS=y
|
||||||
|
CONFIG_KALLSYMS_ALL=y
|
||||||
|
# CONFIG_KEYBOARD_ATKBD is not set
|
||||||
|
# CONFIG_KEYBOARD_GPIO is not set
|
||||||
|
# CONFIG_KEYBOARD_LKKBD is not set
|
||||||
|
CONFIG_KEYBOARD_MATRIX=y
|
||||||
|
# CONFIG_KEYBOARD_NEWTON is not set
|
||||||
|
# CONFIG_KEYBOARD_STOWAWAY is not set
|
||||||
|
# CONFIG_KEYBOARD_SUNKBD is not set
|
||||||
|
# CONFIG_KEYBOARD_XTKBD is not set
|
||||||
|
# CONFIG_KGDB is not set
|
||||||
|
# CONFIG_KMEMCHECK is not set
|
||||||
|
# CONFIG_LBDAF is not set
|
||||||
|
CONFIG_LEGACY_PTYS=y
|
||||||
|
CONFIG_LEGACY_PTY_COUNT=2
|
||||||
|
# CONFIG_LEMOTE_FULONG is not set
|
||||||
|
CONFIG_LOCALVERSION_AUTO=y
|
||||||
|
CONFIG_LOCKD=y
|
||||||
|
CONFIG_LOCK_KERNEL=y
|
||||||
|
# CONFIG_LOCK_STAT is not set
|
||||||
|
CONFIG_LOGO=y
|
||||||
|
CONFIG_LOGO_LINUX_CLUT224=y
|
||||||
|
CONFIG_LOGO_LINUX_MONO=y
|
||||||
|
CONFIG_LOGO_LINUX_VGA16=y
|
||||||
|
CONFIG_LZO_COMPRESS=y
|
||||||
|
CONFIG_LZO_DECOMPRESS=y
|
||||||
|
# CONFIG_MAC80211_DEFAULT_PS is not set
|
||||||
|
CONFIG_MAC80211_DEFAULT_PS_VALUE=0
|
||||||
|
# CONFIG_MACH_ALCHEMY is not set
|
||||||
|
# CONFIG_MACH_DECSTATION is not set
|
||||||
|
# CONFIG_MACH_JAZZ is not set
|
||||||
|
# CONFIG_MACH_TX39XX is not set
|
||||||
|
# CONFIG_MACH_TX49XX is not set
|
||||||
|
# CONFIG_MACH_VR41XX is not set
|
||||||
|
CONFIG_MAGIC_SYSRQ=y
|
||||||
|
# CONFIG_MEDIA_SUPPORT is not set
|
||||||
|
# CONFIG_MIKROTIK_RB532 is not set
|
||||||
|
CONFIG_MIPS=y
|
||||||
|
# CONFIG_MIPS_COBALT is not set
|
||||||
|
# CONFIG_MIPS_FPU_EMU is not set
|
||||||
|
CONFIG_MIPS_L1_CACHE_SHIFT=5
|
||||||
|
# CONFIG_MIPS_MACHINE is not set
|
||||||
|
# CONFIG_MIPS_MALTA is not set
|
||||||
|
CONFIG_MIPS_MT_DISABLED=y
|
||||||
|
# CONFIG_MIPS_MT_SMP is not set
|
||||||
|
# CONFIG_MIPS_MT_SMTC is not set
|
||||||
|
# CONFIG_MIPS_SIM is not set
|
||||||
|
CONFIG_MMC=y
|
||||||
|
CONFIG_MMC_BLOCK=y
|
||||||
|
CONFIG_MMC_BLOCK_BOUNCE=y
|
||||||
|
# CONFIG_MMC_DEBUG is not set
|
||||||
|
# CONFIG_MMC_JZ is not set
|
||||||
|
# CONFIG_MMC_SDHCI is not set
|
||||||
|
# CONFIG_MMC_UNSAFE_RESUME is not set
|
||||||
|
CONFIG_MODULE_SRCVERSION_ALL=y
|
||||||
|
CONFIG_MODVERSIONS=y
|
||||||
|
CONFIG_MSDOS_FS=y
|
||||||
|
CONFIG_MTD_CONCAT=y
|
||||||
|
CONFIG_MTD_NAND=y
|
||||||
|
CONFIG_MTD_NAND_JZ4740=y
|
||||||
|
CONFIG_MTD_NAND_VERIFY_WRITE=y
|
||||||
|
CONFIG_MTD_UBI=y
|
||||||
|
CONFIG_MTD_UBI_BEB_RESERVE=1
|
||||||
|
# CONFIG_MTD_UBI_DEBUG is not set
|
||||||
|
# CONFIG_MTD_UBI_GLUEBI is not set
|
||||||
|
CONFIG_MTD_UBI_WL_THRESHOLD=4096
|
||||||
|
# CONFIG_NETDEVICES is not set
|
||||||
|
# CONFIG_NETFILTER is not set
|
||||||
|
# CONFIG_NET_SCHED is not set
|
||||||
|
# CONFIG_NEW_LEDS is not set
|
||||||
|
CONFIG_NFS_ACL_SUPPORT=y
|
||||||
|
CONFIG_NFS_FS=y
|
||||||
|
CONFIG_NFS_V3_ACL=y
|
||||||
|
# CONFIG_NFS_V4_1 is not set
|
||||||
|
CONFIG_NLS=y
|
||||||
|
CONFIG_NLS_ASCII=y
|
||||||
|
CONFIG_NLS_CODEPAGE_437=y
|
||||||
|
CONFIG_NLS_CODEPAGE_936=y
|
||||||
|
CONFIG_NLS_ISO8859_1=y
|
||||||
|
# CONFIG_NO_IOPORT is not set
|
||||||
|
# CONFIG_NXP_STB220 is not set
|
||||||
|
# CONFIG_NXP_STB225 is not set
|
||||||
|
# CONFIG_PACKET_MMAP is not set
|
||||||
|
CONFIG_PAGEFLAGS_EXTENDED=y
|
||||||
|
# CONFIG_PAGE_POISONING is not set
|
||||||
|
CONFIG_PCSPKR_PLATFORM=y
|
||||||
|
# CONFIG_PMC_MSP is not set
|
||||||
|
# CONFIG_PMC_YOSEMITE is not set
|
||||||
|
# CONFIG_PNX8550_JBS is not set
|
||||||
|
# CONFIG_PNX8550_STB810 is not set
|
||||||
|
# CONFIG_PPS is not set
|
||||||
|
CONFIG_PREEMPT=y
|
||||||
|
# CONFIG_PREEMPT_NONE is not set
|
||||||
|
# CONFIG_PROM_EMU is not set
|
||||||
|
# CONFIG_PROVE_LOCKING is not set
|
||||||
|
# CONFIG_RCU_TORTURE_TEST is not set
|
||||||
|
CONFIG_RELAY=y
|
||||||
|
CONFIG_ROOT_NFS=y
|
||||||
|
CONFIG_RPCSEC_GSS_KRB5=y
|
||||||
|
# CONFIG_RT_GROUP_SCHED is not set
|
||||||
|
# CONFIG_RT_MUTEX_TESTER is not set
|
||||||
|
# CONFIG_RUNTIME_DEBUG is not set
|
||||||
|
# CONFIG_SCHEDSTATS is not set
|
||||||
|
CONFIG_SCHED_DEBUG=y
|
||||||
|
CONFIG_SCHED_OMIT_FRAME_POINTER=y
|
||||||
|
CONFIG_SCSI=y
|
||||||
|
# CONFIG_SCSI_MULTI_LUN is not set
|
||||||
|
# CONFIG_SDIO_UART is not set
|
||||||
|
CONFIG_SECCOMP=y
|
||||||
|
# CONFIG_SERIAL_8250_EXTENDED is not set
|
||||||
|
CONFIG_SERIAL_8250_NR_UARTS=1
|
||||||
|
CONFIG_SERIAL_8250_RUNTIME_UARTS=1
|
||||||
|
CONFIG_SERIO=y
|
||||||
|
# CONFIG_SERIO_I8042 is not set
|
||||||
|
CONFIG_SERIO_LIBPS2=y
|
||||||
|
# CONFIG_SERIO_RAW is not set
|
||||||
|
CONFIG_SERIO_SERPORT=y
|
||||||
|
# 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_BIGSUR is not set
|
||||||
|
# CONFIG_SIBYTE_CARMEL is not set
|
||||||
|
# CONFIG_SIBYTE_CRHINE is not set
|
||||||
|
# CONFIG_SIBYTE_CRHONE is not set
|
||||||
|
# CONFIG_SIBYTE_LITTLESUR is not set
|
||||||
|
# CONFIG_SIBYTE_RHONE is not set
|
||||||
|
# CONFIG_SIBYTE_SENTOSA is not set
|
||||||
|
# CONFIG_SIBYTE_SWARM is not set
|
||||||
|
# CONFIG_SLOW_WORK is not set
|
||||||
|
CONFIG_SOC_JZ4740=y
|
||||||
|
CONFIG_SOUND=y
|
||||||
|
CONFIG_SOUND_OSS_CORE=y
|
||||||
|
CONFIG_SOUND_PRIME=y
|
||||||
|
CONFIG_SUNRPC=y
|
||||||
|
CONFIG_SUNRPC_GSS=y
|
||||||
|
# CONFIG_SYN_COOKIES is not set
|
||||||
|
CONFIG_SYSFS_DEPRECATED=y
|
||||||
|
CONFIG_SYSFS_DEPRECATED_V2=y
|
||||||
|
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
|
||||||
|
CONFIG_SYS_HAS_EARLY_PRINTK=y
|
||||||
|
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
|
||||||
|
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
|
||||||
|
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
|
||||||
|
# CONFIG_TCP_CONG_ADVANCED is not set
|
||||||
|
CONFIG_TCP_CONG_CUBIC=y
|
||||||
|
# CONFIG_TIMER_STATS is not set
|
||||||
|
CONFIG_TRACING_SUPPORT=y
|
||||||
|
CONFIG_TRAD_SIGNALS=y
|
||||||
|
CONFIG_UBIFS_FS=y
|
||||||
|
# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
|
||||||
|
# CONFIG_UBIFS_FS_DEBUG is not set
|
||||||
|
CONFIG_UBIFS_FS_LZO=y
|
||||||
|
# CONFIG_UBIFS_FS_XATTR is not set
|
||||||
|
CONFIG_UBIFS_FS_ZLIB=y
|
||||||
|
CONFIG_USER_SCHED=y
|
||||||
|
CONFIG_VFAT_FS=y
|
||||||
|
# CONFIG_VGA_CONSOLE is not set
|
||||||
|
# CONFIG_VLAN_8021Q is not set
|
||||||
|
CONFIG_VM_EVENT_COUNTERS=y
|
||||||
|
CONFIG_VT=y
|
||||||
|
CONFIG_VT_CONSOLE=y
|
||||||
|
CONFIG_VT_HW_CONSOLE_BINDING=y
|
||||||
|
CONFIG_ZONE_DMA_FLAG=0
|
@ -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
|
@ -0,0 +1,4 @@
|
|||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* linux/arch/mips/boot/compressed/head.S
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005-2008 Ingenic Semiconductor Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/asm.h>
|
||||||
|
#include <asm/cacheops.h>
|
||||||
|
#include <asm/cachectl.h>
|
||||||
|
#include <asm/regdef.h>
|
||||||
|
|
||||||
|
#define IndexInvalidate_I 0x00
|
||||||
|
#define IndexWriteBack_D 0x01
|
||||||
|
|
||||||
|
.set noreorder
|
||||||
|
LEAF(startup)
|
||||||
|
startup:
|
||||||
|
move s0, a0 /* Save the boot loader transfered args */
|
||||||
|
move s1, a1
|
||||||
|
move s2, a2
|
||||||
|
move s3, a3
|
||||||
|
|
||||||
|
la a0, _edata
|
||||||
|
la a1, _end
|
||||||
|
1: sw zero, 0(a0) /* Clear BSS section */
|
||||||
|
bne a1, a0, 1b
|
||||||
|
addu a0, 4
|
||||||
|
|
||||||
|
la sp, (.stack + 8192)
|
||||||
|
|
||||||
|
la a0, __image_begin
|
||||||
|
la a1, IMAGESIZE
|
||||||
|
la a2, LOADADDR
|
||||||
|
la ra, 1f
|
||||||
|
la k0, decompress_kernel
|
||||||
|
jr k0
|
||||||
|
nop
|
||||||
|
1:
|
||||||
|
|
||||||
|
move a0, s0
|
||||||
|
move a1, s1
|
||||||
|
move a2, s2
|
||||||
|
move a3, s3
|
||||||
|
li k0, KERNEL_ENTRY
|
||||||
|
jr k0
|
||||||
|
nop
|
||||||
|
2:
|
||||||
|
b 32
|
||||||
|
END(startup)
|
||||||
|
|
||||||
|
|
||||||
|
LEAF(flushcaches)
|
||||||
|
la t0, 1f
|
||||||
|
la t1, 0xa0000000
|
||||||
|
or t0, t0, t1
|
||||||
|
jr t0
|
||||||
|
nop
|
||||||
|
1:
|
||||||
|
li k0, 0x80000000 # start address
|
||||||
|
li k1, 0x80004000 # end address (16KB I-Cache)
|
||||||
|
subu k1, 128
|
||||||
|
|
||||||
|
2:
|
||||||
|
.set mips3
|
||||||
|
cache IndexWriteBack_D, 0(k0)
|
||||||
|
cache IndexWriteBack_D, 32(k0)
|
||||||
|
cache IndexWriteBack_D, 64(k0)
|
||||||
|
cache IndexWriteBack_D, 96(k0)
|
||||||
|
cache IndexInvalidate_I, 0(k0)
|
||||||
|
cache IndexInvalidate_I, 32(k0)
|
||||||
|
cache IndexInvalidate_I, 64(k0)
|
||||||
|
cache IndexInvalidate_I, 96(k0)
|
||||||
|
.set mips0
|
||||||
|
|
||||||
|
bne k0, k1, 2b
|
||||||
|
addu k0, k0, 128
|
||||||
|
la t0, 3f
|
||||||
|
jr t0
|
||||||
|
nop
|
||||||
|
3:
|
||||||
|
jr ra
|
||||||
|
nop
|
||||||
|
END(flushcaches)
|
||||||
|
|
||||||
|
.comm .stack,4096*2,4
|
@ -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) }
|
||||||
|
}
|
@ -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<n;i++) ss[i] = c;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* memcpy(void* __dest, __const void* __src, size_t __n)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
|
||||||
|
|
||||||
|
for (i = __n >> 3; i > 0; i--) {
|
||||||
|
*d++ = *s++;
|
||||||
|
*d++ = *s++;
|
||||||
|
*d++ = *s++;
|
||||||
|
*d++ = *s++;
|
||||||
|
*d++ = *s++;
|
||||||
|
*d++ = *s++;
|
||||||
|
*d++ = *s++;
|
||||||
|
*d++ = *s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__n & 1 << 2) {
|
||||||
|
*d++ = *s++;
|
||||||
|
*d++ = *s++;
|
||||||
|
*d++ = *s++;
|
||||||
|
*d++ = *s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__n & 1 << 1) {
|
||||||
|
*d++ = *s++;
|
||||||
|
*d++ = *s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__n & 1)
|
||||||
|
*d++ = *s++;
|
||||||
|
|
||||||
|
return __dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================================================================
|
||||||
|
* Fill the input buffer. This is called only when the buffer is empty
|
||||||
|
* and at least one byte is really needed.
|
||||||
|
*/
|
||||||
|
static int fill_inbuf(void)
|
||||||
|
{
|
||||||
|
if (insize != 0) {
|
||||||
|
error("ran out of input data\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
inbuf = input_data;
|
||||||
|
insize = input_len;
|
||||||
|
inptr = 1;
|
||||||
|
return inbuf[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================================================================
|
||||||
|
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
|
||||||
|
* (Used for the decompressed data only.)
|
||||||
|
*/
|
||||||
|
static void flush_window(void)
|
||||||
|
{
|
||||||
|
ulg c = crc; /* temporary variable */
|
||||||
|
unsigned n;
|
||||||
|
uch *in, *out, ch;
|
||||||
|
|
||||||
|
in = window;
|
||||||
|
out = &output_data[output_ptr];
|
||||||
|
for (n = 0; n < outcnt; n++) {
|
||||||
|
ch = *out++ = *in++;
|
||||||
|
c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
|
||||||
|
}
|
||||||
|
crc = c;
|
||||||
|
bytes_out += (ulg)outcnt;
|
||||||
|
output_ptr += (ulg)outcnt;
|
||||||
|
outcnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void error(char *x)
|
||||||
|
{
|
||||||
|
puts("\n\n");
|
||||||
|
puts(x);
|
||||||
|
puts("\n\n -- System halted");
|
||||||
|
|
||||||
|
while(1); /* Halt */
|
||||||
|
}
|
||||||
|
|
||||||
|
void decompress_kernel(unsigned int imageaddr, unsigned int imagesize, unsigned int loadaddr)
|
||||||
|
{
|
||||||
|
input_data = (char *)imageaddr;
|
||||||
|
input_len = imagesize;
|
||||||
|
output_ptr = 0;
|
||||||
|
output_data = (uch *)loadaddr;
|
||||||
|
free_mem_ptr = (unsigned long)_end;
|
||||||
|
free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
|
||||||
|
|
||||||
|
makecrc();
|
||||||
|
puts("Uncompressing Linux...");
|
||||||
|
gunzip();
|
||||||
|
flushcaches();
|
||||||
|
puts("Ok, booting the kernel.");
|
||||||
|
}
|
12
target/linux/xburst/files-2.6.31/arch/mips/boot/tools/entry
Normal file
12
target/linux/xburst/files-2.6.31/arch/mips/boot/tools/entry
Normal file
@ -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
|
@ -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
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* linux/include/asm-mips/jzsoc.h
|
||||||
|
*
|
||||||
|
* Ingenic's JZXXXX SoC common include.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* Author: <jlwei@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM_JZSOC_H__
|
||||||
|
#define __ASM_JZSOC_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SoC include
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SOC_JZ4740
|
||||||
|
#include <asm/mach-jz4740/jz4740.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __ASM_JZSOC_H__ */
|
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* linux/include/asm-mips/mach-jz4740/board-dipper.h
|
||||||
|
*
|
||||||
|
* JZ4725-based (16bit) Dipper board ver 1.x definition.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* Author: <lhhuang@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM_JZ4725_DIPPER_H__
|
||||||
|
#define __ASM_JZ4725_DIPPER_H__
|
||||||
|
|
||||||
|
/*======================================================================
|
||||||
|
* Frequencies of on-board oscillators
|
||||||
|
*/
|
||||||
|
#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */
|
||||||
|
#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
|
||||||
|
|
||||||
|
/*======================================================================
|
||||||
|
* GPIO JZ4725
|
||||||
|
*/
|
||||||
|
#define GPIO_SD_VCC_EN_N 85 /* GPC21 */
|
||||||
|
#define GPIO_SD_CD_N 91 /* GPC27 */
|
||||||
|
#define GPIO_SD_WP 112 /* GPD16 */
|
||||||
|
#define GPIO_USB_DETE 124 /* GPD28 */
|
||||||
|
#define GPIO_DC_DETE_N 103 /* GPD7 */
|
||||||
|
#define GPIO_CHARG_STAT_N 86 /* GPC22 */
|
||||||
|
#define GPIO_DISP_OFF_N 118 /* GPD22 */
|
||||||
|
|
||||||
|
#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
|
||||||
|
|
||||||
|
/*======================================================================
|
||||||
|
* MMC/SD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MSC_WP_PIN GPIO_SD_WP
|
||||||
|
#define MSC_HOTPLUG_PIN GPIO_SD_CD_N
|
||||||
|
#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N)
|
||||||
|
|
||||||
|
#define __msc_init_io() \
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(GPIO_SD_VCC_EN_N); \
|
||||||
|
__gpio_as_input(GPIO_SD_CD_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __msc_enable_power() \
|
||||||
|
do { \
|
||||||
|
__gpio_clear_pin(GPIO_SD_VCC_EN_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __msc_disable_power() \
|
||||||
|
do { \
|
||||||
|
__gpio_set_pin(GPIO_SD_VCC_EN_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __msc_card_detected(s) \
|
||||||
|
({ \
|
||||||
|
int detected = 1; \
|
||||||
|
if (__gpio_get_pin(GPIO_SD_CD_N)) \
|
||||||
|
detected = 0; \
|
||||||
|
detected; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif /* __ASM_JZ4740_DIPPER_H__ */
|
@ -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__ */
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* linux/include/asm-mips/mach-jz4740/board-lyra.h
|
||||||
|
*
|
||||||
|
* JZ4740-based LYRA board ver 2.x definition.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* Author: <lhhuang@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM_JZ4740_LYRA_H__
|
||||||
|
#define __ASM_JZ4740_LYRA_H__
|
||||||
|
|
||||||
|
/*======================================================================
|
||||||
|
* Frequencies of on-board oscillators
|
||||||
|
*/
|
||||||
|
#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */
|
||||||
|
#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
|
||||||
|
|
||||||
|
|
||||||
|
/*======================================================================
|
||||||
|
* GPIO
|
||||||
|
*/
|
||||||
|
#define GPIO_SD_VCC_EN_N 113 /* GPD17 */
|
||||||
|
#define GPIO_SD_CD_N 110 /* GPD14 */
|
||||||
|
#define GPIO_SD_WP 112 /* GPD16 */
|
||||||
|
#define GPIO_USB_DETE 102 /* GPD6 */
|
||||||
|
#define GPIO_DC_DETE_N 103 /* GPD7 */
|
||||||
|
#define GPIO_CHARG_STAT_N 111 /* GPD15 */
|
||||||
|
#define GPIO_DISP_OFF_N 118 /* GPD22 */
|
||||||
|
#define GPIO_LED_EN 124 /* GPD28 */
|
||||||
|
|
||||||
|
#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
|
||||||
|
/*======================================================================
|
||||||
|
* MMC/SD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MSC_WP_PIN GPIO_SD_WP
|
||||||
|
#define MSC_HOTPLUG_PIN GPIO_SD_CD_N
|
||||||
|
#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N)
|
||||||
|
|
||||||
|
#define __msc_init_io() \
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(GPIO_SD_VCC_EN_N); \
|
||||||
|
__gpio_as_input(GPIO_SD_CD_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __msc_enable_power() \
|
||||||
|
do { \
|
||||||
|
__gpio_clear_pin(GPIO_SD_VCC_EN_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __msc_disable_power() \
|
||||||
|
do { \
|
||||||
|
__gpio_set_pin(GPIO_SD_VCC_EN_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __msc_card_detected(s) \
|
||||||
|
({ \
|
||||||
|
int detected = 1; \
|
||||||
|
if (!(__gpio_get_pin(GPIO_SD_CD_N))) \
|
||||||
|
detected = 0; \
|
||||||
|
detected; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif /* __ASM_JZ4740_LYRA_H__ */
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* linux/include/asm-mips/mach-jz4740/board-pavo.h
|
||||||
|
*
|
||||||
|
* JZ4730-based PAVO board ver 2.x definition.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* Author: <lhhuang@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM_JZ4740_PAVO_H__
|
||||||
|
#define __ASM_JZ4740_PAVO_H__
|
||||||
|
|
||||||
|
/*======================================================================
|
||||||
|
* Frequencies of on-board oscillators
|
||||||
|
*/
|
||||||
|
#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */
|
||||||
|
#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
|
||||||
|
|
||||||
|
|
||||||
|
/*======================================================================
|
||||||
|
* 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__ */
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* linux/include/asm-mips/mach-jz4740/board-virgo.h
|
||||||
|
*
|
||||||
|
* JZ4720-based VIRGO board ver 1.x definition.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* Author: <lhhuang@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM_JZ4720_VIRGO_H__
|
||||||
|
#define __ASM_JZ4720_VIRGO_H__
|
||||||
|
|
||||||
|
/*======================================================================
|
||||||
|
* Frequencies of on-board oscillators
|
||||||
|
*/
|
||||||
|
#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */
|
||||||
|
#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */
|
||||||
|
|
||||||
|
/*======================================================================
|
||||||
|
* GPIO VIRGO(JZ4720)
|
||||||
|
*/
|
||||||
|
#define GPIO_SD_VCC_EN_N 115 /* GPD19 */
|
||||||
|
#define GPIO_SD_CD_N 116 /* GPD20 */
|
||||||
|
#define GPIO_USB_DETE 114 /* GPD18 */
|
||||||
|
#define GPIO_DC_DETE_N 120 /* GPD24 */
|
||||||
|
#define GPIO_DISP_OFF_N 118 /* GPD22 */
|
||||||
|
#define GPIO_LED_EN 117 /* GPD21 */
|
||||||
|
|
||||||
|
#define GPIO_UDC_HOTPLUG GPIO_USB_DETE
|
||||||
|
|
||||||
|
/*======================================================================
|
||||||
|
* MMC/SD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MSC_HOTPLUG_PIN GPIO_SD_CD_N
|
||||||
|
#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N)
|
||||||
|
|
||||||
|
#define __msc_init_io() \
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(GPIO_SD_VCC_EN_N); \
|
||||||
|
__gpio_as_input(GPIO_SD_CD_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __msc_enable_power() \
|
||||||
|
do { \
|
||||||
|
__gpio_clear_pin(GPIO_SD_VCC_EN_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __msc_disable_power() \
|
||||||
|
do { \
|
||||||
|
__gpio_set_pin(GPIO_SD_VCC_EN_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __msc_card_detected(s) \
|
||||||
|
({ \
|
||||||
|
int detected = 1; \
|
||||||
|
if (__gpio_get_pin(GPIO_SD_CD_N)) \
|
||||||
|
detected = 0; \
|
||||||
|
detected; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif /* __ASM_JZ4720_VIRGO_H__ */
|
@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* linux/include/asm-mips/mach-jz4740/clock.h
|
||||||
|
*
|
||||||
|
* JZ4740 clocks definition.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* Author: <lhhuang@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM_JZ4740_CLOCK_H__
|
||||||
|
#define __ASM_JZ4740_CLOCK_H__
|
||||||
|
|
||||||
|
#ifndef JZ_EXTAL
|
||||||
|
//#define JZ_EXTAL 3686400 /* 3.6864 MHz */
|
||||||
|
#define JZ_EXTAL 12000000 /* 3.6864 MHz */
|
||||||
|
#endif
|
||||||
|
#ifndef JZ_EXTAL2
|
||||||
|
#define JZ_EXTAL2 32768 /* 32.768 KHz */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JZ4740 clocks structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
unsigned int cclk; /* CPU clock */
|
||||||
|
unsigned int hclk; /* System bus clock */
|
||||||
|
unsigned int pclk; /* Peripheral bus clock */
|
||||||
|
unsigned int mclk; /* Flash/SRAM/SDRAM clock */
|
||||||
|
unsigned int lcdclk; /* LCDC module clock */
|
||||||
|
unsigned int pixclk; /* LCD pixel clock */
|
||||||
|
unsigned int i2sclk; /* AIC module clock */
|
||||||
|
unsigned int usbclk; /* USB module clock */
|
||||||
|
unsigned int mscclk; /* MSC module clock */
|
||||||
|
unsigned int extalclk; /* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */
|
||||||
|
unsigned int rtcclk; /* RTC clock for CPM,INTC,RTC,TCU,WDT */
|
||||||
|
} jz_clocks_t;
|
||||||
|
|
||||||
|
extern jz_clocks_t jz_clocks;
|
||||||
|
|
||||||
|
|
||||||
|
/* PLL output frequency */
|
||||||
|
static __inline__ unsigned int __cpm_get_pllout(void)
|
||||||
|
{
|
||||||
|
unsigned long m, n, no, pllout;
|
||||||
|
unsigned long cppcr = REG_CPM_CPPCR;
|
||||||
|
unsigned long od[4] = {1, 2, 2, 4};
|
||||||
|
if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) {
|
||||||
|
m = __cpm_get_pllm() + 2;
|
||||||
|
n = __cpm_get_plln() + 2;
|
||||||
|
no = od[__cpm_get_pllod()];
|
||||||
|
pllout = ((JZ_EXTAL) / (n * no)) * m;
|
||||||
|
} else
|
||||||
|
pllout = JZ_EXTAL;
|
||||||
|
return pllout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PLL output frequency for MSC/I2S/LCD/USB */
|
||||||
|
static __inline__ unsigned int __cpm_get_pllout2(void)
|
||||||
|
{
|
||||||
|
if (REG_CPM_CPCCR & CPM_CPCCR_PCS)
|
||||||
|
return __cpm_get_pllout();
|
||||||
|
else
|
||||||
|
return __cpm_get_pllout()/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CPU core clock */
|
||||||
|
static __inline__ unsigned int __cpm_get_cclk(void)
|
||||||
|
{
|
||||||
|
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
|
||||||
|
|
||||||
|
return __cpm_get_pllout() / div[__cpm_get_cdiv()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AHB system bus clock */
|
||||||
|
static __inline__ unsigned int __cpm_get_hclk(void)
|
||||||
|
{
|
||||||
|
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
|
||||||
|
|
||||||
|
return __cpm_get_pllout() / div[__cpm_get_hdiv()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Memory bus clock */
|
||||||
|
static __inline__ unsigned int __cpm_get_mclk(void)
|
||||||
|
{
|
||||||
|
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
|
||||||
|
|
||||||
|
return __cpm_get_pllout() / div[__cpm_get_mdiv()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* APB peripheral bus clock */
|
||||||
|
static __inline__ unsigned int __cpm_get_pclk(void)
|
||||||
|
{
|
||||||
|
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
|
||||||
|
|
||||||
|
return __cpm_get_pllout() / div[__cpm_get_pdiv()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LCDC module clock */
|
||||||
|
static __inline__ unsigned int __cpm_get_lcdclk(void)
|
||||||
|
{
|
||||||
|
return __cpm_get_pllout2() / (__cpm_get_ldiv() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LCD pixel clock */
|
||||||
|
static __inline__ unsigned int __cpm_get_pixclk(void)
|
||||||
|
{
|
||||||
|
return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* I2S clock */
|
||||||
|
static __inline__ unsigned int __cpm_get_i2sclk(void)
|
||||||
|
{
|
||||||
|
if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) {
|
||||||
|
return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return JZ_EXTAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* USB clock */
|
||||||
|
static __inline__ unsigned int __cpm_get_usbclk(void)
|
||||||
|
{
|
||||||
|
if (REG_CPM_CPCCR & CPM_CPCCR_UCS) {
|
||||||
|
return __cpm_get_pllout2() / (__cpm_get_udiv() + 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return JZ_EXTAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MSC clock */
|
||||||
|
static __inline__ unsigned int __cpm_get_mscclk(void)
|
||||||
|
{
|
||||||
|
return __cpm_get_pllout2() / (__cpm_get_mscdiv() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */
|
||||||
|
static __inline__ unsigned int __cpm_get_extalclk(void)
|
||||||
|
{
|
||||||
|
return JZ_EXTAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RTC clock for CPM,INTC,RTC,TCU,WDT */
|
||||||
|
static __inline__ unsigned int __cpm_get_rtcclk(void)
|
||||||
|
{
|
||||||
|
return JZ_EXTAL2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output 24MHz for SD and 16MHz for MMC.
|
||||||
|
*/
|
||||||
|
static inline void __cpm_select_msc_clk(int sd)
|
||||||
|
{
|
||||||
|
unsigned int pllout2 = __cpm_get_pllout2();
|
||||||
|
unsigned int div = 0;
|
||||||
|
|
||||||
|
if (sd) {
|
||||||
|
div = pllout2 / 24000000;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
div = pllout2 / 16000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
REG_CPM_MSCCDR = div - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __ASM_JZ4740_CLOCK_H__ */
|
@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* linux/include/asm-mips/mach-jz4740/dma.h
|
||||||
|
*
|
||||||
|
* JZ4740 DMA definition.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* Author: <lhhuang@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM_JZ4740_DMA_H__
|
||||||
|
#define __ASM_JZ4740_DMA_H__
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <asm/io.h> /* need byte IO */
|
||||||
|
#include <linux/spinlock.h> /* And spinlocks */
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <asm/system.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Descriptor structure for JZ4740 DMA engine
|
||||||
|
* Note: this structure must always be aligned to a 16-bytes boundary.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
volatile u32 dcmd; /* DCMD value for the current transfer */
|
||||||
|
volatile u32 dsadr; /* DSAR value for the current transfer */
|
||||||
|
volatile u32 dtadr; /* DTAR value for the current transfer */
|
||||||
|
volatile u32 ddadr; /* Points to the next descriptor + transfer count */
|
||||||
|
} jz_dma_desc;
|
||||||
|
|
||||||
|
|
||||||
|
/* DMA Device ID's follow */
|
||||||
|
enum {
|
||||||
|
DMA_ID_UART0_TX = 0,
|
||||||
|
DMA_ID_UART0_RX,
|
||||||
|
DMA_ID_SSI_TX,
|
||||||
|
DMA_ID_SSI_RX,
|
||||||
|
DMA_ID_AIC_TX,
|
||||||
|
DMA_ID_AIC_RX,
|
||||||
|
DMA_ID_MSC_TX,
|
||||||
|
DMA_ID_MSC_RX,
|
||||||
|
DMA_ID_TCU_OVERFLOW,
|
||||||
|
DMA_ID_AUTO,
|
||||||
|
DMA_ID_RAW_SET,
|
||||||
|
DMA_ID_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
/* DMA modes, simulated by sw */
|
||||||
|
#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */
|
||||||
|
#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */
|
||||||
|
#define DMA_AUTOINIT 0x2
|
||||||
|
#define DMA_MODE_MASK 0x3
|
||||||
|
|
||||||
|
struct jz_dma_chan {
|
||||||
|
int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */
|
||||||
|
unsigned int io; /* DMA channel number */
|
||||||
|
const char *dev_str; /* string describes the DMA channel */
|
||||||
|
int irq; /* DMA irq number */
|
||||||
|
void *irq_dev; /* DMA private device structure */
|
||||||
|
unsigned int fifo_addr; /* physical fifo address of the requested device */
|
||||||
|
unsigned int cntl; /* DMA controll */
|
||||||
|
unsigned int mode; /* DMA configuration */
|
||||||
|
unsigned int source; /* DMA request source */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct jz_dma_chan jz_dma_table[];
|
||||||
|
|
||||||
|
|
||||||
|
#define DMA_8BIT_RX_CMD \
|
||||||
|
DMAC_DCMD_DAI | \
|
||||||
|
DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
|
||||||
|
DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_8BIT_TX_CMD \
|
||||||
|
DMAC_DCMD_SAI | \
|
||||||
|
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
|
||||||
|
DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_16BIT_RX_CMD \
|
||||||
|
DMAC_DCMD_DAI | \
|
||||||
|
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \
|
||||||
|
DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_16BIT_TX_CMD \
|
||||||
|
DMAC_DCMD_SAI | \
|
||||||
|
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \
|
||||||
|
DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_32BIT_RX_CMD \
|
||||||
|
DMAC_DCMD_DAI | \
|
||||||
|
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
|
||||||
|
DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_32BIT_TX_CMD \
|
||||||
|
DMAC_DCMD_SAI | \
|
||||||
|
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
|
||||||
|
DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_16BYTE_RX_CMD \
|
||||||
|
DMAC_DCMD_DAI | \
|
||||||
|
DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
|
||||||
|
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_16BYTE_TX_CMD \
|
||||||
|
DMAC_DCMD_SAI | \
|
||||||
|
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
|
||||||
|
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_32BYTE_RX_CMD \
|
||||||
|
DMAC_DCMD_DAI | \
|
||||||
|
DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
|
||||||
|
DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_32BYTE_TX_CMD \
|
||||||
|
DMAC_DCMD_SAI | \
|
||||||
|
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
|
||||||
|
DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_AIC_32_16BYTE_TX_CMD \
|
||||||
|
DMAC_DCMD_SAI | \
|
||||||
|
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
|
||||||
|
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_AIC_32_16BYTE_RX_CMD \
|
||||||
|
DMAC_DCMD_DAI | \
|
||||||
|
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
|
||||||
|
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_AIC_16BIT_TX_CMD \
|
||||||
|
DMAC_DCMD_SAI | \
|
||||||
|
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
|
||||||
|
DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_AIC_16BIT_RX_CMD \
|
||||||
|
DMAC_DCMD_DAI | \
|
||||||
|
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
|
||||||
|
DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_AIC_16BYTE_RX_CMD \
|
||||||
|
DMAC_DCMD_DAI | \
|
||||||
|
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
|
||||||
|
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
#define DMA_AIC_16BYTE_TX_CMD \
|
||||||
|
DMAC_DCMD_SAI | \
|
||||||
|
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
|
||||||
|
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
|
||||||
|
|
||||||
|
extern int jz_request_dma(int dev_id,
|
||||||
|
const char *dev_str,
|
||||||
|
irqreturn_t (*irqhandler)(int, void *),
|
||||||
|
unsigned long irqflags,
|
||||||
|
void *irq_dev_id);
|
||||||
|
extern void jz_free_dma(unsigned int dmanr);
|
||||||
|
|
||||||
|
extern int jz_dma_read_proc(char *buf, char **start, off_t fpos,
|
||||||
|
int length, int *eof, void *data);
|
||||||
|
extern void dump_jz_dma_channel(unsigned int dmanr);
|
||||||
|
|
||||||
|
extern void enable_dma(unsigned int dmanr);
|
||||||
|
extern void disable_dma(unsigned int dmanr);
|
||||||
|
extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr);
|
||||||
|
extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt);
|
||||||
|
extern void set_dma_mode(unsigned int dmanr, unsigned int mode);
|
||||||
|
extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
|
||||||
|
extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
|
||||||
|
extern unsigned int get_dma_residue(unsigned int dmanr);
|
||||||
|
|
||||||
|
extern spinlock_t dma_spin_lock;
|
||||||
|
|
||||||
|
static __inline__ unsigned long claim_dma_lock(void)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
spin_lock_irqsave(&dma_spin_lock, flags);
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ void release_dma_lock(unsigned long flags)
|
||||||
|
{
|
||||||
|
spin_unlock_irqrestore(&dma_spin_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the 'DMA Pointer Flip Flop'.
|
||||||
|
* Write 0 for LSB/MSB, 1 for MSB/LSB access.
|
||||||
|
*/
|
||||||
|
#define clear_dma_ff(channel)
|
||||||
|
|
||||||
|
static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
if (dmanr > MAX_DMA_NUM
|
||||||
|
|| jz_dma_table[dmanr].dev_id < 0)
|
||||||
|
return NULL;
|
||||||
|
return &jz_dma_table[dmanr];
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ int dma_halted(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
if (!chan)
|
||||||
|
return 1;
|
||||||
|
return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ unsigned int get_dma_mode(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
if (!chan)
|
||||||
|
return 0;
|
||||||
|
return chan->mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ void clear_dma_done(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ void clear_dma_halt(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT);
|
||||||
|
REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ void clear_dma_flag(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
|
||||||
|
REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ unsigned int get_dma_done_status(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
unsigned long dccsr;
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
if (!chan)
|
||||||
|
return 0;
|
||||||
|
dccsr = REG_DMAC_DCCSR(chan->io);
|
||||||
|
return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ int get_dma_done_irq(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
if (!chan)
|
||||||
|
return -1;
|
||||||
|
return chan->irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __ASM_JZ4740_DMA_H__ */
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* linux/include/asm-mips/mach-jz4740/jz4740.h
|
||||||
|
*
|
||||||
|
* JZ4740 common definition.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* Author: <lhhuang@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM_JZ4740_H__
|
||||||
|
#define __ASM_JZ4740_H__
|
||||||
|
|
||||||
|
#include <asm/mach-jz4740/regs.h>
|
||||||
|
#include <asm/mach-jz4740/ops.h>
|
||||||
|
#include <asm/mach-jz4740/dma.h>
|
||||||
|
#include <asm/mach-jz4740/misc.h>
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
* Platform definitions
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_JZ4740_PAVO
|
||||||
|
#include <asm/mach-jz4740/board-pavo.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_JZ4740_LEO
|
||||||
|
#include <asm/mach-jz4740/board-leo.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_JZ4740_LYRA
|
||||||
|
#include <asm/mach-jz4740/board-lyra.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_JZ4725_DIPPER
|
||||||
|
#include <asm/mach-jz4740/board-dipper.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_JZ4720_VIRGO
|
||||||
|
#include <asm/mach-jz4740/board-virgo.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Add other platform definition here ... */
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
* Follows are related to platform definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/mach-jz4740/clock.h>
|
||||||
|
#include <asm/mach-jz4740/serial.h>
|
||||||
|
|
||||||
|
#endif /* __ASM_JZ4740_H__ */
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* linux/include/asm-mips/mach-jz4740/misc.h
|
||||||
|
*
|
||||||
|
* Ingenic's JZ4740 common include.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* Author: <yliu@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM_JZ4740_MISC_H__
|
||||||
|
#define __ASM_JZ4740_MISC_H__
|
||||||
|
|
||||||
|
/*==========================================================
|
||||||
|
* I2C
|
||||||
|
*===========================================================*/
|
||||||
|
|
||||||
|
#define I2C_EEPROM_DEV 0xA /* b'1010 */
|
||||||
|
#define I2C_RTC_DEV 0xD /* b'1101 */
|
||||||
|
#define DIMM0_SPD_ADDR 0
|
||||||
|
#define DIMM1_SPD_ADDR 1
|
||||||
|
#define DIMM2_SPD_ADDR 2
|
||||||
|
#define DIMM3_SPD_ADDR 3
|
||||||
|
#define JZ_HCI_ADDR 7
|
||||||
|
|
||||||
|
#define DIMM_SPD_LEN 128
|
||||||
|
#define JZ_HCI_LEN 512 /* 4K bits E2PROM */
|
||||||
|
#define I2C_RTC_LEN 16
|
||||||
|
#define HCI_MAC_OFFSET 64
|
||||||
|
|
||||||
|
extern void i2c_open(void);
|
||||||
|
extern void i2c_close(void);
|
||||||
|
extern void i2c_setclk(unsigned int i2cclk);
|
||||||
|
extern int i2c_read(unsigned char device, unsigned char *buf,
|
||||||
|
unsigned char address, int count);
|
||||||
|
extern int i2c_write(unsigned char device, unsigned char *buf,
|
||||||
|
unsigned char address, int count);
|
||||||
|
|
||||||
|
#endif /* __ASM_JZ4740_MISC_H__ */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* linux/include/asm-mips/mach-jz4740/serial.h
|
||||||
|
*
|
||||||
|
* Ingenic's JZ4740 common include.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* Author: <yliu@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ASM_BOARD_SERIAL_H__
|
||||||
|
#define __ASM_BOARD_SERIAL_H__
|
||||||
|
|
||||||
|
#ifndef CONFIG_SERIAL_MANY_PORTS
|
||||||
|
#undef RS_TABLE_SIZE
|
||||||
|
#define RS_TABLE_SIZE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define JZ_BASE_BAUD (12000000/16)
|
||||||
|
|
||||||
|
#define JZ_SERIAL_PORT_DEFNS \
|
||||||
|
{ .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \
|
||||||
|
.flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \
|
||||||
|
.iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM },
|
||||||
|
|
||||||
|
#endif /* __ASM_BORAD_SERIAL_H__ */
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* This file is subject to the terms and conditions of the GNU General Public
|
||||||
|
* License. See the file "COPYING" in the main directory of this archive
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
|
||||||
|
*/
|
||||||
|
#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H
|
||||||
|
#define __ASM_MIPS_MACH_JZ4740_WAR_H
|
||||||
|
|
||||||
|
#define R4600_V1_INDEX_ICACHEOP_WAR 0
|
||||||
|
#define R4600_V1_HIT_CACHEOP_WAR 0
|
||||||
|
#define R4600_V2_HIT_CACHEOP_WAR 0
|
||||||
|
#define R5432_CP0_INTERRUPT_WAR 0
|
||||||
|
#define BCM1250_M3_WAR 0
|
||||||
|
#define SIBYTE_1956_WAR 0
|
||||||
|
#define MIPS4K_ICACHE_REFILL_WAR 0
|
||||||
|
#define MIPS_CACHE_SYNC_WAR 0
|
||||||
|
#define TX49XX_ICACHE_INDEX_INV_WAR 0
|
||||||
|
#define RM9000_CDEX_SMP_WAR 0
|
||||||
|
#define ICACHE_REFILLS_WORKAROUND_WAR 0
|
||||||
|
#define R10000_LLSC_WAR 0
|
||||||
|
#define MIPS34K_MISSED_ITLB_WAR 0
|
||||||
|
|
||||||
|
#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */
|
26
target/linux/xburst/files-2.6.31/arch/mips/jz4740/Makefile
Normal file
26
target/linux/xburst/files-2.6.31/arch/mips/jz4740/Makefile
Normal file
@ -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
|
602
target/linux/xburst/files-2.6.31/arch/mips/jz4740/cpufreq.c
Normal file
602
target/linux/xburst/files-2.6.31/arch/mips/jz4740/cpufreq.c
Normal file
@ -0,0 +1,602 @@
|
|||||||
|
/*
|
||||||
|
* linux/arch/mips/jz4740/cpufreq.c
|
||||||
|
*
|
||||||
|
* cpufreq driver for JZ4740
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
|
||||||
|
* Author: <lhhuang@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
|
||||||
|
#include <linux/cpufreq.h>
|
||||||
|
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
#include <asm/processor.h>
|
||||||
|
|
||||||
|
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
|
||||||
|
"cpufreq-jz4740", msg)
|
||||||
|
|
||||||
|
#undef CHANGE_PLL
|
||||||
|
|
||||||
|
#define PLL_UNCHANGED 0
|
||||||
|
#define PLL_GOES_UP 1
|
||||||
|
#define PLL_GOES_DOWN 2
|
||||||
|
|
||||||
|
#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000))
|
||||||
|
|
||||||
|
/* Saved the boot-time parameters */
|
||||||
|
static struct {
|
||||||
|
/* SDRAM parameters */
|
||||||
|
unsigned int mclk; /* memory clock, KHz */
|
||||||
|
unsigned int tras; /* RAS pulse width, cycles of mclk */
|
||||||
|
unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */
|
||||||
|
unsigned int tpc; /* RAS Precharge time, cycles of mclk */
|
||||||
|
unsigned int trwl; /* Write Precharge Time, cycles of mclk */
|
||||||
|
unsigned int trc; /* RAS Cycle Time, cycles of mclk */
|
||||||
|
unsigned int rtcor; /* Refresh Time Constant */
|
||||||
|
unsigned int sdram_initialized;
|
||||||
|
|
||||||
|
/* LCD parameters */
|
||||||
|
unsigned int lcd_clk; /* LCD clock, Hz */
|
||||||
|
unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */
|
||||||
|
unsigned int lcd_clks_initialized;
|
||||||
|
} boot_config;
|
||||||
|
|
||||||
|
struct jz4740_freq_percpu_info {
|
||||||
|
struct cpufreq_frequency_table table[7];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_freq_percpu_info jz4740_freq_table;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This contains the registers value for an operating point.
|
||||||
|
* If only part of a register needs to change then there is
|
||||||
|
* a mask value for that register.
|
||||||
|
* When going to a new operating point the current register
|
||||||
|
* value is ANDed with the ~mask and ORed with the new value.
|
||||||
|
*/
|
||||||
|
struct dpm_regs {
|
||||||
|
u32 cpccr; /* Clock Freq Control Register */
|
||||||
|
u32 cpccr_mask; /* Clock Freq Control Register mask */
|
||||||
|
u32 cppcr; /* PLL1 Control Register */
|
||||||
|
u32 cppcr_mask; /* PLL1 Control Register mask */
|
||||||
|
u32 pll_up_flag; /* New PLL freq is higher than current or not */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern jz_clocks_t jz_clocks;
|
||||||
|
|
||||||
|
static void jz_update_clocks(void)
|
||||||
|
{
|
||||||
|
/* Next clocks must be updated if we have changed
|
||||||
|
* the PLL or divisors.
|
||||||
|
*/
|
||||||
|
jz_clocks.cclk = __cpm_get_cclk();
|
||||||
|
jz_clocks.hclk = __cpm_get_hclk();
|
||||||
|
jz_clocks.mclk = __cpm_get_mclk();
|
||||||
|
jz_clocks.pclk = __cpm_get_pclk();
|
||||||
|
jz_clocks.lcdclk = __cpm_get_lcdclk();
|
||||||
|
jz_clocks.pixclk = __cpm_get_pixclk();
|
||||||
|
jz_clocks.i2sclk = __cpm_get_i2sclk();
|
||||||
|
jz_clocks.usbclk = __cpm_get_usbclk();
|
||||||
|
jz_clocks.mscclk = __cpm_get_mscclk();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
jz_init_boot_config(void)
|
||||||
|
{
|
||||||
|
if (!boot_config.lcd_clks_initialized) {
|
||||||
|
/* the first time to scale pll */
|
||||||
|
boot_config.lcd_clk = __cpm_get_lcdclk();
|
||||||
|
boot_config.lcdpix_clk = __cpm_get_pixclk();
|
||||||
|
boot_config.lcd_clks_initialized = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!boot_config.sdram_initialized) {
|
||||||
|
/* the first time to scale frequencies */
|
||||||
|
unsigned int dmcr, rtcor;
|
||||||
|
unsigned int tras, rcd, tpc, trwl, trc;
|
||||||
|
|
||||||
|
dmcr = REG_EMC_DMCR;
|
||||||
|
rtcor = REG_EMC_RTCOR;
|
||||||
|
|
||||||
|
tras = (dmcr >> 13) & 0x7;
|
||||||
|
rcd = (dmcr >> 11) & 0x3;
|
||||||
|
tpc = (dmcr >> 8) & 0x7;
|
||||||
|
trwl = (dmcr >> 5) & 0x3;
|
||||||
|
trc = (dmcr >> 2) & 0x7;
|
||||||
|
|
||||||
|
boot_config.mclk = __cpm_get_mclk() / 1000;
|
||||||
|
boot_config.tras = tras + 4;
|
||||||
|
boot_config.rcd = rcd + 1;
|
||||||
|
boot_config.tpc = tpc + 1;
|
||||||
|
boot_config.trwl = trwl + 1;
|
||||||
|
boot_config.trc = trc * 2 + 1;
|
||||||
|
boot_config.rtcor = rtcor;
|
||||||
|
|
||||||
|
boot_config.sdram_initialized = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_update_dram_rtcor(unsigned int new_mclk)
|
||||||
|
{
|
||||||
|
unsigned int rtcor;
|
||||||
|
|
||||||
|
new_mclk /= 1000;
|
||||||
|
rtcor = boot_config.rtcor * new_mclk / boot_config.mclk;
|
||||||
|
rtcor--;
|
||||||
|
|
||||||
|
if (rtcor < 1) rtcor = 1;
|
||||||
|
if (rtcor > 255) rtcor = 255;
|
||||||
|
|
||||||
|
REG_EMC_RTCOR = rtcor;
|
||||||
|
REG_EMC_RTCNT = rtcor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_update_dram_dmcr(unsigned int new_mclk)
|
||||||
|
{
|
||||||
|
unsigned int dmcr;
|
||||||
|
unsigned int tras, rcd, tpc, trwl, trc;
|
||||||
|
unsigned int valid_time, new_time; /* ns */
|
||||||
|
|
||||||
|
new_mclk /= 1000;
|
||||||
|
tras = boot_config.tras * new_mclk / boot_config.mclk;
|
||||||
|
rcd = boot_config.rcd * new_mclk / boot_config.mclk;
|
||||||
|
tpc = boot_config.tpc * new_mclk / boot_config.mclk;
|
||||||
|
trwl = boot_config.trwl * new_mclk / boot_config.mclk;
|
||||||
|
trc = boot_config.trc * new_mclk / boot_config.mclk;
|
||||||
|
|
||||||
|
/* Validation checking */
|
||||||
|
valid_time = (boot_config.tras * 1000000) / boot_config.mclk;
|
||||||
|
new_time = (tras * 1000000) / new_mclk;
|
||||||
|
if (new_time < valid_time) tras += 1;
|
||||||
|
|
||||||
|
valid_time = (boot_config.rcd * 1000000) / boot_config.mclk;
|
||||||
|
new_time = (rcd * 1000000) / new_mclk;
|
||||||
|
if (new_time < valid_time) rcd += 1;
|
||||||
|
|
||||||
|
valid_time = (boot_config.tpc * 1000000) / boot_config.mclk;
|
||||||
|
new_time = (tpc * 1000000) / new_mclk;
|
||||||
|
if (new_time < valid_time) tpc += 1;
|
||||||
|
|
||||||
|
valid_time = (boot_config.trwl * 1000000) / boot_config.mclk;
|
||||||
|
new_time = (trwl * 1000000) / new_mclk;
|
||||||
|
if (new_time < valid_time) trwl += 1;
|
||||||
|
|
||||||
|
valid_time = (boot_config.trc * 1000000) / boot_config.mclk;
|
||||||
|
new_time = (trc * 1000000) / new_mclk;
|
||||||
|
if (new_time < valid_time) trc += 2;
|
||||||
|
|
||||||
|
tras = (tras < 4) ? 4: tras;
|
||||||
|
tras = (tras > 11) ? 11: tras;
|
||||||
|
tras -= 4;
|
||||||
|
|
||||||
|
rcd = (rcd < 1) ? 1: rcd;
|
||||||
|
rcd = (rcd > 4) ? 4: rcd;
|
||||||
|
rcd -= 1;
|
||||||
|
|
||||||
|
tpc = (tpc < 1) ? 1: tpc;
|
||||||
|
tpc = (tpc > 8) ? 8: tpc;
|
||||||
|
tpc -= 1;
|
||||||
|
|
||||||
|
trwl = (trwl < 1) ? 1: trwl;
|
||||||
|
trwl = (trwl > 4) ? 4: trwl;
|
||||||
|
trwl -= 1;
|
||||||
|
|
||||||
|
trc = (trc < 1) ? 1: trc;
|
||||||
|
trc = (trc > 15) ? 15: trc;
|
||||||
|
trc /= 2;
|
||||||
|
|
||||||
|
dmcr = REG_EMC_DMCR;
|
||||||
|
|
||||||
|
dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK);
|
||||||
|
dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT));
|
||||||
|
|
||||||
|
REG_EMC_DMCR = dmcr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk)
|
||||||
|
{
|
||||||
|
/* No risk, no fun: run with interrupts on! */
|
||||||
|
if (new_mclk > cur_mclk) {
|
||||||
|
/* We're going FASTER, so first update TRAS, RCD, TPC, TRWL
|
||||||
|
* and TRC of DMCR before changing the frequency.
|
||||||
|
*/
|
||||||
|
jz_update_dram_dmcr(new_mclk);
|
||||||
|
} else {
|
||||||
|
/* We're going SLOWER: first update RTCOR value
|
||||||
|
* before changing the frequency.
|
||||||
|
*/
|
||||||
|
jz_update_dram_rtcor(new_mclk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk)
|
||||||
|
{
|
||||||
|
/* No risk, no fun: run with interrupts on! */
|
||||||
|
if (new_mclk > cur_mclk) {
|
||||||
|
/* We're going FASTER, so update RTCOR
|
||||||
|
* after changing the frequency
|
||||||
|
*/
|
||||||
|
jz_update_dram_rtcor(new_mclk);
|
||||||
|
} else {
|
||||||
|
/* We're going SLOWER: so update TRAS, RCD, TPC, TRWL
|
||||||
|
* and TRC of DMCR after changing the frequency.
|
||||||
|
*/
|
||||||
|
jz_update_dram_dmcr(new_mclk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_scale_divisors(struct dpm_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned int cpccr;
|
||||||
|
unsigned int cur_mclk, new_mclk;
|
||||||
|
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
|
||||||
|
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
|
||||||
|
|
||||||
|
cpccr = REG_CPM_CPCCR;
|
||||||
|
cpccr &= ~((unsigned long)regs->cpccr_mask);
|
||||||
|
cpccr |= regs->cpccr;
|
||||||
|
cpccr |= CPM_CPCCR_CE; /* update immediately */
|
||||||
|
|
||||||
|
cur_mclk = __cpm_get_mclk();
|
||||||
|
new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT];
|
||||||
|
|
||||||
|
/* Update some DRAM parameters before changing frequency */
|
||||||
|
jz_update_dram_prev(cur_mclk, new_mclk);
|
||||||
|
|
||||||
|
/* update register to change the clocks.
|
||||||
|
* align this code to a cache line.
|
||||||
|
*/
|
||||||
|
__asm__ __volatile__(
|
||||||
|
".set noreorder\n\t"
|
||||||
|
".align 5\n"
|
||||||
|
"sw %1,0(%0)\n\t"
|
||||||
|
"li %3,0\n\t"
|
||||||
|
"1:\n\t"
|
||||||
|
"bne %3,%2,1b\n\t"
|
||||||
|
"addi %3, 1\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
".set reorder\n\t"
|
||||||
|
:
|
||||||
|
: "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
|
||||||
|
|
||||||
|
/* Update some other DRAM parameters after changing frequency */
|
||||||
|
jz_update_dram_post(cur_mclk, new_mclk);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CHANGE_PLL
|
||||||
|
/* Maintain the LCD clock and pixel clock */
|
||||||
|
static void jz_scale_lcd_divisors(struct dpm_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned int new_pll, new_lcd_div, new_lcdpix_div;
|
||||||
|
unsigned int cpccr;
|
||||||
|
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
|
||||||
|
|
||||||
|
if (!boot_config.lcd_clks_initialized) return;
|
||||||
|
|
||||||
|
new_pll = __cpm_get_pllout();
|
||||||
|
new_lcd_div = new_pll / boot_config.lcd_clk;
|
||||||
|
new_lcdpix_div = new_pll / boot_config.lcdpix_clk;
|
||||||
|
|
||||||
|
if (new_lcd_div < 1)
|
||||||
|
new_lcd_div = 1;
|
||||||
|
if (new_lcd_div > 16)
|
||||||
|
new_lcd_div = 16;
|
||||||
|
|
||||||
|
if (new_lcdpix_div < 1)
|
||||||
|
new_lcdpix_div = 1;
|
||||||
|
if (new_lcdpix_div > 512)
|
||||||
|
new_lcdpix_div = 512;
|
||||||
|
|
||||||
|
// REG_CPM_CPCCR2 = new_lcdpix_div - 1;
|
||||||
|
|
||||||
|
cpccr = REG_CPM_CPCCR;
|
||||||
|
cpccr &= ~CPM_CPCCR_LDIV_MASK;
|
||||||
|
cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT);
|
||||||
|
cpccr |= CPM_CPCCR_CE; /* update immediately */
|
||||||
|
|
||||||
|
/* update register to change the clocks.
|
||||||
|
* align this code to a cache line.
|
||||||
|
*/
|
||||||
|
__asm__ __volatile__(
|
||||||
|
".set noreorder\n\t"
|
||||||
|
".align 5\n"
|
||||||
|
"sw %1,0(%0)\n\t"
|
||||||
|
"li %3,0\n\t"
|
||||||
|
"1:\n\t"
|
||||||
|
"bne %3,%2,1b\n\t"
|
||||||
|
"addi %3, 1\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
".set reorder\n\t"
|
||||||
|
:
|
||||||
|
: "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_scale_pll(struct dpm_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned int cppcr;
|
||||||
|
unsigned int cur_mclk, new_mclk, new_pll;
|
||||||
|
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
|
||||||
|
int od[] = {1, 2, 2, 4};
|
||||||
|
|
||||||
|
cppcr = REG_CPM_CPPCR;
|
||||||
|
cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK);
|
||||||
|
regs->cppcr &= ~CPM_CPPCR_PLLEN;
|
||||||
|
cppcr |= (regs->cppcr | 0xff);
|
||||||
|
|
||||||
|
/* Update some DRAM parameters before changing frequency */
|
||||||
|
new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]);
|
||||||
|
cur_mclk = __cpm_get_mclk();
|
||||||
|
new_mclk = new_pll / div[(REG_CPM_CPCCR>>CPM_CPCCR_MDIV_BIT) & 0xf];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update some SDRAM parameters
|
||||||
|
*/
|
||||||
|
jz_update_dram_prev(cur_mclk, new_mclk);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update PLL, align code to cache line.
|
||||||
|
*/
|
||||||
|
cppcr |= CPM_CPPCR_PLLEN;
|
||||||
|
__asm__ __volatile__(
|
||||||
|
".set noreorder\n\t"
|
||||||
|
".align 5\n"
|
||||||
|
"sw %1,0(%0)\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
".set reorder\n\t"
|
||||||
|
:
|
||||||
|
: "r" (CPM_CPPCR), "r" (cppcr));
|
||||||
|
|
||||||
|
/* Update some other DRAM parameters after changing frequency */
|
||||||
|
jz_update_dram_post(cur_mclk, new_mclk);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void jz4740_transition(struct dpm_regs *regs)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Get and save some boot-time conditions.
|
||||||
|
*/
|
||||||
|
jz_init_boot_config();
|
||||||
|
|
||||||
|
#ifdef CHANGE_PLL
|
||||||
|
/*
|
||||||
|
* Disable LCD before scaling pll.
|
||||||
|
* LCD and LCD pixel clocks should not be changed even if the PLL
|
||||||
|
* output frequency has been changed.
|
||||||
|
*/
|
||||||
|
REG_LCD_CTRL &= ~LCD_CTRL_ENA;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop module clocks before scaling PLL
|
||||||
|
*/
|
||||||
|
__cpm_stop_eth();
|
||||||
|
__cpm_stop_aic(1);
|
||||||
|
__cpm_stop_aic(2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ... add more as necessary */
|
||||||
|
|
||||||
|
if (regs->pll_up_flag == PLL_GOES_UP) {
|
||||||
|
/* the pll frequency is going up, so change dividors first */
|
||||||
|
jz_scale_divisors(regs);
|
||||||
|
#ifdef CHANGE_PLL
|
||||||
|
jz_scale_pll(regs);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (regs->pll_up_flag == PLL_GOES_DOWN) {
|
||||||
|
/* the pll frequency is going down, so change pll first */
|
||||||
|
#ifdef CHANGE_PLL
|
||||||
|
jz_scale_pll(regs);
|
||||||
|
#endif
|
||||||
|
jz_scale_divisors(regs);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* the pll frequency is unchanged, so change divisors only */
|
||||||
|
jz_scale_divisors(regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CHANGE_PLL
|
||||||
|
/*
|
||||||
|
* Restart module clocks before scaling PLL
|
||||||
|
*/
|
||||||
|
__cpm_start_eth();
|
||||||
|
__cpm_start_aic(1);
|
||||||
|
__cpm_start_aic(2);
|
||||||
|
|
||||||
|
/* ... add more as necessary */
|
||||||
|
|
||||||
|
/* Scale the LCD divisors after scaling pll */
|
||||||
|
if (regs->pll_up_flag != PLL_UNCHANGED) {
|
||||||
|
jz_scale_lcd_divisors(regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable LCD controller */
|
||||||
|
REG_LCD_CTRL &= ~LCD_CTRL_DIS;
|
||||||
|
REG_LCD_CTRL |= LCD_CTRL_ENA;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Update system clocks */
|
||||||
|
jz_update_clocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern unsigned int idle_times;
|
||||||
|
static unsigned int jz4740_freq_get(unsigned int cpu)
|
||||||
|
{
|
||||||
|
return (__cpm_get_cclk() / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs)
|
||||||
|
{
|
||||||
|
int n2FR[33] = {
|
||||||
|
0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
|
||||||
|
7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
9
|
||||||
|
};
|
||||||
|
int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */
|
||||||
|
unsigned int div_of_cclk, new_freq, i;
|
||||||
|
|
||||||
|
regs->pll_up_flag = PLL_UNCHANGED;
|
||||||
|
regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK;
|
||||||
|
|
||||||
|
new_freq = jz4740_freq_table.table[index].frequency;
|
||||||
|
|
||||||
|
do {
|
||||||
|
div_of_cclk = __cpm_get_pllout() / (1000 * new_freq);
|
||||||
|
} while (div_of_cclk==0);
|
||||||
|
|
||||||
|
if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) {
|
||||||
|
for(i = 1; i<4; i++) {
|
||||||
|
div[i] = 3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(i = 1; i<4; i++) {
|
||||||
|
div[i] = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i<4; i++) {
|
||||||
|
div[i] *= div_of_cclk;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]);
|
||||||
|
|
||||||
|
regs->cpccr =
|
||||||
|
(n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
|
||||||
|
(n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
|
||||||
|
(n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
|
||||||
|
(n2FR[div[3]] << CPM_CPCCR_MDIV_BIT);
|
||||||
|
|
||||||
|
return div_of_cclk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4740_set_cpu_divider_index(unsigned int cpu, unsigned int index)
|
||||||
|
{
|
||||||
|
unsigned long divisor, old_divisor;
|
||||||
|
struct cpufreq_freqs freqs;
|
||||||
|
struct dpm_regs regs;
|
||||||
|
|
||||||
|
old_divisor = __cpm_get_pllout() / __cpm_get_cclk();
|
||||||
|
divisor = index_to_divisor(index, ®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 <lhhuang@ingenic.cn>");
|
||||||
|
MODULE_DESCRIPTION("cpufreq driver for Jz4740");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
768
target/linux/xburst/files-2.6.31/arch/mips/jz4740/dma.c
Normal file
768
target/linux/xburst/files-2.6.31/arch/mips/jz4740/dma.c
Normal file
@ -0,0 +1,768 @@
|
|||||||
|
/*
|
||||||
|
* linux/arch/mips/jz4740/dma.c
|
||||||
|
*
|
||||||
|
* Support functions for the JZ4740 internal DMA channels.
|
||||||
|
* No-descriptor transfer only.
|
||||||
|
* Descriptor transfer should also call jz_request_dma() to get a free
|
||||||
|
* channel and call jz_free_dma() to free the channel. And driver should
|
||||||
|
* build the DMA descriptor and setup the DMA channel by itself.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/soundcard.h>
|
||||||
|
|
||||||
|
#include <asm/system.h>
|
||||||
|
#include <asm/addrspace.h>
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A note on resource allocation:
|
||||||
|
*
|
||||||
|
* All drivers needing DMA channels, should allocate and release them
|
||||||
|
* through the public routines `jz_request_dma()' and `jz_free_dma()'.
|
||||||
|
*
|
||||||
|
* In order to avoid problems, all processes should allocate resources in
|
||||||
|
* the same sequence and release them in the reverse order.
|
||||||
|
*
|
||||||
|
* So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ.
|
||||||
|
* When releasing them, first release the IRQ, then release the DMA. The
|
||||||
|
* main reason for this order is that, if you are requesting the DMA buffer
|
||||||
|
* done interrupt, you won't know the irq number until the DMA channel is
|
||||||
|
* returned from jz_request_dma().
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = {
|
||||||
|
{dev_id:-1,},
|
||||||
|
{dev_id:-1,},
|
||||||
|
{dev_id:-1,},
|
||||||
|
{dev_id:-1,},
|
||||||
|
{dev_id:-1,},
|
||||||
|
{dev_id:-1,},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Device FIFO addresses and default DMA modes
|
||||||
|
static const struct {
|
||||||
|
unsigned int fifo_addr;
|
||||||
|
unsigned int dma_mode;
|
||||||
|
unsigned int dma_source;
|
||||||
|
} dma_dev_table[DMA_ID_MAX] = {
|
||||||
|
{CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT},
|
||||||
|
{CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN},
|
||||||
|
{CPHYSADDR(SSI_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSIOUT},
|
||||||
|
{CPHYSADDR(SSI_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSIIN},
|
||||||
|
{CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT},
|
||||||
|
{CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN},
|
||||||
|
{CPHYSADDR(MSC_TXFIFO), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSCOUT},
|
||||||
|
{CPHYSADDR(MSC_RXFIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSCIN},
|
||||||
|
{0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU},
|
||||||
|
{0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO},
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int jz_dma_read_proc(char *buf, char **start, off_t fpos,
|
||||||
|
int length, int *eof, void *data)
|
||||||
|
{
|
||||||
|
int i, len = 0;
|
||||||
|
struct jz_dma_chan *chan;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_DMA_NUM; i++) {
|
||||||
|
if ((chan = get_dma_chan(i)) != NULL) {
|
||||||
|
len += sprintf(buf + len, "%2d: %s\n",
|
||||||
|
i, chan->dev_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fpos >= len) {
|
||||||
|
*start = buf;
|
||||||
|
*eof = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*start = buf + fpos;
|
||||||
|
if ((len -= fpos) > length)
|
||||||
|
return length;
|
||||||
|
*eof = 1;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dump_jz_dma_channel(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan;
|
||||||
|
|
||||||
|
if (dmanr > MAX_DMA_NUM)
|
||||||
|
return;
|
||||||
|
chan = &jz_dma_table[dmanr];
|
||||||
|
|
||||||
|
printk("DMA%d Registers:\n", dmanr);
|
||||||
|
printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR);
|
||||||
|
printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr));
|
||||||
|
printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr));
|
||||||
|
printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr));
|
||||||
|
printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr));
|
||||||
|
printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr));
|
||||||
|
printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr));
|
||||||
|
printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr));
|
||||||
|
printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* jz_request_dma - dynamically allcate an idle DMA channel to return
|
||||||
|
* @dev_id: the specified dma device id or DMA_ID_RAW_SET
|
||||||
|
* @dev_str: the specified dma device string name
|
||||||
|
* @irqhandler: the irq handler, or NULL
|
||||||
|
* @irqflags: the irq handler flags
|
||||||
|
* @irq_dev_id: the irq handler device id for shared irq
|
||||||
|
*
|
||||||
|
* Finds a free channel, and binds the requested device to it.
|
||||||
|
* Returns the allocated channel number, or negative on error.
|
||||||
|
* Requests the DMA done IRQ if irqhandler != NULL.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/*int jz_request_dma(int dev_id, const char *dev_str,
|
||||||
|
void (*irqhandler)(int, void *, struct pt_regs *),
|
||||||
|
unsigned long irqflags,
|
||||||
|
void *irq_dev_id)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int jz_request_dma(int dev_id, const char *dev_str,
|
||||||
|
irqreturn_t (*irqhandler)(int, void *),
|
||||||
|
unsigned long irqflags,
|
||||||
|
void *irq_dev_id)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
if (dev_id < 0 || dev_id >= DMA_ID_MAX)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_DMA_NUM; i++) {
|
||||||
|
if (jz_dma_table[i].dev_id < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == MAX_DMA_NUM) /* no free channel */
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
/* we got a free channel */
|
||||||
|
chan = &jz_dma_table[i];
|
||||||
|
|
||||||
|
if (irqhandler) {
|
||||||
|
chan->irq = IRQ_DMA_0 + i; // allocate irq number
|
||||||
|
chan->irq_dev = irq_dev_id;
|
||||||
|
if ((ret = request_irq(chan->irq, irqhandler, irqflags,
|
||||||
|
dev_str, chan->irq_dev))) {
|
||||||
|
chan->irq = -1;
|
||||||
|
chan->irq_dev = NULL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chan->irq = -1;
|
||||||
|
chan->irq_dev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill it in
|
||||||
|
chan->io = i;
|
||||||
|
chan->dev_id = dev_id;
|
||||||
|
chan->dev_str = dev_str;
|
||||||
|
chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
|
||||||
|
chan->mode = dma_dev_table[dev_id].dma_mode;
|
||||||
|
chan->source = dma_dev_table[dev_id].dma_source;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void jz_free_dma(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
|
||||||
|
if (!chan) {
|
||||||
|
printk("Trying to free DMA%d\n", dmanr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
disable_dma(dmanr);
|
||||||
|
if (chan->irq)
|
||||||
|
free_irq(chan->irq, chan->irq_dev);
|
||||||
|
|
||||||
|
chan->irq = -1;
|
||||||
|
chan->irq_dev = NULL;
|
||||||
|
chan->dev_id = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void jz_set_dma_dest_width(int dmanr, int nbit)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
chan->mode &= ~DMAC_DCMD_DWDH_MASK;
|
||||||
|
switch (nbit) {
|
||||||
|
case 8:
|
||||||
|
chan->mode |= DMAC_DCMD_DWDH_8;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
chan->mode |= DMAC_DCMD_DWDH_16;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
chan->mode |= DMAC_DCMD_DWDH_32;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void jz_set_dma_src_width(int dmanr, int nbit)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
chan->mode &= ~DMAC_DCMD_SWDH_MASK;
|
||||||
|
switch (nbit) {
|
||||||
|
case 8:
|
||||||
|
chan->mode |= DMAC_DCMD_SWDH_8;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
chan->mode |= DMAC_DCMD_SWDH_16;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
chan->mode |= DMAC_DCMD_SWDH_32;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void jz_set_dma_block_size(int dmanr, int nbyte)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
chan->mode &= ~DMAC_DCMD_DS_MASK;
|
||||||
|
switch (nbyte) {
|
||||||
|
case 1:
|
||||||
|
chan->mode |= DMAC_DCMD_DS_8BIT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
chan->mode |= DMAC_DCMD_DS_16BIT;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
chan->mode |= DMAC_DCMD_DS_32BIT;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
chan->mode |= DMAC_DCMD_DS_16BYTE;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
chan->mode |= DMAC_DCMD_DS_32BYTE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int jz_get_dma_command(int dmanr)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
return chan->mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* jz_set_dma_mode - do the raw settings for the specified DMA channel
|
||||||
|
* @dmanr: the specified DMA channel
|
||||||
|
* @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE
|
||||||
|
* @dma_mode: dma raw mode
|
||||||
|
* @dma_source: dma raw request source
|
||||||
|
* @fifo_addr: dma raw device fifo address
|
||||||
|
*
|
||||||
|
* Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call
|
||||||
|
* jz_set_dma_mode() rather than set_dma_mode() if you work with
|
||||||
|
* and external request dma device.
|
||||||
|
*
|
||||||
|
* NOTE: Don not dynamically allocate dma channel if one external request
|
||||||
|
* dma device will occupy this channel.
|
||||||
|
*/
|
||||||
|
int jz_set_dma_mode(unsigned int dmanr, unsigned int mode,
|
||||||
|
unsigned int dma_mode, unsigned int dma_source,
|
||||||
|
unsigned int fifo_addr)
|
||||||
|
{
|
||||||
|
int dev_id, i;
|
||||||
|
struct jz_dma_chan *chan;
|
||||||
|
|
||||||
|
if (dmanr > MAX_DMA_NUM)
|
||||||
|
return -ENODEV;
|
||||||
|
for (i = 0; i < MAX_DMA_NUM; i++) {
|
||||||
|
if (jz_dma_table[i].dev_id < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == MAX_DMA_NUM)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
chan = &jz_dma_table[dmanr];
|
||||||
|
dev_id = chan->dev_id;
|
||||||
|
if (dev_id > 0) {
|
||||||
|
printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n",
|
||||||
|
__FUNCTION__, dmanr);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clone it from the dynamically allocated. */
|
||||||
|
if (i != dmanr) {
|
||||||
|
chan->irq = jz_dma_table[i].irq;
|
||||||
|
chan->irq_dev = jz_dma_table[i].irq_dev;
|
||||||
|
chan->dev_str = jz_dma_table[i].dev_str;
|
||||||
|
jz_dma_table[i].irq = 0;
|
||||||
|
jz_dma_table[i].irq_dev = NULL;
|
||||||
|
jz_dma_table[i].dev_id = -1;
|
||||||
|
}
|
||||||
|
chan->dev_id = DMA_ID_RAW_SET;
|
||||||
|
chan->io = dmanr;
|
||||||
|
chan->fifo_addr = fifo_addr;
|
||||||
|
chan->mode = dma_mode;
|
||||||
|
chan->source = dma_source;
|
||||||
|
|
||||||
|
set_dma_mode(dmanr, dma_mode);
|
||||||
|
|
||||||
|
return dmanr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_dma(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
|
||||||
|
REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */
|
||||||
|
__dmac_enable_channel(dmanr);
|
||||||
|
if (chan->irq)
|
||||||
|
__dmac_channel_enable_irq(dmanr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DMA_DISABLE_POLL 0x10000
|
||||||
|
|
||||||
|
void disable_dma(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!__dmac_channel_enabled(dmanr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < DMA_DISABLE_POLL; i++)
|
||||||
|
if (__dmac_channel_transmit_end_detected(dmanr))
|
||||||
|
break;
|
||||||
|
#if 0
|
||||||
|
if (i == DMA_DISABLE_POLL)
|
||||||
|
printk(KERN_INFO "disable_dma: poll expired!\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__dmac_disable_channel(dmanr);
|
||||||
|
if (chan->irq)
|
||||||
|
__dmac_channel_disable_irq(dmanr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: DMA_MODE_MASK is simulated by sw */
|
||||||
|
void set_dma_mode(unsigned int dmanr, unsigned int mode)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
|
||||||
|
mode &= DMA_MODE_MASK;
|
||||||
|
if (mode == DMA_MODE_READ) {
|
||||||
|
chan->mode |= DMAC_DCMD_DAI;
|
||||||
|
chan->mode &= ~DMAC_DCMD_SAI;
|
||||||
|
} else if (mode == DMA_MODE_WRITE) {
|
||||||
|
chan->mode |= DMAC_DCMD_SAI;
|
||||||
|
chan->mode &= ~DMAC_DCMD_DAI;
|
||||||
|
} else {
|
||||||
|
printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
|
||||||
|
}
|
||||||
|
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
|
||||||
|
REG_DMAC_DRSR(chan->io) = chan->source;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_dma_addr(unsigned int dmanr, unsigned int phyaddr)
|
||||||
|
{
|
||||||
|
unsigned int mode;
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mode = chan->mode & DMA_MODE_MASK;
|
||||||
|
if (mode == DMA_MODE_READ) {
|
||||||
|
REG_DMAC_DSAR(chan->io) = chan->fifo_addr;
|
||||||
|
REG_DMAC_DTAR(chan->io) = phyaddr;
|
||||||
|
} else if (mode == DMA_MODE_WRITE) {
|
||||||
|
REG_DMAC_DSAR(chan->io) = phyaddr;
|
||||||
|
REG_DMAC_DTAR(chan->io) = chan->fifo_addr;
|
||||||
|
} else
|
||||||
|
printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_dma_count(unsigned int dmanr, unsigned int bytecnt)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
int dma_ds[] = {4, 1, 2, 16, 32};
|
||||||
|
unsigned int ds;
|
||||||
|
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
|
||||||
|
REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int get_dma_residue(unsigned int dmanr)
|
||||||
|
{
|
||||||
|
unsigned int count, ds;
|
||||||
|
int dma_ds[] = {4, 1, 2, 16, 32};
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
if (!chan)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT;
|
||||||
|
count = REG_DMAC_DTCR(chan->io);
|
||||||
|
count = count * dma_ds[ds];
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (audio_fmt) {
|
||||||
|
case AFMT_U8:
|
||||||
|
/* burst mode : 32BIT */
|
||||||
|
break;
|
||||||
|
case AFMT_S16_LE:
|
||||||
|
/* burst mode : 16BYTE */
|
||||||
|
if (mode == DMA_MODE_READ) {
|
||||||
|
chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ;
|
||||||
|
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
|
||||||
|
mode &= DMA_MODE_MASK;
|
||||||
|
chan->mode |= DMAC_DCMD_DAI;
|
||||||
|
chan->mode &= ~DMAC_DCMD_SAI;
|
||||||
|
} else if (mode == DMA_MODE_WRITE) {
|
||||||
|
chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE;
|
||||||
|
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
|
||||||
|
mode &= DMA_MODE_MASK;
|
||||||
|
chan->mode |= DMAC_DCMD_SAI;
|
||||||
|
chan->mode &= ~DMAC_DCMD_DAI;
|
||||||
|
} else
|
||||||
|
printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
|
||||||
|
|
||||||
|
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
|
||||||
|
REG_DMAC_DRSR(chan->io) = chan->source;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt)
|
||||||
|
{
|
||||||
|
struct jz_dma_chan *chan = get_dma_chan(dmanr);
|
||||||
|
|
||||||
|
if (!chan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (audio_fmt) {
|
||||||
|
case 8:
|
||||||
|
/* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
/* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */
|
||||||
|
if (mode == DMA_MODE_READ) {
|
||||||
|
chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ;
|
||||||
|
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
|
||||||
|
mode &= DMA_MODE_MASK;
|
||||||
|
chan->mode |= DMAC_DCMD_DAI;
|
||||||
|
chan->mode &= ~DMAC_DCMD_SAI;
|
||||||
|
} else if (mode == DMA_MODE_WRITE) {
|
||||||
|
chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE;
|
||||||
|
chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI);
|
||||||
|
mode &= DMA_MODE_MASK;
|
||||||
|
chan->mode |= DMAC_DCMD_SAI;
|
||||||
|
chan->mode &= ~DMAC_DCMD_DAI;
|
||||||
|
} else
|
||||||
|
printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n");
|
||||||
|
|
||||||
|
REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK;
|
||||||
|
REG_DMAC_DRSR(chan->io) = chan->source;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef JZ4740_DMAC_TEST_ENABLE
|
||||||
|
|
||||||
|
#ifdef JZ4740_DMAC_TEST_ENABLE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DMA test: external address <--> external address
|
||||||
|
*/
|
||||||
|
#define TEST_DMA_SIZE 16*1024
|
||||||
|
|
||||||
|
static jz_dma_desc *dma_desc;
|
||||||
|
|
||||||
|
static int dma_chan;
|
||||||
|
static dma_addr_t dma_desc_phys_addr;
|
||||||
|
static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr;
|
||||||
|
|
||||||
|
static int dma_check_result(void *src, void *dst, int size)
|
||||||
|
{
|
||||||
|
unsigned int addr1, addr2, i, err = 0;
|
||||||
|
|
||||||
|
addr1 = (unsigned int)src;
|
||||||
|
addr2 = (unsigned int)dst;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i += 4) {
|
||||||
|
if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) {
|
||||||
|
err++;
|
||||||
|
printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2);
|
||||||
|
}
|
||||||
|
addr1 += 4;
|
||||||
|
addr2 += 4;
|
||||||
|
}
|
||||||
|
printk("check DMA result err=%d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4740_dma_irq(int irq, void *dev_id, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
printk("jz4740_dma_irq %d\n", irq);
|
||||||
|
|
||||||
|
REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */
|
||||||
|
|
||||||
|
if (__dmac_channel_transmit_halt_detected(dma_chan)) {
|
||||||
|
printk("DMA HALT\n");
|
||||||
|
__dmac_channel_clear_transmit_halt(dma_chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__dmac_channel_address_error_detected(dma_chan)) {
|
||||||
|
printk("DMA ADDR ERROR\n");
|
||||||
|
__dmac_channel_clear_address_error(dma_chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__dmac_channel_descriptor_invalid_detected(dma_chan)) {
|
||||||
|
printk("DMA DESC INVALID\n");
|
||||||
|
__dmac_channel_clear_descriptor_invalid(dma_chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__dmac_channel_count_terminated_detected(dma_chan)) {
|
||||||
|
printk("DMA CT\n");
|
||||||
|
__dmac_channel_clear_count_terminated(dma_chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__dmac_channel_transmit_end_detected(dma_chan)) {
|
||||||
|
printk("DMA TT\n");
|
||||||
|
__dmac_channel_clear_transmit_end(dma_chan);
|
||||||
|
dump_jz_dma_channel(dma_chan);
|
||||||
|
dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free buffers */
|
||||||
|
printk("free DMA buffers\n");
|
||||||
|
free_pages(dma_src_addr, 2);
|
||||||
|
free_pages(dma_dst_addr, 2);
|
||||||
|
|
||||||
|
if (dma_desc)
|
||||||
|
free_pages((unsigned int)dma_desc, 0);
|
||||||
|
|
||||||
|
/* free dma */
|
||||||
|
jz_free_dma(dma_chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dma_nodesc_test(void)
|
||||||
|
{
|
||||||
|
unsigned int addr, i;
|
||||||
|
|
||||||
|
printk("dma_nodesc_test\n");
|
||||||
|
|
||||||
|
/* Request DMA channel and setup irq handler */
|
||||||
|
dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4740_dma_irq,
|
||||||
|
SA_INTERRUPT, NULL);
|
||||||
|
if (dma_chan < 0) {
|
||||||
|
printk("Setup irq failed\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Requested DMA channel = %d\n", dma_chan);
|
||||||
|
|
||||||
|
/* Allocate DMA buffers */
|
||||||
|
dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
|
||||||
|
dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
|
||||||
|
|
||||||
|
dma_src_phys_addr = CPHYSADDR(dma_src_addr);
|
||||||
|
dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
|
||||||
|
|
||||||
|
printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||||
|
dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
|
||||||
|
|
||||||
|
/* Prepare data for source buffer */
|
||||||
|
addr = (unsigned int)dma_src_addr;
|
||||||
|
for (i = 0; i < TEST_DMA_SIZE; i += 4) {
|
||||||
|
*(volatile unsigned int *)addr = addr;
|
||||||
|
addr += 4;
|
||||||
|
}
|
||||||
|
dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
|
||||||
|
|
||||||
|
/* Init target buffer */
|
||||||
|
memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
|
||||||
|
dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
|
||||||
|
|
||||||
|
/* Init DMA module */
|
||||||
|
printk("Starting DMA\n");
|
||||||
|
REG_DMAC_DMACR = 0;
|
||||||
|
REG_DMAC_DCCSR(dma_chan) = 0;
|
||||||
|
REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
|
||||||
|
REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr;
|
||||||
|
REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr;
|
||||||
|
REG_DMAC_DTCR(dma_chan) = 512;
|
||||||
|
REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE;
|
||||||
|
REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN;
|
||||||
|
REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */
|
||||||
|
|
||||||
|
printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dma_desc_test(void)
|
||||||
|
{
|
||||||
|
unsigned int next, addr, i;
|
||||||
|
static jz_dma_desc *desc;
|
||||||
|
|
||||||
|
printk("dma_desc_test\n");
|
||||||
|
|
||||||
|
/* Request DMA channel and setup irq handler */
|
||||||
|
dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4740_dma_irq,
|
||||||
|
SA_INTERRUPT, NULL);
|
||||||
|
if (dma_chan < 0) {
|
||||||
|
printk("Setup irq failed\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Requested DMA channel = %d\n", dma_chan);
|
||||||
|
|
||||||
|
/* Allocate DMA buffers */
|
||||||
|
dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
|
||||||
|
dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */
|
||||||
|
|
||||||
|
dma_src_phys_addr = CPHYSADDR(dma_src_addr);
|
||||||
|
dma_dst_phys_addr = CPHYSADDR(dma_dst_addr);
|
||||||
|
|
||||||
|
printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||||
|
dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr);
|
||||||
|
|
||||||
|
/* Prepare data for source buffer */
|
||||||
|
addr = (unsigned int)dma_src_addr;
|
||||||
|
for (i = 0; i < TEST_DMA_SIZE; i += 4) {
|
||||||
|
*(volatile unsigned int *)addr = addr;
|
||||||
|
addr += 4;
|
||||||
|
}
|
||||||
|
dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE);
|
||||||
|
|
||||||
|
/* Init target buffer */
|
||||||
|
memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE);
|
||||||
|
dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE);
|
||||||
|
|
||||||
|
/* Allocate DMA descriptors */
|
||||||
|
dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0);
|
||||||
|
dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc);
|
||||||
|
|
||||||
|
printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr);
|
||||||
|
|
||||||
|
/* Setup DMA descriptors */
|
||||||
|
desc = dma_desc;
|
||||||
|
next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4;
|
||||||
|
|
||||||
|
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
|
||||||
|
desc->dsadr = dma_src_phys_addr; /* DMA source address */
|
||||||
|
desc->dtadr = dma_dst_phys_addr; /* DMA target address */
|
||||||
|
desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */
|
||||||
|
|
||||||
|
desc++;
|
||||||
|
next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4;
|
||||||
|
|
||||||
|
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
|
||||||
|
desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */
|
||||||
|
desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */
|
||||||
|
desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
|
||||||
|
|
||||||
|
desc++;
|
||||||
|
next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4;
|
||||||
|
|
||||||
|
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK;
|
||||||
|
desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */
|
||||||
|
desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */
|
||||||
|
desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */
|
||||||
|
|
||||||
|
desc++;
|
||||||
|
next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4;
|
||||||
|
|
||||||
|
desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE;
|
||||||
|
desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */
|
||||||
|
desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */
|
||||||
|
desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */
|
||||||
|
|
||||||
|
dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc)));
|
||||||
|
|
||||||
|
/* Setup DMA descriptor address */
|
||||||
|
REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr;
|
||||||
|
|
||||||
|
/* Setup request source */
|
||||||
|
REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO;
|
||||||
|
|
||||||
|
/* Setup DMA channel control/status register */
|
||||||
|
REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */
|
||||||
|
|
||||||
|
/* Enable DMA */
|
||||||
|
REG_DMAC_DMACR = DMAC_DMACR_DMAE;
|
||||||
|
|
||||||
|
/* DMA doorbell set -- start DMA now ... */
|
||||||
|
REG_DMAC_DMADBSR = 1 << dma_chan;
|
||||||
|
|
||||||
|
printk("DMA started. IMR=%08x\n", REG_INTC_IMR);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//EXPORT_SYMBOL_NOVERS(jz_dma_table);
|
||||||
|
EXPORT_SYMBOL(jz_dma_table);
|
||||||
|
EXPORT_SYMBOL(jz_request_dma);
|
||||||
|
EXPORT_SYMBOL(jz_free_dma);
|
||||||
|
EXPORT_SYMBOL(jz_set_dma_src_width);
|
||||||
|
EXPORT_SYMBOL(jz_set_dma_dest_width);
|
||||||
|
EXPORT_SYMBOL(jz_set_dma_block_size);
|
||||||
|
EXPORT_SYMBOL(jz_set_dma_mode);
|
||||||
|
EXPORT_SYMBOL(set_dma_mode);
|
||||||
|
EXPORT_SYMBOL(jz_set_oss_dma);
|
||||||
|
EXPORT_SYMBOL(jz_set_alsa_dma);
|
||||||
|
EXPORT_SYMBOL(set_dma_addr);
|
||||||
|
EXPORT_SYMBOL(set_dma_count);
|
||||||
|
EXPORT_SYMBOL(get_dma_residue);
|
||||||
|
EXPORT_SYMBOL(enable_dma);
|
||||||
|
EXPORT_SYMBOL(disable_dma);
|
||||||
|
EXPORT_SYMBOL(dump_jz_dma_channel);
|
297
target/linux/xburst/files-2.6.31/arch/mips/jz4740/gpio.c
Normal file
297
target/linux/xburst/files-2.6.31/arch/mips/jz4740/gpio.c
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
|
||||||
|
* JZ74xx platform GPIO support
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
|
#include <asm/mach-jz4740/regs.h>
|
||||||
|
|
||||||
|
#define JZ_GPIO_BASE_A (32*0)
|
||||||
|
#define JZ_GPIO_BASE_B (32*1)
|
||||||
|
#define JZ_GPIO_BASE_C (32*2)
|
||||||
|
#define JZ_GPIO_BASE_D (32*3)
|
||||||
|
|
||||||
|
#define JZ_GPIO_NUM_A 32
|
||||||
|
#define JZ_GPIO_NUM_B 32
|
||||||
|
#define JZ_GPIO_NUM_C 31
|
||||||
|
#define JZ_GPIO_NUM_D 28
|
||||||
|
|
||||||
|
#define JZ_IRQ_GPIO_BASE_A JZ_IRQ_GPIO(0) + JZ_GPIO_BASE_A
|
||||||
|
#define JZ_IRQ_GPIO_BASE_B JZ_IRQ_GPIO(0) + JZ_GPIO_BASE_B
|
||||||
|
#define JZ_IRQ_GPIO_BASE_C JZ_IRQ_GPIO(0) + JZ_GPIO_BASE_C
|
||||||
|
#define JZ_IRQ_GPIO_BASE_D JZ_IRQ_GPIO(0) + JZ_GPIO_BASE_D
|
||||||
|
|
||||||
|
#define JZ_IRQ_GPIO_A(num) (num < JZ_GPIO_NUM_A ? JZ_IRQ_GPIO_BASE_A + num : -EINVAL)
|
||||||
|
#define JZ_IRQ_GPIO_B(num) (num < JZ_GPIO_NUM_B ? JZ_IRQ_GPIO_BASE_B + num : -EINVAL)
|
||||||
|
#define JZ_IRQ_GPIO_C(num) (num < JZ_GPIO_NUM_C ? JZ_IRQ_GPIO_BASE_C + num : -EINVAL)
|
||||||
|
#define JZ_IRQ_GPIO_D(num) (num < JZ_GPIO_NUM_D ? JZ_IRQ_GPIO_BASE_D + num : -EINVAL)
|
||||||
|
|
||||||
|
|
||||||
|
#define CHIP_TO_REG(chip, reg) (jz_gpio_base + (((chip)->base) << 3) + reg)
|
||||||
|
#define CHIP_TO_PIN_REG(chip) CHIP_TO_REG(chip, 0x00)
|
||||||
|
#define CHIP_TO_DATA_REG(chip) CHIP_TO_REG(chip, 0x10)
|
||||||
|
#define CHIP_TO_DATA_SET_REG(chip) CHIP_TO_REG(chip, 0x14)
|
||||||
|
#define CHIP_TO_DATA_CLEAR_REG(chip) CHIP_TO_REG(chip, 0x18)
|
||||||
|
#define CHIP_TO_PULL_REG(chip) CHIP_TO_REG(chip, 0x30)
|
||||||
|
#define CHIP_TO_PULL_SET_REG(chip) CHIP_TO_REG(chip, 0x34)
|
||||||
|
#define CHIP_TO_PULL_CLEAR_REG(chip) CHIP_TO_REG(chip, 0x38)
|
||||||
|
#define CHIP_TO_DATA_SELECT_REG(chip) CHIP_TO_REG(chip, 0x50)
|
||||||
|
#define CHIP_TO_DATA_SELECT_SET_REG(chip) CHIP_TO_REG(chip, 0x54)
|
||||||
|
#define CHIP_TO_DATA_SELECT_CLEAR_REG(chip) CHIP_TO_REG(chip, 0x58)
|
||||||
|
#define CHIP_TO_DATA_DIRECION_REG(chip) CHIP_TO_REG(chip, 0x60)
|
||||||
|
#define CHIP_TO_DATA_DIRECTION_SET_REG(chip) CHIP_TO_REG(chip, 0x64)
|
||||||
|
#define CHIP_TO_DATA_DIRECTION_CLEAR_REG(chip) CHIP_TO_REG(chip, 0x68)
|
||||||
|
|
||||||
|
#define GPIO_TO_REG(gpio, reg) (jz_gpio_base + ((gpio >> 5) << 8) + reg)
|
||||||
|
#define GPIO_TO_PULL_REG(gpio) GPIO_TO_REG(gpio, 0x30)
|
||||||
|
#define GPIO_TO_PULL_SET_REG(gpio) GPIO_TO_REG(gpio, 0x34)
|
||||||
|
#define GPIO_TO_PULL_CLEAR_REG(gpio) GPIO_TO_REG(gpio, 0x38)
|
||||||
|
|
||||||
|
static void __iomem *jz_gpio_base;
|
||||||
|
static spinlock_t jz_gpio_lock;
|
||||||
|
|
||||||
|
struct jz_gpio_chip {
|
||||||
|
unsigned int irq_base;
|
||||||
|
struct gpio_chip gpio_chip;
|
||||||
|
struct irq_chip irq_chip;
|
||||||
|
};
|
||||||
|
|
||||||
|
void jz_gpio_enable_pullup(unsigned gpio)
|
||||||
|
{
|
||||||
|
writel(BIT(gpio & 0x1f), GPIO_TO_PULL_CLEAR_REG(gpio));
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(jz_gpio_enable_pullup);
|
||||||
|
|
||||||
|
void jz_gpio_disable_pullup(unsigned gpio)
|
||||||
|
{
|
||||||
|
writel(BIT(gpio & 0x1f), GPIO_TO_PULL_SET_REG(gpio));
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(jz_gpio_disable_pullup);
|
||||||
|
|
||||||
|
void jz_gpio_set_function(unsigned gpio, unsigned function)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(jz_gpio_set_function);
|
||||||
|
|
||||||
|
|
||||||
|
static int jz_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
|
||||||
|
{
|
||||||
|
return !!(readl(CHIP_TO_PIN_REG(chip)) & BIT(gpio));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
|
||||||
|
{
|
||||||
|
uint32_t __iomem *reg = CHIP_TO_DATA_SET_REG(chip) + ((!value) << 2);
|
||||||
|
writel(BIT(gpio), reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
|
||||||
|
{
|
||||||
|
writel(BIT(gpio), CHIP_TO_DATA_DIRECTION_SET_REG(chip));
|
||||||
|
jz_gpio_set_value(chip, gpio, value);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
||||||
|
{
|
||||||
|
writel(BIT(gpio), CHIP_TO_DATA_DIRECTION_CLEAR_REG(chip));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define IRQ_TO_GPIO(irq) (irq - JZ_IRQ_GPIO(0))
|
||||||
|
#define IRQ_TO_BIT(irq) BIT(IRQ_TO_GPIO(irq) & 0x1f)
|
||||||
|
|
||||||
|
|
||||||
|
#define IRQ_TO_REG(irq, reg) GPIO_TO_REG(IRQ_TO_GPIO(irq), reg)
|
||||||
|
#define IRQ_TO_MASK_REG(irq) IRQ_TO_REG(irq, 0x20)
|
||||||
|
#define IRQ_TO_MASK_SET_REG(irq) IRQ_TO_REG(irq, 0x24)
|
||||||
|
#define IRQ_TO_MASK_CLEAR_REG(irq) IRQ_TO_REG(irq, 0x28)
|
||||||
|
#define IRQ_TO_SELECT_REG(irq) IRQ_TO_REG(irq, 0x50)
|
||||||
|
#define IRQ_TO_SELECT_SET_REG(irq) IRQ_TO_REG(irq, 0x54)
|
||||||
|
#define IRQ_TO_SELECT_CLEAR_REG(irq) IRQ_TO_REG(irq, 0x58)
|
||||||
|
#define IRQ_TO_DIRECTION_REG(irq) IRQ_TO_REG(irq, 0x60)
|
||||||
|
#define IRQ_TO_DIRECTION_SET_REG(irq) IRQ_TO_REG(irq, 0x64)
|
||||||
|
#define IRQ_TO_DIRECTION_CLEAR_REG(irq) IRQ_TO_REG(irq, 0x68)
|
||||||
|
#define IRQ_TO_TRIGGER_REG(irq) IRQ_TO_REG(irq, 0x70)
|
||||||
|
#define IRQ_TO_TRIGGER_SET_REG(irq) IRQ_TO_REG(irq, 0x74)
|
||||||
|
#define IRQ_TO_TRIGGER_CLEAR_REG(irq) IRQ_TO_REG(irq, 0x78)
|
||||||
|
#define IRQ_TO_FLAG_REG(irq) IRQ_TO_REG(irq, 0x80)
|
||||||
|
#define IRQ_TO_FLAG_CLEAR_REG(irq) IRQ_TO_REG(irq, 0x14)
|
||||||
|
|
||||||
|
|
||||||
|
static void jz_gpio_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
|
{
|
||||||
|
uint32_t flag;
|
||||||
|
unsigned int gpio_irq;
|
||||||
|
unsigned int gpio_bank;
|
||||||
|
|
||||||
|
gpio_bank = IRQ_GPIO0 - irq;
|
||||||
|
|
||||||
|
flag = readl(jz_gpio_base + (gpio_bank << 8) + 0x80);
|
||||||
|
|
||||||
|
gpio_irq = ffs(flag);
|
||||||
|
|
||||||
|
gpio_irq += (gpio_bank << 5) + JZ_IRQ_GPIO(0) - 1;
|
||||||
|
|
||||||
|
generic_handle_irq(gpio_irq);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TODO: Check if function is gpio */
|
||||||
|
static unsigned int jz_gpio_irq_startup(unsigned int irq)
|
||||||
|
{
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_SELECT_SET_REG(irq));
|
||||||
|
spin_lock(&jz_gpio_lock);
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_MASK_CLEAR_REG(irq));
|
||||||
|
spin_unlock(&jz_gpio_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_gpio_irq_shutdown(unsigned int irq)
|
||||||
|
{
|
||||||
|
spin_lock(&jz_gpio_lock);
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_MASK_SET_REG(irq));
|
||||||
|
spin_unlock(&jz_gpio_lock);
|
||||||
|
/* Set direction to input */
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_DIRECTION_CLEAR_REG(irq));
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_SELECT_CLEAR_REG(irq));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_gpio_irq_mask(unsigned int irq)
|
||||||
|
{
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_MASK_SET_REG(irq));
|
||||||
|
};
|
||||||
|
|
||||||
|
static void jz_gpio_irq_unmask(unsigned int irq)
|
||||||
|
{
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_MASK_CLEAR_REG(irq));
|
||||||
|
};
|
||||||
|
|
||||||
|
static void jz_gpio_irq_ack(unsigned int irq)
|
||||||
|
{
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_FLAG_CLEAR_REG(irq));
|
||||||
|
};
|
||||||
|
|
||||||
|
static int jz_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
|
||||||
|
{
|
||||||
|
uint32_t mask;
|
||||||
|
spin_lock(&jz_gpio_lock);
|
||||||
|
|
||||||
|
mask = readl(IRQ_TO_MASK_REG(irq));
|
||||||
|
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_MASK_CLEAR_REG(irq));
|
||||||
|
|
||||||
|
switch(flow_type) {
|
||||||
|
case IRQ_TYPE_EDGE_RISING:
|
||||||
|
case IRQ_TYPE_EDGE_BOTH:
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_DIRECTION_SET_REG(irq));
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_TRIGGER_SET_REG(irq));
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_EDGE_FALLING:
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_DIRECTION_CLEAR_REG(irq));
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_TRIGGER_SET_REG(irq));
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_LEVEL_HIGH:
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_DIRECTION_SET_REG(irq));
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_TRIGGER_CLEAR_REG(irq));
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_LEVEL_LOW:
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_DIRECTION_CLEAR_REG(irq));
|
||||||
|
writel(IRQ_TO_BIT(irq), IRQ_TO_TRIGGER_CLEAR_REG(irq));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel(mask, IRQ_TO_MASK_SET_REG(irq));
|
||||||
|
|
||||||
|
spin_unlock(&jz_gpio_lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_to_irq(unsigned gpio)
|
||||||
|
{
|
||||||
|
return JZ_IRQ_GPIO(0) + gpio;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(gpio_to_irq);
|
||||||
|
|
||||||
|
int irq_to_gpio(unsigned gpio)
|
||||||
|
{
|
||||||
|
return IRQ_TO_GPIO(gpio);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_to_gpio);
|
||||||
|
|
||||||
|
#define JZ_GPIO_CHIP(_bank) { \
|
||||||
|
.irq_base = JZ_IRQ_GPIO_BASE_ ## _bank, \
|
||||||
|
.gpio_chip = { \
|
||||||
|
.label = "Bank " # _bank, \
|
||||||
|
.owner = THIS_MODULE, \
|
||||||
|
.set = jz_gpio_set_value, \
|
||||||
|
.get = jz_gpio_get_value, \
|
||||||
|
.direction_output = jz_gpio_direction_output, \
|
||||||
|
.direction_input = jz_gpio_direction_input, \
|
||||||
|
.base = JZ_GPIO_BASE_ ## _bank, \
|
||||||
|
.ngpio = JZ_GPIO_NUM_ ## _bank, \
|
||||||
|
}, \
|
||||||
|
.irq_chip = { \
|
||||||
|
.name = "GPIO Bank " # _bank, \
|
||||||
|
.mask = jz_gpio_irq_mask, \
|
||||||
|
.unmask = jz_gpio_irq_unmask, \
|
||||||
|
.ack = jz_gpio_irq_ack, \
|
||||||
|
.startup = jz_gpio_irq_startup, \
|
||||||
|
.shutdown = jz_gpio_irq_shutdown, \
|
||||||
|
.set_type = jz_gpio_irq_set_type, \
|
||||||
|
}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct jz_gpio_chip jz_gpio_chips[] = {
|
||||||
|
JZ_GPIO_CHIP(A),
|
||||||
|
JZ_GPIO_CHIP(B),
|
||||||
|
JZ_GPIO_CHIP(C),
|
||||||
|
JZ_GPIO_CHIP(D),
|
||||||
|
};
|
||||||
|
|
||||||
|
__init int jz_gpiolib_init(void)
|
||||||
|
{
|
||||||
|
struct jz_gpio_chip *chip = jz_gpio_chips;
|
||||||
|
int i, irq;
|
||||||
|
|
||||||
|
jz_gpio_base = ioremap(0x10010000, 0x400);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(jz_gpio_chips); ++i, ++chip) {
|
||||||
|
gpiochip_add(&chip->gpio_chip);
|
||||||
|
enable_irq(JZ_IRQ_INTC_GPIO(i));
|
||||||
|
set_irq_chained_handler(JZ_IRQ_INTC_GPIO(i), jz_gpio_irq_demux_handler);
|
||||||
|
for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio;
|
||||||
|
++irq)
|
||||||
|
set_irq_chip_and_handler(irq, &chip->irq_chip, handle_level_irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("JZ GPIO initalized\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
273
target/linux/xburst/files-2.6.31/arch/mips/jz4740/i2c.c
Normal file
273
target/linux/xburst/files-2.6.31/arch/mips/jz4740/i2c.c
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
/*
|
||||||
|
* linux/arch/mips/jz4740/i2c.c
|
||||||
|
*
|
||||||
|
* Jz4740 I2C routines.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005,2006 Ingenic Semiconductor Inc.
|
||||||
|
* Author: <lhhuang@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can distribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License (Version 2) as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/addrspace.h>
|
||||||
|
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
/* I2C protocol */
|
||||||
|
#define I2C_READ 1
|
||||||
|
#define I2C_WRITE 0
|
||||||
|
|
||||||
|
#define TIMEOUT 1000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I2C bus protocol basic routines
|
||||||
|
*/
|
||||||
|
static int i2c_put_data(unsigned char data)
|
||||||
|
{
|
||||||
|
unsigned int timeout = TIMEOUT*10;
|
||||||
|
|
||||||
|
__i2c_write(data);
|
||||||
|
__i2c_set_drf();
|
||||||
|
while (__i2c_check_drf() != 0);
|
||||||
|
while (!__i2c_transmit_ended());
|
||||||
|
while (!__i2c_received_ack() && timeout)
|
||||||
|
timeout--;
|
||||||
|
|
||||||
|
if (timeout)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_JZ_TPANEL_ATA2508
|
||||||
|
static int i2c_put_data_nack(unsigned char data)
|
||||||
|
{
|
||||||
|
unsigned int timeout = TIMEOUT*10;
|
||||||
|
|
||||||
|
__i2c_write(data);
|
||||||
|
__i2c_set_drf();
|
||||||
|
while (__i2c_check_drf() != 0);
|
||||||
|
while (!__i2c_transmit_ended());
|
||||||
|
while (timeout--);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int i2c_get_data(unsigned char *data, int ack)
|
||||||
|
{
|
||||||
|
int timeout = TIMEOUT*10;
|
||||||
|
|
||||||
|
if (!ack)
|
||||||
|
__i2c_send_nack();
|
||||||
|
else
|
||||||
|
__i2c_send_ack();
|
||||||
|
|
||||||
|
while (__i2c_check_drf() == 0 && timeout)
|
||||||
|
timeout--;
|
||||||
|
|
||||||
|
if (timeout) {
|
||||||
|
if (!ack)
|
||||||
|
__i2c_send_stop();
|
||||||
|
*data = __i2c_read();
|
||||||
|
__i2c_clear_drf();
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I2C interface
|
||||||
|
*/
|
||||||
|
void i2c_open(void)
|
||||||
|
{
|
||||||
|
__i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */
|
||||||
|
__i2c_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void i2c_close(void)
|
||||||
|
{
|
||||||
|
udelay(300); /* wait for STOP goes over. */
|
||||||
|
__i2c_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void i2c_setclk(unsigned int i2cclk)
|
||||||
|
{
|
||||||
|
__i2c_set_clk(jz_clocks.extalclk, i2cclk);
|
||||||
|
}
|
||||||
|
|
||||||
|
int i2c_lseek(unsigned char device, unsigned char offset)
|
||||||
|
{
|
||||||
|
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
|
||||||
|
__i2c_send_start();
|
||||||
|
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
|
||||||
|
goto device_err;
|
||||||
|
if (i2c_put_data(offset) < 0)
|
||||||
|
goto address_err;
|
||||||
|
return 0;
|
||||||
|
device_err:
|
||||||
|
printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device);
|
||||||
|
__i2c_send_stop();
|
||||||
|
return -ENODEV;
|
||||||
|
address_err:
|
||||||
|
printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device);
|
||||||
|
__i2c_send_stop();
|
||||||
|
return -EREMOTEIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i2c_read(unsigned char device, unsigned char *buf,
|
||||||
|
unsigned char address, int count)
|
||||||
|
{
|
||||||
|
int cnt = count;
|
||||||
|
int timeout = 5;
|
||||||
|
|
||||||
|
L_try_again:
|
||||||
|
|
||||||
|
if (timeout < 0)
|
||||||
|
goto L_timeout;
|
||||||
|
|
||||||
|
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
|
||||||
|
__i2c_send_start();
|
||||||
|
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
|
||||||
|
goto device_werr;
|
||||||
|
if (i2c_put_data(address) < 0)
|
||||||
|
goto address_err;
|
||||||
|
|
||||||
|
__i2c_send_start();
|
||||||
|
if (i2c_put_data( (device << 1) | I2C_READ ) < 0)
|
||||||
|
goto device_rerr;
|
||||||
|
__i2c_send_ack(); /* Master sends ACK for continue reading */
|
||||||
|
while (cnt) {
|
||||||
|
if (cnt == 1) {
|
||||||
|
if (i2c_get_data(buf, 0) < 0)
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (i2c_get_data(buf, 1) < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cnt--;
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
|
||||||
|
__i2c_send_stop();
|
||||||
|
return count - cnt;
|
||||||
|
device_rerr:
|
||||||
|
device_werr:
|
||||||
|
address_err:
|
||||||
|
timeout --;
|
||||||
|
__i2c_send_stop();
|
||||||
|
goto L_try_again;
|
||||||
|
|
||||||
|
L_timeout:
|
||||||
|
__i2c_send_stop();
|
||||||
|
printk("Read I2C device 0x%2x failed.\n", device);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i2c_write(unsigned char device, unsigned char *buf,
|
||||||
|
unsigned char address, int count)
|
||||||
|
{
|
||||||
|
int cnt = count;
|
||||||
|
int cnt_in_pg;
|
||||||
|
int timeout = 5;
|
||||||
|
unsigned char *tmpbuf;
|
||||||
|
unsigned char tmpaddr;
|
||||||
|
|
||||||
|
__i2c_send_nack(); /* Master does not send ACK, slave sends it */
|
||||||
|
|
||||||
|
W_try_again:
|
||||||
|
if (timeout < 0)
|
||||||
|
goto W_timeout;
|
||||||
|
|
||||||
|
cnt = count;
|
||||||
|
tmpbuf = (unsigned char *)buf;
|
||||||
|
tmpaddr = address;
|
||||||
|
|
||||||
|
start_write_page:
|
||||||
|
cnt_in_pg = 0;
|
||||||
|
__i2c_send_start();
|
||||||
|
if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0)
|
||||||
|
goto device_err;
|
||||||
|
#ifdef CONFIG_JZ_TPANEL_ATA2508
|
||||||
|
if (address == 0xff) {
|
||||||
|
if (i2c_put_data_nack(tmpaddr) < 0)
|
||||||
|
goto address_err;
|
||||||
|
while (cnt) {
|
||||||
|
if (++cnt_in_pg > 8) {
|
||||||
|
__i2c_send_stop();
|
||||||
|
mdelay(1);
|
||||||
|
tmpaddr += 8;
|
||||||
|
goto start_write_page;
|
||||||
|
}
|
||||||
|
if (i2c_put_data_nack(*tmpbuf) < 0)
|
||||||
|
break;
|
||||||
|
cnt--;
|
||||||
|
tmpbuf++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
if (i2c_put_data(tmpaddr) < 0)
|
||||||
|
goto address_err;
|
||||||
|
while (cnt) {
|
||||||
|
if (++cnt_in_pg > 8) {
|
||||||
|
__i2c_send_stop();
|
||||||
|
mdelay(1);
|
||||||
|
tmpaddr += 8;
|
||||||
|
goto start_write_page;
|
||||||
|
}
|
||||||
|
if (i2c_put_data(*tmpbuf) < 0)
|
||||||
|
break;
|
||||||
|
cnt--;
|
||||||
|
tmpbuf++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (i2c_put_data(tmpaddr) < 0)
|
||||||
|
goto address_err;
|
||||||
|
while (cnt) {
|
||||||
|
if (++cnt_in_pg > 8) {
|
||||||
|
__i2c_send_stop();
|
||||||
|
mdelay(1);
|
||||||
|
tmpaddr += 8;
|
||||||
|
goto start_write_page;
|
||||||
|
}
|
||||||
|
if (i2c_put_data(*tmpbuf) < 0)
|
||||||
|
break;
|
||||||
|
cnt--;
|
||||||
|
tmpbuf++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
__i2c_send_stop();
|
||||||
|
return count - cnt;
|
||||||
|
device_err:
|
||||||
|
address_err:
|
||||||
|
timeout--;
|
||||||
|
__i2c_send_stop();
|
||||||
|
goto W_try_again;
|
||||||
|
|
||||||
|
W_timeout:
|
||||||
|
printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device);
|
||||||
|
__i2c_send_stop();
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(i2c_open);
|
||||||
|
EXPORT_SYMBOL(i2c_close);
|
||||||
|
EXPORT_SYMBOL(i2c_setclk);
|
||||||
|
EXPORT_SYMBOL(i2c_read);
|
||||||
|
EXPORT_SYMBOL(i2c_write);
|
150
target/linux/xburst/files-2.6.31/arch/mips/jz4740/irq.c
Normal file
150
target/linux/xburst/files-2.6.31/arch/mips/jz4740/irq.c
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* linux/arch/mips/jz4740/irq.c
|
||||||
|
*
|
||||||
|
* JZ4740 interrupt routines.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
|
||||||
|
* Author: <lhhuang@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*/
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/kernel_stat.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/signal.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/timex.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/random.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
|
#include <asm/bootinfo.h>
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <asm/mipsregs.h>
|
||||||
|
#include <asm/system.h>
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
static void __iomem *jz_intc_base;
|
||||||
|
|
||||||
|
#define JZ_REG_BASE_INTC 0x10001000
|
||||||
|
|
||||||
|
#define JZ_REG_INTC_STATUS 0x00
|
||||||
|
#define JZ_REG_INTC_MASK 0x04
|
||||||
|
#define JZ_REG_INTC_SET_MASK 0x08
|
||||||
|
#define JZ_REG_INTC_CLEAR_MASK 0x0c
|
||||||
|
#define JZ_REG_INTC_PENDING 0x10
|
||||||
|
|
||||||
|
/*
|
||||||
|
* INTC irq type
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void intc_irq_unmask(unsigned int irq)
|
||||||
|
{
|
||||||
|
writel(BIT(irq), jz_intc_base + JZ_REG_INTC_CLEAR_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intc_irq_mask(unsigned int irq)
|
||||||
|
{
|
||||||
|
writel(BIT(irq), jz_intc_base + JZ_REG_INTC_SET_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intc_irq_ack(unsigned int irq)
|
||||||
|
{
|
||||||
|
writel(BIT(irq), jz_intc_base + JZ_REG_INTC_PENDING);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intc_irq_end(unsigned int irq)
|
||||||
|
{
|
||||||
|
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
|
||||||
|
intc_irq_unmask(irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct irq_chip intc_irq_type = {
|
||||||
|
.name = "INTC",
|
||||||
|
.mask = intc_irq_mask,
|
||||||
|
.unmask = intc_irq_unmask,
|
||||||
|
.ack = intc_irq_ack,
|
||||||
|
.end = intc_irq_end,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 struct irq_chip dma_irq_type = {
|
||||||
|
.name = "DMA",
|
||||||
|
.unmask = enable_dma_irq,
|
||||||
|
.mask = disable_dma_irq,
|
||||||
|
.ack = mask_and_ack_dma_irq,
|
||||||
|
.end = end_dma_irq,
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void __init arch_init_irq(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
clear_c0_status(0xff04); /* clear ERL */
|
||||||
|
set_c0_status(0x0400); /* set IP2 */
|
||||||
|
|
||||||
|
jz_intc_base = ioremap(JZ_REG_BASE_INTC, 0x14);
|
||||||
|
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
intc_irq_mask(i);
|
||||||
|
set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Set up DMAC irq
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NUM_DMA; i++) {
|
||||||
|
disable_dma_irq(IRQ_DMA_0 + i);
|
||||||
|
set_irq_chip_and_handler(IRQ_DMA_0 + i, &dma_irq_type, handle_level_irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
asmlinkage void plat_irq_dispatch(void)
|
||||||
|
{
|
||||||
|
uint32_t irq_reg;
|
||||||
|
|
||||||
|
irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING);
|
||||||
|
|
||||||
|
if (irq_reg)
|
||||||
|
do_IRQ(ffs(irq_reg) - 1);
|
||||||
|
}
|
340
target/linux/xburst/files-2.6.31/arch/mips/jz4740/platform.c
Normal file
340
target/linux/xburst/files-2.6.31/arch/mips/jz4740/platform.c
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
/*
|
||||||
|
* Platform device support for Jz4740 SoC.
|
||||||
|
*
|
||||||
|
* Copyright 2007, <yliu@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This file is licensed under the terms of the GNU General Public
|
||||||
|
* License version 2. This program is licensed "as is" without any
|
||||||
|
* warranty of any kind, whether express or implied.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/resource.h>
|
||||||
|
#include <linux/mtd/jz4740_nand.h>
|
||||||
|
#include <linux/input/matrix_keypad.h>
|
||||||
|
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
/* OHCI (USB full speed host controller) */
|
||||||
|
static struct resource jz_usb_ohci_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = CPHYSADDR(UHC_BASE), // phys addr for ioremap
|
||||||
|
.end = CPHYSADDR(UHC_BASE) + 0x10000 - 1,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.start = IRQ_UHC,
|
||||||
|
.end = IRQ_UHC,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The dmamask must be set for OHCI to work */
|
||||||
|
static u64 ohci_dmamask = ~(u32)0;
|
||||||
|
|
||||||
|
static struct platform_device jz_usb_ohci_device = {
|
||||||
|
.name = "jz-ohci",
|
||||||
|
.id = 0,
|
||||||
|
.dev = {
|
||||||
|
.dma_mask = &ohci_dmamask,
|
||||||
|
.coherent_dma_mask = 0xffffffff,
|
||||||
|
},
|
||||||
|
.num_resources = ARRAY_SIZE(jz_usb_ohci_resources),
|
||||||
|
.resource = jz_usb_ohci_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*** LCD controller ***/
|
||||||
|
static struct resource jz_lcd_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = CPHYSADDR(LCD_BASE),
|
||||||
|
.end = CPHYSADDR(LCD_BASE) + 0x10000 - 1,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.start = IRQ_LCD,
|
||||||
|
.end = IRQ_LCD,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static u64 jz_lcd_dmamask = ~(u32)0;
|
||||||
|
|
||||||
|
static struct platform_device jz_lcd_device = {
|
||||||
|
.name = "jz-lcd",
|
||||||
|
.id = 0,
|
||||||
|
.dev = {
|
||||||
|
.dma_mask = &jz_lcd_dmamask,
|
||||||
|
.coherent_dma_mask = 0xffffffff,
|
||||||
|
},
|
||||||
|
.num_resources = ARRAY_SIZE(jz_lcd_resources),
|
||||||
|
.resource = jz_lcd_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* UDC (USB gadget controller) */
|
||||||
|
static struct resource jz_usb_gdt_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = CPHYSADDR(UDC_BASE),
|
||||||
|
.end = CPHYSADDR(UDC_BASE) + 0x10000 - 1,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.start = IRQ_UDC,
|
||||||
|
.end = IRQ_UDC,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static u64 udc_dmamask = ~(u32)0;
|
||||||
|
|
||||||
|
static struct platform_device jz_usb_gdt_device = {
|
||||||
|
.name = "jz-udc",
|
||||||
|
.id = 0,
|
||||||
|
.dev = {
|
||||||
|
.dma_mask = &udc_dmamask,
|
||||||
|
.coherent_dma_mask = 0xffffffff,
|
||||||
|
},
|
||||||
|
.num_resources = ARRAY_SIZE(jz_usb_gdt_resources),
|
||||||
|
.resource = jz_usb_gdt_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** MMC/SD controller **/
|
||||||
|
static struct resource jz_mmc_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = CPHYSADDR(MSC_BASE),
|
||||||
|
.end = CPHYSADDR(MSC_BASE) + 0x10000 - 1,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.start = IRQ_MSC,
|
||||||
|
.end = IRQ_MSC,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static u64 jz_mmc_dmamask = ~(u32)0;
|
||||||
|
|
||||||
|
static struct platform_device jz_mmc_device = {
|
||||||
|
.name = "jz-mmc",
|
||||||
|
.id = 0,
|
||||||
|
.dev = {
|
||||||
|
.dma_mask = &jz_mmc_dmamask,
|
||||||
|
.coherent_dma_mask = 0xffffffff,
|
||||||
|
},
|
||||||
|
.num_resources = ARRAY_SIZE(jz_mmc_resources),
|
||||||
|
.resource = jz_mmc_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** I2C controller **/
|
||||||
|
static struct resource jz_i2c_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = CPHYSADDR(I2C_BASE),
|
||||||
|
.end = CPHYSADDR(I2C_BASE) + 0x10000 - 1,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.start = IRQ_I2C,
|
||||||
|
.end = IRQ_I2C,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static u64 jz_i2c_dmamask = ~(u32)0;
|
||||||
|
|
||||||
|
static struct platform_device jz_i2c_device = {
|
||||||
|
.name = "jz_i2c",
|
||||||
|
.id = 0,
|
||||||
|
.dev = {
|
||||||
|
.dma_mask = &jz_i2c_dmamask,
|
||||||
|
.coherent_dma_mask = 0xffffffff,
|
||||||
|
},
|
||||||
|
.num_resources = ARRAY_SIZE(jz_i2c_resources),
|
||||||
|
.resource = jz_i2c_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource jz_nand_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = CPHYSADDR(EMC_BASE),
|
||||||
|
.end = CPHYSADDR(EMC_BASE) + 0x10000 - 1,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct nand_ecclayout qi_lb60_ecclayout = {
|
||||||
|
.eccbytes = 36,
|
||||||
|
.eccpos = {
|
||||||
|
6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21,
|
||||||
|
22, 23, 24, 25, 26, 27, 28, 29,
|
||||||
|
30, 31, 32, 33, 34, 35, 36, 37,
|
||||||
|
38, 39, 40, 41},
|
||||||
|
.oobfree = {
|
||||||
|
{.offset = 0,
|
||||||
|
.length = 6},
|
||||||
|
{.offset = 42,
|
||||||
|
.length = 22}}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mtd_partition qi_lb60_partitions[] = {
|
||||||
|
{ .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 = 20 * 0x100000,
|
||||||
|
},
|
||||||
|
{ .name = "NAND DATA partition",
|
||||||
|
.offset = 100 * 0x100000,
|
||||||
|
.size = 20 * 0x100000,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz_nand_platform_data jz_nand_platform_data = {
|
||||||
|
.num_partitions = ARRAY_SIZE(qi_lb60_partitions),
|
||||||
|
.partitions = qi_lb60_partitions,
|
||||||
|
.ecc_layout = &qi_lb60_ecclayout,
|
||||||
|
.busy_gpio = 94,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device jz_nand_device = {
|
||||||
|
.name = "jz4740-nand",
|
||||||
|
.num_resources = ARRAY_SIZE(jz_nand_resources),
|
||||||
|
.resource = jz_nand_resources,
|
||||||
|
.dev = {
|
||||||
|
.platform_data = &jz_nand_platform_data,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#define KEEP_UART_ALIVE
|
||||||
|
|
||||||
|
#define KEY_QI_QI KEY_F9
|
||||||
|
#define KEY_QI_UPBIG KEY_F10
|
||||||
|
#define KEY_QI_DOWNBIG KEY_F11
|
||||||
|
#define KEY_QI_UPRED KEY_F12
|
||||||
|
#define KEY_QI_VOLUP KEY_F13
|
||||||
|
#define KEY_QI_VOLDOWN KEY_F14
|
||||||
|
|
||||||
|
static const uint32_t qi_lb60_keymap[] = {
|
||||||
|
KEY(0, 0, KEY_F1), /* S2 */
|
||||||
|
KEY(0, 1, KEY_F2), /* S3 */
|
||||||
|
KEY(0, 2, KEY_F3), /* S4 */
|
||||||
|
KEY(0, 3, KEY_F4), /* S5 */
|
||||||
|
KEY(0, 4, KEY_F5), /* S6 */
|
||||||
|
KEY(0, 5, KEY_F6), /* S7 */
|
||||||
|
KEY(0, 6, KEY_F7), /* S8 */
|
||||||
|
|
||||||
|
KEY(1, 0, KEY_Q), /* S10 */
|
||||||
|
KEY(1, 1, KEY_W), /* S11 */
|
||||||
|
KEY(1, 2, KEY_E), /* S12 */
|
||||||
|
KEY(1, 3, KEY_R), /* S13 */
|
||||||
|
KEY(1, 4, KEY_T), /* S14 */
|
||||||
|
KEY(1, 5, KEY_Y), /* S15 */
|
||||||
|
KEY(1, 6, KEY_U), /* S16 */
|
||||||
|
KEY(1, 7, KEY_I), /* S17 */
|
||||||
|
KEY(2, 0, KEY_A), /* S18 */
|
||||||
|
KEY(2, 1, KEY_S), /* S19 */
|
||||||
|
KEY(2, 2, KEY_D), /* S20 */
|
||||||
|
KEY(2, 3, KEY_F), /* S21 */
|
||||||
|
KEY(2, 4, KEY_G), /* S22 */
|
||||||
|
KEY(2, 5, KEY_H), /* S23 */
|
||||||
|
KEY(2, 6, KEY_J), /* S24 */
|
||||||
|
KEY(2, 7, KEY_K), /* S25 */
|
||||||
|
KEY(3, 0, KEY_ESC), /* S26 */
|
||||||
|
KEY(3, 1, KEY_Z), /* S27 */
|
||||||
|
KEY(3, 2, KEY_X), /* S28 */
|
||||||
|
KEY(3, 3, KEY_C), /* S29 */
|
||||||
|
KEY(3, 4, KEY_V), /* S30 */
|
||||||
|
KEY(3, 5, KEY_B), /* S31 */
|
||||||
|
KEY(3, 6, KEY_N), /* S32 */
|
||||||
|
KEY(3, 7, KEY_M), /* S33 */
|
||||||
|
KEY(4, 0, KEY_TAB), /* S34 */
|
||||||
|
KEY(4, 1, KEY_QI_DOWNBIG), /* S35 */
|
||||||
|
KEY(4, 2, KEY_BACKSLASH), /* S36 */
|
||||||
|
KEY(4, 3, KEY_APOSTROPHE), /* S37 */
|
||||||
|
KEY(4, 4, KEY_COMMA), /* S38 */
|
||||||
|
KEY(4, 5, KEY_DOT), /* S39 */
|
||||||
|
KEY(4, 6, KEY_SLASH), /* S40 */
|
||||||
|
KEY(4, 7, KEY_UP), /* S41 */
|
||||||
|
KEY(5, 0, KEY_O), /* S42 */
|
||||||
|
KEY(5, 1, KEY_L), /* S43 */
|
||||||
|
KEY(5, 2, KEY_EQUAL), /* S44 */
|
||||||
|
KEY(5, 3, KEY_QI_UPRED), /* S45 */
|
||||||
|
KEY(5, 4, KEY_SPACE), /* S46 */
|
||||||
|
KEY(5, 5, KEY_QI_QI), /* S47 */
|
||||||
|
KEY(5, 6, KEY_LEFTCTRL), /* S48 */
|
||||||
|
KEY(5, 7, KEY_LEFT), /* S49 */
|
||||||
|
KEY(6, 0, KEY_F8), /* S50 */
|
||||||
|
KEY(6, 1, KEY_P), /* S51 */
|
||||||
|
KEY(6, 2, KEY_BACKSPACE),/* S52 */
|
||||||
|
KEY(6, 3, KEY_ENTER), /* S53 */
|
||||||
|
KEY(6, 4, KEY_QI_VOLUP), /* S54 */
|
||||||
|
KEY(6, 5, KEY_QI_VOLDOWN), /* S55 */
|
||||||
|
KEY(6, 6, KEY_DOWN), /* S56 */
|
||||||
|
KEY(6, 7, KEY_RIGHT), /* S57 */
|
||||||
|
|
||||||
|
#ifndef KEEP_UART_ALIVE
|
||||||
|
KEY(7, 0, KEY_QI_UPBIG), /* S58 */
|
||||||
|
KEY(7, 1, KEY_LEFTALT), /* S59 */
|
||||||
|
KEY(7, 2, KEY_FN), /* S60 */
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct matrix_keymap_data qi_lb60_keymap_data = {
|
||||||
|
.keymap = qi_lb60_keymap,
|
||||||
|
.keymap_size = ARRAY_SIZE(qi_lb60_keymap),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned int qi_lb60_keypad_cols[] = {
|
||||||
|
74, 75, 76, 77, 78, 79, 80, 81,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned int qi_lb60_keypad_rows[] = {
|
||||||
|
114, 115, 116, 117, 118, 119, 120,
|
||||||
|
#ifndef KEEP_UART_ALIVE
|
||||||
|
122,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct matrix_keypad_platform_data qi_lb60_pdata = {
|
||||||
|
.keymap_data = &qi_lb60_keymap_data,
|
||||||
|
.col_gpios = qi_lb60_keypad_cols,
|
||||||
|
.row_gpios = qi_lb60_keypad_rows,
|
||||||
|
.num_col_gpios = ARRAY_SIZE(qi_lb60_keypad_cols),
|
||||||
|
.num_row_gpios = ARRAY_SIZE(qi_lb60_keypad_rows),
|
||||||
|
.col_scan_delay_us = 10,
|
||||||
|
.debounce_ms = 10,
|
||||||
|
.wakeup = 1,
|
||||||
|
.active_low = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device qi_lb60_keypad = {
|
||||||
|
.name = "matrix-keypad",
|
||||||
|
.id = -1,
|
||||||
|
.dev = {
|
||||||
|
.platform_data = &qi_lb60_pdata,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* All */
|
||||||
|
static struct platform_device *jz_platform_devices[] __initdata = {
|
||||||
|
&jz_usb_ohci_device,
|
||||||
|
&jz_lcd_device,
|
||||||
|
&jz_usb_gdt_device,
|
||||||
|
&jz_mmc_device,
|
||||||
|
&jz_nand_device,
|
||||||
|
&jz_i2c_device,
|
||||||
|
&qi_lb60_keypad,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init jz_platform_init(void)
|
||||||
|
{
|
||||||
|
return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices));
|
||||||
|
}
|
||||||
|
|
||||||
|
arch_initcall(jz_platform_init);
|
410
target/linux/xburst/files-2.6.31/arch/mips/jz4740/pm.c
Normal file
410
target/linux/xburst/files-2.6.31/arch/mips/jz4740/pm.c
Normal file
@ -0,0 +1,410 @@
|
|||||||
|
/*
|
||||||
|
* linux/arch/mips/jz4740/common/pm.c
|
||||||
|
*
|
||||||
|
* JZ4740 Power Management Routines
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 Ingenic Semiconductor Inc.
|
||||||
|
* Author: <jlwei@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can distribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License (Version 2) as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/pm.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/proc_fs.h>
|
||||||
|
#include <linux/sysctl.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
|
#include <asm/cacheops.h>
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
#undef DEBUG
|
||||||
|
//#define DEBUG
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define dprintk(x...) printk(x)
|
||||||
|
#else
|
||||||
|
#define dprintk(x...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define GPIO_WAKEUP 125 /* set SW7(GPIO 125) as WAKEUP key */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* __gpio_as_sleep set all pins to pull-disable, and set all pins as input
|
||||||
|
* except sdram, nand flash pins and the pins which can be used as CS1_N
|
||||||
|
* to CS4_N for chip select.
|
||||||
|
*/
|
||||||
|
#define __gpio_as_sleep() \
|
||||||
|
do { \
|
||||||
|
REG_GPIO_PXFUNC(1) = ~0x9ff9ffff; \
|
||||||
|
REG_GPIO_PXSELC(1) = ~0x9ff9ffff; \
|
||||||
|
REG_GPIO_PXDIRC(1) = ~0x9ff9ffff; \
|
||||||
|
REG_GPIO_PXPES(1) = 0xffffffff; \
|
||||||
|
REG_GPIO_PXFUNC(2) = ~0x37000000; \
|
||||||
|
REG_GPIO_PXSELC(2) = ~0x37000000; \
|
||||||
|
REG_GPIO_PXDIRC(2) = ~0x37000000; \
|
||||||
|
REG_GPIO_PXPES(2) = 0xffffffff; \
|
||||||
|
REG_GPIO_PXFUNC(3) = 0xffffffff; \
|
||||||
|
REG_GPIO_PXSELC(3) = 0xffffffff; \
|
||||||
|
REG_GPIO_PXDIRC(3) = 0xffffffff; \
|
||||||
|
REG_GPIO_PXPES(3) = 0xffffffff; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static int jz_pm_do_hibernate(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
873
target/linux/xburst/files-2.6.31/arch/mips/jz4740/proc.c
Normal file
873
target/linux/xburst/files-2.6.31/arch/mips/jz4740/proc.c
Normal file
@ -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: <jlwei@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can distribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License (Version 2) as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/sysctl.h>
|
||||||
|
#include <linux/proc_fs.h>
|
||||||
|
#include <linux/page-flags.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/pgtable.h>
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
//#define DEBUG 1
|
||||||
|
#undef DEBUG
|
||||||
|
|
||||||
|
|
||||||
|
struct proc_dir_entry *proc_jz_root;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EMC Modules
|
||||||
|
*/
|
||||||
|
static int emc_read_proc (char *page, char **start, off_t off,
|
||||||
|
int count, int *eof, void *data)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4);
|
||||||
|
len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4);
|
||||||
|
len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR);
|
||||||
|
len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR);
|
||||||
|
len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Power Manager Module
|
||||||
|
*/
|
||||||
|
static int pmc_read_proc (char *page, char **start, off_t off,
|
||||||
|
int count, int *eof, void *data)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
unsigned long lcr = REG_CPM_LCR;
|
||||||
|
unsigned long clkgr = REG_CPM_CLKGR;
|
||||||
|
|
||||||
|
len += sprintf (page+len, "Low Power Mode : %s\n",
|
||||||
|
((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ?
|
||||||
|
"IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ?
|
||||||
|
"SLEEP" : "HIBERNATE"));
|
||||||
|
len += sprintf (page+len, "Doze Mode : %s\n",
|
||||||
|
(lcr & CPM_LCR_DOZE_ON) ? "on" : "off");
|
||||||
|
if (lcr & CPM_LCR_DOZE_ON)
|
||||||
|
len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT));
|
||||||
|
len += sprintf (page+len, "IPU : %s\n",
|
||||||
|
(clkgr & CPM_CLKGR_IPU) ? "stopped" : "running");
|
||||||
|
len += sprintf (page+len, "DMAC : %s\n",
|
||||||
|
(clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running");
|
||||||
|
len += sprintf (page+len, "UHC : %s\n",
|
||||||
|
(clkgr & CPM_CLKGR_UHC) ? "stopped" : "running");
|
||||||
|
len += sprintf (page+len, "UDC : %s\n",
|
||||||
|
(clkgr & CPM_CLKGR_UDC) ? "stopped" : "running");
|
||||||
|
len += sprintf (page+len, "LCD : %s\n",
|
||||||
|
(clkgr & CPM_CLKGR_LCD) ? "stopped" : "running");
|
||||||
|
len += sprintf (page+len, "CIM : %s\n",
|
||||||
|
(clkgr & CPM_CLKGR_CIM) ? "stopped" : "running");
|
||||||
|
len += sprintf (page+len, "SADC : %s\n",
|
||||||
|
(clkgr & CPM_CLKGR_SADC) ? "stopped" : "running");
|
||||||
|
len += sprintf (page+len, "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<<page_shift); i++) {
|
||||||
|
SetPageReserved(virt_to_page(virt_addr));
|
||||||
|
virt_addr += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printk("get memory Failed.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ipu_buf_free( unsigned int phys_addr )
|
||||||
|
{
|
||||||
|
unsigned char * virt_addr, *addr;
|
||||||
|
int cnt, i;
|
||||||
|
|
||||||
|
if ( phys_addr == 0 )
|
||||||
|
return ;
|
||||||
|
|
||||||
|
for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt )
|
||||||
|
if ( phys_addr == ipu_buf[cnt].addr )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ( cnt == IPU_BUF_MAX ) { /* addr not in the ipu buffers */
|
||||||
|
printk("Invalid addr:0x%08x\n", (unsigned int)phys_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
virt_addr = (unsigned char *)phys_to_virt(ipu_buf[cnt].addr);
|
||||||
|
addr = virt_addr;
|
||||||
|
for (i = 0; i < (1<<ipu_buf[cnt].page_shift); i++) {
|
||||||
|
ClearPageReserved(virt_to_page(addr));
|
||||||
|
addr += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( cnt == 0 )
|
||||||
|
ipu_del_wired_entry();
|
||||||
|
|
||||||
|
free_pages((unsigned long )virt_addr, ipu_buf[cnt].page_shift);
|
||||||
|
|
||||||
|
ipu_buf[cnt].addr = 0;
|
||||||
|
ipu_buf[cnt].page_shift = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ipu_read_proc (char *page, char **start, off_t off,
|
||||||
|
int count, int *eof, void *data)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
/* read as binary */
|
||||||
|
unsigned int * pint;
|
||||||
|
pint = (unsigned int *) (page+len);
|
||||||
|
|
||||||
|
if ( ipu_buf_cnt >= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */
|
||||||
|
printk("no free buffer.\n");
|
||||||
|
*pint = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */
|
||||||
|
len += sizeof(unsigned int);
|
||||||
|
|
||||||
|
#if defined(DEBUG)
|
||||||
|
show_tlb();
|
||||||
|
#endif
|
||||||
|
return len;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
|
||||||
|
{
|
||||||
|
unsigned int val ;
|
||||||
|
int cnt,i;
|
||||||
|
char buf[12];
|
||||||
|
unsigned long pid, entrylo0, entrylo1, entryhi, pagemask;
|
||||||
|
#if defined(DEBUG)
|
||||||
|
printk("ipu write count=%u\n", count);
|
||||||
|
#endif
|
||||||
|
if (count == (8*5+1)) {
|
||||||
|
for (i=0;i<12;i++) buf[i]=0;
|
||||||
|
strncpy(buf, buffer+8*0, 8);
|
||||||
|
pid = simple_strtoul(buf, 0, 16);
|
||||||
|
for (i=0;i<12;i++) buf[i]=0;
|
||||||
|
strncpy(buf, buffer+8*1, 8);
|
||||||
|
entrylo0 = simple_strtoul(buf, 0, 16);
|
||||||
|
for (i=0;i<12;i++) buf[i]=0;
|
||||||
|
strncpy(buf, buffer+8*2, 8);
|
||||||
|
entrylo1 = simple_strtoul(buf, 0, 16);
|
||||||
|
for (i=0;i<12;i++) buf[i]=0;
|
||||||
|
strncpy(buf, buffer+8*3, 8);
|
||||||
|
entryhi = simple_strtoul(buf, 0, 16);
|
||||||
|
for (i=0;i<12;i++) buf[i]=0;
|
||||||
|
strncpy(buf, buffer+8*4, 8);
|
||||||
|
pagemask = simple_strtoul(buf, 0, 16);
|
||||||
|
|
||||||
|
#if defined(DEBUG)
|
||||||
|
printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n",
|
||||||
|
pid, entrylo0, entrylo1, entryhi, pagemask);
|
||||||
|
#endif
|
||||||
|
ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask);
|
||||||
|
return 41;
|
||||||
|
} else if ( count <= 8+1 ) {
|
||||||
|
for (i=0;i<12;i++) buf[i]=0;
|
||||||
|
strncpy(buf, buffer, 8);
|
||||||
|
val = simple_strtoul(buf, 0, 16);
|
||||||
|
} else if (count == 44) {
|
||||||
|
for (i = 0; i < 12; i++)
|
||||||
|
buf[i] = 0;
|
||||||
|
strncpy(buf, buffer, 10);
|
||||||
|
pid = simple_strtoul(buf, 0, 16);
|
||||||
|
for (i = 0; i < 12; i++)
|
||||||
|
buf[i] = 0;
|
||||||
|
strncpy(buf, buffer + 11, 10);
|
||||||
|
entryhi = simple_strtoul(buf, 0, 16);//vaddr
|
||||||
|
for (i = 0; i < 12; i++)
|
||||||
|
buf[i] = 0;
|
||||||
|
strncpy(buf, buffer + 22, 10);
|
||||||
|
entrylo0 = simple_strtoul(buf, 0, 16);//paddr
|
||||||
|
for (i = 0; i < 12; i++)
|
||||||
|
buf[i] = 0;
|
||||||
|
strncpy(buf, buffer + 33, 10);
|
||||||
|
pagemask = simple_strtoul(buf, 0, 16);
|
||||||
|
pagemask = 0x3ff << 13; /* Fixed to 4MB page size */
|
||||||
|
ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask);
|
||||||
|
return 44;
|
||||||
|
} else {
|
||||||
|
printk("ipu write count error, count=%d\n.", (unsigned int)count);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* val: 1-9, page_shift, val>= 10: ipu_buf.addr */
|
||||||
|
if ( val == 0 ) { /* debug, print ipu_buf info */
|
||||||
|
for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt)
|
||||||
|
printk("ipu_buf[%d]: addr=0x%08x, page_shift=%d\n",
|
||||||
|
cnt, ipu_buf[cnt].addr, ipu_buf[cnt].page_shift );
|
||||||
|
#if defined(DEBUG)
|
||||||
|
show_tlb();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if ( 0< val && val < 10 ) {
|
||||||
|
ipu_buf_get(val);
|
||||||
|
}
|
||||||
|
else if ( val == 0xff ) { /* 255: free all ipu_buf */
|
||||||
|
for ( cnt=0; cnt<IPU_BUF_MAX; ++cnt ) {
|
||||||
|
ipu_buf_free(ipu_buf[cnt].addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ipu_buf_free(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UDC hotplug
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_JZ_UDC_HOTPLUG
|
||||||
|
extern int jz_udc_active; /* defined in drivers/char/jzchar/jz_udc_hotplug.c */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GPIO_UDC_HOTPLUG
|
||||||
|
#define GPIO_UDC_HOTPLUG 86
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int udc_read_proc(char *page, char **start, off_t off,
|
||||||
|
int count, int *eof, void *data)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (__gpio_get_pin(GPIO_UDC_HOTPLUG)) {
|
||||||
|
|
||||||
|
#ifdef CONFIG_JZ_UDC_HOTPLUG
|
||||||
|
|
||||||
|
/* Cable has connected, wait for disconnection. */
|
||||||
|
__gpio_as_irq_fall_edge(GPIO_UDC_HOTPLUG);
|
||||||
|
|
||||||
|
if (jz_udc_active)
|
||||||
|
len += sprintf (page+len, "CONNECT_CABLE\n");
|
||||||
|
else
|
||||||
|
len += sprintf (page+len, "CONNECT_POWER\n");
|
||||||
|
#else
|
||||||
|
len += sprintf (page+len, "CONNECT\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
#ifdef CONFIG_JZ_UDC_HOTPLUG
|
||||||
|
/* Cable has disconnected, wait for connection. */
|
||||||
|
__gpio_as_irq_rise_edge(GPIO_UDC_HOTPLUG);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
len += sprintf (page+len, "REMOVE\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MMC/SD hotplug
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MSC_HOTPLUG_PIN
|
||||||
|
#define MSC_HOTPLUG_PIN 90
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int mmc_read_proc (char *page, char **start, off_t off,
|
||||||
|
int count, int *eof, void *data)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZ4740_LYRA)
|
||||||
|
if (!(__gpio_get_pin(MSC_HOTPLUG_PIN)))
|
||||||
|
#else
|
||||||
|
if (__gpio_get_pin(MSC_HOTPLUG_PIN))
|
||||||
|
#endif
|
||||||
|
len += sprintf (page+len, "REMOVE\n");
|
||||||
|
else
|
||||||
|
len += sprintf (page+len, "INSERT\n");
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* IPU memory management (used by mplayer and other apps)
|
||||||
|
*
|
||||||
|
* We reserved 4MB memory for IPU
|
||||||
|
* The memory base address is jz_ipu_framebuf
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Usage:
|
||||||
|
*
|
||||||
|
* echo n > /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages
|
||||||
|
* echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx
|
||||||
|
* echo FF > /proc/jz/ipu // FF, free all buffers
|
||||||
|
* od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#define DEBUG_IMEM 1
|
||||||
|
|
||||||
|
#define IMEM_MAX_ORDER 10 /* max 2^10 * 4096 = 4MB */
|
||||||
|
|
||||||
|
static unsigned int jz_imem_base; /* physical base address of ipu memory */
|
||||||
|
|
||||||
|
static unsigned int allocated_phys_addr = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocated buffer list
|
||||||
|
*/
|
||||||
|
typedef struct imem_list {
|
||||||
|
unsigned int phys_start; /* physical start addr */
|
||||||
|
unsigned int phys_end; /* physical end addr */
|
||||||
|
struct imem_list *next;
|
||||||
|
} imem_list_t;
|
||||||
|
|
||||||
|
static struct imem_list *imem_list_head = NULL; /* up sorted by phys_start */
|
||||||
|
|
||||||
|
#ifdef DEBUG_IMEM
|
||||||
|
static void dump_imem_list(void)
|
||||||
|
{
|
||||||
|
struct imem_list *imem;
|
||||||
|
|
||||||
|
printk("*** dump_imem_list 0x%x ***\n", (u32)imem_list_head);
|
||||||
|
imem = imem_list_head;
|
||||||
|
while (imem) {
|
||||||
|
printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next);
|
||||||
|
imem = imem->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* allocate 2^order pages inside the 4MB memory */
|
||||||
|
static int imem_alloc(unsigned int order)
|
||||||
|
{
|
||||||
|
int alloc_ok = 0;
|
||||||
|
unsigned int start, end;
|
||||||
|
unsigned int size = (1 << order) * PAGE_SIZE;
|
||||||
|
struct imem_list *imem, *imemn, *imemp;
|
||||||
|
|
||||||
|
allocated_phys_addr = 0;
|
||||||
|
|
||||||
|
start = jz_imem_base;
|
||||||
|
end = start + (1 << IMEM_MAX_ORDER) * PAGE_SIZE;
|
||||||
|
|
||||||
|
imem = imem_list_head;
|
||||||
|
while (imem) {
|
||||||
|
if ((imem->phys_start - start) >= size) {
|
||||||
|
/* we got a valid address range */
|
||||||
|
alloc_ok = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = imem->phys_end + 1;
|
||||||
|
imem = imem->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!alloc_ok) {
|
||||||
|
if ((end - start) >= size)
|
||||||
|
alloc_ok = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alloc_ok) {
|
||||||
|
end = start + size - 1;
|
||||||
|
allocated_phys_addr = start;
|
||||||
|
|
||||||
|
/* add to imem_list, up sorted by phys_start */
|
||||||
|
imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL);
|
||||||
|
if (!imemn) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
imemn->phys_start = start;
|
||||||
|
imemn->phys_end = end;
|
||||||
|
imemn->next = NULL;
|
||||||
|
|
||||||
|
if (!imem_list_head)
|
||||||
|
imem_list_head = imemn;
|
||||||
|
else {
|
||||||
|
imem = imemp = imem_list_head;
|
||||||
|
while (imem) {
|
||||||
|
if (start < imem->phys_start) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
imemp = imem;
|
||||||
|
imem = imem->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imem == imem_list_head) {
|
||||||
|
imem_list_head = imemn;
|
||||||
|
imemn->next = imem;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
imemn->next = imemp->next;
|
||||||
|
imemp->next = imemn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_IMEM
|
||||||
|
dump_imem_list();
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void imem_free(unsigned int phys_addr)
|
||||||
|
{
|
||||||
|
struct imem_list *imem, *imemp;
|
||||||
|
|
||||||
|
imem = imemp = imem_list_head;
|
||||||
|
while (imem) {
|
||||||
|
if (phys_addr == imem->phys_start) {
|
||||||
|
if (imem == imem_list_head) {
|
||||||
|
imem_list_head = imem->next;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
imemp->next = imem->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(imem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
imemp = imem;
|
||||||
|
imem = imem->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_IMEM
|
||||||
|
dump_imem_list();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void imem_free_all(void)
|
||||||
|
{
|
||||||
|
struct imem_list *imem;
|
||||||
|
|
||||||
|
imem = imem_list_head;
|
||||||
|
while (imem) {
|
||||||
|
kfree(imem);
|
||||||
|
imem = imem->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
imem_list_head = NULL;
|
||||||
|
|
||||||
|
allocated_phys_addr = 0;
|
||||||
|
|
||||||
|
#ifdef DEBUG_IMEM
|
||||||
|
dump_imem_list();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the allocated buffer address and the max order of free buffer
|
||||||
|
*/
|
||||||
|
static int imem_read_proc(char *page, char **start, off_t off,
|
||||||
|
int count, int *eof, void *data)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
unsigned int start_addr, end_addr, max_order, max_size;
|
||||||
|
struct imem_list *imem;
|
||||||
|
|
||||||
|
unsigned int *tmp = (unsigned int *)(page + len);
|
||||||
|
|
||||||
|
start_addr = jz_imem_base;
|
||||||
|
end_addr = start_addr + (1 << IMEM_MAX_ORDER) * PAGE_SIZE;
|
||||||
|
|
||||||
|
if (!imem_list_head)
|
||||||
|
max_size = end_addr - start_addr;
|
||||||
|
else {
|
||||||
|
max_size = 0;
|
||||||
|
imem = imem_list_head;
|
||||||
|
while (imem) {
|
||||||
|
if (max_size < (imem->phys_start - start_addr))
|
||||||
|
max_size = imem->phys_start - start_addr;
|
||||||
|
|
||||||
|
start_addr = imem->phys_end + 1;
|
||||||
|
imem = imem->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_size < (end_addr - start_addr))
|
||||||
|
max_size = end_addr - start_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_size > 0) {
|
||||||
|
max_order = get_order(max_size);
|
||||||
|
if (((1 << max_order) * PAGE_SIZE) > max_size)
|
||||||
|
max_order--;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
max_order = 0xffffffff; /* No any free buffer */
|
||||||
|
}
|
||||||
|
|
||||||
|
*tmp++ = allocated_phys_addr; /* address allocated by 'echo n > /proc/jz/imem' */
|
||||||
|
*tmp = max_order; /* max order of current free buffers */
|
||||||
|
|
||||||
|
len += 2 * sizeof(unsigned int);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imem_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
|
||||||
|
{
|
||||||
|
unsigned int val;
|
||||||
|
|
||||||
|
val = simple_strtoul(buffer, 0, 16);
|
||||||
|
|
||||||
|
if (val == 0xff) {
|
||||||
|
/* free all memory */
|
||||||
|
imem_free_all();
|
||||||
|
ipu_del_wired_entry();
|
||||||
|
}
|
||||||
|
else if ((val >= 0) && (val <= IMEM_MAX_ORDER)) {
|
||||||
|
/* allocate 2^val pages */
|
||||||
|
imem_alloc(val);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* free buffer which phys_addr is val */
|
||||||
|
imem_free(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* /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);
|
198
target/linux/xburst/files-2.6.31/arch/mips/jz4740/prom.c
Normal file
198
target/linux/xburst/files-2.6.31/arch/mips/jz4740/prom.c
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* BRIEF MODULE DESCRIPTION
|
||||||
|
* PROM library initialisation code, supports YAMON and U-Boot.
|
||||||
|
*
|
||||||
|
* Copyright 2000, 2001, 2006 MontaVista Software Inc.
|
||||||
|
* Author: MontaVista Software, Inc.
|
||||||
|
* ppopov@mvista.com or source@mvista.com
|
||||||
|
*
|
||||||
|
* This file was derived from Carsten Langgaard's
|
||||||
|
* arch/mips/mips-boards/xx files.
|
||||||
|
*
|
||||||
|
* Carsten Langgaard, carstenl@mips.com
|
||||||
|
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||||
|
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
|
||||||
|
#include <asm/bootinfo.h>
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
/* #define DEBUG_CMDLINE */
|
||||||
|
|
||||||
|
int prom_argc;
|
||||||
|
char **prom_argv, **prom_envp;
|
||||||
|
|
||||||
|
char * prom_getcmdline(void)
|
||||||
|
{
|
||||||
|
return &(arcs_cmdline[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void prom_init_cmdline(void)
|
||||||
|
{
|
||||||
|
char *cp;
|
||||||
|
int actr;
|
||||||
|
|
||||||
|
actr = 1; /* Always ignore argv[0] */
|
||||||
|
|
||||||
|
cp = &(arcs_cmdline[0]);
|
||||||
|
while(actr < prom_argc) {
|
||||||
|
strcpy(cp, prom_argv[actr]);
|
||||||
|
cp += strlen(prom_argv[actr]);
|
||||||
|
*cp++ = ' ';
|
||||||
|
actr++;
|
||||||
|
}
|
||||||
|
if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
|
||||||
|
--cp;
|
||||||
|
if (prom_argc > 1)
|
||||||
|
*cp = '\0';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *prom_getenv(char *envname)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* Return a pointer to the given environment variable.
|
||||||
|
* YAMON uses "name", "value" pairs, while U-Boot uses "name=value".
|
||||||
|
*/
|
||||||
|
|
||||||
|
char **env = prom_envp;
|
||||||
|
int i = strlen(envname);
|
||||||
|
int yamon = (*env && strchr(*env, '=') == NULL);
|
||||||
|
|
||||||
|
while (*env) {
|
||||||
|
if (yamon) {
|
||||||
|
if (strcmp(envname, *env++) == 0)
|
||||||
|
return *env;
|
||||||
|
} else {
|
||||||
|
if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
|
||||||
|
return *env + i + 1;
|
||||||
|
}
|
||||||
|
env++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned char str2hexnum(unsigned char c)
|
||||||
|
{
|
||||||
|
if(c >= '0' && c <= '9')
|
||||||
|
return c - '0';
|
||||||
|
if(c >= 'a' && c <= 'f')
|
||||||
|
return c - 'a' + 10;
|
||||||
|
if(c >= 'A' && c <= 'F')
|
||||||
|
return c - 'A' + 10;
|
||||||
|
return 0; /* foo */
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void str2eaddr(unsigned char *ea, unsigned char *str)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < 6; i++) {
|
||||||
|
unsigned char num;
|
||||||
|
|
||||||
|
if((*str == '.') || (*str == ':'))
|
||||||
|
str++;
|
||||||
|
num = str2hexnum(*str++) << 4;
|
||||||
|
num |= (str2hexnum(*str++));
|
||||||
|
ea[i] = num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_ethernet_addr(char *ethernet_addr)
|
||||||
|
{
|
||||||
|
char *ethaddr_str;
|
||||||
|
|
||||||
|
ethaddr_str = prom_getenv("ethaddr");
|
||||||
|
if (!ethaddr_str) {
|
||||||
|
printk("ethaddr not set in boot prom\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
str2eaddr(ethernet_addr, ethaddr_str);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
printk("get_ethernet_addr: ");
|
||||||
|
for (i=0; i<5; i++)
|
||||||
|
printk("%02x:", (unsigned char)*(ethernet_addr+i));
|
||||||
|
printk("%02x\n", *(ethernet_addr+i));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init prom_free_prom_memory(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init prom_init(void)
|
||||||
|
{
|
||||||
|
unsigned char *memsize_str;
|
||||||
|
unsigned long memsize;
|
||||||
|
|
||||||
|
prom_argc = (int) fw_arg0;
|
||||||
|
prom_argv = (char **) fw_arg1;
|
||||||
|
prom_envp = (char **) fw_arg2;
|
||||||
|
|
||||||
|
mips_machtype = MACH_INGENIC_JZ4740;
|
||||||
|
|
||||||
|
prom_init_cmdline();
|
||||||
|
memsize_str = prom_getenv("memsize");
|
||||||
|
if (!memsize_str) {
|
||||||
|
memsize = 0x04000000;
|
||||||
|
} else {
|
||||||
|
memsize = simple_strtol(memsize_str, NULL, 0);
|
||||||
|
}
|
||||||
|
add_memory_region(0, memsize, BOOT_MEM_RAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* used by early printk */
|
||||||
|
void prom_putchar(char c)
|
||||||
|
{
|
||||||
|
volatile u8 *uart_lsr = (volatile u8 *)(UART0_BASE + OFF_LSR);
|
||||||
|
volatile u8 *uart_tdr = (volatile u8 *)(UART0_BASE + OFF_TDR);
|
||||||
|
|
||||||
|
/* Wait for fifo to shift out some bytes */
|
||||||
|
while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) );
|
||||||
|
|
||||||
|
*uart_tdr = (u8)c;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *get_system_type(void)
|
||||||
|
{
|
||||||
|
return "JZ4740";
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(prom_getcmdline);
|
||||||
|
EXPORT_SYMBOL(get_ethernet_addr);
|
||||||
|
EXPORT_SYMBOL(str2eaddr);
|
46
target/linux/xburst/files-2.6.31/arch/mips/jz4740/reset.c
Normal file
46
target/linux/xburst/files-2.6.31/arch/mips/jz4740/reset.c
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* linux/arch/mips/jz4740/reset.c
|
||||||
|
*
|
||||||
|
* JZ4740 reset routines.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006-2007 Ingenic Semiconductor Inc.
|
||||||
|
* Author: <yliu@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <asm/pgtable.h>
|
||||||
|
#include <asm/processor.h>
|
||||||
|
#include <asm/reboot.h>
|
||||||
|
#include <asm/system.h>
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
void jz_restart(char *command)
|
||||||
|
{
|
||||||
|
printk("Restarting after 4 ms\n");
|
||||||
|
REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN;
|
||||||
|
REG_WDT_TCNT = 0;
|
||||||
|
REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */
|
||||||
|
REG_TCU_TSCR = TCU_TSSR_WDTSC; /* enable wdt clock */
|
||||||
|
REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jz_halt(void)
|
||||||
|
{
|
||||||
|
printk(KERN_NOTICE "\n** You can safely turn off the power\n");
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
__asm__(".set\tmips3\n\t"
|
||||||
|
"wait\n\t"
|
||||||
|
".set\tmips0");
|
||||||
|
}
|
||||||
|
|
||||||
|
void jz_power_off(void)
|
||||||
|
{
|
||||||
|
jz_halt();
|
||||||
|
}
|
188
target/linux/xburst/files-2.6.31/arch/mips/jz4740/setup.c
Normal file
188
target/linux/xburst/files-2.6.31/arch/mips/jz4740/setup.c
Normal file
@ -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 <linux/init.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/tty.h>
|
||||||
|
#include <linux/serial.h>
|
||||||
|
#include <linux/serial_core.h>
|
||||||
|
#include <linux/serial_8250.h>
|
||||||
|
|
||||||
|
#include <asm/cpu.h>
|
||||||
|
#include <asm/bootinfo.h>
|
||||||
|
#include <asm/irq.h>
|
||||||
|
#include <asm/mipsregs.h>
|
||||||
|
#include <asm/reboot.h>
|
||||||
|
#include <asm/pgtable.h>
|
||||||
|
#include <asm/time.h>
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
#include <asm/suspend.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_PC_KEYB
|
||||||
|
#include <asm/keyboard.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
jz_clocks_t jz_clocks;
|
||||||
|
|
||||||
|
extern char * __init prom_getcmdline(void);
|
||||||
|
extern void __init jz_board_setup(void);
|
||||||
|
extern void jz_restart(char *);
|
||||||
|
extern void jz_halt(void);
|
||||||
|
extern void jz_power_off(void);
|
||||||
|
extern void jz_time_init(void);
|
||||||
|
|
||||||
|
static void __init sysclocks_setup(void)
|
||||||
|
{
|
||||||
|
#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */
|
||||||
|
jz_clocks.cclk = __cpm_get_cclk();
|
||||||
|
jz_clocks.hclk = __cpm_get_hclk();
|
||||||
|
jz_clocks.pclk = __cpm_get_pclk();
|
||||||
|
jz_clocks.mclk = __cpm_get_mclk();
|
||||||
|
jz_clocks.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();
|
||||||
|
}
|
||||||
|
|
159
target/linux/xburst/files-2.6.31/arch/mips/jz4740/time.c
Normal file
159
target/linux/xburst/files-2.6.31/arch/mips/jz4740/time.c
Normal file
@ -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: <jlwei@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can distribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License (Version 2) as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/time.h>
|
||||||
|
#include <linux/clockchips.h>
|
||||||
|
|
||||||
|
#include <asm/time.h>
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
/* This is for machines which generate the exact clock. */
|
||||||
|
|
||||||
|
#define JZ_TIMER_CHAN 0
|
||||||
|
#define JZ_TIMER_IRQ IRQ_TCU0
|
||||||
|
|
||||||
|
#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */
|
||||||
|
|
||||||
|
static struct clocksource clocksource_jz; /* Jz clock source */
|
||||||
|
static struct clock_event_device jz_clockevent_device; /* Jz clock event */
|
||||||
|
|
||||||
|
void (*jz_timer_callback)(void);
|
||||||
|
|
||||||
|
static irqreturn_t jz_timer_interrupt(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct clock_event_device *cd = dev_id;
|
||||||
|
|
||||||
|
REG_TCU_TFCR = 1 << JZ_TIMER_CHAN; /* ACK timer */
|
||||||
|
|
||||||
|
if (jz_timer_callback)
|
||||||
|
jz_timer_callback();
|
||||||
|
|
||||||
|
cd->event_handler(cd);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct irqaction jz_irqaction = {
|
||||||
|
.handler = jz_timer_interrupt,
|
||||||
|
.flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
|
||||||
|
.name = "jz-timerirq",
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
cycle_t jz_get_cycles(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);
|
||||||
|
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();
|
||||||
|
}
|
995
target/linux/xburst/files-2.6.31/drivers/mmc/host/jz_mmc.c
Executable file
995
target/linux/xburst/files-2.6.31/drivers/mmc/host/jz_mmc.c
Executable file
@ -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 <linux/dma-mapping.h>
|
||||||
|
#include <linux/mmc/host.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/mmc/host.h>
|
||||||
|
#include <linux/mmc/mmc.h>
|
||||||
|
#include <linux/mmc/sd.h>
|
||||||
|
#include <linux/mmc/sdio.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/signal.h>
|
||||||
|
#include <linux/pm.h>
|
||||||
|
#include <linux/scatterlist.h>
|
||||||
|
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <asm/scatterlist.h>
|
||||||
|
#include <asm/sizes.h>
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
#include "jz_mmc.h"
|
||||||
|
|
||||||
|
#define DRIVER_NAME "jz-mmc"
|
||||||
|
|
||||||
|
#define NR_SG 1
|
||||||
|
|
||||||
|
#if defined(CONFIG_SOC_JZ4725) || defined(CONFIG_SOC_JZ4720)
|
||||||
|
#undef USE_DMA
|
||||||
|
#else
|
||||||
|
#define USE_DMA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct jz_mmc_host {
|
||||||
|
struct mmc_host *mmc;
|
||||||
|
spinlock_t lock;
|
||||||
|
struct {
|
||||||
|
int len;
|
||||||
|
int dir;
|
||||||
|
} dma;
|
||||||
|
struct {
|
||||||
|
int index;
|
||||||
|
int offset;
|
||||||
|
int len;
|
||||||
|
} pio;
|
||||||
|
int irq;
|
||||||
|
unsigned int clkrt;
|
||||||
|
unsigned int cmdat;
|
||||||
|
unsigned int imask;
|
||||||
|
unsigned int power_mode;
|
||||||
|
struct jz_mmc_platform_data *pdata;
|
||||||
|
struct mmc_request *mrq;
|
||||||
|
struct mmc_command *cmd;
|
||||||
|
struct mmc_data *data;
|
||||||
|
dma_addr_t sg_dma;
|
||||||
|
struct jzsoc_dma_desc *sg_cpu;
|
||||||
|
unsigned int dma_len;
|
||||||
|
unsigned int dma_dir;
|
||||||
|
struct pm_dev *pmdev;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int r_type = 0;
|
||||||
|
|
||||||
|
#define MMC_IRQ_MASK() \
|
||||||
|
do { \
|
||||||
|
REG_MSC_IMASK = 0xff; \
|
||||||
|
REG_MSC_IREG = 0xff; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static int rxdmachan = 0;
|
||||||
|
static int txdmachan = 0;
|
||||||
|
static int mmc_slot_enable = 0;
|
||||||
|
|
||||||
|
/* Stop the MMC clock and wait while it happens */
|
||||||
|
static inline int jz_mmc_stop_clock(void)
|
||||||
|
{
|
||||||
|
int timeout = 1000;
|
||||||
|
|
||||||
|
REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP;
|
||||||
|
while (timeout && (REG_MSC_STAT & MSC_STAT_CLK_EN)) {
|
||||||
|
timeout--;
|
||||||
|
if (timeout == 0)
|
||||||
|
return 0;
|
||||||
|
udelay(1);
|
||||||
|
}
|
||||||
|
return MMC_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start the MMC clock and operation */
|
||||||
|
static inline int jz_mmc_start_clock(void)
|
||||||
|
{
|
||||||
|
REG_MSC_STRPCL =
|
||||||
|
MSC_STRPCL_CLOCK_CONTROL_START | MSC_STRPCL_START_OP;
|
||||||
|
return MMC_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 jz_mmc_calc_clkrt(int is_sd, u32 rate)
|
||||||
|
{
|
||||||
|
u32 clkrt;
|
||||||
|
u32 clk_src = is_sd ? 24000000 : 20000000;
|
||||||
|
|
||||||
|
clkrt = 0;
|
||||||
|
while (rate < clk_src) {
|
||||||
|
clkrt++;
|
||||||
|
clk_src >>= 1;
|
||||||
|
}
|
||||||
|
return clkrt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select the MMC clock frequency */
|
||||||
|
static int jz_mmc_set_clock(u32 rate)
|
||||||
|
{
|
||||||
|
int clkrt;
|
||||||
|
|
||||||
|
jz_mmc_stop_clock();
|
||||||
|
__cpm_select_msc_clk(1); /* select clock source from CPM */
|
||||||
|
clkrt = jz_mmc_calc_clkrt(1, rate);
|
||||||
|
REG_MSC_CLKRT = clkrt;
|
||||||
|
return MMC_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_mmc_enable_irq(struct jz_mmc_host *host, unsigned int mask)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
spin_lock_irqsave(&host->lock, flags);
|
||||||
|
host->imask &= ~mask;
|
||||||
|
REG_MSC_IMASK = host->imask;
|
||||||
|
spin_unlock_irqrestore(&host->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_mmc_disable_irq(struct jz_mmc_host *host, unsigned int mask)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&host->lock, flags);
|
||||||
|
host->imask |= mask;
|
||||||
|
REG_MSC_IMASK = host->imask;
|
||||||
|
spin_unlock_irqrestore(&host->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jz_set_dma_block_size(int dmanr, int nbyte);
|
||||||
|
|
||||||
|
#ifdef USE_DMA
|
||||||
|
static inline void
|
||||||
|
jz_mmc_start_dma(int chan, unsigned long phyaddr, int count, int mode)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
flags = claim_dma_lock();
|
||||||
|
disable_dma(chan);
|
||||||
|
clear_dma_ff(chan);
|
||||||
|
jz_set_dma_block_size(chan, 32);
|
||||||
|
set_dma_mode(chan, mode);
|
||||||
|
set_dma_addr(chan, phyaddr);
|
||||||
|
set_dma_count(chan, count + 31);
|
||||||
|
enable_dma(chan);
|
||||||
|
release_dma_lock(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t jz_mmc_dma_rx_callback(int irq, void *devid)
|
||||||
|
{
|
||||||
|
int chan = rxdmachan;
|
||||||
|
|
||||||
|
disable_dma(chan);
|
||||||
|
if (__dmac_channel_address_error_detected(chan)) {
|
||||||
|
printk(KERN_DEBUG "%s: DMAC address error.\n",
|
||||||
|
__FUNCTION__);
|
||||||
|
__dmac_channel_clear_address_error(chan);
|
||||||
|
}
|
||||||
|
if (__dmac_channel_transmit_end_detected(chan)) {
|
||||||
|
__dmac_channel_clear_transmit_end(chan);
|
||||||
|
}
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
static irqreturn_t jz_mmc_dma_tx_callback(int irq, void *devid)
|
||||||
|
{
|
||||||
|
int chan = txdmachan;
|
||||||
|
|
||||||
|
disable_dma(chan);
|
||||||
|
if (__dmac_channel_address_error_detected(chan)) {
|
||||||
|
printk(KERN_DEBUG "%s: DMAC address error.\n",
|
||||||
|
__FUNCTION__);
|
||||||
|
__dmac_channel_clear_address_error(chan);
|
||||||
|
}
|
||||||
|
if (__dmac_channel_transmit_end_detected(chan)) {
|
||||||
|
__dmac_channel_clear_transmit_end(chan);
|
||||||
|
}
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare DMA to start data transfer from the MMC card */
|
||||||
|
static void jz_mmc_rx_setup_data(struct jz_mmc_host *host,
|
||||||
|
struct mmc_data *data)
|
||||||
|
{
|
||||||
|
unsigned int nob = data->blocks;
|
||||||
|
int channelrx = rxdmachan;
|
||||||
|
int i;
|
||||||
|
u32 size;
|
||||||
|
|
||||||
|
if (data->flags & MMC_DATA_STREAM)
|
||||||
|
nob = 0xffff;
|
||||||
|
|
||||||
|
REG_MSC_NOB = nob;
|
||||||
|
REG_MSC_BLKLEN = data->blksz;
|
||||||
|
size = nob * data->blksz;
|
||||||
|
|
||||||
|
if (data->flags & MMC_DATA_READ) {
|
||||||
|
host->dma.dir = DMA_FROM_DEVICE;
|
||||||
|
} else {
|
||||||
|
host->dma.dir = DMA_TO_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
host->dma.len =
|
||||||
|
dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
|
||||||
|
host->dma.dir);
|
||||||
|
|
||||||
|
for (i = 0; i < host->dma.len; i++) {
|
||||||
|
host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
|
||||||
|
host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]);
|
||||||
|
dma_cache_wback_inv((unsigned long)
|
||||||
|
CKSEG0ADDR(sg_dma_address(data->sg)) +
|
||||||
|
data->sg->offset,
|
||||||
|
host->sg_cpu[i].dcmd);
|
||||||
|
jz_mmc_start_dma(channelrx, host->sg_cpu[i].dtadr,
|
||||||
|
host->sg_cpu[i].dcmd, DMA_MODE_READ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare DMA to start data transfer from the MMC card */
|
||||||
|
static void jz_mmc_tx_setup_data(struct jz_mmc_host *host,
|
||||||
|
struct mmc_data *data)
|
||||||
|
{
|
||||||
|
unsigned int nob = data->blocks;
|
||||||
|
int channeltx = txdmachan;
|
||||||
|
int i;
|
||||||
|
u32 size;
|
||||||
|
|
||||||
|
if (data->flags & MMC_DATA_STREAM)
|
||||||
|
nob = 0xffff;
|
||||||
|
|
||||||
|
REG_MSC_NOB = nob;
|
||||||
|
REG_MSC_BLKLEN = data->blksz;
|
||||||
|
size = nob * data->blksz;
|
||||||
|
|
||||||
|
if (data->flags & MMC_DATA_READ) {
|
||||||
|
host->dma.dir = DMA_FROM_DEVICE;
|
||||||
|
} else {
|
||||||
|
host->dma.dir = DMA_TO_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
host->dma.len =
|
||||||
|
dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
|
||||||
|
host->dma.dir);
|
||||||
|
|
||||||
|
for (i = 0; i < host->dma.len; i++) {
|
||||||
|
host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
|
||||||
|
host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]);
|
||||||
|
dma_cache_wback_inv((unsigned long)
|
||||||
|
CKSEG0ADDR(sg_dma_address(data->sg)) +
|
||||||
|
data->sg->offset,
|
||||||
|
host->sg_cpu[i].dcmd);
|
||||||
|
jz_mmc_start_dma(channeltx, host->sg_cpu[i].dtadr,
|
||||||
|
host->sg_cpu[i].dcmd, DMA_MODE_WRITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void jz_mmc_receive_pio(struct jz_mmc_host *host)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct mmc_data *data = 0;
|
||||||
|
int sg_len = 0, max = 0, count = 0;
|
||||||
|
u32 *buf = 0;
|
||||||
|
struct scatterlist *sg;
|
||||||
|
unsigned int nob;
|
||||||
|
|
||||||
|
data = host->mrq->data;
|
||||||
|
nob = data->blocks;
|
||||||
|
REG_MSC_NOB = nob;
|
||||||
|
REG_MSC_BLKLEN = data->blksz;
|
||||||
|
|
||||||
|
max = host->pio.len;
|
||||||
|
if (host->pio.index < host->dma.len) {
|
||||||
|
sg = &data->sg[host->pio.index];
|
||||||
|
buf = sg_virt(sg) + host->pio.offset;
|
||||||
|
|
||||||
|
/* This is the space left inside the buffer */
|
||||||
|
sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
|
||||||
|
/* Check to if we need less then the size of the sg_buffer */
|
||||||
|
if (sg_len < max) max = sg_len;
|
||||||
|
}
|
||||||
|
max = max / 4;
|
||||||
|
for(count = 0; count < max; count++) {
|
||||||
|
while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY)
|
||||||
|
;
|
||||||
|
*buf++ = REG_MSC_RXFIFO;
|
||||||
|
}
|
||||||
|
host->pio.len -= count;
|
||||||
|
host->pio.offset += count;
|
||||||
|
|
||||||
|
if (sg_len && count == sg_len) {
|
||||||
|
host->pio.index++;
|
||||||
|
host->pio.offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_mmc_send_pio(struct jz_mmc_host *host)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct mmc_data *data = 0;
|
||||||
|
int sg_len, max, count = 0;
|
||||||
|
u32 *wbuf = 0;
|
||||||
|
struct scatterlist *sg;
|
||||||
|
unsigned int nob;
|
||||||
|
|
||||||
|
data = host->mrq->data;
|
||||||
|
nob = data->blocks;
|
||||||
|
|
||||||
|
REG_MSC_NOB = nob;
|
||||||
|
REG_MSC_BLKLEN = data->blksz;
|
||||||
|
|
||||||
|
/* This is the pointer to the data buffer */
|
||||||
|
sg = &data->sg[host->pio.index];
|
||||||
|
wbuf = sg_virt(sg) + host->pio.offset;
|
||||||
|
|
||||||
|
/* This is the space left inside the buffer */
|
||||||
|
sg_len = data->sg[host->pio.index].length - host->pio.offset;
|
||||||
|
|
||||||
|
/* Check to if we need less then the size of the sg_buffer */
|
||||||
|
max = (sg_len > host->pio.len) ? host->pio.len : sg_len;
|
||||||
|
max = max / 4;
|
||||||
|
for(count = 0; count < max; count++ ) {
|
||||||
|
while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_FULL)
|
||||||
|
;
|
||||||
|
REG_MSC_TXFIFO = *wbuf++;
|
||||||
|
}
|
||||||
|
|
||||||
|
host->pio.len -= count;
|
||||||
|
host->pio.offset += count;
|
||||||
|
|
||||||
|
if (count == sg_len) {
|
||||||
|
host->pio.index++;
|
||||||
|
host->pio.offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
jz_mmc_prepare_data(struct jz_mmc_host *host, struct mmc_data *data)
|
||||||
|
{
|
||||||
|
int datalen = data->blocks * data->blksz;
|
||||||
|
|
||||||
|
host->dma.dir = DMA_BIDIRECTIONAL;
|
||||||
|
host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg,
|
||||||
|
data->sg_len, host->dma.dir);
|
||||||
|
if (host->dma.len == 0)
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
|
host->pio.index = 0;
|
||||||
|
host->pio.offset = 0;
|
||||||
|
host->pio.len = datalen;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat);
|
||||||
|
|
||||||
|
static void jz_mmc_finish_request(struct jz_mmc_host *host, struct mmc_request *mrq)
|
||||||
|
{
|
||||||
|
jz_mmc_stop_clock();
|
||||||
|
host->mrq = NULL;
|
||||||
|
host->cmd = NULL;
|
||||||
|
host->data = NULL;
|
||||||
|
mmc_request_done(host->mmc, mrq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_mmc_start_cmd(struct jz_mmc_host *host,
|
||||||
|
struct mmc_command *cmd, unsigned int cmdat)
|
||||||
|
{
|
||||||
|
u32 timeout = 0x3fffff;
|
||||||
|
unsigned int stat;
|
||||||
|
struct jz_mmc_host *hst = host;
|
||||||
|
WARN_ON(host->cmd != NULL);
|
||||||
|
host->cmd = cmd;
|
||||||
|
|
||||||
|
/* stop MMC clock */
|
||||||
|
jz_mmc_stop_clock();
|
||||||
|
|
||||||
|
/* mask interrupts */
|
||||||
|
REG_MSC_IMASK = 0xff;
|
||||||
|
|
||||||
|
/* clear status */
|
||||||
|
REG_MSC_IREG = 0xff;
|
||||||
|
|
||||||
|
if (cmd->flags & MMC_RSP_BUSY)
|
||||||
|
cmdat |= MSC_CMDAT_BUSY;
|
||||||
|
|
||||||
|
#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
|
||||||
|
switch (RSP_TYPE(mmc_resp_type(cmd))) {
|
||||||
|
case RSP_TYPE(MMC_RSP_R1): /* r1,r1b, r6, r7 */
|
||||||
|
cmdat |= MSC_CMDAT_RESPONSE_R1;
|
||||||
|
r_type = 1;
|
||||||
|
break;
|
||||||
|
case RSP_TYPE(MMC_RSP_R3):
|
||||||
|
cmdat |= MSC_CMDAT_RESPONSE_R3;
|
||||||
|
r_type = 1;
|
||||||
|
break;
|
||||||
|
case RSP_TYPE(MMC_RSP_R2):
|
||||||
|
cmdat |= MSC_CMDAT_RESPONSE_R2;
|
||||||
|
r_type = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
REG_MSC_CMD = cmd->opcode;
|
||||||
|
|
||||||
|
/* Set argument */
|
||||||
|
#ifdef CONFIG_JZ_MMC_BUS_1
|
||||||
|
if (cmd->opcode == 6) {
|
||||||
|
/* set 1 bit sd card bus*/
|
||||||
|
if (cmd->arg ==2)
|
||||||
|
REG_MSC_ARG = 0;
|
||||||
|
|
||||||
|
/* set 1 bit mmc card bus*/
|
||||||
|
if (cmd->arg == 0x3b70101)
|
||||||
|
REG_MSC_ARG = 0x3b70001;
|
||||||
|
} else
|
||||||
|
REG_MSC_ARG = cmd->arg;
|
||||||
|
#else
|
||||||
|
REG_MSC_ARG = cmd->arg;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Set command */
|
||||||
|
REG_MSC_CMDAT = cmdat;
|
||||||
|
|
||||||
|
/* Send command */
|
||||||
|
jz_mmc_start_clock();
|
||||||
|
|
||||||
|
while (timeout-- && !(REG_MSC_STAT & MSC_STAT_END_CMD_RES))
|
||||||
|
;
|
||||||
|
|
||||||
|
REG_MSC_IREG = MSC_IREG_END_CMD_RES; /* clear irq flag */
|
||||||
|
if (cmd->opcode == 12) {
|
||||||
|
while (timeout-- && !(REG_MSC_IREG & MSC_IREG_PRG_DONE))
|
||||||
|
;
|
||||||
|
REG_MSC_IREG = MSC_IREG_PRG_DONE; /* clear status */
|
||||||
|
}
|
||||||
|
if (!mmc_slot_enable) {
|
||||||
|
/* It seems that MSC can't report the MSC_STAT_TIME_OUT_RES when
|
||||||
|
* card was removed. We force to return here.
|
||||||
|
*/
|
||||||
|
cmd->error = -ETIMEDOUT;
|
||||||
|
jz_mmc_finish_request(hst, hst->mrq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SD_IO_SEND_OP_COND == cmd->opcode) {
|
||||||
|
/*
|
||||||
|
* Don't support SDIO card currently.
|
||||||
|
*/
|
||||||
|
cmd->error = -ETIMEDOUT;
|
||||||
|
jz_mmc_finish_request(hst, hst->mrq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for status */
|
||||||
|
stat = REG_MSC_STAT;
|
||||||
|
jz_mmc_cmd_done(hst, stat);
|
||||||
|
if (host->data) {
|
||||||
|
if (cmd->opcode == MMC_WRITE_BLOCK || cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
|
||||||
|
#ifdef USE_DMA
|
||||||
|
jz_mmc_tx_setup_data(host, host->data);
|
||||||
|
#else
|
||||||
|
jz_mmc_send_pio(host);
|
||||||
|
else
|
||||||
|
jz_mmc_receive_pio(host);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat)
|
||||||
|
{
|
||||||
|
struct mmc_command *cmd = host->cmd;
|
||||||
|
int i, temp[16];
|
||||||
|
u8 *buf;
|
||||||
|
u32 data, v, w1, w2;
|
||||||
|
|
||||||
|
if (!cmd)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
host->cmd = NULL;
|
||||||
|
buf = (u8 *) temp;
|
||||||
|
switch (r_type) {
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
data = REG_MSC_RES;
|
||||||
|
buf[0] = (data >> 8) & 0xff;
|
||||||
|
buf[1] = data & 0xff;
|
||||||
|
data = REG_MSC_RES;
|
||||||
|
buf[2] = (data >> 8) & 0xff;
|
||||||
|
buf[3] = data & 0xff;
|
||||||
|
data = REG_MSC_RES;
|
||||||
|
buf[4] = data & 0xff;
|
||||||
|
cmd->resp[0] =
|
||||||
|
buf[1] << 24 | buf[2] << 16 | buf[3] << 8 |
|
||||||
|
buf[4];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
data = REG_MSC_RES;
|
||||||
|
v = data & 0xffff;
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
data = REG_MSC_RES;
|
||||||
|
w1 = data & 0xffff;
|
||||||
|
data = REG_MSC_RES;
|
||||||
|
w2 = data & 0xffff;
|
||||||
|
cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
|
||||||
|
v = w2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (stat & MSC_STAT_TIME_OUT_RES) {
|
||||||
|
printk("MSC_STAT_TIME_OUT_RES\n");
|
||||||
|
cmd->error = -ETIMEDOUT;
|
||||||
|
} else if (stat & MSC_STAT_CRC_RES_ERR && cmd->flags & MMC_RSP_CRC) {
|
||||||
|
printk("MSC_STAT_CRC\n");
|
||||||
|
if (cmd->opcode == MMC_ALL_SEND_CID ||
|
||||||
|
cmd->opcode == MMC_SEND_CSD ||
|
||||||
|
cmd->opcode == MMC_SEND_CID) {
|
||||||
|
/* a bogus CRC error can appear if the msb of
|
||||||
|
the 15 byte response is a one */
|
||||||
|
if ((cmd->resp[0] & 0x80000000) == 0)
|
||||||
|
cmd->error = -EILSEQ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Did I mention this is Sick. We always need to
|
||||||
|
* discard the upper 8 bits of the first 16-bit word.
|
||||||
|
*/
|
||||||
|
if (host->data && cmd->error == 0)
|
||||||
|
jz_mmc_enable_irq(host, MSC_IMASK_DATA_TRAN_DONE);
|
||||||
|
else
|
||||||
|
jz_mmc_finish_request(host, host->mrq);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz_mmc_data_done(struct jz_mmc_host *host, unsigned int stat)
|
||||||
|
{
|
||||||
|
struct mmc_data *data = host->data;
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return 0;
|
||||||
|
REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE; /* clear status */
|
||||||
|
jz_mmc_stop_clock();
|
||||||
|
dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
|
||||||
|
host->dma_dir);
|
||||||
|
if (stat & MSC_STAT_TIME_OUT_READ) {
|
||||||
|
printk("MMC/SD timeout, MMC_STAT 0x%x\n", stat);
|
||||||
|
data->error = -ETIMEDOUT;
|
||||||
|
} else if (REG_MSC_STAT &
|
||||||
|
(MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR)) {
|
||||||
|
printk("MMC/SD CRC error, MMC_STAT 0x%x\n", stat);
|
||||||
|
data->error = -EILSEQ;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* There appears to be a hardware design bug here. There seems to
|
||||||
|
* be no way to find out how much data was transferred to the card.
|
||||||
|
* This means that if there was an error on any block, we mark all
|
||||||
|
* data blocks as being in error.
|
||||||
|
*/
|
||||||
|
if (data->error == 0)
|
||||||
|
data->bytes_xfered = data->blocks * data->blksz;
|
||||||
|
else
|
||||||
|
data->bytes_xfered = 0;
|
||||||
|
|
||||||
|
jz_mmc_disable_irq(host, MSC_IMASK_DATA_TRAN_DONE);
|
||||||
|
host->data = NULL;
|
||||||
|
if (host->mrq->stop) {
|
||||||
|
jz_mmc_stop_clock();
|
||||||
|
jz_mmc_start_cmd(host, host->mrq->stop, 0);
|
||||||
|
} else {
|
||||||
|
jz_mmc_finish_request(host, host->mrq);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||||
|
{
|
||||||
|
struct jz_mmc_host *host = mmc_priv(mmc);
|
||||||
|
unsigned int cmdat;
|
||||||
|
|
||||||
|
/* stop MMC clock */
|
||||||
|
jz_mmc_stop_clock();
|
||||||
|
|
||||||
|
/* Save current request for the future processing */
|
||||||
|
host->mrq = mrq;
|
||||||
|
host->data = mrq->data;
|
||||||
|
cmdat = host->cmdat;
|
||||||
|
host->cmdat &= ~MSC_CMDAT_INIT;
|
||||||
|
|
||||||
|
if (mrq->data) {
|
||||||
|
cmdat &= ~MSC_CMDAT_BUSY;
|
||||||
|
#ifdef USE_DMA
|
||||||
|
if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6))
|
||||||
|
|
||||||
|
cmdat |=
|
||||||
|
MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN |
|
||||||
|
MSC_CMDAT_DMA_EN;
|
||||||
|
else {
|
||||||
|
#ifdef CONFIG_JZ_MMC_BUS_1
|
||||||
|
cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT;
|
||||||
|
cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN |
|
||||||
|
MSC_CMDAT_DMA_EN;
|
||||||
|
#else
|
||||||
|
cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_DMA_EN;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (mrq->data->flags & MMC_DATA_WRITE)
|
||||||
|
cmdat |= MSC_CMDAT_WRITE;
|
||||||
|
|
||||||
|
if (mrq->data->flags & MMC_DATA_STREAM)
|
||||||
|
cmdat |= MSC_CMDAT_STREAM_BLOCK;
|
||||||
|
if (mrq->cmd->opcode != MMC_WRITE_BLOCK
|
||||||
|
&& mrq->cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)
|
||||||
|
jz_mmc_rx_setup_data(host, mrq->data);
|
||||||
|
#else /*USE_DMA*/
|
||||||
|
|
||||||
|
if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6))
|
||||||
|
cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN;
|
||||||
|
else {
|
||||||
|
#ifdef CONFIG_JZ_MMC_BUS_1
|
||||||
|
cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT;
|
||||||
|
cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN;
|
||||||
|
#else
|
||||||
|
cmdat |= MSC_CMDAT_DATA_EN;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (mrq->data->flags & MMC_DATA_WRITE)
|
||||||
|
cmdat |= MSC_CMDAT_WRITE;
|
||||||
|
|
||||||
|
if (mrq->data->flags & MMC_DATA_STREAM)
|
||||||
|
cmdat |= MSC_CMDAT_STREAM_BLOCK;
|
||||||
|
jz_mmc_prepare_data(host, host->data);
|
||||||
|
#endif /*USE_DMA*/
|
||||||
|
}
|
||||||
|
jz_mmc_start_cmd(host, mrq->cmd, cmdat);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t jz_mmc_irq(int irq, void *devid)
|
||||||
|
{
|
||||||
|
struct jz_mmc_host *host = devid;
|
||||||
|
unsigned int ireg;
|
||||||
|
int handled = 0;
|
||||||
|
|
||||||
|
ireg = REG_MSC_IREG;
|
||||||
|
|
||||||
|
if (ireg) {
|
||||||
|
unsigned stat = REG_MSC_STAT;
|
||||||
|
if (ireg & MSC_IREG_DATA_TRAN_DONE)
|
||||||
|
handled |= jz_mmc_data_done(host, stat);
|
||||||
|
}
|
||||||
|
return IRQ_RETVAL(handled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if MMC slot is empty */
|
||||||
|
static int jz_mmc_slot_is_empty(int slot)
|
||||||
|
{
|
||||||
|
int empty;
|
||||||
|
|
||||||
|
empty = (__msc_card_detected(slot) == 0) ? 1 : 0;
|
||||||
|
|
||||||
|
if (empty) {
|
||||||
|
/* wait for card insertion */
|
||||||
|
#ifdef CONFIG_MIPS_JZ4740_LYRA
|
||||||
|
__gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN);
|
||||||
|
#else
|
||||||
|
__gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
/* wait for card removal */
|
||||||
|
#ifdef CONFIG_MIPS_JZ4740_LYRA
|
||||||
|
__gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN);
|
||||||
|
#else
|
||||||
|
__gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t jz_mmc_detect_irq(int irq, void *devid)
|
||||||
|
{
|
||||||
|
struct jz_mmc_host *host = (struct jz_mmc_host *) devid;
|
||||||
|
|
||||||
|
if (jz_mmc_slot_is_empty(0)) {
|
||||||
|
mmc_slot_enable = 0;
|
||||||
|
mmc_detect_change(host->mmc, 50);
|
||||||
|
} else {
|
||||||
|
mmc_slot_enable = 1;
|
||||||
|
mmc_detect_change(host->mmc, 50);
|
||||||
|
}
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz_mmc_get_ro(struct mmc_host *mmc)
|
||||||
|
{
|
||||||
|
struct jz_mmc_host *host = mmc_priv(mmc);
|
||||||
|
|
||||||
|
if (host->pdata && host->pdata->get_ro)
|
||||||
|
return host->pdata->get_ro(mmc_dev(mmc));
|
||||||
|
/* Host doesn't support read only detection so assume writeable */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set clock and power */
|
||||||
|
static void jz_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||||
|
{
|
||||||
|
struct jz_mmc_host *host = mmc_priv(mmc);
|
||||||
|
|
||||||
|
if (ios->clock)
|
||||||
|
jz_mmc_set_clock(ios->clock);
|
||||||
|
else
|
||||||
|
jz_mmc_stop_clock();
|
||||||
|
|
||||||
|
if (host->power_mode != ios->power_mode) {
|
||||||
|
host->power_mode = ios->power_mode;
|
||||||
|
|
||||||
|
if (ios->power_mode == MMC_POWER_ON)
|
||||||
|
host->cmdat |= CMDAT_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ios->bus_width == MMC_BUS_WIDTH_4) || (ios->bus_width == MMC_BUS_WIDTH_8))
|
||||||
|
host->cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT;
|
||||||
|
else
|
||||||
|
host->cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct mmc_host_ops jz_mmc_ops = {
|
||||||
|
.request = jz_mmc_request,
|
||||||
|
.get_ro = jz_mmc_get_ro,
|
||||||
|
.set_ios = jz_mmc_set_ios,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int jz_mmc_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
struct mmc_host *mmc;
|
||||||
|
struct jz_mmc_host *host = NULL;
|
||||||
|
int irq;
|
||||||
|
struct resource *r;
|
||||||
|
|
||||||
|
__gpio_as_msc();
|
||||||
|
__msc_init_io();
|
||||||
|
__msc_enable_power();
|
||||||
|
|
||||||
|
__msc_reset();
|
||||||
|
|
||||||
|
/* On reset, stop MMC clock */
|
||||||
|
jz_mmc_stop_clock();
|
||||||
|
|
||||||
|
MMC_IRQ_MASK();
|
||||||
|
|
||||||
|
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
irq = platform_get_irq(pdev, 0);
|
||||||
|
if (!r || irq < 0)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
|
||||||
|
if (!r)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
mmc = mmc_alloc_host(sizeof(struct jz_mmc_host), &pdev->dev);
|
||||||
|
if (!mmc) {
|
||||||
|
retval = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
mmc->ops = &jz_mmc_ops;
|
||||||
|
mmc->f_min = MMC_CLOCK_SLOW;
|
||||||
|
mmc->f_max = SD_CLOCK_FAST;
|
||||||
|
/*
|
||||||
|
* We can do SG-DMA, but we don't because we never know how much
|
||||||
|
* data we successfully wrote to the card.
|
||||||
|
*/
|
||||||
|
mmc->max_phys_segs = NR_SG;
|
||||||
|
/*
|
||||||
|
* Our hardware DMA can handle a maximum of one page per SG entry.
|
||||||
|
*/
|
||||||
|
mmc->max_seg_size = PAGE_SIZE;
|
||||||
|
/*
|
||||||
|
* Block length register is 10 bits.
|
||||||
|
*/
|
||||||
|
mmc->max_blk_size = 1023;
|
||||||
|
/*
|
||||||
|
* Block count register is 16 bits.
|
||||||
|
*/
|
||||||
|
mmc->max_blk_count = 65535;
|
||||||
|
host = mmc_priv(mmc);
|
||||||
|
host->mmc = mmc;
|
||||||
|
host->pdata = pdev->dev.platform_data;
|
||||||
|
mmc->ocr_avail = host->pdata ?
|
||||||
|
host->pdata->ocr_mask : MMC_VDD_32_33 | MMC_VDD_33_34;
|
||||||
|
host->mmc->caps =
|
||||||
|
MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED
|
||||||
|
| MMC_CAP_MMC_HIGHSPEED;
|
||||||
|
/*
|
||||||
|
*MMC_CAP_4_BIT_DATA (1 << 0) The host can do 4 bit transfers
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
host->sg_cpu =
|
||||||
|
dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!host->sg_cpu) {
|
||||||
|
retval = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
spin_lock_init(&host->lock);
|
||||||
|
host->irq = IRQ_MSC;
|
||||||
|
host->imask = 0xff;
|
||||||
|
/*
|
||||||
|
* Ensure that the host controller is shut down, and setup
|
||||||
|
* with our defaults.
|
||||||
|
*/
|
||||||
|
retval = request_irq(IRQ_MSC, jz_mmc_irq, 0, "MMC/SD", host);
|
||||||
|
if (retval) {
|
||||||
|
printk(KERN_ERR "MMC/SD: can't request MMC/SD IRQ\n");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
jz_mmc_slot_is_empty(0);
|
||||||
|
/* Request card detect interrupt */
|
||||||
|
|
||||||
|
retval = request_irq(MSC_HOTPLUG_IRQ, jz_mmc_detect_irq, 0, //SA_INTERRUPT,
|
||||||
|
"MMC card detect", host);
|
||||||
|
if (retval) {
|
||||||
|
printk(KERN_ERR "MMC/SD: can't request card detect IRQ\n");
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
#ifdef USE_DMA
|
||||||
|
/* Request MMC Rx DMA channel */
|
||||||
|
rxdmachan =
|
||||||
|
jz_request_dma(DMA_ID_MSC_RX, "MMC Rx", jz_mmc_dma_rx_callback,
|
||||||
|
0, host);
|
||||||
|
if (rxdmachan < 0) {
|
||||||
|
printk(KERN_ERR "jz_request_dma failed for MMC Rx\n");
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Request MMC Tx DMA channel */
|
||||||
|
txdmachan =
|
||||||
|
jz_request_dma(DMA_ID_MSC_TX, "MMC Tx", jz_mmc_dma_tx_callback,
|
||||||
|
0, host);
|
||||||
|
if (txdmachan < 0) {
|
||||||
|
printk(KERN_ERR "jz_request_dma failed for MMC Tx\n");
|
||||||
|
goto err3;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
platform_set_drvdata(pdev, mmc);
|
||||||
|
mmc_add_host(mmc);
|
||||||
|
printk("JZ 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");
|
65
target/linux/xburst/files-2.6.31/drivers/mmc/host/jz_mmc.h
Executable file
65
target/linux/xburst/files-2.6.31/drivers/mmc/host/jz_mmc.h
Executable file
@ -0,0 +1,65 @@
|
|||||||
|
#ifndef __JZ_MMC_H__
|
||||||
|
#define __JZ_MMC_H__
|
||||||
|
|
||||||
|
#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */
|
||||||
|
#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */
|
||||||
|
#define SD_CLOCK_FAST 24000000 /* 24 MHz for SD Cards */
|
||||||
|
#define MMC_NO_ERROR 0
|
||||||
|
/* Extra MMC commands for state control */
|
||||||
|
/* Use negative numbers to disambiguate */
|
||||||
|
#define MMC_CIM_RESET -1
|
||||||
|
#define MMC_SET_CLOCK 100
|
||||||
|
|
||||||
|
typedef struct jzsoc_dma_desc {
|
||||||
|
volatile u32 ddadr; /* Points to the next descriptor + flags */
|
||||||
|
volatile u32 dsadr; /* DSADR value for the current transfer */
|
||||||
|
volatile u32 dtadr; /* DTADR value for the current transfer */
|
||||||
|
volatile u32 dcmd; /* DCMD value for the current transfer */
|
||||||
|
} jzsoc_dma_desc;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
|
||||||
|
struct device;
|
||||||
|
struct mmc_host;
|
||||||
|
|
||||||
|
struct jz_mmc_platform_data {
|
||||||
|
unsigned int ocr_mask; /* available voltages */
|
||||||
|
unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */
|
||||||
|
int (*init)(struct device *, irq_handler_t , void *);
|
||||||
|
int (*get_ro)(struct device *);
|
||||||
|
void (*setpower)(struct device *, unsigned int);
|
||||||
|
void (*exit)(struct device *, void *);
|
||||||
|
};
|
||||||
|
|
||||||
|
//extern void pxa_set_mci_info(struct pxamci_platform_data *info);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define SZ_1K 0x00000400
|
||||||
|
#define SZ_4K 0x00001000
|
||||||
|
#define SZ_8K 0x00002000
|
||||||
|
#define SZ_16K 0x00004000
|
||||||
|
#define SZ_64K 0x00010000
|
||||||
|
#define SZ_128K 0x00020000
|
||||||
|
#define SZ_256K 0x00040000
|
||||||
|
#define SZ_512K 0x00080000
|
||||||
|
|
||||||
|
#define SZ_1M 0x00100000
|
||||||
|
#define SZ_2M 0x00200000
|
||||||
|
#define SZ_4M 0x00400000
|
||||||
|
#define SZ_8M 0x00800000
|
||||||
|
#define SZ_16M 0x01000000
|
||||||
|
#define SZ_32M 0x02000000
|
||||||
|
#define SZ_64M 0x04000000
|
||||||
|
#define SZ_128M 0x08000000
|
||||||
|
#define SZ_256M 0x10000000
|
||||||
|
#define SZ_512M 0x20000000
|
||||||
|
|
||||||
|
#define SZ_1G 0x40000000
|
||||||
|
#define SZ_2G 0x80000000
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __JZ_MMC_H__ */
|
413
target/linux/xburst/files-2.6.31/drivers/mtd/nand/jz4740_nand.c
Normal file
413
target/linux/xburst/files-2.6.31/drivers/mtd/nand/jz4740_nand.c
Normal file
@ -0,0 +1,413 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
|
||||||
|
* JZ4720/JZ4740 SoC NAND controller 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#include <linux/mtd/mtd.h>
|
||||||
|
#include <linux/mtd/nand.h>
|
||||||
|
#include <linux/mtd/partitions.h>
|
||||||
|
|
||||||
|
#include <linux/mtd/jz4740_nand.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
|
||||||
|
#define JZ_REG_NAND_CTRL 0x50
|
||||||
|
#define JZ_REG_NAND_ECC_CTRL 0x100
|
||||||
|
#define JZ_REG_NAND_DATA 0x104
|
||||||
|
#define JZ_REG_NAND_PAR0 0x108
|
||||||
|
#define JZ_REG_NAND_PAR1 0x10C
|
||||||
|
#define JZ_REG_NAND_PAR2 0x110
|
||||||
|
#define JZ_REG_NAND_IRQ_STAT 0x114
|
||||||
|
#define JZ_REG_NAND_IRQ_CTRL 0x118
|
||||||
|
#define JZ_REG_NAND_ERR(x) (0x11C + (x << 2))
|
||||||
|
|
||||||
|
#define JZ_NAND_ECC_CTRL_PAR_READY BIT(4)
|
||||||
|
#define JZ_NAND_ECC_CTRL_ENCODING BIT(3)
|
||||||
|
#define JZ_NAND_ECC_CTRL_RS BIT(2)
|
||||||
|
#define JZ_NAND_ECC_CTRL_RESET BIT(1)
|
||||||
|
#define JZ_NAND_ECC_CTRL_ENABLE BIT(0)
|
||||||
|
|
||||||
|
#define JZ_NAND_STATUS_ERR_COUNT (BIT(31) | BIT(30) | BIT(29))
|
||||||
|
#define JZ_NAND_STATUS_PAD_FINISH BIT(4)
|
||||||
|
#define JZ_NAND_STATUS_DEC_FINISH BIT(3)
|
||||||
|
#define JZ_NAND_STATUS_ENC_FINISH BIT(2)
|
||||||
|
#define JZ_NAND_STATUS_UNCOR_ERROR BIT(1)
|
||||||
|
#define JZ_NAND_STATUS_ERROR BIT(0)
|
||||||
|
|
||||||
|
#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT(x << 1)
|
||||||
|
#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT((x << 1) + 1)
|
||||||
|
|
||||||
|
#define JZ_NAND_DATA_ADDR ((void __iomem *)0xB8000000)
|
||||||
|
#define JZ_NAND_CMD_ADDR (JZ_NAND_DATA_ADDR + 0x8000)
|
||||||
|
#define JZ_NAND_ADDR_ADDR (JZ_NAND_DATA_ADDR + 0x10000)
|
||||||
|
|
||||||
|
struct jz_nand {
|
||||||
|
struct mtd_info mtd;
|
||||||
|
struct nand_chip chip;
|
||||||
|
void __iomem *base;
|
||||||
|
struct resource *mem;
|
||||||
|
|
||||||
|
struct jz_nand_platform_data *pdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
|
||||||
|
{
|
||||||
|
return container_of(mtd, struct jz_nand, mtd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
|
||||||
|
{
|
||||||
|
struct jz_nand *nand = mtd_to_jz_nand(mtd);
|
||||||
|
struct nand_chip *chip = mtd->priv;
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
if (ctrl & NAND_CTRL_CHANGE) {
|
||||||
|
BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
|
||||||
|
if (ctrl & NAND_ALE)
|
||||||
|
chip->IO_ADDR_W = JZ_NAND_ADDR_ADDR;
|
||||||
|
else if (ctrl & NAND_CLE)
|
||||||
|
chip->IO_ADDR_W = JZ_NAND_CMD_ADDR;
|
||||||
|
else
|
||||||
|
chip->IO_ADDR_W = JZ_NAND_DATA_ADDR;
|
||||||
|
|
||||||
|
reg = readl(nand->base + JZ_REG_NAND_CTRL);
|
||||||
|
if ( ctrl & NAND_NCE )
|
||||||
|
reg |= JZ_NAND_CTRL_ASSERT_CHIP(0);
|
||||||
|
else
|
||||||
|
reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0);
|
||||||
|
writel(reg, nand->base + JZ_REG_NAND_CTRL);
|
||||||
|
}
|
||||||
|
if (dat != NAND_CMD_NONE)
|
||||||
|
writeb(dat, chip->IO_ADDR_W);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz_nand_dev_ready(struct mtd_info *mtd)
|
||||||
|
{
|
||||||
|
struct jz_nand *nand = mtd_to_jz_nand(mtd);
|
||||||
|
return gpio_get_value_cansleep(nand->pdata->busy_gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
|
||||||
|
{
|
||||||
|
struct jz_nand *nand = mtd_to_jz_nand(mtd);
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
|
||||||
|
writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
|
||||||
|
reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
|
||||||
|
|
||||||
|
reg |= JZ_NAND_ECC_CTRL_RESET;
|
||||||
|
reg |= JZ_NAND_ECC_CTRL_ENABLE;
|
||||||
|
reg |= JZ_NAND_ECC_CTRL_RS;
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case NAND_ECC_READ:
|
||||||
|
reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
|
||||||
|
break;
|
||||||
|
case NAND_ECC_WRITE:
|
||||||
|
reg |= JZ_NAND_ECC_CTRL_ENCODING;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz_nand_calculate_ecc_rs(struct mtd_info* mtd, const uint8_t* dat,
|
||||||
|
uint8_t *ecc_code)
|
||||||
|
{
|
||||||
|
struct jz_nand *nand = mtd_to_jz_nand(mtd);
|
||||||
|
uint32_t reg, status;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
do {
|
||||||
|
status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
|
||||||
|
} while(!(status & JZ_NAND_STATUS_ENC_FINISH));
|
||||||
|
|
||||||
|
reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
|
||||||
|
reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
|
||||||
|
writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
|
||||||
|
|
||||||
|
for (i = 0; i < 9; ++i) {
|
||||||
|
ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void correct_data(uint8_t *dat, int index, int mask)
|
||||||
|
{
|
||||||
|
int offset = index & 0x7;
|
||||||
|
uint16_t data;
|
||||||
|
printk("correct: ");
|
||||||
|
|
||||||
|
index += (index >> 3);
|
||||||
|
|
||||||
|
data = dat[index];
|
||||||
|
data |= dat[index+1] << 8;
|
||||||
|
|
||||||
|
printk("0x%x -> ", data);
|
||||||
|
|
||||||
|
mask ^= (data >> offset) & 0x1ff;
|
||||||
|
data &= ~(0x1ff << offset);
|
||||||
|
data |= (mask << offset);
|
||||||
|
|
||||||
|
printk("0x%x\n", data);
|
||||||
|
|
||||||
|
dat[index] = data & 0xff;
|
||||||
|
dat[index+1] = (data >> 8) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz_nand_correct_ecc_rs(struct mtd_info* mtd, uint8_t *dat,
|
||||||
|
uint8_t *read_ecc, uint8_t *calc_ecc)
|
||||||
|
{
|
||||||
|
struct jz_nand *nand = mtd_to_jz_nand(mtd);
|
||||||
|
int i, error_count, index;
|
||||||
|
uint32_t reg, status, error;
|
||||||
|
|
||||||
|
for(i = 0; i < 9; ++i) {
|
||||||
|
if (read_ecc[i] != 0xff)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == 9) {
|
||||||
|
for (i = 0; i < nand->chip.ecc.size; ++i) {
|
||||||
|
if (dat[i] != 0xff)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == nand->chip.ecc.size)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < 9; ++i)
|
||||||
|
writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i);
|
||||||
|
|
||||||
|
reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
|
||||||
|
reg |= JZ_NAND_ECC_CTRL_PAR_READY;
|
||||||
|
writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
|
||||||
|
|
||||||
|
do {
|
||||||
|
status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
|
||||||
|
} while (!(status & JZ_NAND_STATUS_DEC_FINISH));
|
||||||
|
|
||||||
|
reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
|
||||||
|
reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
|
||||||
|
writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
|
||||||
|
|
||||||
|
|
||||||
|
if (status & JZ_NAND_STATUS_ERROR) {
|
||||||
|
if (status & JZ_NAND_STATUS_UNCOR_ERROR) {
|
||||||
|
printk("uncorreclteble ecc:");
|
||||||
|
for(i = 0; i < 9; ++i)
|
||||||
|
printk(" 0x%x", read_ecc[i]);
|
||||||
|
printk("\n");
|
||||||
|
printk("uncorreclteble data:");
|
||||||
|
for(i = 0; i < 32; ++i)
|
||||||
|
printk(" 0x%x", dat[i]);
|
||||||
|
printk("\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
|
||||||
|
|
||||||
|
printk("error_count: %d %x\n", error_count, status);
|
||||||
|
|
||||||
|
for(i = 0;i < error_count; ++i) {
|
||||||
|
error = readl(nand->base + JZ_REG_NAND_ERR(i));
|
||||||
|
index = ((error >> 16) & 0x1ff) - 1;
|
||||||
|
if (index >= 0 && index < 512) {
|
||||||
|
correct_data(dat, index, error & 0x1ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_MTD_CMDLINE_PARTS
|
||||||
|
static const char *part_probes[] = {"cmdline", NULL};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int __devinit jz_nand_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct jz_nand *nand;
|
||||||
|
struct nand_chip *chip;
|
||||||
|
struct mtd_info *mtd;
|
||||||
|
struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
|
||||||
|
#ifdef CONFIG_MTD_PARTITIONS
|
||||||
|
struct mtd_partition *partition_info;
|
||||||
|
int num_partitions = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nand = kzalloc(sizeof(*nand), GFP_KERNEL);
|
||||||
|
if (!nand) {
|
||||||
|
dev_err(&pdev->dev, "Failed to allocate device structure.\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
nand->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
if (!nand->mem) {
|
||||||
|
dev_err(&pdev->dev, "Failed to get platform mmio memory\n");
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
nand->mem = request_mem_region(nand->mem->start, resource_size(nand->mem),
|
||||||
|
pdev->name);
|
||||||
|
|
||||||
|
if (!nand->mem) {
|
||||||
|
dev_err(&pdev->dev, "Failed to request mmio memory region\n");
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
nand->base = ioremap(nand->mem->start, resource_size(nand->mem));
|
||||||
|
|
||||||
|
if (!nand->base) {
|
||||||
|
dev_err(&pdev->dev, "Faild to ioremap mmio memory region\n");
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto err_release_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdata && gpio_is_valid(pdata->busy_gpio)) {
|
||||||
|
ret = gpio_request(pdata->busy_gpio, "jz nand busy line");
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Failed to request busy gpio %d: %d\n",
|
||||||
|
pdata->busy_gpio, ret);
|
||||||
|
goto err_iounmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mtd = &nand->mtd;
|
||||||
|
chip = &nand->chip;
|
||||||
|
mtd->priv = chip;
|
||||||
|
mtd->owner = THIS_MODULE;
|
||||||
|
mtd->name = "jz4740-nand";
|
||||||
|
|
||||||
|
chip->ecc.hwctl = jz_nand_hwctl;
|
||||||
|
|
||||||
|
chip->ecc.calculate = jz_nand_calculate_ecc_rs;
|
||||||
|
chip->ecc.correct = jz_nand_correct_ecc_rs;
|
||||||
|
chip->ecc.mode = NAND_ECC_HW;
|
||||||
|
chip->ecc.size = 512;
|
||||||
|
chip->ecc.bytes = 9;
|
||||||
|
if (pdata)
|
||||||
|
chip->ecc.layout = pdata->ecc_layout;
|
||||||
|
|
||||||
|
chip->chip_delay = 50;
|
||||||
|
chip->cmd_ctrl = jz_nand_cmd_ctrl;
|
||||||
|
|
||||||
|
if (pdata && gpio_is_valid(pdata->busy_gpio))
|
||||||
|
chip->dev_ready = jz_nand_dev_ready;
|
||||||
|
|
||||||
|
chip->IO_ADDR_R = JZ_NAND_DATA_ADDR;
|
||||||
|
chip->IO_ADDR_W = JZ_NAND_DATA_ADDR;
|
||||||
|
|
||||||
|
nand->pdata = pdata;
|
||||||
|
platform_set_drvdata(pdev, nand);
|
||||||
|
|
||||||
|
ret = nand_scan(mtd, 1);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Failed to scan nand\n");
|
||||||
|
goto err_gpio_free;
|
||||||
|
}
|
||||||
|
#ifdef CONFIG_MTD_PARTITIONS
|
||||||
|
#ifdef CONFIG_MTD_CMDLINE_PARTS
|
||||||
|
num_partitions = parse_mtd_partitions(mtd, part_probes,
|
||||||
|
&partition_info, 0);
|
||||||
|
if (num_partitions <= 0 && pdata) {
|
||||||
|
num_partitions = pdata->num_partitions;
|
||||||
|
partition_info = pdata->partitions;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (pdata) {
|
||||||
|
num_partitions = pdata->num_partitions;
|
||||||
|
partition_info = pdata->partitions;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (num_partitions > 0)
|
||||||
|
ret = add_mtd_partitions(mtd, partition_info, num_partitions);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
ret = add_mtd_device(mtd);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Failed to add mtd device\n");
|
||||||
|
goto err_nand_release;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err_nand_release:
|
||||||
|
nand_release(&nand->mtd);
|
||||||
|
err_gpio_free:
|
||||||
|
platform_set_drvdata(pdev, NULL);
|
||||||
|
gpio_free(pdata->busy_gpio);
|
||||||
|
err_iounmap:
|
||||||
|
iounmap(nand->base);
|
||||||
|
err_release_mem:
|
||||||
|
release_mem_region(nand->mem->start, resource_size(nand->mem));
|
||||||
|
err_free:
|
||||||
|
kfree(nand);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __devexit jz_nand_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct jz_nand *nand = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
nand_release(&nand->mtd);
|
||||||
|
|
||||||
|
iounmap(nand->base);
|
||||||
|
|
||||||
|
release_mem_region(nand->mem->start, resource_size(nand->mem));
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, NULL);
|
||||||
|
kfree(nand);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct platform_driver jz_nand_driver = {
|
||||||
|
.probe = jz_nand_probe,
|
||||||
|
.remove = __devexit_p(jz_nand_probe),
|
||||||
|
.driver = {
|
||||||
|
.name = "jz4740-nand",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init jz_nand_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&jz_nand_driver);
|
||||||
|
}
|
||||||
|
module_init(jz_nand_init);
|
||||||
|
|
||||||
|
static void __exit jz_nand_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&jz_nand_driver);
|
||||||
|
}
|
||||||
|
module_exit(jz_nand_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||||
|
MODULE_DESCRIPTION("NAND controller driver for JZ4720/JZ4740 SoC");
|
||||||
|
MODULE_ALIAS("platform:jz4740-nand");
|
||||||
|
MODULE_ALIAS("platform:jz4720-nand");
|
298
target/linux/xburst/files-2.6.31/drivers/power/jz_battery.c
Executable file
298
target/linux/xburst/files-2.6.31/drivers/power/jz_battery.c
Executable file
@ -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 <marek.vasut@gmail.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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/power_supply.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
#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 <marek.vasut@gmail.com>");
|
||||||
|
MODULE_DESCRIPTION("Palm T|X battery driver");
|
2297
target/linux/xburst/files-2.6.31/drivers/usb/gadget/jz4740_udc.c
Executable file
2297
target/linux/xburst/files-2.6.31/drivers/usb/gadget/jz4740_udc.c
Executable file
File diff suppressed because it is too large
Load Diff
121
target/linux/xburst/files-2.6.31/drivers/usb/gadget/jz4740_udc.h
Executable file
121
target/linux/xburst/files-2.6.31/drivers/usb/gadget/jz4740_udc.h
Executable file
@ -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: <jlwei@ingenic.cn>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __USB_GADGET_JZ4740_H__
|
||||||
|
#define __USB_GADGET_JZ4740_H__
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// Max packet size
|
||||||
|
#define EP0_MAXPACKETSIZE 64
|
||||||
|
#define EPBULK_MAXPACKETSIZE 512
|
||||||
|
#define EPINTR_MAXPACKETSIZE 64
|
||||||
|
|
||||||
|
#define UDC_MAX_ENDPOINTS 4
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
typedef enum ep_type {
|
||||||
|
ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt
|
||||||
|
} ep_type_t;
|
||||||
|
|
||||||
|
struct jz4740_ep {
|
||||||
|
struct usb_ep ep;
|
||||||
|
struct jz4740_udc *dev;
|
||||||
|
|
||||||
|
const struct usb_endpoint_descriptor *desc;
|
||||||
|
struct list_head queue;
|
||||||
|
unsigned long pio_irqs;
|
||||||
|
|
||||||
|
u8 stopped;
|
||||||
|
u8 bEndpointAddress;
|
||||||
|
u8 bmAttributes;
|
||||||
|
|
||||||
|
ep_type_t ep_type;
|
||||||
|
u32 fifo;
|
||||||
|
u32 csr;
|
||||||
|
|
||||||
|
u32 reg_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4740_request {
|
||||||
|
struct usb_request req;
|
||||||
|
struct list_head queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ep0state {
|
||||||
|
WAIT_FOR_SETUP, /* between STATUS ack and SETUP report */
|
||||||
|
DATA_STATE_XMIT, /* data tx stage */
|
||||||
|
DATA_STATE_NEED_ZLP, /* data tx zlp stage */
|
||||||
|
WAIT_FOR_OUT_STATUS, /* status stages */
|
||||||
|
DATA_STATE_RECV, /* data rx stage */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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__ */
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Ingenic USB Device Contoller Hotplug External Interfaces
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UDC_HOTPLUG_H__
|
||||||
|
#define __UDC_HOTPLUG_H__
|
||||||
|
|
||||||
|
#include <linux/notifier.h>
|
||||||
|
|
||||||
|
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__ */
|
@ -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 <linux/sched.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/notifier.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
#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 <zwang@ingenic.cn>");
|
||||||
|
MODULE_LICENSE("GPL");
|
1334
target/linux/xburst/files-2.6.31/drivers/video/jz4740_slcd.c
Executable file
1334
target/linux/xburst/files-2.6.31/drivers/video/jz4740_slcd.c
Executable file
File diff suppressed because it is too large
Load Diff
376
target/linux/xburst/files-2.6.31/drivers/video/jz4740_slcd.h
Normal file
376
target/linux/xburst/files-2.6.31/drivers/video/jz4740_slcd.h
Normal file
@ -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__*/
|
||||||
|
|
@ -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__ */
|
||||||
|
|
@ -0,0 +1,157 @@
|
|||||||
|
#ifndef __JZ_TOPPOLY_TD043MGEB1_H__
|
||||||
|
#define __JZ_TOPPOLY_TD043MGEB1_H__
|
||||||
|
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
#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__ */
|
1538
target/linux/xburst/files-2.6.31/drivers/video/jzlcd.c
Executable file
1538
target/linux/xburst/files-2.6.31/drivers/video/jzlcd.c
Executable file
File diff suppressed because it is too large
Load Diff
791
target/linux/xburst/files-2.6.31/drivers/video/jzlcd.h
Executable file
791
target/linux/xburst/files-2.6.31/drivers/video/jzlcd.h
Executable file
@ -0,0 +1,791 @@
|
|||||||
|
/*
|
||||||
|
* linux/drivers/video/jzlcd.h -- Ingenic On-Chip LCD frame buffer device
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005-2007, Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __JZLCD_H__
|
||||||
|
#define __JZLCD_H__
|
||||||
|
|
||||||
|
#include <asm/io.h>
|
||||||
|
|
||||||
|
#define NR_PALETTE 256
|
||||||
|
|
||||||
|
struct lcd_desc{
|
||||||
|
unsigned int next_desc; /* LCDDAx */
|
||||||
|
unsigned int databuf; /* LCDSAx */
|
||||||
|
unsigned int frame_id; /* LCDFIDx */
|
||||||
|
unsigned int cmd; /* LCDCMDx */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MODE_MASK 0x0f
|
||||||
|
#define MODE_TFT_GEN 0x00
|
||||||
|
#define MODE_TFT_SHARP 0x01
|
||||||
|
#define MODE_TFT_CASIO 0x02
|
||||||
|
#define MODE_TFT_SAMSUNG 0x03
|
||||||
|
#define MODE_CCIR656_NONINT 0x04
|
||||||
|
#define MODE_CCIR656_INT 0x05
|
||||||
|
#define MODE_STN_COLOR_SINGLE 0x08
|
||||||
|
#define MODE_STN_MONO_SINGLE 0x09
|
||||||
|
#define MODE_STN_COLOR_DUAL 0x0a
|
||||||
|
#define MODE_STN_MONO_DUAL 0x0b
|
||||||
|
#define MODE_8BIT_SERIAL_TFT 0x0c
|
||||||
|
|
||||||
|
#define MODE_TFT_18BIT (1<<7)
|
||||||
|
|
||||||
|
#define STN_DAT_PIN1 (0x00 << 4)
|
||||||
|
#define STN_DAT_PIN2 (0x01 << 4)
|
||||||
|
#define STN_DAT_PIN4 (0x02 << 4)
|
||||||
|
#define STN_DAT_PIN8 (0x03 << 4)
|
||||||
|
#define STN_DAT_PINMASK STN_DAT_PIN8
|
||||||
|
|
||||||
|
#define STFT_PSHI (1 << 15)
|
||||||
|
#define STFT_CLSHI (1 << 14)
|
||||||
|
#define STFT_SPLHI (1 << 13)
|
||||||
|
#define STFT_REVHI (1 << 12)
|
||||||
|
|
||||||
|
#define SYNC_MASTER (0 << 16)
|
||||||
|
#define SYNC_SLAVE (1 << 16)
|
||||||
|
|
||||||
|
#define DE_P (0 << 9)
|
||||||
|
#define DE_N (1 << 9)
|
||||||
|
|
||||||
|
#define PCLK_P (0 << 10)
|
||||||
|
#define PCLK_N (1 << 10)
|
||||||
|
|
||||||
|
#define HSYNC_P (0 << 11)
|
||||||
|
#define HSYNC_N (1 << 11)
|
||||||
|
|
||||||
|
#define VSYNC_P (0 << 8)
|
||||||
|
#define VSYNC_N (1 << 8)
|
||||||
|
|
||||||
|
#define DATA_NORMAL (0 << 17)
|
||||||
|
#define DATA_INVERSE (1 << 17)
|
||||||
|
|
||||||
|
|
||||||
|
/* Jz LCDFB supported I/O controls. */
|
||||||
|
#define FBIOSETBACKLIGHT 0x4688
|
||||||
|
#define FBIODISPON 0x4689
|
||||||
|
#define FBIODISPOFF 0x468a
|
||||||
|
#define FBIORESET 0x468b
|
||||||
|
#define FBIOPRINT_REGS 0x468c
|
||||||
|
#define FBIOGETBUFADDRS 0x468d
|
||||||
|
#define FBIOROTATE 0x46a0 /* rotated fb */
|
||||||
|
|
||||||
|
struct jz_lcd_buffer_addrs_t {
|
||||||
|
int fb_num;
|
||||||
|
unsigned int lcd_desc_phys_addr;
|
||||||
|
unsigned int fb_phys_addr[CONFIG_JZLCD_FRAMEBUFFER_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LCD panel specific definition
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_JZLCD_TRULY_TFTG320240DTSW)
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZ4730_PMP)
|
||||||
|
#define LCD_RESET_PIN 63
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __lcd_special_on() \
|
||||||
|
do { \
|
||||||
|
__gpio_set_pin(LCD_RESET_PIN); \
|
||||||
|
__gpio_as_output(LCD_RESET_PIN); \
|
||||||
|
__gpio_clear_pin(LCD_RESET_PIN); \
|
||||||
|
udelay(100); \
|
||||||
|
__gpio_set_pin(LCD_RESET_PIN); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* CONFIG_JZLCD_TRULY_TFTG320240DTSW */
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZLCD_SAMSUNG_LTV350QVF04)
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZ4730_FPRINT)
|
||||||
|
#define PortSDI 60
|
||||||
|
#define PortSCL 61
|
||||||
|
#define PortCS 62
|
||||||
|
#define PortRST 63
|
||||||
|
#define PortSht 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZ4730_GPS)
|
||||||
|
#define PortSDI 74
|
||||||
|
#define PortSCL 72
|
||||||
|
#define PortCS 73
|
||||||
|
#define PortRST 60
|
||||||
|
#define PortSht 59
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PortSDI
|
||||||
|
#define PortSDI 0
|
||||||
|
#endif
|
||||||
|
#ifndef PortSCL
|
||||||
|
#define PortSCL 0
|
||||||
|
#endif
|
||||||
|
#ifndef PortCS
|
||||||
|
#define PortCS 0
|
||||||
|
#endif
|
||||||
|
#ifndef PortRST
|
||||||
|
#define PortRST 0
|
||||||
|
#endif
|
||||||
|
#ifndef PortSht
|
||||||
|
#define PortSht 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __lcd_special_pin_init() \
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(PortSDI); /* SDI */\
|
||||||
|
__gpio_as_output(PortSCL); /* SCL */ \
|
||||||
|
__gpio_as_output(PortCS); /* CS */ \
|
||||||
|
__gpio_as_output(PortRST); /* Reset */ \
|
||||||
|
__gpio_as_output(PortSht); /* Shut Down # */ \
|
||||||
|
__gpio_set_pin(PortCS); \
|
||||||
|
__gpio_set_pin(PortSCL); \
|
||||||
|
__gpio_set_pin(PortSDI); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __spi_out(val) \
|
||||||
|
do { \
|
||||||
|
int __i__; \
|
||||||
|
unsigned int _t_ = (val); \
|
||||||
|
__gpio_clear_pin(PortCS); \
|
||||||
|
udelay(25); \
|
||||||
|
for (__i__ = 0; __i__ < 24; __i__++ ) { \
|
||||||
|
__gpio_clear_pin(PortSCL); \
|
||||||
|
if (_t_ & 0x800000) \
|
||||||
|
__gpio_set_pin(PortSDI); \
|
||||||
|
else \
|
||||||
|
__gpio_clear_pin(PortSDI); \
|
||||||
|
_t_ <<= 1; \
|
||||||
|
udelay(25); \
|
||||||
|
__gpio_set_pin(PortSCL); \
|
||||||
|
udelay(25); \
|
||||||
|
} \
|
||||||
|
__gpio_set_pin(PortCS); \
|
||||||
|
udelay(25); \
|
||||||
|
__gpio_set_pin(PortSDI); \
|
||||||
|
udelay(25); \
|
||||||
|
__gpio_set_pin(PortSCL); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __spi_id_op_data(rs, rw, val) \
|
||||||
|
__spi_out((0x1d<<18)|((rs)<<17)|((rw)<<16)|(val))
|
||||||
|
|
||||||
|
#define __spi_write_reg(reg, val) \
|
||||||
|
do { \
|
||||||
|
__spi_id_op_data(0, 0, (reg)); \
|
||||||
|
__spi_id_op_data(1, 0, (val)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_special_on() \
|
||||||
|
do { \
|
||||||
|
__gpio_set_pin(PortSht); \
|
||||||
|
__gpio_clear_pin(PortRST); \
|
||||||
|
mdelay(10); \
|
||||||
|
__gpio_set_pin(PortRST); \
|
||||||
|
mdelay(1); \
|
||||||
|
__spi_write_reg(0x09, 0); \
|
||||||
|
mdelay(10); \
|
||||||
|
__spi_write_reg(0x09, 0x4000); \
|
||||||
|
__spi_write_reg(0x0a, 0x2000); \
|
||||||
|
mdelay(40); \
|
||||||
|
__spi_write_reg(0x09, 0x4055); \
|
||||||
|
mdelay(50); \
|
||||||
|
__spi_write_reg(0x01, 0x409d); \
|
||||||
|
__spi_write_reg(0x02, 0x0204); \
|
||||||
|
__spi_write_reg(0x03, 0x0100); \
|
||||||
|
__spi_write_reg(0x04, 0x3000); \
|
||||||
|
__spi_write_reg(0x05, 0x4003); \
|
||||||
|
__spi_write_reg(0x06, 0x000a); \
|
||||||
|
__spi_write_reg(0x07, 0x0021); \
|
||||||
|
__spi_write_reg(0x08, 0x0c00); \
|
||||||
|
__spi_write_reg(0x10, 0x0103); \
|
||||||
|
__spi_write_reg(0x11, 0x0301); \
|
||||||
|
__spi_write_reg(0x12, 0x1f0f); \
|
||||||
|
__spi_write_reg(0x13, 0x1f0f); \
|
||||||
|
__spi_write_reg(0x14, 0x0707); \
|
||||||
|
__spi_write_reg(0x15, 0x0307); \
|
||||||
|
__spi_write_reg(0x16, 0x0707); \
|
||||||
|
__spi_write_reg(0x17, 0x0000); \
|
||||||
|
__spi_write_reg(0x18, 0x0004); \
|
||||||
|
__spi_write_reg(0x19, 0x0000); \
|
||||||
|
mdelay(60); \
|
||||||
|
__spi_write_reg(0x09, 0x4a55); \
|
||||||
|
__spi_write_reg(0x05, 0x5003); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_special_off() \
|
||||||
|
do { \
|
||||||
|
__spi_write_reg(0x09, 0x4055); \
|
||||||
|
__spi_write_reg(0x05, 0x4003); \
|
||||||
|
__spi_write_reg(0x0a, 0x0000); \
|
||||||
|
mdelay(10); \
|
||||||
|
__spi_write_reg(0x09, 0x4000); \
|
||||||
|
__gpio_clear_pin(PortSht); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* CONFIG_JZLCD_SAMSUNG_LTV350QVF04 */
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZLCD_AUO_A030FL01_V1)
|
||||||
|
#if defined(CONFIG_JZ4740_PAVO) /* board pavo */
|
||||||
|
#define SPEN (32*1+18) /*LCD_CS*/
|
||||||
|
#define SPCK (32*1+17) /*LCD_SCL*/
|
||||||
|
#define SPDA (32*2+12) /*LCD_SDA*/
|
||||||
|
#define LCD_RET (32*2+23) /*use for lcd reset*/
|
||||||
|
#elif defined(CONFIG_JZ4740_LYRA) /* board lyra */
|
||||||
|
#define SPEN (32*3+19) //LCD_CS
|
||||||
|
#define SPCK (32*3+18) //LCD_SCL
|
||||||
|
#define SPDA (32*3+20) //LCD_SDA
|
||||||
|
#define LCD_RET (32*3+31) //use for lcd reset
|
||||||
|
#else
|
||||||
|
#error "driver/video/Jzlcd.h, please define SPI pins on your board."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __spi_write_reg(reg, val) \
|
||||||
|
do { \
|
||||||
|
unsigned char no; \
|
||||||
|
unsigned short value; \
|
||||||
|
unsigned char a=0; \
|
||||||
|
unsigned char b=0; \
|
||||||
|
__gpio_as_output(SPEN); /* use SPDA */ \
|
||||||
|
__gpio_as_output(SPCK); /* use SPCK */ \
|
||||||
|
__gpio_as_output(SPDA); /* use SPDA */ \
|
||||||
|
a=reg; \
|
||||||
|
b=val; \
|
||||||
|
__gpio_set_pin(SPEN); \
|
||||||
|
__gpio_clear_pin(SPCK); \
|
||||||
|
udelay(50); \
|
||||||
|
__gpio_clear_pin(SPDA); \
|
||||||
|
__gpio_clear_pin(SPEN); \
|
||||||
|
udelay(50); \
|
||||||
|
value=((a<<8)|(b&0xFF)); \
|
||||||
|
for(no=0;no<16;no++) \
|
||||||
|
{ \
|
||||||
|
if((value&0x8000)==0x8000){ \
|
||||||
|
__gpio_set_pin(SPDA);} \
|
||||||
|
else{ \
|
||||||
|
__gpio_clear_pin(SPDA); } \
|
||||||
|
udelay(400); \
|
||||||
|
__gpio_set_pin(SPCK); \
|
||||||
|
value=(value<<1); \
|
||||||
|
udelay(50); \
|
||||||
|
__gpio_clear_pin(SPCK); \
|
||||||
|
} \
|
||||||
|
__gpio_set_pin(SPEN); \
|
||||||
|
udelay(400); \
|
||||||
|
} while (0)
|
||||||
|
#define __spi_read_reg(reg,val) \
|
||||||
|
do{ \
|
||||||
|
unsigned char no; \
|
||||||
|
unsigned short value; \
|
||||||
|
__gpio_as_output(SPEN); /* use SPDA */ \
|
||||||
|
__gpio_as_output(SPCK); /* use SPCK */ \
|
||||||
|
__gpio_as_output(SPDA); /* use SPDA */ \
|
||||||
|
value = ((reg << 0) | (1 << 7)); \
|
||||||
|
val = 0; \
|
||||||
|
__gpio_as_output(SPDA); \
|
||||||
|
__gpio_set_pin(SPEN); \
|
||||||
|
__gpio_set_pin(SPCK); \
|
||||||
|
udelay(1); \
|
||||||
|
__gpio_clear_pin(SPDA); \
|
||||||
|
__gpio_clear_pin(SPEN); \
|
||||||
|
udelay(1); \
|
||||||
|
for (no = 0; no < 16; no++ ) { \
|
||||||
|
__gpio_clear_pin(SPCK); \
|
||||||
|
udelay(1); \
|
||||||
|
if(no < 8) \
|
||||||
|
{ \
|
||||||
|
if (value & 0x80) /* send data */ \
|
||||||
|
__gpio_set_pin(SPDA); \
|
||||||
|
else \
|
||||||
|
__gpio_clear_pin(SPDA); \
|
||||||
|
value = (value << 1); \
|
||||||
|
udelay(1); \
|
||||||
|
__gpio_set_pin(SPCK); \
|
||||||
|
udelay(1); \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
__gpio_as_input(SPDA); \
|
||||||
|
udelay(1); \
|
||||||
|
__gpio_set_pin(SPCK); \
|
||||||
|
udelay(1); \
|
||||||
|
val = (val << 1); \
|
||||||
|
val |= __gpio_get_pin(SPDA); \
|
||||||
|
udelay(1); \
|
||||||
|
} \
|
||||||
|
udelay(400); \
|
||||||
|
} \
|
||||||
|
__gpio_as_output(SPDA); \
|
||||||
|
__gpio_set_pin(SPEN); \
|
||||||
|
udelay(400); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define __lcd_special_pin_init() \
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(SPEN); /* use SPDA */ \
|
||||||
|
__gpio_as_output(SPCK); /* use SPCK */ \
|
||||||
|
__gpio_as_output(SPDA); /* use SPDA */ \
|
||||||
|
__gpio_as_output(LCD_RET); \
|
||||||
|
udelay(50); \
|
||||||
|
__gpio_clear_pin(LCD_RET); \
|
||||||
|
udelay(100); \
|
||||||
|
__gpio_set_pin(LCD_RET); \
|
||||||
|
} while (0)
|
||||||
|
#define __lcd_special_on() \
|
||||||
|
do { \
|
||||||
|
udelay(50); \
|
||||||
|
__gpio_clear_pin(LCD_RET); \
|
||||||
|
udelay(100); \
|
||||||
|
__gpio_set_pin(LCD_RET); \
|
||||||
|
__spi_write_reg(0x0D, 0x44); \
|
||||||
|
__spi_write_reg(0x0D, 0x4D); \
|
||||||
|
__spi_write_reg(0x0B, 0x06); \
|
||||||
|
__spi_write_reg(0x40, 0xC0); \
|
||||||
|
__spi_write_reg(0x42, 0x43); \
|
||||||
|
__spi_write_reg(0x44, 0x28); \
|
||||||
|
__spi_write_reg(0x0D, 0x4F); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_special_off() \
|
||||||
|
do { \
|
||||||
|
__spi_write_reg(0x04, 0x4C); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* CONFIG_JZLCD_AUO_A030FL01_V1 */
|
||||||
|
|
||||||
|
//#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01)
|
||||||
|
#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) || defined(CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL)
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) /* board pmp */
|
||||||
|
#define MODE 0xcd /* 24bit parellel RGB */
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL)
|
||||||
|
#define MODE 0xc9 /* 8bit serial RGB */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZ4730_PMP)
|
||||||
|
#define SPEN 60 //LCD_SPL
|
||||||
|
#define SPCK 61 //LCD_CLS
|
||||||
|
#define SPDA 62 //LCD_PS
|
||||||
|
#define LCD_RET 63 //LCD_REV //use for lcd reset
|
||||||
|
#elif defined(CONFIG_JZ4740_LEO) /* board leo */
|
||||||
|
#define SPEN (32*1+18) //LCD_SPL
|
||||||
|
#define SPCK (32*1+17) //LCD_CLS
|
||||||
|
#define SPDA (32*2+22) //LCD_PS
|
||||||
|
#define LCD_RET (32*2+23) //LCD_REV //use for lcd reset
|
||||||
|
#elif defined(CONFIG_JZ4740_PAVO) /* board pavo */
|
||||||
|
#define SPEN (32*1+18) //LCD_SPL
|
||||||
|
#define SPCK (32*1+17) //LCD_CLS
|
||||||
|
#define SPDA (32*2+12) //LCD_D12
|
||||||
|
#define LCD_RET (32*2+23) //LCD_REV, GPC23
|
||||||
|
#if 0 /*old driver*/
|
||||||
|
#define SPEN (32*1+18) //LCD_SPL
|
||||||
|
#define SPCK (32*1+17) //LCD_CLS
|
||||||
|
#define SPDA (32*2+12) //LCD_D12
|
||||||
|
#define LCD_RET (32*3+27) //PWM4 //use for lcd reset
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#error "driver/video/Jzlcd.h, please define SPI pins on your board."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __spi_write_reg1(reg, val) \
|
||||||
|
do { \
|
||||||
|
unsigned char no;\
|
||||||
|
unsigned short value;\
|
||||||
|
unsigned char a=0;\
|
||||||
|
unsigned char b=0;\
|
||||||
|
a=reg;\
|
||||||
|
b=val;\
|
||||||
|
__gpio_set_pin(SPEN);\
|
||||||
|
__gpio_set_pin(SPCK);\
|
||||||
|
__gpio_clear_pin(SPDA);\
|
||||||
|
__gpio_clear_pin(SPEN);\
|
||||||
|
udelay(25);\
|
||||||
|
value=((a<<8)|(b&0xFF));\
|
||||||
|
for(no=0;no<16;no++)\
|
||||||
|
{\
|
||||||
|
__gpio_clear_pin(SPCK);\
|
||||||
|
if((value&0x8000)==0x8000)\
|
||||||
|
__gpio_set_pin(SPDA);\
|
||||||
|
else\
|
||||||
|
__gpio_clear_pin(SPDA);\
|
||||||
|
udelay(25);\
|
||||||
|
__gpio_set_pin(SPCK);\
|
||||||
|
value=(value<<1); \
|
||||||
|
udelay(25);\
|
||||||
|
}\
|
||||||
|
__gpio_set_pin(SPEN);\
|
||||||
|
udelay(100);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __spi_write_reg(reg, val) \
|
||||||
|
do {\
|
||||||
|
__spi_write_reg1((reg<<2|2), val); \
|
||||||
|
udelay(100); \
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
#define __lcd_special_pin_init() \
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(SPEN); /* use SPDA */\
|
||||||
|
__gpio_as_output(SPCK); /* use SPCK */\
|
||||||
|
__gpio_as_output(SPDA); /* use SPDA */\
|
||||||
|
__gpio_as_output(LCD_RET);\
|
||||||
|
udelay(50);\
|
||||||
|
__gpio_clear_pin(LCD_RET);\
|
||||||
|
mdelay(150);\
|
||||||
|
__gpio_set_pin(LCD_RET);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_special_on() \
|
||||||
|
do { \
|
||||||
|
udelay(50);\
|
||||||
|
__gpio_clear_pin(LCD_RET);\
|
||||||
|
mdelay(150);\
|
||||||
|
__gpio_set_pin(LCD_RET);\
|
||||||
|
mdelay(10);\
|
||||||
|
__spi_write_reg(0x00, 0x03); \
|
||||||
|
__spi_write_reg(0x01, 0x40); \
|
||||||
|
__spi_write_reg(0x02, 0x11); \
|
||||||
|
__spi_write_reg(0x03, MODE); /* mode */ \
|
||||||
|
__spi_write_reg(0x04, 0x32); \
|
||||||
|
__spi_write_reg(0x05, 0x0e); \
|
||||||
|
__spi_write_reg(0x07, 0x03); \
|
||||||
|
__spi_write_reg(0x08, 0x08); \
|
||||||
|
__spi_write_reg(0x09, 0x32); \
|
||||||
|
__spi_write_reg(0x0A, 0x88); \
|
||||||
|
__spi_write_reg(0x0B, 0xc6); \
|
||||||
|
__spi_write_reg(0x0C, 0x20); \
|
||||||
|
__spi_write_reg(0x0D, 0x20); \
|
||||||
|
} while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level
|
||||||
|
|
||||||
|
/* __spi_write_reg(0x02, 0x03); \
|
||||||
|
__spi_write_reg(0x06, 0x40); \
|
||||||
|
__spi_write_reg(0x0a, 0x11); \
|
||||||
|
__spi_write_reg(0x0e, 0xcd); \
|
||||||
|
__spi_write_reg(0x12, 0x32); \
|
||||||
|
__spi_write_reg(0x16, 0x0e); \
|
||||||
|
__spi_write_reg(0x1e, 0x03); \
|
||||||
|
__spi_write_reg(0x22, 0x08); \
|
||||||
|
__spi_write_reg(0x26, 0x40); \
|
||||||
|
__spi_write_reg(0x2a, 0x88); \
|
||||||
|
__spi_write_reg(0x2e, 0x88); \
|
||||||
|
__spi_write_reg(0x32, 0x20); \
|
||||||
|
__spi_write_reg(0x36, 0x20); \
|
||||||
|
*/
|
||||||
|
// } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level
|
||||||
|
|
||||||
|
#define __lcd_special_off() \
|
||||||
|
do { \
|
||||||
|
__spi_write_reg(0x00, 0x03); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* CONFIG_JZLCD_FOXCONN_PT035TN01 or CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __lcd_special_pin_init
|
||||||
|
#define __lcd_special_pin_init()
|
||||||
|
#endif
|
||||||
|
#ifndef __lcd_special_on
|
||||||
|
#define __lcd_special_on()
|
||||||
|
#endif
|
||||||
|
#ifndef __lcd_special_off
|
||||||
|
#define __lcd_special_off()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Platform specific definition
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZ4730_GPS)
|
||||||
|
|
||||||
|
#define __lcd_set_backlight_level(n) \
|
||||||
|
do { \
|
||||||
|
; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_pin_init() \
|
||||||
|
do { \
|
||||||
|
__lcd_special_pin_init(); \
|
||||||
|
__gpio_as_output(94); /* PWM0 pin */ \
|
||||||
|
__gpio_as_output(95); /* PWM1 pin */ \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_on() \
|
||||||
|
do { \
|
||||||
|
__lcd_special_on(); \
|
||||||
|
__gpio_set_pin(94); /* PWM0 pin */ \
|
||||||
|
__gpio_set_pin(95); /* PWM1 pin */ \
|
||||||
|
__lcd_set_backlight_level(8); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_off() \
|
||||||
|
do { \
|
||||||
|
__lcd_special_off(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* CONFIG_JZ4730_GPS */
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZ4730_FPRINT)
|
||||||
|
|
||||||
|
#define __lcd_set_backlight_level(n) \
|
||||||
|
do { \
|
||||||
|
REG_PWM_DUT(0) = n; \
|
||||||
|
REG_PWM_PER(0) = 7; \
|
||||||
|
REG_PWM_CTR(0) = 0x81; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01)
|
||||||
|
|
||||||
|
#define __lcd_display_pin_init() \
|
||||||
|
do { \
|
||||||
|
__lcd_special_pin_init();\
|
||||||
|
__gpio_as_pwm();\
|
||||||
|
__lcd_set_backlight_level(8);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_on() \
|
||||||
|
do { \
|
||||||
|
__lcd_set_backlight_level(8); \
|
||||||
|
__lcd_special_on();\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_off() \
|
||||||
|
do { \
|
||||||
|
__lcd_set_backlight_level(0); \
|
||||||
|
__lcd_special_off();\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define __lcd_display_pin_init() \
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(GPIO_DISP_OFF_N); \
|
||||||
|
__gpio_as_pwm(); \
|
||||||
|
__lcd_set_backlight_level(8); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_on() \
|
||||||
|
do { \
|
||||||
|
__lcd_set_backlight_level(8); \
|
||||||
|
__gpio_set_pin(GPIO_DISP_OFF_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_off() \
|
||||||
|
do { \
|
||||||
|
__lcd_set_backlight_level(0); \
|
||||||
|
__gpio_clear_pin(GPIO_DISP_OFF_N); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CONFIG_JZ4730_FPRINT */
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZ4730_LIBRA)
|
||||||
|
|
||||||
|
#define __lcd_set_backlight_level(n) \
|
||||||
|
do { \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_pin_init() \
|
||||||
|
do { \
|
||||||
|
__lcd_special_pin_init(); \
|
||||||
|
__gpio_clear_pin(100); \
|
||||||
|
__gpio_as_output(100); \
|
||||||
|
__gpio_as_output(94); \
|
||||||
|
__gpio_as_output(95); \
|
||||||
|
__lcd_set_backlight_level(8); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_on() \
|
||||||
|
do { \
|
||||||
|
__lcd_special_on(); \
|
||||||
|
__gpio_set_pin(100); \
|
||||||
|
__gpio_set_pin(94); \
|
||||||
|
__gpio_set_pin(95); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_off() \
|
||||||
|
do { \
|
||||||
|
__lcd_special_off(); \
|
||||||
|
__gpio_clear_pin(100); \
|
||||||
|
__gpio_clear_pin(94); \
|
||||||
|
__gpio_clear_pin(95); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* CONFIG_JZ4730_LIBRA */
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZ4730_PMP)
|
||||||
|
|
||||||
|
#define __lcd_set_backlight_level(n) \
|
||||||
|
do { \
|
||||||
|
REG_PWM_DUT(0) = n; \
|
||||||
|
REG_PWM_PER(0) = 7; \
|
||||||
|
REG_PWM_CTR(0) = 0x81; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_pin_init() \
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(GPIO_DISP_OFF_N); \
|
||||||
|
__gpio_as_pwm(); \
|
||||||
|
__lcd_set_backlight_level(10); \
|
||||||
|
__lcd_special_pin_init(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_on() \
|
||||||
|
do { \
|
||||||
|
__lcd_special_on(); \
|
||||||
|
__lcd_set_backlight_level(8); \
|
||||||
|
__gpio_set_pin(GPIO_DISP_OFF_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_off() \
|
||||||
|
do { \
|
||||||
|
__lcd_special_off(); \
|
||||||
|
__lcd_set_backlight_level(0); \
|
||||||
|
__gpio_clear_pin(GPIO_DISP_OFF_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* CONFIG_JZ4730_PMP */
|
||||||
|
|
||||||
|
/*#if defined(CONFIG_JZ4740_LEO) || defined(CONFIG_JZ4740_PAVO)*/
|
||||||
|
#if defined(CONFIG_SOC_JZ4740)
|
||||||
|
#if defined(CONFIG_JZ4740_PAVO) || defined(CONFIG_JZ4740_LYRA)
|
||||||
|
#define GPIO_PWM 123 /* GP_D27 */
|
||||||
|
#define PWM_CHN 4 /* pwm channel */
|
||||||
|
#define PWM_FULL 101
|
||||||
|
/* 100 level: 0,1,...,100 */
|
||||||
|
#define __lcd_set_backlight_level(n)\
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(32*3+27); \
|
||||||
|
__gpio_set_pin(32*3+27); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_close_backlight() \
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(GPIO_PWM); \
|
||||||
|
__gpio_clear_pin(GPIO_PWM); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#elif defined(CONFIG_JZ4720_VIRGO)
|
||||||
|
#define GPIO_PWM 119 /* GP_D23 */
|
||||||
|
#define PWM_CHN 0 /* pwm channel */
|
||||||
|
#define PWM_FULL 101
|
||||||
|
/* 100 level: 0,1,...,100 */
|
||||||
|
/*#define __lcd_set_backlight_level(n) \
|
||||||
|
do { \
|
||||||
|
__gpio_as_pwm(0); \
|
||||||
|
__tcu_disable_pwm_output(PWM_CHN); \
|
||||||
|
__tcu_stop_counter(PWM_CHN); \
|
||||||
|
__tcu_init_pwm_output_high(PWM_CHN); \
|
||||||
|
__tcu_set_pwm_output_shutdown_abrupt(PWM_CHN); \
|
||||||
|
__tcu_select_clk_div1(PWM_CHN); \
|
||||||
|
__tcu_mask_full_match_irq(PWM_CHN); \
|
||||||
|
__tcu_mask_half_match_irq(PWM_CHN); \
|
||||||
|
__tcu_set_count(PWM_CHN,0); \
|
||||||
|
__tcu_set_full_data(PWM_CHN,__cpm_get_extalclk()/1000); \
|
||||||
|
__tcu_set_half_data(PWM_CHN,__cpm_get_extalclk()/1000*n/100); \
|
||||||
|
__tcu_enable_pwm_output(PWM_CHN); \
|
||||||
|
__tcu_select_extalclk(PWM_CHN); \
|
||||||
|
__tcu_start_counter(PWM_CHN); \
|
||||||
|
} while (0)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __lcd_set_backlight_level(n) \
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(GPIO_PWM); \
|
||||||
|
__gpio_set_pin(GPIO_PWM); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_close_backlight() \
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(GPIO_PWM); \
|
||||||
|
__gpio_clear_pin(GPIO_PWM); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define __lcd_set_backlight_level(n)
|
||||||
|
#define __lcd_close_backlight()
|
||||||
|
|
||||||
|
#endif /* #if defined(CONFIG_MIPS_JZ4740_PAVO) */
|
||||||
|
|
||||||
|
#define __lcd_display_pin_init() \
|
||||||
|
do { \
|
||||||
|
__gpio_as_output(GPIO_DISP_OFF_N); \
|
||||||
|
__cpm_start_tcu(); \
|
||||||
|
__lcd_special_pin_init(); \
|
||||||
|
} while (0)
|
||||||
|
/* __lcd_set_backlight_level(100); \*/
|
||||||
|
#define __lcd_display_on() \
|
||||||
|
do { \
|
||||||
|
__gpio_set_pin(GPIO_DISP_OFF_N); \
|
||||||
|
__lcd_special_on(); \
|
||||||
|
__lcd_set_backlight_level(80); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __lcd_display_off() \
|
||||||
|
do { \
|
||||||
|
__lcd_special_off(); \
|
||||||
|
__lcd_close_backlight(); \
|
||||||
|
__gpio_clear_pin(GPIO_DISP_OFF_N); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* CONFIG_MIPS_JZ4740_LEO */
|
||||||
|
|
||||||
|
#if defined(CONFIG_JZLCD_MSTN_240x128)
|
||||||
|
|
||||||
|
#if 0 /* The final version does not use software emulation of VCOM. */
|
||||||
|
|
||||||
|
#define GPIO_VSYNC 59
|
||||||
|
#define GPIO_VCOM 90
|
||||||
|
|
||||||
|
#define REG_VCOM REG_GPIO_GPDR((GPIO_VCOM>>5))
|
||||||
|
#define VCOM_BIT (1 << (GPIO_VCOM & 0x1f))
|
||||||
|
static unsigned int vcom_static;
|
||||||
|
static void vsync_irq(int irq, void *dev_id, struct pt_regs *reg)
|
||||||
|
{
|
||||||
|
vcom_static = REG_VCOM;
|
||||||
|
vcom_static ^= VCOM_BIT;
|
||||||
|
REG_VCOM = vcom_static;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __lcd_display_pin_init() \
|
||||||
|
__gpio_as_irq_rise_edge(GPIO_VSYNC); \
|
||||||
|
__gpio_as_output(GPIO_VCOM); \
|
||||||
|
{ \
|
||||||
|
static int inited = 0; \
|
||||||
|
if (!inited) { \
|
||||||
|
inited = 1; \
|
||||||
|
if (request_irq(IRQ_GPIO_0 + GPIO_VSYNC, vsync_irq, SA_INTERRUPT, \
|
||||||
|
"vsync", 0)) { \
|
||||||
|
err = -EBUSY; \
|
||||||
|
goto failed; \
|
||||||
|
}}}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* We uses AC BIAs pin to generate VCOM signal, so above code should be removed.
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
/*****************************************************************************
|
||||||
|
* LCD display pin dummy macros
|
||||||
|
*****************************************************************************/
|
||||||
|
#ifndef __lcd_display_pin_init
|
||||||
|
#define __lcd_display_pin_init()
|
||||||
|
#endif
|
||||||
|
#ifndef __lcd_display_on
|
||||||
|
#define __lcd_display_on()
|
||||||
|
#endif
|
||||||
|
#ifndef __lcd_display_off
|
||||||
|
#define __lcd_display_off()
|
||||||
|
#endif
|
||||||
|
#ifndef __lcd_set_backlight_level
|
||||||
|
#define __lcd_set_backlight_level(n)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __JZLCD_H__ */
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
|
||||||
|
* JZ4720/JZ4740 SoC NAND controller 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.
|
||||||
|
*
|
||||||
|
* You 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 __JZ_NAND_H__
|
||||||
|
#define __JZ_NAND_H__
|
||||||
|
|
||||||
|
#include <linux/mtd/partitions.h>
|
||||||
|
#include <linux/mtd/nand.h>
|
||||||
|
|
||||||
|
struct jz_nand_platform_data {
|
||||||
|
int num_partitions;
|
||||||
|
struct mtd_partition *partitions;
|
||||||
|
|
||||||
|
struct nand_ecclayout *ecc_layout;
|
||||||
|
|
||||||
|
unsigned int busy_gpio;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
725
target/linux/xburst/files-2.6.31/sound/soc/codecs/jzcodec.c
Executable file
725
target/linux/xburst/files-2.6.31/sound/soc/codecs/jzcodec.c
Executable file
@ -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 <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <sound/core.h>
|
||||||
|
#include <sound/pcm.h>
|
||||||
|
#include <sound/ac97_codec.h>
|
||||||
|
#include <sound/initval.h>
|
||||||
|
#include <sound/soc.h>
|
||||||
|
#include <sound/soc-dapm.h>
|
||||||
|
|
||||||
|
#include "../jz4740/jz4740-pcm.h"
|
||||||
|
#include "jzcodec.h"
|
||||||
|
|
||||||
|
#define AUDIO_NAME "jzcodec"
|
||||||
|
#define JZCODEC_VERSION "1.0"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Debug
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define JZCODEC_DEBUG 0
|
||||||
|
|
||||||
|
#ifdef JZCODEC_DEBUG
|
||||||
|
#define dbg(format, arg...) \
|
||||||
|
printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
|
||||||
|
#else
|
||||||
|
#define dbg(format, arg...) do {} while (0)
|
||||||
|
#endif
|
||||||
|
#define err(format, arg...) \
|
||||||
|
printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
|
||||||
|
#define info(format, arg...) \
|
||||||
|
printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
|
||||||
|
#define warn(format, arg...) \
|
||||||
|
printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
|
||||||
|
|
||||||
|
struct snd_soc_codec_device soc_codec_dev_jzcodec;
|
||||||
|
|
||||||
|
/* codec private data */
|
||||||
|
struct jzcodec_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");
|
22
target/linux/xburst/files-2.6.31/sound/soc/codecs/jzcodec.h
Executable file
22
target/linux/xburst/files-2.6.31/sound/soc/codecs/jzcodec.h
Executable file
@ -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
|
981
target/linux/xburst/files-2.6.31/sound/soc/codecs/jzdlv.c
Executable file
981
target/linux/xburst/files-2.6.31/sound/soc/codecs/jzdlv.c
Executable file
@ -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 <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <sound/core.h>
|
||||||
|
#include <sound/pcm.h>
|
||||||
|
#include <sound/ac97_codec.h>
|
||||||
|
#include <sound/initval.h>
|
||||||
|
#include <sound/soc.h>
|
||||||
|
#include <sound/soc-dapm.h>
|
||||||
|
|
||||||
|
#include "../jz4750/jz4750-pcm.h"
|
||||||
|
#include "jzdlv.h"
|
||||||
|
|
||||||
|
#define AUDIO_NAME "jzdlv"
|
||||||
|
#define JZDLV_VERSION "1.0"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Debug
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define JZDLV_DEBUG 0
|
||||||
|
|
||||||
|
#ifdef JZDLV_DEBUG
|
||||||
|
#define dbg(format, arg...) \
|
||||||
|
printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
|
||||||
|
#else
|
||||||
|
#define dbg(format, arg...) do {} while (0)
|
||||||
|
#endif
|
||||||
|
#define err(format, arg...) \
|
||||||
|
printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
|
||||||
|
#define info(format, arg...) \
|
||||||
|
printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
|
||||||
|
#define warn(format, arg...) \
|
||||||
|
printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
|
||||||
|
|
||||||
|
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");
|
50
target/linux/xburst/files-2.6.31/sound/soc/codecs/jzdlv.h
Executable file
50
target/linux/xburst/files-2.6.31/sound/soc/codecs/jzdlv.h
Executable file
@ -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
|
34
target/linux/xburst/files-2.6.31/sound/soc/jz4740/Kconfig
Executable file
34
target/linux/xburst/files-2.6.31/sound/soc/jz4740/Kconfig
Executable file
@ -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.
|
15
target/linux/xburst/files-2.6.31/sound/soc/jz4740/Makefile
Executable file
15
target/linux/xburst/files-2.6.31/sound/soc/jz4740/Makefile
Executable file
@ -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
|
261
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-ac97.c
Executable file
261
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-ac97.c
Executable file
@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
* linux/sound/jz4740-ac97.c -- AC97 support for the Ingenic jz4740 chip.
|
||||||
|
*
|
||||||
|
* Author: Richard
|
||||||
|
* Created: Dec 02, 2007
|
||||||
|
* Copyright: Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
#include <sound/driver.h>
|
||||||
|
#include <sound/core.h>
|
||||||
|
#include <sound/pcm.h>
|
||||||
|
#include <sound/ac97_codec.h>
|
||||||
|
#include <sound/initval.h>
|
||||||
|
#include <sound/soc.h>
|
||||||
|
|
||||||
|
#include <asm/irq.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <asm/hardware.h>
|
||||||
|
#include <asm/arch/audio.h>
|
||||||
|
|
||||||
|
#include "jz4740-pcm.h"
|
||||||
|
#include "jz4740-ac97.h"
|
||||||
|
|
||||||
|
static DEFINE_MUTEX(car_mutex);
|
||||||
|
static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
|
||||||
|
static volatile long gsr_bits;
|
||||||
|
|
||||||
|
static unsigned short jz4740_ac97_read(struct snd_ac97 *ac97,
|
||||||
|
unsigned short reg)
|
||||||
|
{
|
||||||
|
unsigned short val = -1;
|
||||||
|
volatile u32 *reg_addr;
|
||||||
|
|
||||||
|
mutex_lock(&car_mutex);
|
||||||
|
|
||||||
|
out: mutex_unlock(&car_mutex);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4740_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
||||||
|
unsigned short val)
|
||||||
|
{
|
||||||
|
volatile u32 *reg_addr;
|
||||||
|
|
||||||
|
mutex_lock(&car_mutex);
|
||||||
|
|
||||||
|
mutex_unlock(&car_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4740_ac97_warm_reset(struct snd_ac97 *ac97)
|
||||||
|
{
|
||||||
|
gsr_bits = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4740_ac97_cold_reset(struct snd_ac97 *ac97)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t jz4740_ac97_irq(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
long status;
|
||||||
|
return IRQ_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct snd_ac97_bus_ops soc_ac97_ops = {
|
||||||
|
.read = jz4740_ac97_read,
|
||||||
|
.write = jz4740_ac97_write,
|
||||||
|
.warm_reset = jz4740_ac97_warm_reset,
|
||||||
|
.reset = jz4740_ac97_cold_reset,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_out = {
|
||||||
|
.name = "AC97 PCM Stereo out",
|
||||||
|
.dev_addr = __PREG(PCDR),
|
||||||
|
.drcmr = &DRCMRTXPCDR,
|
||||||
|
.dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
|
||||||
|
DCMD_BURST32 | DCMD_WIDTH4,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_in = {
|
||||||
|
.name = "AC97 PCM Stereo in",
|
||||||
|
.dev_addr = __PREG(PCDR),
|
||||||
|
.drcmr = &DRCMRRXPCDR,
|
||||||
|
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
||||||
|
DCMD_BURST32 | DCMD_WIDTH4,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_out = {
|
||||||
|
.name = "AC97 Aux PCM (Slot 5) Mono out",
|
||||||
|
.dev_addr = __PREG(MODR),
|
||||||
|
.drcmr = &DRCMRTXMODR,
|
||||||
|
.dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
|
||||||
|
DCMD_BURST16 | DCMD_WIDTH2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_in = {
|
||||||
|
.name = "AC97 Aux PCM (Slot 5) Mono in",
|
||||||
|
.dev_addr = __PREG(MODR),
|
||||||
|
.drcmr = &DRCMRRXMODR,
|
||||||
|
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
||||||
|
DCMD_BURST16 | DCMD_WIDTH2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_mic_mono_in = {
|
||||||
|
.name = "AC97 Mic PCM (Slot 6) Mono in",
|
||||||
|
.dev_addr = __PREG(MCDR),
|
||||||
|
.drcmr = &DRCMRRXMCDR,
|
||||||
|
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
||||||
|
DCMD_BURST16 | DCMD_WIDTH2,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int jz4740_ac97_suspend(struct platform_device *pdev,
|
||||||
|
struct snd_soc_cpu_dai *dai)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4740_ac97_resume(struct platform_device *pdev,
|
||||||
|
struct snd_soc_cpu_dai *dai)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define jz4740_ac97_suspend NULL
|
||||||
|
#define jz4740_ac97_resume NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int jz4740_ac97_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4740_ac97_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4740_ac97_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
|
{
|
||||||
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
|
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||||
|
|
||||||
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
|
cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_out;
|
||||||
|
else
|
||||||
|
cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_in;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4740_ac97_hw_aux_params(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
|
{
|
||||||
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
|
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||||
|
|
||||||
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
|
cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_out;
|
||||||
|
else
|
||||||
|
cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_in;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4740_ac97_hw_mic_params(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
|
{
|
||||||
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
|
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||||
|
|
||||||
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
|
return -ENODEV;
|
||||||
|
else
|
||||||
|
cpu_dai->dma_data = &jz4740_ac97_pcm_mic_mono_in;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define JZ4740_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||||
|
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
|
||||||
|
SNDRV_PCM_RATE_48000)
|
||||||
|
|
||||||
|
struct snd_soc_cpu_dai jz4740_ac97_dai[] = {
|
||||||
|
{
|
||||||
|
.name = "jz4740-ac97",
|
||||||
|
.id = 0,
|
||||||
|
.type = SND_SOC_DAI_AC97,
|
||||||
|
.probe = jz4740_ac97_probe,
|
||||||
|
.remove = jz4740_ac97_remove,
|
||||||
|
.suspend = jz4740_ac97_suspend,
|
||||||
|
.resume = jz4740_ac97_resume,
|
||||||
|
.playback = {
|
||||||
|
.stream_name = "AC97 Playback",
|
||||||
|
.channels_min = 2,
|
||||||
|
.channels_max = 2,
|
||||||
|
.rates = JZ4740_AC97_RATES,
|
||||||
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||||
|
.capture = {
|
||||||
|
.stream_name = "AC97 Capture",
|
||||||
|
.channels_min = 2,
|
||||||
|
.channels_max = 2,
|
||||||
|
.rates = JZ4740_AC97_RATES,
|
||||||
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||||
|
.ops = {
|
||||||
|
.hw_params = jz4740_ac97_hw_params,},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "jz4740-ac97-aux",
|
||||||
|
.id = 1,
|
||||||
|
.type = SND_SOC_DAI_AC97,
|
||||||
|
.playback = {
|
||||||
|
.stream_name = "AC97 Aux Playback",
|
||||||
|
.channels_min = 1,
|
||||||
|
.channels_max = 1,
|
||||||
|
.rates = JZ4740_AC97_RATES,
|
||||||
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||||
|
.capture = {
|
||||||
|
.stream_name = "AC97 Aux Capture",
|
||||||
|
.channels_min = 1,
|
||||||
|
.channels_max = 1,
|
||||||
|
.rates = JZ4740_AC97_RATES,
|
||||||
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||||
|
.ops = {
|
||||||
|
.hw_params = jz4740_ac97_hw_aux_params,},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "jz4740-ac97-mic",
|
||||||
|
.id = 2,
|
||||||
|
.type = SND_SOC_DAI_AC97,
|
||||||
|
.capture = {
|
||||||
|
.stream_name = "AC97 Mic Capture",
|
||||||
|
.channels_min = 1,
|
||||||
|
.channels_max = 1,
|
||||||
|
.rates = JZ4740_AC97_RATES,
|
||||||
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||||
|
.ops = {
|
||||||
|
.hw_params = jz4740_ac97_hw_mic_params,},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPORT_SYMBOL_GPL(jz4740_ac97_dai);
|
||||||
|
EXPORT_SYMBOL_GPL(soc_ac97_ops);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Richard");
|
||||||
|
MODULE_DESCRIPTION("AC97 driver for the Ingenic jz4740 chip");
|
||||||
|
MODULE_LICENSE("GPL");
|
21
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-ac97.h
Executable file
21
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-ac97.h
Executable file
@ -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
|
297
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-i2s.c
Executable file
297
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-i2s.c
Executable file
@ -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 <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <sound/driver.h>
|
||||||
|
#include <sound/core.h>
|
||||||
|
#include <sound/pcm.h>
|
||||||
|
#include <sound/pcm_params.h>
|
||||||
|
#include <sound/initval.h>
|
||||||
|
#include <sound/soc.h>
|
||||||
|
|
||||||
|
#include "jz4740-pcm.h"
|
||||||
|
#include "jz4740-i2s.h"
|
||||||
|
|
||||||
|
static struct jz4740_dma_client jz4740_dma_client_out = {
|
||||||
|
.name = "I2S PCM Stereo out"
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_dma_client jz4740_dma_client_in = {
|
||||||
|
.name = "I2S PCM Stereo in"
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_out = {
|
||||||
|
.client = &jz4740_dma_client_out,
|
||||||
|
.channel = DMA_ID_AIC_TX,
|
||||||
|
.dma_addr = AIC_DR,
|
||||||
|
.dma_size = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_in = {
|
||||||
|
.client = &jz4740_dma_client_in,
|
||||||
|
.channel = DMA_ID_AIC_RX,
|
||||||
|
.dma_addr = AIC_DR,
|
||||||
|
.dma_size = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int jz4740_i2s_startup(struct snd_pcm_substream *substream)
|
||||||
|
{
|
||||||
|
/*struct snd_soc_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");
|
18
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-i2s.h
Executable file
18
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-i2s.h
Executable file
@ -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
|
689
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-pcm.c
Executable file
689
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-pcm.c
Executable file
@ -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 <linux/module.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
|
||||||
|
#include <sound/driver.h>
|
||||||
|
#include <sound/core.h>
|
||||||
|
#include <sound/pcm.h>
|
||||||
|
#include <sound/pcm_params.h>
|
||||||
|
#include <sound/soc.h>
|
||||||
|
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include "jz4740-pcm.h"
|
||||||
|
|
||||||
|
static long sum_bytes = 0;
|
||||||
|
static int first_transfer = 0;
|
||||||
|
static int printk_flag = 0;
|
||||||
|
static int tran_bit = 0;
|
||||||
|
#ifdef CONFIG_SND_OSSEMUL
|
||||||
|
static int hw_params_cnt = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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");
|
33
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-pcm.h
Executable file
33
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-pcm.h
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _JZ4740_PCM_H
|
||||||
|
#define _JZ4740_PCM_H
|
||||||
|
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
#define ST_RUNNING (1<<0)
|
||||||
|
#define ST_OPENED (1<<1)
|
||||||
|
|
||||||
|
#define AIC_START_DMA (1<<0)
|
||||||
|
#define AIC_END_DMA (1<<1)
|
||||||
|
|
||||||
|
struct jz4740_dma_client {
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4740_pcm_dma_params {
|
||||||
|
struct jz4740_dma_client *client; /* stream identifier */
|
||||||
|
int channel; /* Channel ID */
|
||||||
|
dma_addr_t dma_addr;
|
||||||
|
int dma_size; /* Size of the DMA transfer */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* platform data */
|
||||||
|
extern struct snd_soc_platform jz4740_soc_platform;
|
||||||
|
|
||||||
|
#endif
|
364
target/linux/xburst/files-2.6.31/sound/soc/jz4740/pavo.c
Executable file
364
target/linux/xburst/files-2.6.31/sound/soc/jz4740/pavo.c
Executable file
@ -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 <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <sound/driver.h>
|
||||||
|
#include <sound/core.h>
|
||||||
|
#include <sound/pcm.h>
|
||||||
|
#include <sound/soc.h>
|
||||||
|
#include <sound/soc-dapm.h>
|
||||||
|
|
||||||
|
#include "../codecs/jzcodec.h"
|
||||||
|
#include "jz4740-pcm.h"
|
||||||
|
#include "jz4740-i2s.h"
|
||||||
|
|
||||||
|
#define PAVO_HP 0
|
||||||
|
#define PAVO_MIC 1
|
||||||
|
#define PAVO_LINE 2
|
||||||
|
#define PAVO_HEADSET 3
|
||||||
|
#define PAVO_HP_OFF 4
|
||||||
|
#define PAVO_SPK_ON 0
|
||||||
|
#define PAVO_SPK_OFF 1
|
||||||
|
|
||||||
|
/* audio clock in Hz - rounded from 12.235MHz */
|
||||||
|
#define PAVO_AUDIO_CLOCK 12288000
|
||||||
|
|
||||||
|
static int pavo_jack_func;
|
||||||
|
static int pavo_spk_func;
|
||||||
|
|
||||||
|
unsigned short set_scoop_gpio(struct device *dev, unsigned short bit)
|
||||||
|
{
|
||||||
|
unsigned short gpio_bit = 0;
|
||||||
|
|
||||||
|
return gpio_bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit)
|
||||||
|
{
|
||||||
|
unsigned short gpio_bit = 0;
|
||||||
|
|
||||||
|
return gpio_bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pavo_ext_control(struct snd_soc_codec *codec)
|
||||||
|
{
|
||||||
|
int spk = 0, mic = 0, line = 0, hp = 0, hs = 0;
|
||||||
|
|
||||||
|
/* set up jack connection */
|
||||||
|
switch (pavo_jack_func) {
|
||||||
|
case PAVO_HP:
|
||||||
|
hp = 1;
|
||||||
|
/* set = unmute headphone */
|
||||||
|
//set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
|
||||||
|
//set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
|
||||||
|
break;
|
||||||
|
case PAVO_MIC:
|
||||||
|
mic = 1;
|
||||||
|
/* reset = mute headphone */
|
||||||
|
//reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
|
||||||
|
//reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
|
||||||
|
break;
|
||||||
|
case PAVO_LINE:
|
||||||
|
line = 1;
|
||||||
|
//reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
|
||||||
|
//reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
|
||||||
|
break;
|
||||||
|
case PAVO_HEADSET:
|
||||||
|
hs = 1;
|
||||||
|
mic = 1;
|
||||||
|
//reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
|
||||||
|
//set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pavo_spk_func == PAVO_SPK_ON)
|
||||||
|
spk = 1;
|
||||||
|
|
||||||
|
#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");
|
34
target/linux/xburst/files-2.6.31/sound/soc/jz4750/Kconfig
Executable file
34
target/linux/xburst/files-2.6.31/sound/soc/jz4750/Kconfig
Executable file
@ -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.
|
15
target/linux/xburst/files-2.6.31/sound/soc/jz4750/Makefile
Executable file
15
target/linux/xburst/files-2.6.31/sound/soc/jz4750/Makefile
Executable file
@ -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
|
405
target/linux/xburst/files-2.6.31/sound/soc/jz4750/apus.c
Executable file
405
target/linux/xburst/files-2.6.31/sound/soc/jz4750/apus.c
Executable file
@ -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 <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <sound/driver.h>
|
||||||
|
#include <sound/core.h>
|
||||||
|
#include <sound/pcm.h>
|
||||||
|
#include <sound/soc.h>
|
||||||
|
#include <sound/soc-dapm.h>
|
||||||
|
#include <sound/tlv.h>
|
||||||
|
|
||||||
|
#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");
|
261
target/linux/xburst/files-2.6.31/sound/soc/jz4750/jz4750-ac97.c
Executable file
261
target/linux/xburst/files-2.6.31/sound/soc/jz4750/jz4750-ac97.c
Executable file
@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
* linux/sound/jz4740-ac97.c -- AC97 support for the Ingenic jz4740 chip.
|
||||||
|
*
|
||||||
|
* Author: Richard
|
||||||
|
* Created: Dec 02, 2007
|
||||||
|
* Copyright: Ingenic Semiconductor Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
#include <sound/driver.h>
|
||||||
|
#include <sound/core.h>
|
||||||
|
#include <sound/pcm.h>
|
||||||
|
#include <sound/ac97_codec.h>
|
||||||
|
#include <sound/initval.h>
|
||||||
|
#include <sound/soc.h>
|
||||||
|
|
||||||
|
#include <asm/irq.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <asm/hardware.h>
|
||||||
|
#include <asm/arch/audio.h>
|
||||||
|
|
||||||
|
#include "jz4740-pcm.h"
|
||||||
|
#include "jz4740-ac97.h"
|
||||||
|
|
||||||
|
static DEFINE_MUTEX(car_mutex);
|
||||||
|
static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
|
||||||
|
static volatile long gsr_bits;
|
||||||
|
|
||||||
|
static unsigned short jz4740_ac97_read(struct snd_ac97 *ac97,
|
||||||
|
unsigned short reg)
|
||||||
|
{
|
||||||
|
unsigned short val = -1;
|
||||||
|
volatile u32 *reg_addr;
|
||||||
|
|
||||||
|
mutex_lock(&car_mutex);
|
||||||
|
|
||||||
|
out: mutex_unlock(&car_mutex);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4740_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
||||||
|
unsigned short val)
|
||||||
|
{
|
||||||
|
volatile u32 *reg_addr;
|
||||||
|
|
||||||
|
mutex_lock(&car_mutex);
|
||||||
|
|
||||||
|
mutex_unlock(&car_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4740_ac97_warm_reset(struct snd_ac97 *ac97)
|
||||||
|
{
|
||||||
|
gsr_bits = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4740_ac97_cold_reset(struct snd_ac97 *ac97)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t jz4740_ac97_irq(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
long status;
|
||||||
|
return IRQ_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct snd_ac97_bus_ops soc_ac97_ops = {
|
||||||
|
.read = jz4740_ac97_read,
|
||||||
|
.write = jz4740_ac97_write,
|
||||||
|
.warm_reset = jz4740_ac97_warm_reset,
|
||||||
|
.reset = jz4740_ac97_cold_reset,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_out = {
|
||||||
|
.name = "AC97 PCM Stereo out",
|
||||||
|
.dev_addr = __PREG(PCDR),
|
||||||
|
.drcmr = &DRCMRTXPCDR,
|
||||||
|
.dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
|
||||||
|
DCMD_BURST32 | DCMD_WIDTH4,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_in = {
|
||||||
|
.name = "AC97 PCM Stereo in",
|
||||||
|
.dev_addr = __PREG(PCDR),
|
||||||
|
.drcmr = &DRCMRRXPCDR,
|
||||||
|
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
||||||
|
DCMD_BURST32 | DCMD_WIDTH4,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_out = {
|
||||||
|
.name = "AC97 Aux PCM (Slot 5) Mono out",
|
||||||
|
.dev_addr = __PREG(MODR),
|
||||||
|
.drcmr = &DRCMRTXMODR,
|
||||||
|
.dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
|
||||||
|
DCMD_BURST16 | DCMD_WIDTH2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_in = {
|
||||||
|
.name = "AC97 Aux PCM (Slot 5) Mono in",
|
||||||
|
.dev_addr = __PREG(MODR),
|
||||||
|
.drcmr = &DRCMRRXMODR,
|
||||||
|
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
||||||
|
DCMD_BURST16 | DCMD_WIDTH2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_mic_mono_in = {
|
||||||
|
.name = "AC97 Mic PCM (Slot 6) Mono in",
|
||||||
|
.dev_addr = __PREG(MCDR),
|
||||||
|
.drcmr = &DRCMRRXMCDR,
|
||||||
|
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
||||||
|
DCMD_BURST16 | DCMD_WIDTH2,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int jz4740_ac97_suspend(struct platform_device *pdev,
|
||||||
|
struct snd_soc_cpu_dai *dai)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4740_ac97_resume(struct platform_device *pdev,
|
||||||
|
struct snd_soc_cpu_dai *dai)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define jz4740_ac97_suspend NULL
|
||||||
|
#define jz4740_ac97_resume NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int jz4740_ac97_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jz4740_ac97_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4740_ac97_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
|
{
|
||||||
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
|
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||||
|
|
||||||
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
|
cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_out;
|
||||||
|
else
|
||||||
|
cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_in;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4740_ac97_hw_aux_params(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
|
{
|
||||||
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
|
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||||
|
|
||||||
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
|
cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_out;
|
||||||
|
else
|
||||||
|
cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_in;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jz4740_ac97_hw_mic_params(struct snd_pcm_substream *substream,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
|
{
|
||||||
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
|
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||||
|
|
||||||
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
|
return -ENODEV;
|
||||||
|
else
|
||||||
|
cpu_dai->dma_data = &jz4740_ac97_pcm_mic_mono_in;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define JZ4740_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||||
|
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
|
||||||
|
SNDRV_PCM_RATE_48000)
|
||||||
|
|
||||||
|
struct snd_soc_cpu_dai jz4740_ac97_dai[] = {
|
||||||
|
{
|
||||||
|
.name = "jz4740-ac97",
|
||||||
|
.id = 0,
|
||||||
|
.type = SND_SOC_DAI_AC97,
|
||||||
|
.probe = jz4740_ac97_probe,
|
||||||
|
.remove = jz4740_ac97_remove,
|
||||||
|
.suspend = jz4740_ac97_suspend,
|
||||||
|
.resume = jz4740_ac97_resume,
|
||||||
|
.playback = {
|
||||||
|
.stream_name = "AC97 Playback",
|
||||||
|
.channels_min = 2,
|
||||||
|
.channels_max = 2,
|
||||||
|
.rates = JZ4740_AC97_RATES,
|
||||||
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||||
|
.capture = {
|
||||||
|
.stream_name = "AC97 Capture",
|
||||||
|
.channels_min = 2,
|
||||||
|
.channels_max = 2,
|
||||||
|
.rates = JZ4740_AC97_RATES,
|
||||||
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||||
|
.ops = {
|
||||||
|
.hw_params = jz4740_ac97_hw_params,},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "jz4740-ac97-aux",
|
||||||
|
.id = 1,
|
||||||
|
.type = SND_SOC_DAI_AC97,
|
||||||
|
.playback = {
|
||||||
|
.stream_name = "AC97 Aux Playback",
|
||||||
|
.channels_min = 1,
|
||||||
|
.channels_max = 1,
|
||||||
|
.rates = JZ4740_AC97_RATES,
|
||||||
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||||
|
.capture = {
|
||||||
|
.stream_name = "AC97 Aux Capture",
|
||||||
|
.channels_min = 1,
|
||||||
|
.channels_max = 1,
|
||||||
|
.rates = JZ4740_AC97_RATES,
|
||||||
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||||
|
.ops = {
|
||||||
|
.hw_params = jz4740_ac97_hw_aux_params,},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "jz4740-ac97-mic",
|
||||||
|
.id = 2,
|
||||||
|
.type = SND_SOC_DAI_AC97,
|
||||||
|
.capture = {
|
||||||
|
.stream_name = "AC97 Mic Capture",
|
||||||
|
.channels_min = 1,
|
||||||
|
.channels_max = 1,
|
||||||
|
.rates = JZ4740_AC97_RATES,
|
||||||
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
||||||
|
.ops = {
|
||||||
|
.hw_params = jz4740_ac97_hw_mic_params,},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPORT_SYMBOL_GPL(jz4740_ac97_dai);
|
||||||
|
EXPORT_SYMBOL_GPL(soc_ac97_ops);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Richard");
|
||||||
|
MODULE_DESCRIPTION("AC97 driver for the Ingenic jz4740 chip");
|
||||||
|
MODULE_LICENSE("GPL");
|
21
target/linux/xburst/files-2.6.31/sound/soc/jz4750/jz4750-ac97.h
Executable file
21
target/linux/xburst/files-2.6.31/sound/soc/jz4750/jz4750-ac97.h
Executable file
@ -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
|
311
target/linux/xburst/files-2.6.31/sound/soc/jz4750/jz4750-i2s.c
Executable file
311
target/linux/xburst/files-2.6.31/sound/soc/jz4750/jz4750-i2s.c
Executable file
@ -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 <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <sound/driver.h>
|
||||||
|
#include <sound/core.h>
|
||||||
|
#include <sound/pcm.h>
|
||||||
|
#include <sound/pcm_params.h>
|
||||||
|
#include <sound/initval.h>
|
||||||
|
#include <sound/soc.h>
|
||||||
|
|
||||||
|
#include "jz4750-pcm.h"
|
||||||
|
#include "jz4750-i2s.h"
|
||||||
|
#include "../codecs/jzdlv.h"
|
||||||
|
|
||||||
|
static struct jz4750_dma_client jz4750_dma_client_out = {
|
||||||
|
.name = "I2S PCM Stereo out"
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4750_dma_client jz4750_dma_client_in = {
|
||||||
|
.name = "I2S PCM Stereo in"
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4750_pcm_dma_params jz4750_i2s_pcm_stereo_out = {
|
||||||
|
.client = &jz4750_dma_client_out,
|
||||||
|
.channel = DMA_ID_AIC_TX,
|
||||||
|
.dma_addr = AIC_DR,
|
||||||
|
.dma_size = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4750_pcm_dma_params jz4750_i2s_pcm_stereo_in = {
|
||||||
|
.client = &jz4750_dma_client_in,
|
||||||
|
.channel = DMA_ID_AIC_RX,
|
||||||
|
.dma_addr = AIC_DR,
|
||||||
|
.dma_size = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int jz4750_i2s_startup(struct snd_pcm_substream *substream)
|
||||||
|
{
|
||||||
|
/*struct snd_soc_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");
|
18
target/linux/xburst/files-2.6.31/sound/soc/jz4750/jz4750-i2s.h
Executable file
18
target/linux/xburst/files-2.6.31/sound/soc/jz4750/jz4750-i2s.h
Executable file
@ -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
|
687
target/linux/xburst/files-2.6.31/sound/soc/jz4750/jz4750-pcm.c
Executable file
687
target/linux/xburst/files-2.6.31/sound/soc/jz4750/jz4750-pcm.c
Executable file
@ -0,0 +1,687 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
|
||||||
|
#include <sound/driver.h>
|
||||||
|
#include <sound/core.h>
|
||||||
|
#include <sound/pcm.h>
|
||||||
|
#include <sound/pcm_params.h>
|
||||||
|
#include <sound/soc.h>
|
||||||
|
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include "jz4750-pcm.h"
|
||||||
|
|
||||||
|
static long sum_bytes = 0;
|
||||||
|
static int first_transfer = 0;
|
||||||
|
static int printk_flag = 0;
|
||||||
|
static int tran_bit = 0;
|
||||||
|
#ifdef CONFIG_SND_OSSEMUL
|
||||||
|
static int hw_params_cnt = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct jz4750_dma_buf_aic {
|
||||||
|
struct jz4750_dma_buf_aic *next;
|
||||||
|
int size; /* buffer size in bytes */
|
||||||
|
dma_addr_t data; /* start of DMA data */
|
||||||
|
dma_addr_t ptr; /* where the DMA got to [1] */
|
||||||
|
void *id; /* client's id */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4750_runtime_data {
|
||||||
|
spinlock_t lock;
|
||||||
|
int state;
|
||||||
|
int aic_dma_flag; /* start dma transfer or not */
|
||||||
|
unsigned int dma_loaded;
|
||||||
|
unsigned int dma_limit;
|
||||||
|
unsigned int dma_period;
|
||||||
|
dma_addr_t dma_start;
|
||||||
|
dma_addr_t dma_pos;
|
||||||
|
dma_addr_t dma_end;
|
||||||
|
struct jz4750_pcm_dma_params *params;
|
||||||
|
|
||||||
|
dma_addr_t user_cur_addr; /* user current write buffer start address */
|
||||||
|
unsigned int user_cur_len; /* user current write buffer length */
|
||||||
|
|
||||||
|
/* buffer list and information */
|
||||||
|
struct jz4750_dma_buf_aic *curr; /* current dma buffer */
|
||||||
|
struct jz4750_dma_buf_aic *next; /* next buffer to load */
|
||||||
|
struct jz4750_dma_buf_aic *end; /* end of queue */
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* identify hardware playback capabilities */
|
||||||
|
static const struct snd_pcm_hardware jz4750_pcm_hardware = {
|
||||||
|
.info = SNDRV_PCM_INFO_MMAP |
|
||||||
|
SNDRV_PCM_INFO_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");
|
33
target/linux/xburst/files-2.6.31/sound/soc/jz4750/jz4750-pcm.h
Executable file
33
target/linux/xburst/files-2.6.31/sound/soc/jz4750/jz4750-pcm.h
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _JZ4750_PCM_H
|
||||||
|
#define _JZ4750_PCM_H
|
||||||
|
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
#define ST_RUNNING (1<<0)
|
||||||
|
#define ST_OPENED (1<<1)
|
||||||
|
|
||||||
|
#define AIC_START_DMA (1<<0)
|
||||||
|
#define AIC_END_DMA (1<<1)
|
||||||
|
|
||||||
|
struct jz4750_dma_client {
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jz4750_pcm_dma_params {
|
||||||
|
struct jz4750_dma_client *client; /* stream identifier */
|
||||||
|
int channel; /* Channel ID */
|
||||||
|
dma_addr_t dma_addr;
|
||||||
|
int dma_size; /* Size of the DMA transfer */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* platform data */
|
||||||
|
extern struct snd_soc_platform jz4750_soc_platform;
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
726
target/linux/xburst/patches-2.6.31/001-core.patch
Normal file
726
target/linux/xburst/patches-2.6.31/001-core.patch
Normal file
@ -0,0 +1,726 @@
|
|||||||
|
From ac50b482e2278cdff65e67c8a31079bf9c5ae289 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lars-Peter Clausen <lars@metafoo.de>
|
||||||
|
Date: Wed, 19 Aug 2009 14:47:08 +0200
|
||||||
|
Subject: [PATCH] core
|
||||||
|
|
||||||
|
---
|
||||||
|
arch/mips/Kconfig | 48 +++++
|
||||||
|
arch/mips/Makefile | 18 ++
|
||||||
|
arch/mips/boot/Makefile | 23 ++-
|
||||||
|
arch/mips/include/asm/bootinfo.h | 6 +
|
||||||
|
arch/mips/include/asm/cpu.h | 13 ++-
|
||||||
|
arch/mips/include/asm/mach-generic/irq.h | 2 +-
|
||||||
|
arch/mips/include/asm/r4kcache.h | 231 ++++++++++++++++++++++
|
||||||
|
arch/mips/include/asm/suspend.h | 3 +
|
||||||
|
arch/mips/kernel/cpu-probe.c | 21 ++
|
||||||
|
arch/mips/kernel/signal.c | 6 +
|
||||||
|
arch/mips/kernel/unaligned.c | 5 +
|
||||||
|
arch/mips/mm/c-r4k.c | 30 +++
|
||||||
|
arch/mips/mm/cache.c | 2 +
|
||||||
|
arch/mips/mm/tlbex.c | 5 +
|
||||||
|
include/linux/suspend.h | 315 ------------------------------
|
||||||
|
15 files changed, 409 insertions(+), 319 deletions(-)
|
||||||
|
delete mode 100644 include/linux/suspend.h
|
||||||
|
|
||||||
|
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
|
||||||
|
index 3ca0fe1..e8f8027 100644
|
||||||
|
--- a/arch/mips/Kconfig
|
||||||
|
+++ b/arch/mips/Kconfig
|
||||||
|
@@ -671,6 +671,29 @@ source "arch/mips/cavium-octeon/Kconfig"
|
||||||
|
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
+#####################################################
|
||||||
|
+# Ingenic SOC series
|
||||||
|
+#####################################################
|
||||||
|
+
|
||||||
|
+config SOC_JZ4720
|
||||||
|
+ bool
|
||||||
|
+ select JZSOC
|
||||||
|
+
|
||||||
|
+config SOC_JZ4740
|
||||||
|
+ bool
|
||||||
|
+ select JZSOC
|
||||||
|
+
|
||||||
|
+config JZSOC
|
||||||
|
+ bool
|
||||||
|
+ select JZRISC
|
||||||
|
+ select SYS_HAS_CPU_MIPS32_R1
|
||||||
|
+ select SYS_SUPPORTS_32BIT_KERNEL
|
||||||
|
+
|
||||||
|
+config JZRISC
|
||||||
|
+ bool
|
||||||
|
+
|
||||||
|
+####################################################
|
||||||
|
+
|
||||||
|
config RWSEM_GENERIC_SPINLOCK
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
@@ -1893,6 +1916,14 @@ config NR_CPUS
|
||||||
|
|
||||||
|
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
|
||||||
|
#
|
||||||
|
@@ -2164,6 +2195,23 @@ config BINFMT_ELF32
|
||||||
|
|
||||||
|
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_HIBERNATION_POSSIBLE
|
||||||
|
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
|
||||||
|
index 861da51..14a6f9a 100644
|
||||||
|
--- a/arch/mips/Makefile
|
||||||
|
+++ b/arch/mips/Makefile
|
||||||
|
@@ -180,6 +180,14 @@ cflags-$(CONFIG_AR7) += -I$(srctree)/arch/mips/include/asm/mach-ar7
|
||||||
|
load-$(CONFIG_AR7) += 0xffffffff94100000
|
||||||
|
|
||||||
|
#
|
||||||
|
+# Commond Ingenic JZ4740 series
|
||||||
|
+#
|
||||||
|
+
|
||||||
|
+core-$(CONFIG_SOC_JZ4740) += arch/mips/jz4740/
|
||||||
|
+cflags-$(CONFIG_SOC_JZ4740) += -I$(srctree)/arch/mips/include/asm/mach-jz4740
|
||||||
|
+load-$(CONFIG_SOC_JZ4740) += 0xffffffff80010000
|
||||||
|
+
|
||||||
|
+#
|
||||||
|
# Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
|
||||||
|
#
|
||||||
|
core-$(CONFIG_MACH_JAZZ) += arch/mips/jazz/
|
||||||
|
@@ -711,6 +719,12 @@ makeboot =$(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) $(1)
|
||||||
|
|
||||||
|
all: $(all-y)
|
||||||
|
|
||||||
|
+uImage: $(vmlinux-32)
|
||||||
|
+ +@$(call makeboot,$@)
|
||||||
|
+
|
||||||
|
+zImage: $(vmlinux-32)
|
||||||
|
+ +@$(call makeboot,$@)
|
||||||
|
+
|
||||||
|
vmlinux.bin: $(vmlinux-32)
|
||||||
|
+@$(call makeboot,$@)
|
||||||
|
|
||||||
|
@@ -740,6 +754,7 @@ install:
|
||||||
|
|
||||||
|
archclean:
|
||||||
|
@$(MAKE) $(clean)=arch/mips/boot
|
||||||
|
+ @$(MAKE) $(clean)=arch/mips/boot/compressed
|
||||||
|
@$(MAKE) $(clean)=arch/mips/lasat
|
||||||
|
|
||||||
|
define archhelp
|
||||||
|
@@ -747,6 +762,9 @@ define archhelp
|
||||||
|
echo ' vmlinux.ecoff - ECOFF boot image'
|
||||||
|
echo ' vmlinux.bin - Raw binary boot image'
|
||||||
|
echo ' vmlinux.srec - SREC boot image'
|
||||||
|
+ echo ' uImage - u-boot format image (arch/$(ARCH)/boot/uImage)'
|
||||||
|
+ echo ' zImage - Compressed binary image (arch/$(ARCH)/boot/compressed/zImage)'
|
||||||
|
+ echo ' vmlinux.bin - Uncompressed binary image (arch/$(ARCH)/boot/vmlinux.bin)'
|
||||||
|
echo
|
||||||
|
echo ' These will be default as apropriate for a configured platform.'
|
||||||
|
endef
|
||||||
|
diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
|
||||||
|
index 2a209d7..1cfce3e 100644
|
||||||
|
--- a/arch/mips/boot/Makefile
|
||||||
|
+++ b/arch/mips/boot/Makefile
|
||||||
|
@@ -7,6 +7,9 @@
|
||||||
|
# Copyright (C) 2004 Maciej W. Rozycki
|
||||||
|
#
|
||||||
|
|
||||||
|
+# This one must match the LOADADDR in arch/mips/Makefile!
|
||||||
|
+LOADADDR=0x80010000
|
||||||
|
+
|
||||||
|
#
|
||||||
|
# Some DECstations need all possible sections of an ECOFF executable
|
||||||
|
#
|
||||||
|
@@ -25,7 +28,7 @@ strip-flags = $(addprefix --remove-section=,$(drop-sections))
|
||||||
|
|
||||||
|
VMLINUX = vmlinux
|
||||||
|
|
||||||
|
-all: vmlinux.ecoff vmlinux.srec addinitrd
|
||||||
|
+all: vmlinux.ecoff vmlinux.srec addinitrd uImage zImage
|
||||||
|
|
||||||
|
vmlinux.ecoff: $(obj)/elf2ecoff $(VMLINUX)
|
||||||
|
$(obj)/elf2ecoff $(VMLINUX) vmlinux.ecoff $(E2EFLAGS)
|
||||||
|
@@ -42,8 +45,24 @@ vmlinux.srec: $(VMLINUX)
|
||||||
|
$(obj)/addinitrd: $(obj)/addinitrd.c
|
||||||
|
$(HOSTCC) -o $@ $^
|
||||||
|
|
||||||
|
+uImage: $(VMLINUX) vmlinux.bin
|
||||||
|
+ rm -f $(obj)/vmlinux.bin.gz
|
||||||
|
+ gzip -9 $(obj)/vmlinux.bin
|
||||||
|
+ mkimage -A mips -O linux -T kernel -C gzip \
|
||||||
|
+ -a $(LOADADDR) -e $(shell sh ./$(obj)/tools/entry $(NM) $(VMLINUX) ) \
|
||||||
|
+ -n 'Linux-$(KERNELRELEASE)' \
|
||||||
|
+ -d $(obj)/vmlinux.bin.gz $(obj)/uImage
|
||||||
|
+ @echo ' Kernel: arch/mips/boot/$@ is ready'
|
||||||
|
+
|
||||||
|
+zImage:
|
||||||
|
+ $(Q)$(MAKE) $(build)=$(obj)/compressed loadaddr=$(LOADADDR) $@
|
||||||
|
+ @echo ' Kernel: arch/mips/boot/compressed/$@ is ready'
|
||||||
|
+
|
||||||
|
clean-files += addinitrd \
|
||||||
|
elf2ecoff \
|
||||||
|
vmlinux.bin \
|
||||||
|
vmlinux.ecoff \
|
||||||
|
- vmlinux.srec
|
||||||
|
+ vmlinux.srec \
|
||||||
|
+ vmlinux.bin.gz \
|
||||||
|
+ uImage \
|
||||||
|
+ zImage
|
||||||
|
diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h
|
||||||
|
index 610fe3a..8451d28 100644
|
||||||
|
--- a/arch/mips/include/asm/bootinfo.h
|
||||||
|
+++ b/arch/mips/include/asm/bootinfo.h
|
||||||
|
@@ -57,6 +57,12 @@
|
||||||
|
#define MACH_MIKROTIK_RB532 0 /* Mikrotik RouterBoard 532 */
|
||||||
|
#define MACH_MIKROTIK_RB532A 1 /* Mikrotik RouterBoard 532A */
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Valid machtype for group INGENIC
|
||||||
|
+ */
|
||||||
|
+#define MACH_INGENIC_JZ4720 0 /* JZ4730 SOC */
|
||||||
|
+#define MACH_INGENIC_JZ4740 1 /* JZ4740 SOC */
|
||||||
|
+
|
||||||
|
#define CL_SIZE COMMAND_LINE_SIZE
|
||||||
|
|
||||||
|
extern char *system_type;
|
||||||
|
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
|
||||||
|
index 3bdc0e3..904c574 100644
|
||||||
|
--- a/arch/mips/include/asm/cpu.h
|
||||||
|
+++ b/arch/mips/include/asm/cpu.h
|
||||||
|
@@ -34,7 +34,7 @@
|
||||||
|
#define PRID_COMP_LSI 0x080000
|
||||||
|
#define PRID_COMP_LEXRA 0x0b0000
|
||||||
|
#define PRID_COMP_CAVIUM 0x0d0000
|
||||||
|
-
|
||||||
|
+#define PRID_COMP_INGENIC 0xd00000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assigned values for the product ID register. In order to detect a
|
||||||
|
@@ -127,6 +127,12 @@
|
||||||
|
#define PRID_IMP_CAVIUM_CN52XX 0x0700
|
||||||
|
|
||||||
|
/*
|
||||||
|
+ * These are the PRID's for when 23:16 == PRID_COMP_INGENIC
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#define PRID_IMP_JZRISC 0x0200
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
* Definitions for 7:0 on legacy processors
|
||||||
|
*/
|
||||||
|
|
||||||
|
@@ -217,6 +223,11 @@ enum cpu_type_enum {
|
||||||
|
CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
|
||||||
|
CPU_CAVIUM_OCTEON,
|
||||||
|
|
||||||
|
+ /*
|
||||||
|
+ * Ingenic class processors
|
||||||
|
+ */
|
||||||
|
+ CPU_JZRISC, CPU_XBURST,
|
||||||
|
+
|
||||||
|
CPU_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/arch/mips/include/asm/mach-generic/irq.h b/arch/mips/include/asm/mach-generic/irq.h
|
||||||
|
index 70d9a25..73b7a83 100644
|
||||||
|
--- a/arch/mips/include/asm/mach-generic/irq.h
|
||||||
|
+++ b/arch/mips/include/asm/mach-generic/irq.h
|
||||||
|
@@ -9,7 +9,7 @@
|
||||||
|
#define __ASM_MACH_GENERIC_IRQ_H
|
||||||
|
|
||||||
|
#ifndef NR_IRQS
|
||||||
|
-#define NR_IRQS 128
|
||||||
|
+#define NR_IRQS 256
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_I8259
|
||||||
|
diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h
|
||||||
|
index 387bf59..b500056 100644
|
||||||
|
--- a/arch/mips/include/asm/r4kcache.h
|
||||||
|
+++ b/arch/mips/include/asm/r4kcache.h
|
||||||
|
@@ -17,6 +17,58 @@
|
||||||
|
#include <asm/cpu-features.h>
|
||||||
|
#include <asm/mipsmtregs.h>
|
||||||
|
|
||||||
|
+#ifdef CONFIG_JZRISC
|
||||||
|
+
|
||||||
|
+#define K0_TO_K1() \
|
||||||
|
+do { \
|
||||||
|
+ unsigned long __k0_addr; \
|
||||||
|
+ \
|
||||||
|
+ __asm__ __volatile__( \
|
||||||
|
+ "la %0, 1f\n\t" \
|
||||||
|
+ "or %0, %0, %1\n\t" \
|
||||||
|
+ "jr %0\n\t" \
|
||||||
|
+ "nop\n\t" \
|
||||||
|
+ "1: nop\n" \
|
||||||
|
+ : "=&r"(__k0_addr) \
|
||||||
|
+ : "r" (0x20000000) ); \
|
||||||
|
+} while(0)
|
||||||
|
+
|
||||||
|
+#define K1_TO_K0() \
|
||||||
|
+do { \
|
||||||
|
+ unsigned long __k0_addr; \
|
||||||
|
+ __asm__ __volatile__( \
|
||||||
|
+ "nop;nop;nop;nop;nop;nop;nop\n\t" \
|
||||||
|
+ "la %0, 1f\n\t" \
|
||||||
|
+ "jr %0\n\t" \
|
||||||
|
+ "nop\n\t" \
|
||||||
|
+ "1: nop\n" \
|
||||||
|
+ : "=&r" (__k0_addr)); \
|
||||||
|
+} while (0)
|
||||||
|
+
|
||||||
|
+#define INVALIDATE_BTB() \
|
||||||
|
+do { \
|
||||||
|
+ unsigned long tmp; \
|
||||||
|
+ __asm__ __volatile__( \
|
||||||
|
+ ".set mips32\n\t" \
|
||||||
|
+ "mfc0 %0, $16, 7\n\t" \
|
||||||
|
+ "nop\n\t" \
|
||||||
|
+ "ori %0, 2\n\t" \
|
||||||
|
+ "mtc0 %0, $16, 7\n\t" \
|
||||||
|
+ "nop\n\t" \
|
||||||
|
+ : "=&r" (tmp)); \
|
||||||
|
+} while (0)
|
||||||
|
+
|
||||||
|
+#define SYNC_WB() __asm__ __volatile__ ("sync")
|
||||||
|
+
|
||||||
|
+#else /* CONFIG_JZRISC */
|
||||||
|
+
|
||||||
|
+#define K0_TO_K1() do { } while (0)
|
||||||
|
+#define K1_TO_K0() do { } while (0)
|
||||||
|
+#define INVALIDATE_BTB() do { } while (0)
|
||||||
|
+#define SYNC_WB() do { } while (0)
|
||||||
|
+
|
||||||
|
+#endif /* CONFIG_JZRISC */
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* This macro return a properly sign-extended address suitable as base address
|
||||||
|
* for indexed cache operations. Two issues here:
|
||||||
|
@@ -144,6 +196,7 @@ static inline void flush_icache_line_indexed(unsigned long addr)
|
||||||
|
{
|
||||||
|
__iflush_prologue
|
||||||
|
cache_op(Index_Invalidate_I, addr);
|
||||||
|
+ INVALIDATE_BTB();
|
||||||
|
__iflush_epilogue
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -151,6 +204,7 @@ static inline void flush_dcache_line_indexed(unsigned long addr)
|
||||||
|
{
|
||||||
|
__dflush_prologue
|
||||||
|
cache_op(Index_Writeback_Inv_D, addr);
|
||||||
|
+ SYNC_WB();
|
||||||
|
__dflush_epilogue
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -163,6 +217,7 @@ static inline void flush_icache_line(unsigned long addr)
|
||||||
|
{
|
||||||
|
__iflush_prologue
|
||||||
|
cache_op(Hit_Invalidate_I, addr);
|
||||||
|
+ INVALIDATE_BTB();
|
||||||
|
__iflush_epilogue
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -170,6 +225,7 @@ static inline void flush_dcache_line(unsigned long addr)
|
||||||
|
{
|
||||||
|
__dflush_prologue
|
||||||
|
cache_op(Hit_Writeback_Inv_D, addr);
|
||||||
|
+ SYNC_WB();
|
||||||
|
__dflush_epilogue
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -177,6 +233,7 @@ static inline void invalidate_dcache_line(unsigned long addr)
|
||||||
|
{
|
||||||
|
__dflush_prologue
|
||||||
|
cache_op(Hit_Invalidate_D, addr);
|
||||||
|
+ SYNC_WB();
|
||||||
|
__dflush_epilogue
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -209,6 +266,7 @@ static inline void flush_scache_line(unsigned long addr)
|
||||||
|
static inline void protected_flush_icache_line(unsigned long addr)
|
||||||
|
{
|
||||||
|
protected_cache_op(Hit_Invalidate_I, addr);
|
||||||
|
+ INVALIDATE_BTB();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -220,6 +278,7 @@ static inline void protected_flush_icache_line(unsigned long addr)
|
||||||
|
static inline void protected_writeback_dcache_line(unsigned long addr)
|
||||||
|
{
|
||||||
|
protected_cache_op(Hit_Writeback_Inv_D, addr);
|
||||||
|
+ SYNC_WB();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void protected_writeback_scache_line(unsigned long addr)
|
||||||
|
@@ -396,8 +455,10 @@ static inline void blast_##pfx##cache##lsize##_page_indexed(unsigned long page)
|
||||||
|
__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16)
|
||||||
|
__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16)
|
||||||
|
__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16)
|
||||||
|
+#ifndef CONFIG_JZRISC
|
||||||
|
__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32)
|
||||||
|
__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32)
|
||||||
|
+#endif
|
||||||
|
__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32)
|
||||||
|
__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 64)
|
||||||
|
__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
|
||||||
|
@@ -405,12 +466,122 @@ __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
|
||||||
|
__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
|
||||||
|
|
||||||
|
__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16)
|
||||||
|
+#ifndef CONFIG_JZRISC
|
||||||
|
__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32)
|
||||||
|
+#endif
|
||||||
|
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16)
|
||||||
|
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32)
|
||||||
|
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64)
|
||||||
|
__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128)
|
||||||
|
|
||||||
|
+#ifdef CONFIG_JZRISC
|
||||||
|
+
|
||||||
|
+static inline void blast_dcache32(void)
|
||||||
|
+{
|
||||||
|
+ unsigned long start = INDEX_BASE;
|
||||||
|
+ unsigned long end = start + current_cpu_data.dcache.waysize;
|
||||||
|
+ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
|
||||||
|
+ unsigned long ws_end = current_cpu_data.dcache.ways <<
|
||||||
|
+ current_cpu_data.dcache.waybit;
|
||||||
|
+ unsigned long ws, addr;
|
||||||
|
+
|
||||||
|
+ for (ws = 0; ws < ws_end; ws += ws_inc)
|
||||||
|
+ for (addr = start; addr < end; addr += 0x400)
|
||||||
|
+ cache32_unroll32(addr|ws,Index_Writeback_Inv_D);
|
||||||
|
+
|
||||||
|
+ SYNC_WB();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void blast_dcache32_page(unsigned long page)
|
||||||
|
+{
|
||||||
|
+ unsigned long start = page;
|
||||||
|
+ unsigned long end = page + PAGE_SIZE;
|
||||||
|
+
|
||||||
|
+ do {
|
||||||
|
+ cache32_unroll32(start,Hit_Writeback_Inv_D);
|
||||||
|
+ start += 0x400;
|
||||||
|
+ } while (start < end);
|
||||||
|
+
|
||||||
|
+ SYNC_WB();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void blast_dcache32_page_indexed(unsigned long page)
|
||||||
|
+{
|
||||||
|
+ unsigned long indexmask = current_cpu_data.dcache.waysize - 1;
|
||||||
|
+ unsigned long start = INDEX_BASE + (page & indexmask);
|
||||||
|
+ unsigned long end = start + PAGE_SIZE;
|
||||||
|
+ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
|
||||||
|
+ unsigned long ws_end = current_cpu_data.dcache.ways <<
|
||||||
|
+ current_cpu_data.dcache.waybit;
|
||||||
|
+ unsigned long ws, addr;
|
||||||
|
+
|
||||||
|
+ for (ws = 0; ws < ws_end; ws += ws_inc)
|
||||||
|
+ for (addr = start; addr < end; addr += 0x400)
|
||||||
|
+ cache32_unroll32(addr|ws,Index_Writeback_Inv_D);
|
||||||
|
+
|
||||||
|
+ SYNC_WB();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void blast_icache32(void)
|
||||||
|
+{
|
||||||
|
+ unsigned long start = INDEX_BASE;
|
||||||
|
+ unsigned long end = start + current_cpu_data.icache.waysize;
|
||||||
|
+ unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit;
|
||||||
|
+ unsigned long ws_end = current_cpu_data.icache.ways <<
|
||||||
|
+ current_cpu_data.icache.waybit;
|
||||||
|
+ unsigned long ws, addr;
|
||||||
|
+
|
||||||
|
+ K0_TO_K1();
|
||||||
|
+
|
||||||
|
+ for (ws = 0; ws < ws_end; ws += ws_inc)
|
||||||
|
+ for (addr = start; addr < end; addr += 0x400)
|
||||||
|
+ cache32_unroll32(addr|ws,Index_Invalidate_I);
|
||||||
|
+
|
||||||
|
+ INVALIDATE_BTB();
|
||||||
|
+
|
||||||
|
+ K1_TO_K0();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void blast_icache32_page(unsigned long page)
|
||||||
|
+{
|
||||||
|
+ unsigned long start = page;
|
||||||
|
+ unsigned long end = page + PAGE_SIZE;
|
||||||
|
+
|
||||||
|
+ K0_TO_K1();
|
||||||
|
+
|
||||||
|
+ do {
|
||||||
|
+ cache32_unroll32(start,Hit_Invalidate_I);
|
||||||
|
+ start += 0x400;
|
||||||
|
+ } while (start < end);
|
||||||
|
+
|
||||||
|
+ INVALIDATE_BTB();
|
||||||
|
+
|
||||||
|
+ K1_TO_K0();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void blast_icache32_page_indexed(unsigned long page)
|
||||||
|
+{
|
||||||
|
+ unsigned long indexmask = current_cpu_data.icache.waysize - 1;
|
||||||
|
+ unsigned long start = INDEX_BASE + (page & indexmask);
|
||||||
|
+ unsigned long end = start + PAGE_SIZE;
|
||||||
|
+ unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit;
|
||||||
|
+ unsigned long ws_end = current_cpu_data.icache.ways <<
|
||||||
|
+ current_cpu_data.icache.waybit;
|
||||||
|
+ unsigned long ws, addr;
|
||||||
|
+
|
||||||
|
+ K0_TO_K1();
|
||||||
|
+
|
||||||
|
+ for (ws = 0; ws < ws_end; ws += ws_inc)
|
||||||
|
+ for (addr = start; addr < end; addr += 0x400)
|
||||||
|
+ cache32_unroll32(addr|ws,Index_Invalidate_I);
|
||||||
|
+
|
||||||
|
+ INVALIDATE_BTB();
|
||||||
|
+
|
||||||
|
+ K1_TO_K0();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#endif /* CONFIG_JZRISC */
|
||||||
|
+
|
||||||
|
/* build blast_xxx_range, protected_blast_xxx_range */
|
||||||
|
#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
|
||||||
|
static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
|
||||||
|
@@ -432,13 +603,73 @@ static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
|
||||||
|
__##pfx##flush_epilogue \
|
||||||
|
}
|
||||||
|
|
||||||
|
+#ifndef CONFIG_JZRISC
|
||||||
|
__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_)
|
||||||
|
+#endif
|
||||||
|
__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_)
|
||||||
|
+#ifndef CONFIG_JZRISC
|
||||||
|
__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_)
|
||||||
|
__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, )
|
||||||
|
+#endif
|
||||||
|
__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, )
|
||||||
|
/* blast_inv_dcache_range */
|
||||||
|
__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, )
|
||||||
|
__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, )
|
||||||
|
|
||||||
|
+#ifdef CONFIG_JZRISC
|
||||||
|
+
|
||||||
|
+static inline void protected_blast_dcache_range(unsigned long start,
|
||||||
|
+ unsigned long end)
|
||||||
|
+{
|
||||||
|
+ unsigned long lsize = cpu_dcache_line_size();
|
||||||
|
+ unsigned long addr = start & ~(lsize - 1);
|
||||||
|
+ unsigned long aend = (end - 1) & ~(lsize - 1);
|
||||||
|
+
|
||||||
|
+ while (1) {
|
||||||
|
+ protected_cache_op(Hit_Writeback_Inv_D, addr);
|
||||||
|
+ if (addr == aend)
|
||||||
|
+ break;
|
||||||
|
+ addr += lsize;
|
||||||
|
+ }
|
||||||
|
+ SYNC_WB();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void protected_blast_icache_range(unsigned long start,
|
||||||
|
+ unsigned long end)
|
||||||
|
+{
|
||||||
|
+ unsigned long lsize = cpu_icache_line_size();
|
||||||
|
+ unsigned long addr = start & ~(lsize - 1);
|
||||||
|
+ unsigned long aend = (end - 1) & ~(lsize - 1);
|
||||||
|
+
|
||||||
|
+ K0_TO_K1();
|
||||||
|
+
|
||||||
|
+ while (1) {
|
||||||
|
+ protected_cache_op(Hit_Invalidate_I, addr);
|
||||||
|
+ if (addr == aend)
|
||||||
|
+ break;
|
||||||
|
+ addr += lsize;
|
||||||
|
+ }
|
||||||
|
+ INVALIDATE_BTB();
|
||||||
|
+
|
||||||
|
+ K1_TO_K0();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void blast_dcache_range(unsigned long start,
|
||||||
|
+ unsigned long end)
|
||||||
|
+{
|
||||||
|
+ unsigned long lsize = cpu_dcache_line_size();
|
||||||
|
+ unsigned long addr = start & ~(lsize - 1);
|
||||||
|
+ unsigned long aend = (end - 1) & ~(lsize - 1);
|
||||||
|
+
|
||||||
|
+ while (1) {
|
||||||
|
+ cache_op(Hit_Writeback_Inv_D, addr);
|
||||||
|
+ if (addr == aend)
|
||||||
|
+ break;
|
||||||
|
+ addr += lsize;
|
||||||
|
+ }
|
||||||
|
+ SYNC_WB();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#endif /* CONFIG_JZRISC */
|
||||||
|
+
|
||||||
|
#endif /* _ASM_R4KCACHE_H */
|
||||||
|
diff --git a/arch/mips/include/asm/suspend.h b/arch/mips/include/asm/suspend.h
|
||||||
|
index 294cdb6..94dc597 100644
|
||||||
|
--- a/arch/mips/include/asm/suspend.h
|
||||||
|
+++ b/arch/mips/include/asm/suspend.h
|
||||||
|
@@ -2,6 +2,9 @@
|
||||||
|
#define __ASM_SUSPEND_H
|
||||||
|
|
||||||
|
static inline int arch_prepare_suspend(void) { return 0; }
|
||||||
|
+#if defined(CONFIG_PM) && defined(CONFIG_JZSOC)
|
||||||
|
+extern int jz_pm_init(void);
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
/* References to section boundaries */
|
||||||
|
extern const void __nosave_begin, __nosave_end;
|
||||||
|
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
|
||||||
|
index 1abe990..4535ae7 100644
|
||||||
|
--- a/arch/mips/kernel/cpu-probe.c
|
||||||
|
+++ b/arch/mips/kernel/cpu-probe.c
|
||||||
|
@@ -160,6 +160,7 @@ void __init check_wait(void)
|
||||||
|
case CPU_PR4450:
|
||||||
|
case CPU_BCM3302:
|
||||||
|
case CPU_CAVIUM_OCTEON:
|
||||||
|
+ case CPU_JZRISC:
|
||||||
|
cpu_wait = r4k_wait;
|
||||||
|
break;
|
||||||
|
|
||||||
|
@@ -888,6 +889,23 @@ static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
|
||||||
|
+{
|
||||||
|
+ decode_configs(c);
|
||||||
|
+ c->options &= ~MIPS_CPU_COUNTER; /* JZRISC does not implement the CP0 counter. */
|
||||||
|
+ switch (c->processor_id & 0xff00) {
|
||||||
|
+ case PRID_IMP_JZRISC:
|
||||||
|
+ c->cputype = CPU_JZRISC;
|
||||||
|
+ c->isa_level = MIPS_CPU_ISA_M32R1;
|
||||||
|
+ c->tlbsize = 32;
|
||||||
|
+ __cpu_name[cpu] = "Ingenic JZRISC";
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ panic("Unknown Ingenic Processor ID!");
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
const char *__cpu_name[NR_CPUS];
|
||||||
|
|
||||||
|
__cpuinit void cpu_probe(void)
|
||||||
|
@@ -925,6 +943,9 @@ __cpuinit void cpu_probe(void)
|
||||||
|
case PRID_COMP_CAVIUM:
|
||||||
|
cpu_probe_cavium(c, cpu);
|
||||||
|
break;
|
||||||
|
+ case PRID_COMP_INGENIC:
|
||||||
|
+ cpu_probe_ingenic(c, cpu);
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BUG_ON(!__cpu_name[cpu]);
|
||||||
|
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
|
||||||
|
index 67bd626..e26ebe0 100644
|
||||||
|
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
|
||||||
|
index 6721ee2..dd4b70b 100644
|
||||||
|
--- a/arch/mips/mm/c-r4k.c
|
||||||
|
+++ b/arch/mips/mm/c-r4k.c
|
||||||
|
@@ -928,6 +928,36 @@ static void __cpuinit probe_pcache(void)
|
||||||
|
c->dcache.waybit = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
+ case CPU_JZRISC:
|
||||||
|
+ config1 = read_c0_config1();
|
||||||
|
+ config1 = (config1 >> 22) & 0x07;
|
||||||
|
+ if (config1 == 0x07)
|
||||||
|
+ config1 = 10;
|
||||||
|
+ else
|
||||||
|
+ config1 = config1 + 11;
|
||||||
|
+ config1 += 2;
|
||||||
|
+ icache_size = (1 << config1);
|
||||||
|
+ c->icache.linesz = 32;
|
||||||
|
+ c->icache.ways = 4;
|
||||||
|
+ c->icache.waybit = __ffs(icache_size / c->icache.ways);
|
||||||
|
+
|
||||||
|
+ config1 = read_c0_config1();
|
||||||
|
+ config1 = (config1 >> 13) & 0x07;
|
||||||
|
+ if (config1 == 0x07)
|
||||||
|
+ config1 = 10;
|
||||||
|
+ else
|
||||||
|
+ config1 = config1 + 11;
|
||||||
|
+ config1 += 2;
|
||||||
|
+ dcache_size = (1 << config1);
|
||||||
|
+ c->dcache.linesz = 32;
|
||||||
|
+ c->dcache.ways = 4;
|
||||||
|
+ c->dcache.waybit = __ffs(dcache_size / c->dcache.ways);
|
||||||
|
+
|
||||||
|
+ c->dcache.flags = 0;
|
||||||
|
+ c->options |= MIPS_CPU_PREFETCH;
|
||||||
|
+
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
default:
|
||||||
|
if (!(config & MIPS_CONF_M))
|
||||||
|
panic("Don't know how to probe P-caches on this cpu.");
|
||||||
|
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
|
||||||
|
index 694d51f..4b2bc95 100644
|
||||||
|
--- a/arch/mips/mm/cache.c
|
||||||
|
+++ b/arch/mips/mm/cache.c
|
||||||
|
@@ -52,6 +52,8 @@ void (*_dma_cache_wback)(unsigned long start, unsigned long size);
|
||||||
|
void (*_dma_cache_inv)(unsigned long start, unsigned long size);
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(_dma_cache_wback_inv);
|
||||||
|
+EXPORT_SYMBOL(_dma_cache_wback);
|
||||||
|
+EXPORT_SYMBOL(_dma_cache_inv);
|
||||||
|
|
||||||
|
#endif /* CONFIG_DMA_NONCOHERENT */
|
||||||
|
|
||||||
|
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
|
||||||
|
index 9a17bf8..9b80053 100644
|
||||||
|
--- a/arch/mips/mm/tlbex.c
|
||||||
|
+++ b/arch/mips/mm/tlbex.c
|
||||||
|
@@ -385,6 +385,11 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
|
||||||
|
tlbw(p);
|
||||||
|
break;
|
||||||
|
|
||||||
|
+ case CPU_JZRISC:
|
||||||
|
+ tlbw(p);
|
||||||
|
+ uasm_i_nop(p);
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
default:
|
||||||
|
panic("No TLB refill handler yet (CPU type: %d)",
|
||||||
|
current_cpu_data.cputype);
|
||||||
|
--
|
||||||
|
1.5.6.5
|
||||||
|
|
156
target/linux/xburst/patches-2.6.31/050-nand.patch
Normal file
156
target/linux/xburst/patches-2.6.31/050-nand.patch
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
--- a/drivers/mtd/nand/Kconfig
|
||||||
|
+++ b/drivers/mtd/nand/Kconfig
|
||||||
|
@@ -420,4 +420,10 @@ config MTD_NAND_SH_FLCTL
|
||||||
|
Several Renesas SuperH CPU has FLCTL. This option enables support
|
||||||
|
for NAND Flash using FLCTL. This driver support SH7723.
|
||||||
|
|
||||||
|
+config MTD_NAND_JZ4740
|
||||||
|
+ tristate "Support NAND Flash device on Jz4740 board"
|
||||||
|
+ depends on SOC_JZ4740
|
||||||
|
+ help
|
||||||
|
+ Support NAND Flash device on Jz4740 board
|
||||||
|
+
|
||||||
|
endif # MTD_NAND
|
||||||
|
--- a/drivers/mtd/nand/Makefile
|
||||||
|
+++ b/drivers/mtd/nand/Makefile
|
||||||
|
@@ -40,5 +40,6 @@ obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_
|
||||||
|
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
|
||||||
|
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
|
||||||
|
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
|
||||||
|
+obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
|
||||||
|
|
||||||
|
nand-objs := nand_base.o nand_bbt.o
|
||||||
|
|
||||||
|
diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
|
||||||
|
index 4ce8e3a..ee5c90d 100644
|
||||||
|
--- a/arch/mips/jz4740/platform.c
|
||||||
|
+++ b/arch/mips/jz4740/platform.c
|
||||||
|
@@ -13,6 +13,7 @@
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/resource.h>
|
||||||
|
+#include <linux/mtd/jz4740_nand.h>
|
||||||
|
|
||||||
|
#include <asm/jzsoc.h>
|
||||||
|
|
||||||
|
@@ -152,12 +153,70 @@ static struct platform_device jz_i2c_device = {
|
||||||
|
.resource = jz_i2c_resources,
|
||||||
|
};
|
||||||
|
|
||||||
|
+static struct resource jz_nand_resources[] = {
|
||||||
|
+ [0] = {
|
||||||
|
+ .start = CPHYSADDR(EMC_BASE),
|
||||||
|
+ .end = CPHYSADDR(EMC_BASE) + 0x10000 - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct nand_ecclayout qi_lb60_ecclayout = {
|
||||||
|
+ .eccbytes = 36,
|
||||||
|
+ .eccpos = {
|
||||||
|
+ 6, 7, 8, 9, 10, 11, 12, 13,
|
||||||
|
+ 14, 15, 16, 17, 18, 19, 20, 21,
|
||||||
|
+ 22, 23, 24, 25, 26, 27, 28, 29,
|
||||||
|
+ 30, 31, 32, 33, 34, 35, 36, 37,
|
||||||
|
+ 38, 39, 40, 41},
|
||||||
|
+ .oobfree = {
|
||||||
|
+ {.offset = 0,
|
||||||
|
+ .length = 6},
|
||||||
|
+ {.offset = 42,
|
||||||
|
+ .length = 22}}
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct mtd_partition qi_lb60_partitions[] = {
|
||||||
|
+ { .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 = 20 * 0x100000,
|
||||||
|
+ },
|
||||||
|
+ { .name = "NAND DATA partition",
|
||||||
|
+ .offset = 100 * 0x100000,
|
||||||
|
+ .size = 20 * 0x100000,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct jz_nand_platform_data jz_nand_platform_data = {
|
||||||
|
+ .num_partitions = ARRAY_SIZE(qi_lb60_partitions),
|
||||||
|
+ .partitions = qi_lb60_partitions,
|
||||||
|
+ .ecc_layout = &qi_lb60_ecclayout,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device jz_nand_device = {
|
||||||
|
+ .name = "jz4740-nand",
|
||||||
|
+ .num_resources = ARRAY_SIZE(jz_nand_resources),
|
||||||
|
+ .resource = jz_nand_resources,
|
||||||
|
+ .dev = {
|
||||||
|
+ .platform_data = &jz_nand_platform_data,
|
||||||
|
+ }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
/* All */
|
||||||
|
static struct platform_device *jz_platform_devices[] __initdata = {
|
||||||
|
&jz_usb_ohci_device,
|
||||||
|
&jz_lcd_device,
|
||||||
|
&jz_usb_gdt_device,
|
||||||
|
&jz_mmc_device,
|
||||||
|
+ &jz_nand_device,
|
||||||
|
&jz_i2c_device,
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
|
||||||
|
index 92f0afe..08a7b37 100644
|
||||||
|
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
|
||||||
|
index 0a9c9cd..3870dcc 100644
|
||||||
|
--- a/drivers/mtd/nand/nand_base.c
|
||||||
|
+++ b/drivers/mtd/nand/nand_base.c
|
||||||
|
@@ -896,29 +896,22 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
|
uint8_t *ecc_calc = chip->buffers->ecccalc;
|
||||||
|
uint8_t *ecc_code = chip->buffers->ecccode;
|
||||||
|
uint32_t *eccpos = chip->ecc.layout->eccpos;
|
||||||
|
-
|
||||||
|
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
||||||
|
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
|
||||||
|
- chip->read_buf(mtd, p, eccsize);
|
||||||
|
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
||||||
|
- }
|
||||||
|
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||||
|
+ int stat;
|
||||||
|
|
||||||
|
for (i = 0; i < chip->ecc.total; i++)
|
||||||
|
ecc_code[i] = chip->oob_poi[eccpos[i]];
|
||||||
|
|
||||||
|
- eccsteps = chip->ecc.steps;
|
||||||
|
- p = buf;
|
||||||
|
-
|
||||||
|
- for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
||||||
|
- int stat;
|
||||||
|
|
||||||
|
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
||||||
|
+ 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;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1068,6 +1061,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||||
|
bufpoi = aligned ? buf : chip->buffers->databuf;
|
||||||
|
|
||||||
|
if (likely(sndcmd)) {
|
||||||
|
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0x00, page);
|
||||||
|
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||||
|
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
|
||||||
|
sndcmd = 0;
|
||||||
|
}
|
36
target/linux/xburst/patches-2.6.31/100-battery.patch
Normal file
36
target/linux/xburst/patches-2.6.31/100-battery.patch
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
From e8e05da0df412b041b9bb7d7d0dc30931a3e1344 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lars-Peter Clausen <lars@metafoo.de>
|
||||||
|
Date: Wed, 19 Aug 2009 14:47:33 +0200
|
||||||
|
Subject: [PATCH] battery
|
||||||
|
|
||||||
|
---
|
||||||
|
drivers/power/Kconfig | 5 +++++
|
||||||
|
drivers/power/Makefile | 1 +
|
||||||
|
2 files changed, 6 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
|
||||||
|
index bdbc4f7..3942136 100644
|
||||||
|
--- a/drivers/power/Kconfig
|
||||||
|
+++ b/drivers/power/Kconfig
|
||||||
|
@@ -103,4 +103,9 @@ config CHARGER_PCF50633
|
||||||
|
help
|
||||||
|
Say Y to include support for NXP PCF50633 Main Battery Charger.
|
||||||
|
|
||||||
|
+config BATTERY_JZ
|
||||||
|
+ tristate "JZ battery"
|
||||||
|
+ help
|
||||||
|
+ Say Y to enable support for the battery in JZ SOC.
|
||||||
|
+
|
||||||
|
endif # POWER_SUPPLY
|
||||||
|
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
|
||||||
|
index 380d17c..4eebbf5 100644
|
||||||
|
--- a/drivers/power/Makefile
|
||||||
|
+++ b/drivers/power/Makefile
|
||||||
|
@@ -28,3 +28,4 @@ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
|
||||||
|
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
|
||||||
|
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
|
||||||
|
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
|
||||||
|
+obj-$(CONFIG_BATTERY_JZ) += jz_battery.o
|
||||||
|
--
|
||||||
|
1.5.6.5
|
||||||
|
|
45
target/linux/xburst/patches-2.6.31/101-mmc.patch
Normal file
45
target/linux/xburst/patches-2.6.31/101-mmc.patch
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
From 18cd35fce85884d15b1c600dd6e132ed25d6954b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lars-Peter Clausen <lars@metafoo.de>
|
||||||
|
Date: Wed, 19 Aug 2009 14:47:20 +0200
|
||||||
|
Subject: [PATCH] mmc
|
||||||
|
|
||||||
|
---
|
||||||
|
drivers/mmc/host/Kconfig | 9 +++++++++
|
||||||
|
drivers/mmc/host/Makefile | 1 +
|
||||||
|
2 files changed, 10 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
|
||||||
|
index 891ef18..11e35bd 100644
|
||||||
|
--- a/drivers/mmc/host/Kconfig
|
||||||
|
+++ b/drivers/mmc/host/Kconfig
|
||||||
|
@@ -66,6 +66,15 @@ config MMC_RICOH_MMC
|
||||||
|
useless. It is safe to select this driver even if you don't
|
||||||
|
have a Ricoh based card reader.
|
||||||
|
|
||||||
|
+config MMC_JZ
|
||||||
|
+ tristate "JZ SD/Multimedia Card Interface support"
|
||||||
|
+ depends on SOC_JZ4720 || SOC_JZ4740
|
||||||
|
+ help
|
||||||
|
+ This selects the Ingenic JZ4720/JZ4740 SD/Multimedia card Interface.
|
||||||
|
+ If you have abIngenic platform with a Multimedia Card slot,
|
||||||
|
+ say Y or M here.
|
||||||
|
+
|
||||||
|
+ If unsure, say N.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here:
|
||||||
|
the module will be called ricoh_mmc.
|
||||||
|
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
|
||||||
|
index cf153f6..5396cd6 100644
|
||||||
|
--- a/drivers/mmc/host/Makefile
|
||||||
|
+++ b/drivers/mmc/host/Makefile
|
||||||
|
@@ -6,6 +6,7 @@ ifeq ($(CONFIG_MMC_DEBUG),y)
|
||||||
|
EXTRA_CFLAGS += -DDEBUG
|
||||||
|
endif
|
||||||
|
|
||||||
|
+obj-$(CONFIG_MMC_JZ) += jz_mmc.o
|
||||||
|
obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
|
||||||
|
obj-$(CONFIG_MMC_PXA) += pxamci.o
|
||||||
|
obj-$(CONFIG_MMC_IMX) += imxmmc.o
|
||||||
|
--
|
||||||
|
1.5.6.5
|
||||||
|
|
151
target/linux/xburst/patches-2.6.31/102-video.patch
Normal file
151
target/linux/xburst/patches-2.6.31/102-video.patch
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
From 2623194f73c9d272245263c8a54c7b1a63766e8e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lars-Peter Clausen <lars@metafoo.de>
|
||||||
|
Date: Wed, 19 Aug 2009 14:49:48 +0200
|
||||||
|
Subject: [PATCH] video
|
||||||
|
|
||||||
|
---
|
||||||
|
drivers/video/Kconfig | 113 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
drivers/video/Makefile | 3 +
|
||||||
|
2 files changed, 116 insertions(+), 0 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
|
||||||
|
index 3b54b39..3d5d623 100644
|
||||||
|
--- a/drivers/video/Kconfig
|
||||||
|
+++ b/drivers/video/Kconfig
|
||||||
|
@@ -237,6 +237,119 @@ config FB_TILEBLITTING
|
||||||
|
comment "Frame buffer hardware drivers"
|
||||||
|
depends on FB
|
||||||
|
|
||||||
|
+/************************************************************/
|
||||||
|
+config FB_JZSOC
|
||||||
|
+ tristate "JZSOC LCD controller support"
|
||||||
|
+ depends on FB && JZSOC
|
||||||
|
+ select FB_CFB_FILLRECT
|
||||||
|
+ select FB_CFB_COPYAREA
|
||||||
|
+ select FB_CFB_IMAGEBLIT
|
||||||
|
+ ---help---
|
||||||
|
+ JZSOC LCD Controller and Smart LCD Controller driver support.
|
||||||
|
+
|
||||||
|
+config FB_JZ4740_SLCD
|
||||||
|
+ tristate "JZ4740 Smart LCD controller support"
|
||||||
|
+ depends on FB_JZSOC && SOC_JZ4740
|
||||||
|
+ default n
|
||||||
|
+ ---help---
|
||||||
|
+ This is the frame buffer device driver for the JZ4740 Smart LCD controller.
|
||||||
|
+ If select this, please set <JZ4740 LCD controller support> to <n>.
|
||||||
|
+
|
||||||
|
+choice
|
||||||
|
+ depends on FB_JZ4740_SLCD
|
||||||
|
+ prompt "SLCD Panel"
|
||||||
|
+ default JZ_SLCD_LGDP4551_8BUS
|
||||||
|
+
|
||||||
|
+config JZ_SLCD_LGDP4551
|
||||||
|
+ bool "LG LGDP4551 Smart LCD panel"
|
||||||
|
+ ---help---
|
||||||
|
+ Driver for Smart LCD LGDP4551, 8-bit sytem interface, 16BPP.
|
||||||
|
+
|
||||||
|
+config JZ_SLCD_SPFD5420A
|
||||||
|
+ bool "SPFD5420A Smart LCD panel"
|
||||||
|
+ ---help---
|
||||||
|
+ Driver for Smart LCD SPFD5420A 18-bit sytem interface, 18BPP.
|
||||||
|
+
|
||||||
|
+config JZ_SLCD_TRULY
|
||||||
|
+ bool "TRULY Smart LCD panel (MAX Pixels 400x240)"
|
||||||
|
+ ---help---
|
||||||
|
+
|
||||||
|
+endchoice
|
||||||
|
+
|
||||||
|
+config FB_JZLCD_4730_4740
|
||||||
|
+ tristate "JZ4730 JZ4740 LCD controller support"
|
||||||
|
+ depends on FB_JZSOC && (SOC_JZ4730 || SOC_JZ4740)
|
||||||
|
+ help
|
||||||
|
+ This is the frame buffer device driver for the JZ4730 and JZ4740 LCD controller.
|
||||||
|
+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_CIRRUS
|
||||||
|
tristate "Cirrus Logic support"
|
||||||
|
depends on FB && (ZORRO || PCI)
|
||||||
|
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
|
||||||
|
index 01a819f..289b6e9 100644
|
||||||
|
--- a/drivers/video/Makefile
|
||||||
|
+++ b/drivers/video/Makefile
|
||||||
|
@@ -28,6 +28,9 @@ obj-$(CONFIG_FB_DDC) += fb_ddc.o
|
||||||
|
obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
|
||||||
|
|
||||||
|
# Hardware specific drivers go first
|
||||||
|
+obj-$(CONFIG_FB_JZLCD_4720_4740) += jzlcd.o
|
||||||
|
+obj-$(CONFIG_FB_JZ4740_SLCD) += jz4740_slcd.o
|
||||||
|
+
|
||||||
|
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o
|
||||||
|
obj-$(CONFIG_FB_ARC) += arcfb.o
|
||||||
|
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
|
||||||
|
--
|
||||||
|
1.5.6.5
|
||||||
|
|
178
target/linux/xburst/patches-2.6.31/103-serial.patch
Normal file
178
target/linux/xburst/patches-2.6.31/103-serial.patch
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
From 35d6fcb8cc04d368abef00b00e6af04b8c71ba46 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lars-Peter Clausen <lars@metafoo.de>
|
||||||
|
Date: Wed, 19 Aug 2009 14:54:02 +0200
|
||||||
|
Subject: [PATCH] serial
|
||||||
|
|
||||||
|
---
|
||||||
|
drivers/serial/8250.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||||
|
1 files changed, 103 insertions(+), 1 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
|
||||||
|
index fb867a9..d8784c3 100644
|
||||||
|
--- a/drivers/serial/8250.c
|
||||||
|
+++ b/drivers/serial/8250.c
|
||||||
|
@@ -194,7 +194,7 @@ static const struct serial8250_config uart_config[] = {
|
||||||
|
[PORT_16550A] = {
|
||||||
|
.name = "16550A",
|
||||||
|
.fifo_size = 16,
|
||||||
|
- .tx_loadsz = 16,
|
||||||
|
+ .tx_loadsz = 8,
|
||||||
|
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
|
||||||
|
.flags = UART_CAP_FIFO,
|
||||||
|
},
|
||||||
|
@@ -401,6 +401,10 @@ static unsigned int mem_serial_in(struct uart_port *p, int offset)
|
||||||
|
static void mem_serial_out(struct uart_port *p, int offset, int value)
|
||||||
|
{
|
||||||
|
offset = map_8250_out_reg(p, offset) << p->regshift;
|
||||||
|
+#if defined(CONFIG_JZSOC)
|
||||||
|
+ if (offset == (UART_FCR << p->regshift))
|
||||||
|
+ value |= 0x10; /* set FCR.UUE */
|
||||||
|
+#endif
|
||||||
|
writeb(value, p->membase + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -2213,6 +2217,83 @@ static void serial8250_shutdown(struct uart_port *port)
|
||||||
|
serial_unlink_irq_chain(up);
|
||||||
|
}
|
||||||
|
|
||||||
|
+#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
|
||||||
|
+static unsigned short quot1[3] = {0}; /* quot[0]:baud_div, quot[1]:umr, quot[2]:uacr */
|
||||||
|
+static unsigned short * serial8250_get_divisor(struct uart_port *port, unsigned int baud)
|
||||||
|
+{
|
||||||
|
+ int err, sum, i, j;
|
||||||
|
+ int a[12], b[12];
|
||||||
|
+ unsigned short div, umr, uacr;
|
||||||
|
+ unsigned short umr_best, div_best, uacr_best;
|
||||||
|
+ long long t0, t1, t2, t3;
|
||||||
|
+
|
||||||
|
+ sum = 0;
|
||||||
|
+ umr_best = div_best = uacr_best = 0;
|
||||||
|
+ div = 1;
|
||||||
|
+
|
||||||
|
+ if ((port->uartclk % (16 * baud)) == 0) {
|
||||||
|
+ quot1[0] = port->uartclk / (16 * baud);
|
||||||
|
+ quot1[1] = 16;
|
||||||
|
+ quot1[2] = 0;
|
||||||
|
+ return quot1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ while (1) {
|
||||||
|
+ umr = port->uartclk / (baud * div);
|
||||||
|
+ if (umr > 32) {
|
||||||
|
+ div++;
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ if (umr < 4) {
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ for (i = 0; i < 12; i++) {
|
||||||
|
+ a[i] = umr;
|
||||||
|
+ b[i] = 0;
|
||||||
|
+ sum = 0;
|
||||||
|
+ for (j = 0; j <= i; j++) {
|
||||||
|
+ sum += a[j];
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* the precision could be 1/2^(36) due to the value of t0 */
|
||||||
|
+ t0 = 0x1000000000LL;
|
||||||
|
+ t1 = (i + 1) * t0;
|
||||||
|
+ t2 = (sum * div) * t0;
|
||||||
|
+ t3 = div * t0;
|
||||||
|
+ do_div(t1, baud);
|
||||||
|
+ do_div(t2, port->uartclk);
|
||||||
|
+ do_div(t3, (2 * port->uartclk));
|
||||||
|
+ err = t1 - t2 - t3;
|
||||||
|
+
|
||||||
|
+ if (err > 0) {
|
||||||
|
+ a[i] += 1;
|
||||||
|
+ b[i] = 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ uacr = 0;
|
||||||
|
+ for (i = 0; i < 12; i++) {
|
||||||
|
+ if (b[i] == 1) {
|
||||||
|
+ uacr |= 1 << i;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* the best value of umr should be near 16, and the value of uacr should better be smaller */
|
||||||
|
+ if (abs(umr - 16) < abs(umr_best - 16) || (abs(umr - 16) == abs(umr_best - 16) && uacr_best > uacr)) {
|
||||||
|
+ div_best = div;
|
||||||
|
+ umr_best = umr;
|
||||||
|
+ uacr_best = uacr;
|
||||||
|
+ }
|
||||||
|
+ div++;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ quot1[0] = div_best;
|
||||||
|
+ quot1[1] = umr_best;
|
||||||
|
+ quot1[2] = uacr_best;
|
||||||
|
+
|
||||||
|
+ return quot1;
|
||||||
|
+}
|
||||||
|
+#else
|
||||||
|
static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
|
||||||
|
{
|
||||||
|
unsigned int quot;
|
||||||
|
@@ -2232,6 +2313,7 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int
|
||||||
|
|
||||||
|
return quot;
|
||||||
|
}
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
|
@@ -2241,6 +2323,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
|
unsigned char cval, fcr = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned int baud, quot;
|
||||||
|
+#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
|
||||||
|
+ unsigned short *quot1;
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
switch (termios->c_cflag & CSIZE) {
|
||||||
|
case CS5:
|
||||||
|
@@ -2273,7 +2358,12 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
|
* Ask the core to calculate the divisor for us.
|
||||||
|
*/
|
||||||
|
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
|
||||||
|
+#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
|
||||||
|
+ quot1 = serial8250_get_divisor(port, baud);
|
||||||
|
+ quot = quot1[0]; /* not usefull, just let gcc happy */
|
||||||
|
+#else
|
||||||
|
quot = serial8250_get_divisor(port, baud);
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Oxford Semi 952 rev B workaround
|
||||||
|
@@ -2351,6 +2441,10 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
|
if (up->capabilities & UART_CAP_UUE)
|
||||||
|
up->ier |= UART_IER_UUE | UART_IER_RTOIE;
|
||||||
|
|
||||||
|
+#ifdef CONFIG_JZSOC
|
||||||
|
+ up->ier |= UART_IER_RTOIE; /* Set this flag, or very slow */
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
serial_out(up, UART_IER, up->ier);
|
||||||
|
|
||||||
|
if (up->capabilities & UART_CAP_EFR) {
|
||||||
|
@@ -2385,7 +2479,15 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
|
serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
|
||||||
|
}
|
||||||
|
|
||||||
|
+#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
|
||||||
|
+#define UART_UMR 9
|
||||||
|
+#define UART_UACR 10
|
||||||
|
+ serial_dl_write(up, quot1[0]);
|
||||||
|
+ serial_outp(up, UART_UMR, quot1[1]);
|
||||||
|
+ serial_outp(up, UART_UACR, quot1[2]);
|
||||||
|
+#else
|
||||||
|
serial_dl_write(up, quot);
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
|
||||||
|
--
|
||||||
|
1.5.6.5
|
||||||
|
|
183
target/linux/xburst/patches-2.6.31/104-usb.patch
Normal file
183
target/linux/xburst/patches-2.6.31/104-usb.patch
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
From d6e1e759473e3b62bb2a7b906bbb27f1f1f2aff2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lars-Peter Clausen <lars@metafoo.de>
|
||||||
|
Date: Wed, 19 Aug 2009 14:54:18 +0200
|
||||||
|
Subject: [PATCH] usb
|
||||||
|
|
||||||
|
---
|
||||||
|
drivers/usb/Kconfig | 1 +
|
||||||
|
drivers/usb/core/hub.c | 43 +++++++++++++++++++++++++++++++++++++
|
||||||
|
drivers/usb/gadget/Kconfig | 18 ++++++++++++++-
|
||||||
|
drivers/usb/gadget/Makefile | 3 ++
|
||||||
|
drivers/usb/gadget/gadget_chips.h | 9 +++++++
|
||||||
|
5 files changed, 73 insertions(+), 1 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
|
||||||
|
index dcd49f1..a520bed 100644
|
||||||
|
--- a/drivers/usb/Kconfig
|
||||||
|
+++ b/drivers/usb/Kconfig
|
||||||
|
@@ -44,6 +44,7 @@ config USB_ARCH_HAS_OHCI
|
||||||
|
default y if PPC_MPC52xx
|
||||||
|
# MIPS:
|
||||||
|
default y if SOC_AU1X00
|
||||||
|
+ default y if JZSOC
|
||||||
|
# SH:
|
||||||
|
default y if CPU_SUBTYPE_SH7720
|
||||||
|
default y if CPU_SUBTYPE_SH7721
|
||||||
|
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
|
||||||
|
index 71f86c6..d3f9344 100644
|
||||||
|
--- a/drivers/usb/core/hub.c
|
||||||
|
+++ b/drivers/usb/core/hub.c
|
||||||
|
@@ -1857,6 +1857,25 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
||||||
|
{
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
@@ -2818,11 +2837,35 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||||
|
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 --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
|
||||||
|
index 7f8e83a..a973ce7 100644
|
||||||
|
--- a/drivers/usb/gadget/Kconfig
|
||||||
|
+++ b/drivers/usb/gadget/Kconfig
|
||||||
|
@@ -121,11 +121,24 @@ choice
|
||||||
|
#
|
||||||
|
# Integrated controllers
|
||||||
|
#
|
||||||
|
+config USB_GADGET_JZ4740
|
||||||
|
+ boolean "JZ4740 UDC"
|
||||||
|
+ depends on SOC_JZ4740
|
||||||
|
+ select USB_GADGET_DUALSPEED
|
||||||
|
+ help
|
||||||
|
+ Select this to support the Ingenic JZ4740 processor
|
||||||
|
+ high speed USB device controller.
|
||||||
|
+
|
||||||
|
+config USB_JZ4740
|
||||||
|
+ tristate
|
||||||
|
+ depends on USB_GADGET_JZ4740
|
||||||
|
+ default USB_GADGET
|
||||||
|
|
||||||
|
config USB_GADGET_AT91
|
||||||
|
boolean "Atmel AT91 USB Device Port"
|
||||||
|
depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9
|
||||||
|
select USB_GADGET_SELECTED
|
||||||
|
+
|
||||||
|
help
|
||||||
|
Many Atmel AT91 processors (such as the AT91RM2000) have a
|
||||||
|
full speed USB Device Port with support for five configurable
|
||||||
|
@@ -534,6 +547,10 @@ config USB_DUMMY_HCD
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
+config USB_JZ_UDC_HOTPLUG
|
||||||
|
+ boolean "Ingenic USB Device Controller Hotplug Support"
|
||||||
|
+ depends on USB_GADGET_JZ4750
|
||||||
|
+
|
||||||
|
config USB_GADGET_DUALSPEED
|
||||||
|
bool
|
||||||
|
depends on USB_GADGET
|
||||||
|
@@ -541,7 +558,6 @@ config USB_GADGET_DUALSPEED
|
||||||
|
help
|
||||||
|
Means that gadget drivers should include extra descriptors
|
||||||
|
and code to handle dual-speed controllers.
|
||||||
|
-
|
||||||
|
#
|
||||||
|
# USB Gadget Drivers
|
||||||
|
#
|
||||||
|
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
|
||||||
|
index e6017e6..b758686 100644
|
||||||
|
--- a/drivers/usb/gadget/Makefile
|
||||||
|
+++ b/drivers/usb/gadget/Makefile
|
||||||
|
@@ -27,6 +27,9 @@ obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
|
||||||
|
obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o
|
||||||
|
obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
|
||||||
|
obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
|
||||||
|
+obj-$(CONFIG_USB_JZ4740) += jz4740_udc.o
|
||||||
|
+
|
||||||
|
+obj-$(CONFIG_USB_JZ_UDC_HOTPLUG)+= udc_hotplug_core.o
|
||||||
|
|
||||||
|
#
|
||||||
|
# USB gadget drivers
|
||||||
|
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
|
||||||
|
index 8e0e9a0..d9c0990 100644
|
||||||
|
--- a/drivers/usb/gadget/gadget_chips.h
|
||||||
|
+++ b/drivers/usb/gadget/gadget_chips.h
|
||||||
|
@@ -15,6 +15,12 @@
|
||||||
|
#ifndef __GADGET_CHIPS_H
|
||||||
|
#define __GADGET_CHIPS_H
|
||||||
|
|
||||||
|
+#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_NET2280
|
||||||
|
#define gadget_is_net2280(g) !strcmp("net2280", (g)->name)
|
||||||
|
#else
|
||||||
|
@@ -239,6 +245,9 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
|
||||||
|
return 0x23;
|
||||||
|
else if (gadget_is_langwell(gadget))
|
||||||
|
return 0x24;
|
||||||
|
+ else if (gadget_is_jz4740(gadget))
|
||||||
|
+ return 0x25;
|
||||||
|
+
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
1.5.6.5
|
||||||
|
|
268
target/linux/xburst/patches-2.6.31/105-sound.patch
Normal file
268
target/linux/xburst/patches-2.6.31/105-sound.patch
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
From 1a6fa6adbd597171648c7cb308cc9e3efe488668 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lars-Peter Clausen <lars@metafoo.de>
|
||||||
|
Date: Wed, 19 Aug 2009 14:54:29 +0200
|
||||||
|
Subject: [PATCH] sound
|
||||||
|
|
||||||
|
---
|
||||||
|
include/sound/pcm.h | 26 ++++++------
|
||||||
|
sound/core/pcm_lib.c | 94 +++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
sound/core/pcm_native.c | 15 ++++++-
|
||||||
|
sound/soc/Kconfig | 1 +
|
||||||
|
sound/soc/Makefile | 1 +
|
||||||
|
sound/soc/codecs/Kconfig | 12 ++++++
|
||||||
|
sound/soc/codecs/Makefile | 2 +
|
||||||
|
7 files changed, 135 insertions(+), 16 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
|
||||||
|
index 2389352..24dcb18 100644
|
||||||
|
--- a/include/sound/pcm.h
|
||||||
|
+++ b/include/sound/pcm.h
|
||||||
|
@@ -113,23 +113,23 @@ struct snd_pcm_ops {
|
||||||
|
#define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */
|
||||||
|
#define SNDRV_PCM_RATE_8000 (1<<1) /* 8000Hz */
|
||||||
|
#define SNDRV_PCM_RATE_11025 (1<<2) /* 11025Hz */
|
||||||
|
-#define SNDRV_PCM_RATE_16000 (1<<3) /* 16000Hz */
|
||||||
|
-#define SNDRV_PCM_RATE_22050 (1<<4) /* 22050Hz */
|
||||||
|
-#define SNDRV_PCM_RATE_32000 (1<<5) /* 32000Hz */
|
||||||
|
-#define SNDRV_PCM_RATE_44100 (1<<6) /* 44100Hz */
|
||||||
|
-#define SNDRV_PCM_RATE_48000 (1<<7) /* 48000Hz */
|
||||||
|
-#define SNDRV_PCM_RATE_64000 (1<<8) /* 64000Hz */
|
||||||
|
-#define SNDRV_PCM_RATE_88200 (1<<9) /* 88200Hz */
|
||||||
|
-#define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */
|
||||||
|
-#define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */
|
||||||
|
-#define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */
|
||||||
|
+#define SNDRV_PCM_RATE_12000 (1<<3) /* 12000Hz */
|
||||||
|
+#define SNDRV_PCM_RATE_16000 (1<<4) /* 16000Hz */
|
||||||
|
+#define SNDRV_PCM_RATE_22050 (1<<5) /* 22050Hz */
|
||||||
|
+#define SNDRV_PCM_RATE_24000 (1<<6) /* 24000Hz */
|
||||||
|
+#define SNDRV_PCM_RATE_32000 (1<<7) /* 32000Hz */
|
||||||
|
+#define SNDRV_PCM_RATE_44100 (1<<8) /* 44100Hz */
|
||||||
|
+#define SNDRV_PCM_RATE_48000 (1<<9) /* 48000Hz */
|
||||||
|
+#define SNDRV_PCM_RATE_64000 (1<<10) /* 64000Hz */
|
||||||
|
+#define SNDRV_PCM_RATE_88200 (1<<11) /* 88200Hz */
|
||||||
|
+#define SNDRV_PCM_RATE_96000 (1<<12) /* 96000Hz */
|
||||||
|
+#define SNDRV_PCM_RATE_176400 (1<<13) /* 176400Hz */
|
||||||
|
+#define SNDRV_PCM_RATE_192000 (1<<14) /* 192000Hz */
|
||||||
|
|
||||||
|
#define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */
|
||||||
|
#define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */
|
||||||
|
|
||||||
|
-#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 --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
|
||||||
|
index 72cfd47..5ae0a2d 100644
|
||||||
|
--- a/sound/core/pcm_lib.c
|
||||||
|
+++ b/sound/core/pcm_lib.c
|
||||||
|
@@ -2076,6 +2076,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
|
||||||
|
return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
|
||||||
|
}
|
||||||
|
|
||||||
|
+#if 0
|
||||||
|
snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size)
|
||||||
|
{
|
||||||
|
struct snd_pcm_runtime *runtime;
|
||||||
|
@@ -2091,6 +2092,99 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u
|
||||||
|
return -EINVAL;
|
||||||
|
return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
|
||||||
|
}
|
||||||
|
+#else
|
||||||
|
+snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size)
|
||||||
|
+{
|
||||||
|
+ struct snd_pcm_runtime *runtime;
|
||||||
|
+ int nonblock;
|
||||||
|
+
|
||||||
|
+ snd_pcm_sframes_t tmp_frames;
|
||||||
|
+ snd_pcm_sframes_t final_frames;
|
||||||
|
+ int channels;
|
||||||
|
+
|
||||||
|
+ 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 --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
|
||||||
|
index ac2150e..2a57ab7 100644
|
||||||
|
--- a/sound/core/pcm_native.c
|
||||||
|
+++ b/sound/core/pcm_native.c
|
||||||
|
@@ -1748,12 +1748,13 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
|
||||||
|
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
-#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12
|
||||||
|
+#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 14
|
||||||
|
#error "Change this table"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,
|
||||||
|
- 48000, 64000, 88200, 96000, 176400, 192000 };
|
||||||
|
+static unsigned int rates[] = { 5512, 8000, 11025, 12000, 16000, 22050, 24000,
|
||||||
|
+ 32000, 44100, 48000, 64000, 88200, 96000,
|
||||||
|
+ 176400, 192000 };
|
||||||
|
|
||||||
|
const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
|
||||||
|
.count = ARRAY_SIZE(rates),
|
||||||
|
@@ -1764,9 +1765,17 @@ static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params,
|
||||||
|
struct snd_pcm_hw_rule *rule)
|
||||||
|
{
|
||||||
|
struct snd_pcm_hardware *hw = rule->private;
|
||||||
|
+#if 0
|
||||||
|
return snd_interval_list(hw_param_interval(params, rule->var),
|
||||||
|
snd_pcm_known_rates.count,
|
||||||
|
snd_pcm_known_rates.list, hw->rates);
|
||||||
|
+#else
|
||||||
|
+ //printk("hw->rates=0x%08x\n",hw->rates);//0x3b6
|
||||||
|
+ hw->rates = 0x3fe;//12KHz and 24KHz bits are all zero,you need set 1
|
||||||
|
+ return snd_interval_list(hw_param_interval(params, rule->var),
|
||||||
|
+ snd_pcm_known_rates.count,
|
||||||
|
+ snd_pcm_known_rates.list, hw->rates);
|
||||||
|
+#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params,
|
||||||
|
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
|
||||||
|
index d3e786a..a5335f4 100644
|
||||||
|
--- a/sound/soc/Kconfig
|
||||||
|
+++ b/sound/soc/Kconfig
|
||||||
|
@@ -35,6 +35,7 @@ source "sound/soc/s3c24xx/Kconfig"
|
||||||
|
source "sound/soc/s6000/Kconfig"
|
||||||
|
source "sound/soc/sh/Kconfig"
|
||||||
|
source "sound/soc/txx9/Kconfig"
|
||||||
|
+source "sound/soc/jz4740/Kconfig"
|
||||||
|
|
||||||
|
# Supported codecs
|
||||||
|
source "sound/soc/codecs/Kconfig"
|
||||||
|
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
|
||||||
|
index 6f1e28d..132772d 100644
|
||||||
|
--- a/sound/soc/Makefile
|
||||||
|
+++ b/sound/soc/Makefile
|
||||||
|
@@ -13,3 +13,4 @@ obj-$(CONFIG_SND_SOC) += s3c24xx/
|
||||||
|
obj-$(CONFIG_SND_SOC) += s6000/
|
||||||
|
obj-$(CONFIG_SND_SOC) += sh/
|
||||||
|
obj-$(CONFIG_SND_SOC) += txx9/
|
||||||
|
+obj-$(CONFIG_SND_SOC) += jz4740/
|
||||||
|
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
|
||||||
|
index bbc97fd..493e216 100644
|
||||||
|
--- a/sound/soc/codecs/Kconfig
|
||||||
|
+++ b/sound/soc/codecs/Kconfig
|
||||||
|
@@ -176,3 +176,15 @@ config SND_SOC_WM9712
|
||||||
|
|
||||||
|
config SND_SOC_WM9713
|
||||||
|
tristate
|
||||||
|
+
|
||||||
|
+config SND_SOC_ICODEC
|
||||||
|
+ tristate "Jz4740 internal codec"
|
||||||
|
+ depends on SND_SOC && SND_JZ4740_SOC_PAVO && SND_JZ4740_SOC_I2S
|
||||||
|
+ help
|
||||||
|
+ Say Y if you want to use internal codec on Ingenic Jz4740 PAVO board.
|
||||||
|
+
|
||||||
|
+config SND_SOC_DLV
|
||||||
|
+ tristate "Jz4750 internal codec"
|
||||||
|
+ depends on SND_SOC && SND_JZ4750_SOC_APUS && SND_JZ4750_SOC_I2S
|
||||||
|
+ help
|
||||||
|
+ Say Y if you want to use internal codec on Ingenic Jz4750 APUS board.
|
||||||
|
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
|
||||||
|
index 8b75305..f053c15 100644
|
||||||
|
--- a/sound/soc/codecs/Makefile
|
||||||
|
+++ b/sound/soc/codecs/Makefile
|
||||||
|
@@ -34,6 +34,7 @@ snd-soc-wm9081-objs := wm9081.o
|
||||||
|
snd-soc-wm9705-objs := wm9705.o
|
||||||
|
snd-soc-wm9712-objs := wm9712.o
|
||||||
|
snd-soc-wm9713-objs := wm9713.o
|
||||||
|
+snd-soc-jzcodec-objs := jzcodec.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
|
||||||
|
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
|
||||||
|
@@ -71,3 +72,4 @@ obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o
|
||||||
|
obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
|
||||||
|
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
|
||||||
|
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
|
||||||
|
+obj-$(CONFIG_SND_SOC_ICODEC) += snd-soc-jzcodec.o
|
||||||
|
--
|
||||||
|
1.5.6.5
|
||||||
|
|
319
target/linux/xburst/patches-2.6.31/200-qi_lb60.patch
Normal file
319
target/linux/xburst/patches-2.6.31/200-qi_lb60.patch
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
--- /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 <xiangfu@qi-hardware.com>
|
||||||
|
+ *
|
||||||
|
+ * 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 <linux/init.h>
|
||||||
|
+#include <linux/sched.h>
|
||||||
|
+#include <linux/ioport.h>
|
||||||
|
+#include <linux/mm.h>
|
||||||
|
+#include <linux/console.h>
|
||||||
|
+#include <linux/delay.h>
|
||||||
|
+
|
||||||
|
+#include <asm/cpu.h>
|
||||||
|
+#include <asm/bootinfo.h>
|
||||||
|
+#include <asm/mipsregs.h>
|
||||||
|
+#include <asm/reboot.h>
|
||||||
|
+
|
||||||
|
+#include <asm/jzsoc.h>
|
||||||
|
+
|
||||||
|
+extern void (*jz_timer_callback)(void);
|
||||||
|
+
|
||||||
|
+static void dancing(void)
|
||||||
|
+{
|
||||||
|
+ static unsigned int count = 0;
|
||||||
|
+
|
||||||
|
+ count ++;
|
||||||
|
+ count &= 1;
|
||||||
|
+ if (count)
|
||||||
|
+ __gpio_set_pin(GPIO_LED_EN);
|
||||||
|
+ else
|
||||||
|
+ __gpio_clear_pin(GPIO_LED_EN);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void 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
|
||||||
|
@@ -655,6 +655,14 @@ choice
|
||||||
|
Kodama
|
||||||
|
Hikari
|
||||||
|
Say Y here for most Octeon reference boards.
|
||||||
|
+
|
||||||
|
+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
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
--- 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/arch/mips/include/asm/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 <xiangfu@qi-hardware.com>
|
||||||
|
+ *
|
||||||
|
+ * 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/arch/mips/include/asm/mach-jz4740/jz4740.h
|
||||||
|
+++ b/arch/mips/include/asm/mach-jz4740/jz4740.h
|
||||||
|
@@ -43,6 +43,10 @@
|
||||||
|
#include <asm/mach-jz4740/board-virgo.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#ifdef CONFIG_JZ4740_QI_LB60
|
||||||
|
+#include <asm/mach-jz4740/board-qi_lb60.h>
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/* Add other platform definition here ... */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user